Sentinel是面向分布式服務架構的流量控制組件,主要以流量為切入點,從限流、流量整形、熔斷降級、系統負載保護、熱點防護等多個維度來幫助開發者保障微服務的穩定性。本文主要介紹Sentinel的基本使用,文中使用到的軟件版本:Sentinel 1.3.2、Spring Boot 2.2.5.RELEASE、Spring Cloud Hoxton.SR3、Java 1.8.0_191。
1、簡介
隨着微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
1.1、Sentinel特性
1.2、Sentinel組成部分
a、核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
b、控制台(Dashboard)基於 Spring Boot 開發,打包后可以直接運行,不需要額外的 Tomcat 等應用容器。
2、規則
Sentinel的所有規則都可以在內存中動態地查詢及修改,修改之后立即生效。同時Sentinel也提供相關API,供您來定制自己的規則策略。Sentinel支持以下幾種規則:流量控制規則、熔斷降級規則、系統保護規則、來源訪問控制規則和熱點參數規則。
2.1、流量控制規則(FlowRule)
同一個資源可以同時有多個限流規則,檢查規則時會依次檢查。其重要屬性:
Field | 說明 | 默認值 |
---|---|---|
resource | 資源名,資源名是限流規則的作用對象 | |
count | 限流閾值 | |
grade | 限流閾值類型,QPS 模式(1)或並發線程數模式(0) | QPS 模式 |
limitApp | 流控針對的調用來源 | default ,代表不區分調用來源 |
strategy | 調用關系限流策略:直接、鏈路、關聯 | 根據資源本身(直接) |
controlBehavior | 流控效果(直接拒絕/WarmUp/勻速+排隊等待),不支持按調用關系限流 | 直接拒絕 |
clusterMode | 是否集群限流 | 否 |
編碼方式定義規則:
private void initFlowQpsRule() { List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(resourceName); // set limit qps to 20 rule.setCount(20); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setLimitApp("default"); rules.add(rule); FlowRuleManager.loadRules(rules); }
2.2、熔斷降級規則(DegradeRule)
同一個資源可以同時有多個降級規則。其重要屬性:
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 void initDegradeRule() { List<DegradeRule> rules = new ArrayList<>(); DegradeRule rule = new DegradeRule(); rule.setResource(KEY); // set threshold RT, 10 ms rule.setCount(10); rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); rule.setTimeWindow(10); rules.add(rule); DegradeRuleManager.loadRules(rules); }
2.3、系統保護規則(SystemRule)
Sentinel系統自適應限流從整體維度對應用入口流量進行控制,結合應用的 Load、CPU 使用率、總體平均 RT、入口 QPS 和並發線程數等幾個維度的監控指標,通過自適應的流控策略,讓系統的入口流量和系統的負載達到一個平衡,讓系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性。其重要屬性:
Field | 說明 | 默認值 |
---|---|---|
highestSystemLoad | load1 觸發值,用於觸發自適應控制階段 |
-1 (不生效) |
avgRt | 所有入口流量的平均響應時間 | -1 (不生效) |
maxThread | 入口流量的最大並發數 | -1 (不生效) |
qps | 所有入口資源的 QPS | -1 (不生效) |
highestCpuUsage | 當前系統的 CPU 使用率(0.0-1.0) | -1 (不生效) |
編碼方式定義規則:
private void initSystemRule() { List<SystemRule> rules = new ArrayList<>(); SystemRule rule = new SystemRule(); rule.setHighestSystemLoad(10); rules.add(rule); SystemRuleManager.loadRules(rules); }
2.4、訪問控制規則(AuthorityRule)
很多時候,我們需要根據調用方來限制資源是否通過,這時候可以使用 Sentinel 的訪問控制(黑白名單)的功能。其重要屬性:
resource:資源名,即規則的作用對象
limitApp:對應的黑名單/白名單,不同 origin 用 , 分隔,如 appA,appB
strategy:限制模式,AUTHORITY_WHITE 為白名單模式,AUTHORITY_BLACK 為黑名單模式,默認為白名單模式
編碼方式定義規則:
AuthorityRule rule = new AuthorityRule(); rule.setResource("test"); rule.setStrategy(RuleConstant.AUTHORITY_WHITE); rule.setLimitApp("appA,appB"); AuthorityRuleManager.loadRules(Collections.singletonList(rule));
2.5、熱點規則(ParamFlowRule)
熱點參數限流會統計傳入參數中的熱點參數,並根據配置的限流閾值與模式,對包含熱點參數的資源調用進行限流。熱點參數限流可以看做是一種特殊的流量控制,僅對包含熱點參數的資源調用生效。其重要屬性類似於流量控制規則:
屬性 | 說明 | 默認值 |
---|---|---|
resource | 資源名,必填 | |
count | 限流閾值,必填 | |
grade | 限流模式 | QPS 模式 |
durationInSec | 統計窗口時間長度(單位為秒),1.6.0 版本開始支持 | 1s |
controlBehavior | 流控效果(支持快速失敗和勻速排隊模式),1.6.0 版本開始支持 | 快速失敗 |
maxQueueingTimeMs | 最大排隊等待時長(僅在勻速排隊模式生效),1.6.0 版本開始支持 | 0ms |
paramIdx | 熱點參數的索引,必填,對應 SphU.entry(xxx, args) 中的參數索引位置 |
|
paramFlowItemList | 參數例外項,可以針對指定的參數值單獨設置限流閾值,不受前面 count 閾值的限制。僅支持基本類型和字符串類型 |
|
clusterMode | 是否是集群參數流控規則 | false |
clusterConfig | 集群流控相關配置 |
編碼方式定義規則:
ParamFlowRule rule = new ParamFlowRule(resourceName) .setParamIdx(0) .setCount(5); // 針對 int 類型的參數 PARAM_B,單獨設置限流 QPS 閾值為 10,而不是全局的閾值 5. ParamFlowItem item = new ParamFlowItem().setObject(String.valueOf(PARAM_B)) .setClassType(int.class.getName()) .setCount(10); rule.setParamFlowItemList(Collections.singletonList(item)); ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
3、使用
3.1、拋出異常方式使用
SphU包含了try-catch風格的 API。用這種方式,當資源發生了限流之后會拋出 BlockException。這個時候可以捕捉異常,進行限流之后的邏輯處理。
3.1.1、引入依賴
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>1.8.0</version> </dependency>
3.1.2、樣例
package com.inspur.demo.test; import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import java.util.ArrayList; import java.util.List; public class Sentinel { public static void main(String[] args) { // 配置規則. initFlowRules(); test(); } private static void test() { while(true) { // 1.5.0 版本開始可以直接利用 try-with-resources 特性 Entry entry = null; try { entry = SphU.entry("HelloWorld"); // 被保護的邏輯 System.out.println("hello world"); //Thread.sleep(1000 * 10); } catch (BlockException ex) { // 處理被流控的邏輯 System.out.println("blocked!"); } catch (Exception e) { e.printStackTrace(); } finally { if (entry != null) entry.exit(); } } } private static void initFlowRules(){ List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(); rule.setResource("HelloWorld"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // Set limit QPS to 20. rule.setCount(10); rules.add(rule); FlowRuleManager.loadRules(rules); } }
3.2、結合Spring Cloud使用
3.2.1、引入依賴
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.3.RELEASE</version> </dependency>
3.2.2、注解方式使用sentinel
@SentinelResource注解用來標識資源是否被限流、降級。
package com.inspur.scdemo.server.service; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import org.springframework.stereotype.Service; @Service public class SentinelService { @SentinelResource(value = "sentinel-test", blockHandler = "blockHandler", fallback = "fallback") public String test(long id) { // if (true) { // throw new RuntimeException("a"); // } return "test"; } /** * Block異常處理函數,用來處理Sentinel限流/熔斷等錯誤 * 參數最后多一個BlockException,其余與原函數一致 */ public String blockHandler(long id, BlockException e) { e.printStackTrace(); return "blockHandler"; } /** * Fallback函數,用來處理接口中業務代碼所有異常 * 函數簽名與原函數一致或加一個 Throwable 類型的參數. */ public String fallback(long id) { return "fallback"; } }
package com.inspur.scdemo.server.controller; import com.inspur.scdemo.server.service.SentinelService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/sentinel") public class SentinelController { private Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired private SentinelService service; @RequestMapping("/test") public String test(long id) { logger.info(id + ""); return service.test(id); } @RequestMapping("/test2") public String test2(long id) { logger.info(id + ""); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return "test2"; } }
一般推薦將@SentinelResource注解加到服務實現上,而在Web層可以在snetinel控制台查看url並定義規則。
3.2.3、sentinel控制台
Sentinel控制台提供一個輕量級的控制台,它提供機器發現、單機資源實時監控、集群資源匯總,以及規則管理的功能。直接使用Spring Cloud Alibaba自帶的Web埋點適配。
a、下載控制台的安裝包
https://github.com/alibaba/Sentinel/releases
b、啟動
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
c、控制台
http://10.49.196.10:8080/ 用戶名/密碼為:sentinel/sentinel
3.2.4、SpingCloud應用中配置Sentinel控制台地址
spring: cloud: sentinel: transport: port: 8719 dashboard: 10.49.196.10:8080 project: name: scdemo-server
啟動應用后並訪問響應的url,sentinel控制台會出現監控信息:
可以在對應的url后定義流控規則:
定義降級規則: