上一篇文章我們已經(jīng)對(duì) Sentinel 有個(gè)簡(jiǎn)單的了解,接下來我們將講解 Sentinel的具體使用。
Sentinel的使用分為兩部分:
- Sentinel-Dashboard: 與 Hystrix-Dashboard類似,但是它的功能更加強(qiáng)大。除了與 hystrix-dashboard 一樣提供實(shí)時(shí)監(jiān)控之外,還提供了流控規(guī)則、熔斷規(guī)則的在線維護(hù)等功能。
- 客戶端整合:每個(gè)微服務(wù)客戶端都需要整合 sentinel 的客戶端封裝與配置,才能將監(jiān)控信息上報(bào)給 dashboard 展示以及實(shí)時(shí)的更改限流或熔斷規(guī)則等。
下面我們就分兩部分來看,如果使用Sentinel來實(shí)現(xiàn)接口限流。
部署Sentinel Dashboard
- 下載地址:Sentinel/releases
這里我采用最新版:sentinel-dashboard-1.6.2.jar
命令行啟動(dòng)
java -jar sentinel-dashboard-1.6.2.jar
sentinel-dashboard 不像Nacos的服務(wù)端那樣還提供了外置配置文件,比較容易修改參數(shù)。不過沒關(guān)系,由于 sentinel-dashboard是一個(gè)標(biāo)準(zhǔn)的SpringBoot應(yīng)用,所以如果需要自定義端口號(hào)等配置的話,可以通過在啟動(dòng)參數(shù)中增加參數(shù)來調(diào)整,比如:-Dserver.port=8888。
默認(rèn)情況下,sentinel-dashboard以8080端口啟動(dòng),所以可以通過訪問: http://localhost:8080 來驗(yàn)證是否啟動(dòng)成功,如果一切順利,可以看到如下界面:

注意: 只要 1.6.0 及以上的版本,才有這個(gè)簡(jiǎn)單的登錄頁面。默認(rèn)用戶名密碼都是: sentinel。對(duì)于用戶登錄相關(guān)的配置可在啟動(dòng)命令中添加下面參數(shù)來修改默認(rèn)配置:
-
Dsentinel.dashboard.auth.username=sentinel:用于指定控制臺(tái)的登錄用戶名為 sentinel; -
Dsentinel.dashboard.auth.password=123456:用于指定控制臺(tái)的登錄密碼為 123456;如果省略這兩個(gè)參數(shù),默認(rèn)用戶和密碼均為 sentinel -
Dserver.servlet.session.timeout=7200:用于指定 Spring Boot 服務(wù)端 session 的過期時(shí)間,如 7200 表示 7200 秒;60m 表示 60 分鐘,默認(rèn)為 30 分鐘;
輸入用戶名密碼登錄后,會(huì)看下如下頁面:

整合Sentinel
第一步: 創(chuàng)建 alibaba-sentinel-rate-limiting web應(yīng)用,并在的pom.xml 中引入 Spring Cloud Alibaba的Sentinel模塊依賴:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
第二步: 在Spring Cloud 應(yīng)用中 application.yml 配置 sentinel dashboard 的訪問地址:
spring:
cloud:
sentinel:
transport:
# 指定sentinel控制臺(tái)地址
dashboard: localhost:8080
控制臺(tái)相關(guān)配置項(xiàng):
| 配置項(xiàng) | 默認(rèn)值 | 最小值 | 描述 |
|---|---|---|---|
| sentinel.dashboard.app.hideAppNoMachineMillis | 0 | 60000 | 是否隱藏?zé)o健康節(jié)點(diǎn)的應(yīng)用,距離最近一次主機(jī)心跳時(shí)間的毫秒數(shù),默認(rèn)關(guān)閉 |
| sentinel.dashboard.removeAppNoMachineMillis | 0 | 120000 | 是否自動(dòng)刪除無健康節(jié)點(diǎn)的應(yīng)用,距離最近一次其下節(jié)點(diǎn)的心跳時(shí)間毫秒數(shù),默認(rèn)關(guān)閉 |
| sentinel.dashboard.unhealthyMachineMillis | 60000 | 30000 | 主機(jī)失聯(lián)判定,不可關(guān)閉 |
| sentinel.dashboard.autoRemoveMachineMillis | 0 | 300000 | 距離最近心跳時(shí)間超過指定時(shí)間是否自動(dòng)刪除失聯(lián)節(jié)點(diǎn),默認(rèn)關(guān)閉 |
| server.port | 8080 | - | 指定端口 |
| csp.sentinel.dashboard.server | localhost:8080 | - | 指定地址 |
| project.name | - | - | 指定程序的名稱 |
| sentinel.dashboard.auth.username [1.6版本支持] | sentinel | - | Sentinel Dashboard登錄賬號(hào) |
| sentinel.dashboard.auth.password [1.6版本支持] | sentinel | - | Sentinel Dashboard登錄密碼 |
| server.servlet.session.timeout [1.6版本支持] | 30分鐘 | - | 登錄Session過期時(shí)間。配置為7200表示7200秒;配置為60m表示60分鐘 |
控制臺(tái)配置項(xiàng)需在啟動(dòng)命令中指定,例如指定賬戶密碼,如下:
java -jar -Dsentinel.dashboard.auth.username=admin -Dsentinel.dashboard.auth.password=123456 sentinel-dashboard-1.6.3.jar
第三步: 創(chuàng)建應(yīng)用rest接口:
@Slf4j
@RestController
public class UserController {
@GetMapping("/findById")
public String getUser(@RequestParam String id) {
return "hello sentinel dashboard";
}
}
第四步: 啟動(dòng)應(yīng)用,然后通過 postman 訪問:http://localhost:9005/findById接口。
sentinel 是懶加載應(yīng)用的,所有這里需要通過postman先訪問,才能在控制臺(tái)看到應(yīng)用客戶端。
此時(shí),在Sentinel Dashboard界面中就可以看到我們啟動(dòng)的這個(gè)服務(wù)以及接口調(diào)用的實(shí)時(shí)監(jiān)控了。
實(shí)時(shí)監(jiān)控

控制臺(tái)配置規(guī)則
配置限流規(guī)則
在完成了上面配置以后,我們?cè)?Sentinel 控制臺(tái)的 alibaba-sentinel-rate-limiting服務(wù)下,單擊 簇點(diǎn)鏈路 菜單,可以看到如下頁面:

點(diǎn)擊流控按鈕,便可以為應(yīng)用設(shè)置流控規(guī)則

資源名:唯一名稱,默認(rèn)請(qǐng)求路徑
針對(duì)來源:Sentinel可以針對(duì)調(diào)用者進(jìn)行限流,填寫微服務(wù)名,默認(rèn)default(不區(qū)分來源)
-
閾值類型/單機(jī)閾值:
- QPS(每秒鐘的請(qǐng)求數(shù)量):當(dāng)調(diào)用該api的QPS達(dá)到閾值的時(shí)候,進(jìn)行限流
- 線程數(shù):當(dāng)調(diào)用該api的線程數(shù)達(dá)到閾值的時(shí)候,進(jìn)行限流
是否集群:不需要集群,暫不研究
-
流控模式:
- 直接:api達(dá)到限流條件時(shí),直接限流
- 關(guān)聯(lián):當(dāng)關(guān)聯(lián)的資源達(dá)到閾值時(shí),就限流自己
- 鏈路:只記錄指定鏈路上的流量(指定資源從入口資源進(jìn)來的流量,如果達(dá)到閾值,就進(jìn)行限流)【api級(jí)別的針對(duì)來源】
鏈路模式稍微有些抽象,這里舉個(gè)簡(jiǎn)單的例子說明一下。下圖中有兩個(gè)調(diào)用鏈路,圖中的/test-b和/test-a實(shí)際就是兩個(gè)接口,它們都調(diào)用了同一個(gè)common資源,所以/test-b和/test-a就稱為common的入口資源:
此時(shí)我為common添加一個(gè)限流規(guī)則如下:
可以看到流控模式選擇鏈路后,需要填寫一個(gè)入口資源,我這里填的是/test-a,那么這意味著什么呢?意味著當(dāng)/test-a的QPS達(dá)到該規(guī)則的閾值后,就會(huì)對(duì)/test-a限流,同時(shí)/test-b不會(huì)受到任何影響。說明這種流控模式可以針對(duì)接口級(jí)別的來源進(jìn)行限流,而“針對(duì)來源”則是對(duì)微服務(wù)級(jí)別的來源進(jìn)行限流。
-
流控效果:
- 快速失?。褐苯邮?,拋出異常,不做任何額外的處理,是最簡(jiǎn)單的效果
相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController - Warm Up(預(yù)熱):會(huì)根據(jù)codeFactor(默認(rèn)3)的值,從閾值除以codeFactor,經(jīng)過預(yù)熱時(shí)長(zhǎng),才到達(dá)設(shè)置的QPS閾值。適用于將突然增大的流量轉(zhuǎn)換為緩步增長(zhǎng)的場(chǎng)景。
相關(guān)的官方文檔:限流 - 冷啟動(dòng)
相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController - 排隊(duì)等待:勻速排隊(duì),讓請(qǐng)求以均勻的速度通過,若請(qǐng)求等待時(shí)間超過設(shè)置的超時(shí)時(shí)間則拋棄該請(qǐng)求,閾值類型必須設(shè)置成QPS,否則無效。適用于突發(fā)流量的場(chǎng)景。
相關(guān)的官方文檔:限流 - 勻速器
相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
- 快速失?。褐苯邮?,拋出異常,不做任何額外的處理,是最簡(jiǎn)單的效果
降級(jí)規(guī)則(斷路器模式)
點(diǎn)擊降級(jí)按鈕,便可以為應(yīng)用設(shè)置降級(jí)規(guī)則

降級(jí)策略:
-
RT:平均響應(yīng)時(shí)間(秒級(jí)統(tǒng)計(jì))超出閾值 且 在時(shí)間窗口內(nèi)的請(qǐng)求 >= 5時(shí),觸發(fā)降級(jí)(斷路器打開);時(shí)間窗口結(jié)束后,關(guān)閉降級(jí)【Sentinel默認(rèn)最大的RT為4900ms,可以通過
-Dcsp.sentinel.statistic.max.rt=xxx修改】 - 異常比例:QPS >= 5 且異常比例(秒級(jí)統(tǒng)計(jì))超過閾值時(shí),觸發(fā)降級(jí);時(shí)間窗口結(jié)束后,關(guān)閉降級(jí)
-
異常數(shù):異常數(shù)(分鐘統(tǒng)計(jì))超過閾值時(shí),觸發(fā)降級(jí);時(shí)間窗口結(jié)束后,關(guān)閉降級(jí)【時(shí)間窗口 < 60秒可能會(huì)出現(xiàn)問題】
關(guān)于異常數(shù)這種降級(jí)策略需要注意的點(diǎn):
若將時(shí)間窗口的值設(shè)置小于60秒則可能會(huì)出問題,因?yàn)楫惓?shù)的統(tǒng)計(jì)是分鐘級(jí)別的,時(shí)間窗口小于60秒就有可能不斷進(jìn)入降級(jí)狀態(tài).
降級(jí)規(guī)則的相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.degradeDegradeRule#passCheck(對(duì)降級(jí)的判斷都在這個(gè)方法里完成)
熱點(diǎn)規(guī)則(熱點(diǎn)參數(shù)限流規(guī)則)
Sentinel默認(rèn)顯示的端點(diǎn)并不支持熱點(diǎn)規(guī)則,要顯示熱點(diǎn)規(guī)則,需要自己添加代碼:
@GetMapping("test")
@SentinelResource("test")
public String testHot(@RequestParam(required = false) String a,
@RequestParam(required = false) String b) {
return a + "-" + b;
}
點(diǎn)擊熱點(diǎn)按鈕,便可以為test設(shè)置熱點(diǎn)規(guī)則

在時(shí)間窗口以內(nèi),一旦該api指定索引的參數(shù)QPS達(dá)到了域名,就會(huì)觸發(fā)限流
- 參數(shù)索引:從0開始,上面的代碼中:a的參數(shù)索引為0;b的參數(shù)索引為1【參數(shù)索引對(duì)應(yīng)的參數(shù)必須時(shí)基本類型或者String】
熱點(diǎn)規(guī)則適用的場(chǎng)景:
- 適用于存在熱點(diǎn)參數(shù)并希望提升API可用性的場(chǎng)景,即某個(gè)特定請(qǐng)求參數(shù)QPS偏高于其他請(qǐng)求參數(shù)時(shí),僅對(duì)該參數(shù)的請(qǐng)求限流,使用其他請(qǐng)求參數(shù)則可以正常響應(yīng),這樣可以提高一定的可用性
使用熱點(diǎn)規(guī)則需要注意的點(diǎn):
- 參數(shù)必須是基本類型或者String類型,否則將不會(huì)生效
熱點(diǎn)規(guī)則相關(guān)源碼:
com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowChecker#passCheck(對(duì)熱點(diǎn)參數(shù)規(guī)則的判斷邏輯都在這個(gè)方法里)
系統(tǒng)規(guī)則
閾值類型
- LOAD(
僅對(duì) Linux/Unix-like 機(jī)器生效):當(dāng)系統(tǒng) load1 超過閾值,且系統(tǒng)當(dāng)前的并發(fā)線程數(shù)超過系統(tǒng)容量時(shí)才會(huì)觸發(fā)系統(tǒng)保護(hù)。系統(tǒng)容量由系統(tǒng)的 maxQps * minRt 計(jì)算得出。設(shè)定參考值一般是CPU cores * 2.5 - RT:當(dāng)單臺(tái)機(jī)器上所有入口流量的平均 RT 達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù),單位是毫秒
- 線程數(shù):當(dāng)單臺(tái)機(jī)器上所有入口流量的并發(fā)線程數(shù)達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù)
- 入口 QPS:當(dāng)單臺(tái)機(jī)器上所有入口流量的 QPS 達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù)
- CPU 使用率:當(dāng)系統(tǒng) CPU 使用率超過閾值即觸發(fā)系統(tǒng)保護(hù)(取值范圍 0.0-1.0)
授權(quán)規(guī)則
點(diǎn)擊授權(quán)按鈕,便可以為應(yīng)用設(shè)置授權(quán)規(guī)則

資源名所代表的資源只允許流控應(yīng)用中添加的微服務(wù)使用(白名單)、不允許使用(黑名單)
代碼配置規(guī)則
流控規(guī)則
參數(shù)
| Field | 說明 | 默認(rèn)值 |
|---|---|---|
| resource | 資源名,資源名是限流規(guī)則的作用對(duì)象 | 無 |
| count | 限流閾值 | 無 |
| grade | 限流閾值類型,QPS 或線程數(shù)模式 | QPS模式 |
| limitApp | 流控針對(duì)的調(diào)用來源 | default,代表不區(qū)分調(diào)用來源 |
| strategy | default,代表不區(qū)分調(diào)用來源 | 根據(jù)資源本身 |
| controlBehavior | 流控效果(直接拒絕 / 排隊(duì)等待 / 慢啟動(dòng)模式) | 直接拒絕 |
代碼
private void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule(resourceName);
// 設(shè)置QPS閾值為20
rule.setCount(20);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
降級(jí)規(guī)則
參數(shù)
| Field | 說明 | 默認(rèn)值 |
|---|---|---|
| resource | 資源名,即限流規(guī)則的作用對(duì)象 | 無 |
| count | 閾值 | 無 |
| grade | 降級(jí)模式,根據(jù) RT 降級(jí)還是根據(jù)異常比例降級(jí) | RT |
| timeWindow | 降級(jí)的時(shí)間,單位為 s | 無 |
代碼
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);
}
熱點(diǎn)規(guī)則
參數(shù)
| Field | 說明 | 默認(rèn)值 |
|---|---|---|
| resource | 資源名,必填 | 無 |
| count | 限流閾值,必填 | 無 |
| grade | 限流模式 | QPS 模式 |
| durationInSec | 統(tǒng)計(jì)窗口時(shí)間長(zhǎng)度(單位為秒) | 1s |
| controlBehavior | 流控效果(支持快速失敗和勻速排隊(duì)模式) | 快速失敗 |
| maxQueueingTimeMs | 最大排隊(duì)等待時(shí)長(zhǎng)(僅在勻速排隊(duì)模式生效) | 0ms |
| paramIdx | 熱點(diǎn)參數(shù)的索引,必填,對(duì)應(yīng) SphU.entry(xxx, args) 中的參數(shù)索引位置 | 無 |
| paramFlowItemList | 參數(shù)例外項(xiàng),可以針對(duì)指定的參數(shù)值單獨(dú)設(shè)置限流閾值,不受前面 count 閾值的限制。僅支持基本類型 | 無 |
| clusterMode | 是否是集群參數(shù)流控規(guī)則 | false |
| clusterConfig | 集群流控相關(guān)配置 | 無 |
代碼
ParamFlowRule rule = new ParamFlowRule(resourceName)
.setParamIdx(0)
.setCount(5);
// 針對(duì) int 類型的參數(shù) PARAM_B,單獨(dú)設(shè)置限流 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));
系統(tǒng)規(guī)則
參數(shù)
| Field | 說明 | 默認(rèn)值 |
|---|---|---|
| highestSystemLoad | 最大的 load1 | -1(不生效) |
| avgRt | 所有入口流量的平均響應(yīng)時(shí)間 | -1(不生效) |
| maxThread | 入口流量的最大并發(fā)數(shù) | -1(不生效) |
| qpa | 所有入口資源的 QPS | -1(不生效) |
代碼
private void initSystemRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(10);
rules.add(rule);
SystemRuleManager.loadRules(rules);
}
授權(quán)規(guī)則
參數(shù)
| Field | 說明 | 默認(rèn)值 |
|---|---|---|
| resource | 資源名,即限流規(guī)則的作用對(duì)象 | 無 |
| limitApp | 對(duì)應(yīng)的黑名單/白名單,不同 origin 用 , 分隔,如 appA,appB | default,代表不區(qū)分調(diào)用來源 |
| strategy | 限制模式,AUTHORITY_WHITE 為白名單模式,AUTHORITY_BLACK 為黑名單模式,默認(rèn)為白名單模式 | AUTHORITY_WHITE |
代碼
AuthorityRule rule = new AuthorityRule();
rule.setResource("test");
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
rule.setLimitApp("appA,appB");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
Sentinel組件與控制臺(tái)通信原理

注冊(cè)/心跳發(fā)送
源碼:com.alibaba.csp.sentinel.transport.heartbeat.SimpleHttpHeatbeatSender通信API
源碼:com.alibaba.csp.sentinel.command.CommandHandler

