9.Spring Cloud Alibaba Sentinel流控熔斷元件
Sentinel
Sentinel 是面向分散式服務架構的高可用防護元件,主要以流量為切入點,從流量控制、熔斷降級、系統自適應保護等多個維度來幫助使用者保障微服務的穩定性。
GitHub:Sentinel
官網:Sentinel
Sentinel 功能和設計理念
-
流量控制
任意時間到來的請求往往是不可控的,而系統的處理能力是有限的。這就需要根據系統的能力對流量進行控制。
流量控制有一下幾個角度:
- 資源的呼叫關係(資源的呼叫鏈路,資源與資源之間的關係等)
- 執行指標(QPS、執行緒池、系統負載等)
- 控制的效果(直接限流、冷啟動、排隊等)
Sentinel的設計可以自由選擇控制的角度,並進行靈活的組合,從而達到理想的效果。
-
熔斷降級
Sentinel和Hystrix的原則是一致的:當呼叫鏈路中某個資源不穩定,則對這個資源的呼叫進行限制,並讓請求快速失敗,避免影響其他的資源,導致請求發生堆積,產生雪崩效應。
在限制手段上,Hystrix通過執行緒池的方式,使資源和資源之間做到了徹底的隔離。缺點是增加了執行緒切換的成本,還需預先給各個資源做執行緒池大小分配。
Sentinel對這個問題採取兩種手段:
-
通過併發數進行限制
當執行緒數在特定資源上堆積到一定數量,對該資源的新請求會被拒絕,堆積的執行緒完成任務後才開始繼續接收請求。
-
通過響應時間對資源進行降級
當依賴的資源響應時間過長,所有對該資源的訪問都被直接拒絕,直到過了指定的時間視窗之後才恢復。
-
-
系統負載保護
當系統負載較高的時候,如果還持續讓請求進入,可能會導致系統崩潰,無法響應。在叢集環境下,網路負載會把本應這臺機器承載的流量轉發到其他機器上,如果此時其他機器也處在一個邊緣狀態,增加的流量就會導致這臺機器也崩潰,最終導致整個叢集不可用。針對這個情況,Sentinel提供了對應的保護機制,讓系統的入口流量和系統的負載達到一個平衡,保證系統在能力範圍內處理最多的請求。
Sentinel 的主要工作機制如下:
- 對主流框架提供適配或者顯示的 API,來定義需要保護的資源,並提供設施對資源進行實時統計和呼叫鏈路分析。
- 根據預設的規則,結合對資源的實時統計資訊,對流量進行控制。同時,Sentinel 提供開放的介面,方便您定義及改變規則。
- Sentinel 提供實時的監控系統,方便您快速瞭解目前系統的狀態。
關於更加詳細的介紹,這裡就不在介紹了,直接去官網檢視官方文件,以及GitHub上面給的例子即可。
demo:sentinel-demo
上手使用
-
準備工作
上篇部落格使用了Spring Cloud Alibaba Nacos作為服務註冊中心,並在Idea中使用Alibaba Cloud Tookit外掛建立專案。這裡沿用昨天的book-service服務,再新建student-service服務,並使用OpenFeign呼叫book-service的服務。關於OpenFeign宣告式服務呼叫在前面部落格也講解過,直接使用即可。引入OpenFeign依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
先在book-service中編寫demo
在student-service中編寫demo,並使用OpenFeign呼叫book-service中的服務。這裡要在啟動類新增
@EnableFeignClients
在Nacos中確認兩個服務均已註冊。
補充一下:這裡為啥啟動類中沒有加
@EnableDiscoveryClient
?我們在檢視生成的專案中,有一個nacosdiscovery包中有一個NacosDiscoveryConfiguration
,該類中新增了@EnableDiscoveryClient
註解執行student-service呼叫book-service服務
-
安裝Sentinel Dashboard
下載地址:Sentinel Dashboard
下載完成以後,可以在本地執行。
java -jar sentinel-dashboard-1.8.0.jar
。啟動以後發現Sentinel Dashboard的預設埠為8080,佔用了別的埠,直接修改啟動埠:java -jar -Dserver.port=8888 sentinel-dashboard-1.8.0.jar
直接訪問ip+port 訪問(使用者名稱密碼均為sentinel)
這裡面暫時是沒有服務列表的。需要在服務中進行配置登記。
-
服務呼叫方(student-service)新增Sentinel依賴。完整核心pom.xml
<properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.3.4.RELEASE</spring-boot.version> <spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version> <spring-cloud.version>Hoxton.SR8</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
在配置檔案中新增配置:
spring: application: name: student-service cloud: nacos: discovery: username: nacos password: nacos server-addr: localhoost:8848 sentinel: transport: dashboard: localhost:8888
啟動專案呼叫服務後,重新整理Sentinel Dashboard頁面。
我們可以在這裡設定流控、降級。根據不同的情況設定。
設定流控
設定降級
這裡簡單驗證:設定流控
頻繁重新整理以後
補充:以student-service為例,微服務如何與Sentinel Dashboard通訊?
在微服務中引入Sentinel依賴以後,微服務中有一個sentinel-transport-simple-http客戶端,該客戶端預設在主機上開啟一個新的埠(並不會使用微服務的埠),預設從8719開始,如果埠被佔用,依次+1再次嘗試。
sentinel-transport-simple-http客戶端會獲取微服務的狀態等資訊,進行健康檢查(預設10秒向Sentinel Dashboard傳送心跳包通知健康狀態)。而如果我們在Sentinel Dashboard中設定了微服務的流控,降級,則Sentinel Dashboard會呼叫sentinel-transport-simple-http客戶端中提供的API進行設定。
從Sentinel Dashboard中我們看到微服務student-service中的sentinel-transport-simple-http埠為8720(8719已經被佔用了)。我們直接訪問
ip
+port
+/api
-
上面的方法是在Sentinel Dashboard中設定流控,降級規則,我們也可以在程式碼中實現:
流量規則
Field 說明 預設值 resource 資源名,資源名是限流規則的作用物件 count 限流閾值 grade 限流閾值型別,QPS 或執行緒數模式 QPS 模式 limitApp 流控針對的呼叫來源 default
,代表不區分呼叫來源strategy 呼叫關係限流策略:直接、鏈路、關聯 根據資源本身(直接) controlBehavior 流控效果(直接拒絕 / 排隊等待 / 慢啟動模式),不支援按呼叫關係限流 直接拒絕 private void initFlowRule(){ List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); //設定資源名稱 rule.setResource("/student/info/{stuNo}/{id}"); //設定限流閾值 rule.setCount(100); //設定限流閾值型別 rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //設定策略 rule.setStrategy(RuleConstant.STRATEGY_DIRECT); //設定流控效果 設為預熱 rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP); //設定預熱時間 rule.setWarmUpPeriodSec(10); //設定呼叫來源 rule.setLimitApp("default"); rules.add(rule); //定義流量控制規則 FlowRuleManager.loadRules(rules); }
熔斷降級規則
Field 說明 預設值 resource 資源名,即規則的作用物件 grade 熔斷策略,支援慢呼叫比例/異常比例/異常數策略 慢呼叫比例 count 慢呼叫比例模式下為慢呼叫臨界 RT(超出該值計為慢呼叫);異常比例/異常數模式下為對應的閾值 timeWindow 熔斷時長,單位為 s minRequestAmount 熔斷觸發的最小請求數,請求數小於該值時即使異常比率超出閾值也不會熔斷(1.7.0 引入) 5 statIntervalMs 統計時長(單位為 ms),如 60*1000 代表分鐘級(1.8.0 引入) 1000 ms slowRatioThreshold 慢呼叫比例閾值,僅慢呼叫比例模式有效(1.8.0 引入) private static void initDegradeRule() { List<DegradeRule> rules = new ArrayList<>(); DegradeRule rule = new DegradeRule("/student/info/{stuNo}/{id}"); rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType()) .setCount(0.7) .setMinRequestAmount(100) .setStatIntervalMs(30000) .setTimeWindow(10); rules.add(rule); DegradeRuleManager.loadRules(rules); }
系統保護規則
Field 說明 預設值 highestSystemLoad load1
觸發值,用於觸發自適應控制階段-1 (不生效) avgRt 所有入口流量的平均響應時間 -1 (不生效) maxThread 入口流量的最大併發數 -1 (不生效) qps 所有入口資源的 QPS -1 (不生效) highestCpuUsage 當前系統的 CPU 使用率(0.0-1.0) -1 (不生效) private void initSystemProtectionRule() { List<SystemRule> rules = new ArrayList<>(); SystemRule rule = new SystemRule(); rule.setHighestSystemLoad(1.0); rules.add(rule); SystemRuleManager.loadRules(rules); }
更多講解,參見文件:基本使用 - 資源與規則
-
Sentinel異常處理
通過之前的測試,從頁面返回的資訊檢視不夠完整。
這裡新建異常處理類,實現
BlockExceptionHandler
/** * 自定義Sentinel異常返回資訊 */ @Component public class BlockHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception { String message = null; if(e instanceof FlowException){ message = "請求已被限流!"; } if(e instanceof DegradeException){ message = "熔斷!"; } if(e instanceof ParamFlowException){ message = "熱點資料限流"; } if(e instanceof SystemBlockException){ message = "系統規則異常"; } if(e instanceof AuthorityException){ message = "授權規則異常"; } httpServletResponse.setStatus(500); httpServletResponse.setCharacterEncoding("utf-8"); httpServletResponse.setContentType("application/json"); //使用ObjectMapper將物件轉換成字串 ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.writeValue(httpServletResponse.getWriter(),new Result(500,message)); } }
補充:統一返回結果類
public class Result<T> { private Integer code; private String message; private T data; public Result(){} public Result(T data){ this.code = 200; this.message = "success"; this.data = data; } public Result(Integer code, T data) { this.code = code; this.data = data; } public Result(Integer code, String message, T data) { this.code = code; this.message = message; this.data = data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
設定限流規則以後再次嘗試重新整理
-
Sentinel與OpenFeign整合
配置檔案中新增配置
feign: sentinel: enabled: true
編寫fallback回撥方法
@FeignClient(name = "book-service",fallbackFactory = BookServiceFallback.class) public interface BookService { @GetMapping("/book/info/{id}") Result<Book> bookMessage(@PathVariable("id")String id); }
回撥
@Component public class BookServiceFallback implements FallbackFactory<BookService> { @Override public BookService create(Throwable throwable) { return new BookService() { @Override public Result<Book> bookMessage(String id) { return new Result<>(500,throwable.getMessage(),null); } }; } }
劃重點:
- 回撥方法實現
FallbackFactory
介面並新增對應的泛型。 - 實現create方法,編寫回撥邏輯。
- 新增
@Component
註解
- 回撥方法實現
-
Sentinel在Nacos配置中心配置持久化
在上述進行試驗驗證的過程中,會發現專案每次重啟以後,設定的限流策略就失效了,需要重新設定。Nacos作為配置中心的講解,後續在部落格中更新。
訪問Nacos地址,在配置管理類-》配置列表中新建配置
這裡的值與規則列表中的值一致。
引入依賴
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
配置檔案中新建配置
完整配置檔案
server:
port: 8050
spring:
application:
name: student-service
cloud:
nacos:
discovery:
username: nacos
password: nacos
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8888
datasource:
flow-bs: #自定義名稱
nacos:
server-addr: localhost:8848
username: nacos
password: nacos
dataId: book-service-rule #data id
groupId: DEFAULT_GROUP #分組
ruleType: flow #flow代表流控規則,degrade代表熔斷規則
feign:
sentinel:
enabled: true
同理配置熔斷規則與限流規則一樣操作即可(在Nacos中新建配置)。
在配置檔案中新增配置:
驗證:
重啟專案,呼叫服務後,直接在Sentinel Dashboard流控規則中可看到。
相關文章
- Spring Cloud Alibaba:Sentinel實現熔斷與限流SpringCloud
- 一個名叫Sentinel-Rules-SDK的元件,使得Sentinel的流控&熔斷規則的配置更加方便元件
- Spring Cloud Alibaba元件之SentinelSpringCloud元件
- 微服務架構 | 5.4 Sentinel 流控、統計和熔斷的原始碼分析微服務架構原始碼
- Spring Cloud Alibaba SentinelSpringCloud
- SpringMvc整合開源流量監控、限流、熔斷降級、負載保護元件SentinelSpringMVC負載元件
- 記一次spring cloud alibaba+Sentinel監控整合SpringCloud
- Spring-Cloud-Alibaba之SentinelSpringCloud
- Spring Cloud Alibaba(9)---Sentinel概述SpringCloud
- Sentinel 成為 Spring Cloud 官方推薦的主流熔斷降級方案SpringCloud
- Spring Cloud Alibaba教程:Sentinel的使用SpringCloud
- Spring Cloud Alibaba(四)--Gateway與SentinelSpringCloudGateway
- 《重磅 | Sentinel 成為 Spring Cloud 官方推薦的主流熔斷降級方案》SpringCloud
- Spring cloud(4)-熔斷(Hystrix)SpringCloud
- [Spring-Cloud-Alibaba] Sentinel 規則持久化SpringCloud持久化
- Spring Cloud Alibaba(11)---Sentinel+Nacos持久化SpringCloud持久化
- Sentinel入門到實操 (限流熔斷降級)
- 一篇搞定Sentinel-搭建Spring Cloud Alibaba服務元件Sentinel實現服務資源控制SpringCloud元件
- Sentinel分散式限流元件,SpringCloud Alibaba整合分散式元件SpringGCCloud
- Spring Cloud Alibaba | Sentinel: 服務限流基礎篇SpringCloud
- Spring Cloud Alibaba | Sentinel: 服務限流高階篇SpringCloud
- springcloud(六):熔斷監控TurbineSpringGCCloud
- Spring Cloud Alibaba系列(六)sentinel的實際應用SpringCloud
- Spring Cloud Alibaba Sentinel 主要原理和核心類介紹SpringCloud
- Sentinel全域性Feign預設熔斷設計實現
- 聊聊自定義SPI如何與sentinel整合實現熔斷限流
- springcloud(五):熔斷監控Hystrix DashboardSpringGCCloud
- Spring Cloud Alibaba - Sentinel入門案例(四)(熱點規則 )SpringCloud
- Spring Cloud Alibaba基礎教程:使用Sentinel實現介面限流SpringCloud
- spring cloud alibaba系列(二)Sentinel應用的限流管理SpringCloud
- Spring Cloud Alibaba(10)---Sentinel控制檯搭建+整合SpringCloudAlibabaSpringCloudGC
- 當Spring Cloud Alibaba Sentinel碰上Spring Cloud Sleuth會擦出怎樣的火花SpringCloud
- Spring Cloud實戰系列(四) - 熔斷器HystrixSpringCloud
- Spring Cloud Feign 熔斷機制填坑SpringCloud
- Spring Cloud Alibaba系列(五)sentinel實現服務限流降級SpringCloud
- Spring Cloud Alibaba基礎教程:Sentinel使用Apollo儲存規則SpringCloud
- Spring Cloud Alibaba基礎教程:Sentinel使用Nacos儲存規則SpringCloud
- 微服務架構 | 5.2 基於 Sentinel 的服務限流及熔斷微服務架構