一、簡介
二、下載安裝
打開上面的下載地址,下載jar包,使用java -jar命令運行(當然本地得安裝好java運行環境)
安裝好后,使用如下地址:http://localhost:8080/#/dashboard。默認用戶名密碼都是sentinel
三、初始化演示工程
新建Module:cloudalibaba-sentinel-service8401
1、POM

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-sentinel-service8401</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</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-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
2、YML
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: 192.168.216.132:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 #默認8719,假如被占用了會自動從8719開始依次+1掃描。直至找到未被占用的端口
management:
endpoints:
web:
exposure:
include: '*'
3、主啟動
@EnableDiscoveryClient @SpringBootApplication public class MainApp8401 { public static void main(String[] args) { SpringApplication.run(MainApp8401.class, args); } }
4、業務類FlowLimitController
@RestController public class FlowLimitController { @GetMapping("/testA") public String testA() { return "------testA"; } @GetMapping("/testB") public String testB() { return "------testB"; } }
- 啟動Sentinel8080和Nacos8848
- 啟動微服務8401,查看sentienl控制台,sentienl采用懶加載,需要執行一次微服務的請求后才會顯示
效果如下
四、流控規則
1、基本介紹
- 資源名:唯一名稱,默認請求路徑
- 針對來源:Sentinel可以針對調用者進行限流,填寫微服務名,默認default(不區分來源)
- 閾值類型/單機閾值:
- QPS(每秒鍾的請求數量):當調用該api的QPS達到閾值的時候,進行限流
- 線程數:當調用該api的線程數達到閾值的時候,進行限流
- 是否集群:不需要集群
- 流控模式
- 直接:api達到限流條件時,直接限流
- 關聯:當關聯的資源達到閾值時,就限流自己
- 鏈路:只記錄指定鏈路上的流量(指定資源從入口資源進來的流量,如果達到閾值,就進行限流)api級別的針對來源
- 流控效果:
- 快速失敗:直接失敗,拋異常
- Warm Up:根據codeFactor(冷加載因子,默認3)的值,從閾值/codeFactor,經過預熱時長,才達到設置的QPS閾值
- 排隊等待:勻速排隊,讓請求以勻速的速度通過,閾值類型必須設置為QPS,否則無效
2、直接(默認)
配置及說明
快速點擊訪問:http://localhost:8401/testA
結果:Blocked by Sentinel (flow limiting)
3、關聯
當關聯的資源達到閾值時,就限流自己(當與A關聯的資源B達到閾值后,就限流自己)通俗的講:B惹事,A掛了
設置效果:當關聯資源/testB的qps閾值超過1時,就限流/testA的Rest訪問地址,當關聯資源到閾值后限制配置好的資源名
4、鏈路
鏈路相比於上面的關聯,可以看到最明顯的變化是“關聯資源”變成了“入口資源”,意思很明顯:當入口資源B的調用超過了閾值,且資源A在B調用的鏈路上,就限流自己。
五、流控效果
1、直接->快速失敗(默認的流控處理)
- 直接失敗,拋出異常:Blocked by Sentinel (flow limiting)
- 源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
2、預熱
- 公式:閾值除以coldFactor(默認值為3),經過預熱時長后才會達到閾值
- com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
-
應用場景如:秒殺系統在開啟的瞬間,會有很多流量上來,很有可能把系統打死,預熱方式就是為了保護系統,可慢慢的把流量放進來,慢慢的把閥值增長到設置的閥值。
3、排隊等待
- 勻速排隊,閾值必須設置為QPS
- com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
六、降級規則
除了流量控制以外,對調用鏈路中不穩定的資源進行熔斷降級也是保障高可用的重要措施之一。一個服務常常會調用別的模塊,可能是另外的一個遠程服務、數據庫,或者第三方 API 等。例如,支付的時候,可能需要遠程調用銀聯提供的 API;查詢某個商品的價格,可能需要進行數據庫查詢。然而,這個被依賴服務的穩定性是不能保證的。如果依賴的服務出現了不穩定的情況,請求的響應時間變長,那么調用服務的方法的響應時間也會變長,線程會產生堆積,最終可能耗盡業務自身的線程池,服務本身也變得不可用。
1、Sentinel 提供以下幾種熔斷策略
- 慢調用比例 (
SLOW_REQUEST_RATIO
):選擇以慢調用比例作為閾值,需要設置允許的慢調用 RT(即最大的響應時間),請求的響應時間大於該值則統計為慢調用。當單位統計時長(statIntervalMs
)內請求數目大於設置的最小請求數目,並且慢調用的比例大於閾值,則接下來的熔斷時長內請求會自動被熔斷。經過熔斷時長后熔斷器會進入探測恢復狀態(HALF-OPEN 狀態),若接下來的一個請求響應時間小於設置的慢調用 RT 則結束熔斷,若大於設置的慢調用 RT 則會再次被熔斷。 - 異常比例 (
ERROR_RATIO
):當單位統計時長(statIntervalMs
)內請求數目大於設置的最小請求數目,並且異常的比例大於閾值,則接下來的熔斷時長內請求會自動被熔斷。經過熔斷時長后熔斷器會進入探測恢復狀態(HALF-OPEN 狀態),若接下來的一個請求成功完成(沒有錯誤)則結束熔斷,否則會再次被熔斷。異常比率的閾值范圍是[0.0, 1.0]
,代表 0% - 100%。 - 異常數 (
ERROR_COUNT
):當單位統計時長內的異常數目超過閾值之后會自動進行熔斷。經過熔斷時長后熔斷器會進入探測恢復狀態(HALF-OPEN 狀態),若接下來的一個請求成功完成(沒有錯誤)則結束熔斷,否則會再次被熔斷。
注意異常降級僅針對業務異常,對 Sentinel 限流降級本身的異常(BlockException
)不生效。
2、RT實戰
代碼
@GetMapping("/testD") public String testD() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } log.info("testD 測試RT"); return "------testD"; }
配置如下:
按照上述配置:一秒中打進來10個線程(大於5個了)調用/testD,我們希望200毫秒處理完本次任務,如果超過200毫秒還沒有處理完,在未來1秒鍾的時間窗口內,斷路器打開(保險絲跳閘)微服務不可用,保險絲跳閘斷電了,后續沒有這么大的訪問量了,斷路器關閉(保險絲恢復)微服務恢復OK。
3、異常比例
代碼
@GetMapping("/testD") public String testD() { log.info("testD 測試RT"); int age = 10 / 0; return "------testD"; }
配置
4、異常數
代碼
@GetMapping("/testE") public String testE() { log.info("testE 測試異常數"); int age = 10 / 0; return "------testE 測試異常數"; }
配置
七、熱點參數限流
源碼位置:com.alibaba.csp.sentinel.slots.block.BlockException
1、根據參數限流
代碼
@GetMapping("/testHotKey") @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey") public String testHotKey(@RequestParam(value = "p1", required = false) String p1, @RequestParam(value = "p2", required = false) String p2) { //int age = 10/0; return "------testHotKey"; } //兜底方法 public String deal_testHotKey(String p1, String p2, BlockException exception) { return "------deal_testHotKey,o(╥﹏╥)o"; }
- @SentinelResource(value = "testHotKey"),異常打到了前台用戶界面看不到,不友好
- @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey"),方法testHostKey里面第一個參數只要QPS超過每秒1次,馬上降級處理,用了我們自己定義的
測試
- 超過閾值限流:http://localhost:8401/testHotKey?p1=abc
- 超過閾值限流:http://localhost:8401/testHotKey?p1=abc&p2=33
- 不限流:http://localhost:8401/testHotKey?p2=abc
2、參數例外項:參數如果為某個值不限流
上述案例演示了第一個參數p1,當QPS超過1秒1次點擊后馬上被限流。我們期望p1參數當它是某個特殊值時,它的限流值和平時不一樣,比如:假如當p1的值等於5時,它的閾值可以達到200
注意:熱點參數的注意點,參數必須是基本類型或者String
測試
- 不限流:http://localhost:8401/testHotKey?p1=5,當p1等於5的時候,閾值變為200
- 限流:http://localhost:8401/testHotKey?p1=3,當p1不等於5的時候,閾值就是平常的1
八、系統自適應限流
系統保護規則是從應用級別的入口流量進行控制,從單台機器的 load、CPU 使用率、平均 RT、入口 QPS 和並發線程數等幾個維度監控應用指標,讓系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性。
系統保護規則是應用整體維度的,而不是資源維度的,並且僅對入口流量生效。入口流量指的是進入應用的流量(EntryType.IN
),比如 Web 服務或 Dubbo 服務端接收的請求,都屬於入口流量。
系統規則支持以下的模式:
- Load 自適應(僅對 Linux/Unix-like 機器生效):系統的 load1 作為啟發指標,進行自適應系統保護。當系統 load1 超過設定的啟發值,且系統當前的並發線程數超過估算的系統容量時才會觸發系統保護(BBR 階段)。系統容量由系統的
maxQps * minRt
估算得出。設定參考值一般是CPU cores * 2.5
。 - CPU usage(1.5.0+ 版本):當系統 CPU 使用率超過閾值即觸發系統保護(取值范圍 0.0-1.0),比較靈敏。
- 平均 RT:當單台機器上所有入口流量的平均 RT 達到閾值即觸發系統保護,單位是毫秒。
- 並發線程數:當單台機器上所有入口流量的並發線程數達到閾值即觸發系統保護。
- 入口 QPS:當單台機器上所有入口流量的 QPS 達到閾值即觸發系統保護。
九、@SentinelResource
@SentinelResource可以處理自定義的限流返回和熔斷返回
1、限流返回形式一
@GetMapping("/byResource") @SentinelResource(value = "byResource", blockHandler = "handleException") public CommonResult byResource() { return new CommonResult(200, "按資源名稱限流測試OK", new Payment(2020L, "serial001")); } public CommonResult handleException(BlockException exception) { return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服務不可用"); }
2、限流返回形式二
@GetMapping("/rateLimit/customerBlockHandler") @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException") public CommonResult customerBlockHandler() { return new CommonResult(200, "按客戶自定義", new Payment(2020L, "serial003")); }
單獨定義限流異常處理類
package com.atguigu.springcloud.alibaba.myhandle; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.atguigu.springcloud.entities.CommonResult; public class CustomerBlockHandler { public static CommonResult handleException(BlockException exception) { return new CommonResult(2020, "自定義限流處理信息....CustomerBlockHandler"); } }
3、熔斷返回形式一
@GetMapping("/fallback") @SentinelResource(value = "fallback", fallback = "handlerFallback") public CommonResult fallback() { int num = 1 / 0; return new CommonResult(200, "按客戶自定義", new Payment(2020L, "serial003")); } public CommonResult handlerFallback(Throwable exception) { return new CommonResult(555, exception.getClass().getCanonicalName() + "\t 服務不可用"); }
4、熔斷返回形式二
@GetMapping("/fallback") @SentinelResource(value = "fallback",
fallbackClass = CustomerFallbackHandler.class,
fallback = "handlerFallback") public CommonResult fallback() { int num = 1 / 0; return new CommonResult(200, "按客戶自定義", new Payment(2020L, "serial003")); }
單獨定義熔斷異常處理類
public class CustomerFallbackHandler { public static CommonResult handlerFallback(Throwable exception) { return new CommonResult(2020, "自定義熔斷處理信息....CustomerFallbackHandler"); } }
十、規則持久化
一旦我們重啟應用,Sentinel規則將消失,生產環境需要將配置規則進行持久化。
其中一個解決方法:將限流配置規則持久化進Nacos保存,只要刷新8401某個rest地址,sentinel控制台的流控規則就能看到,只要Nacos里面的配置不刪除,針對8401上Sentinel上的流控規則持續有效。
修改cloudalibaba-sentinel-service8401,步驟:
1、POM,增加依賴
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
2、YML,添加Nacos數據源配置
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: 192.168.216.132:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 #默認8719,假如被占用了會自動從8719開始依次+1掃描。直至找到未被占用的端口
datasource: ds1: nacos: server-addr: 192.168.216.132:8848 dataId: cloudalibaba-sentinel-service groupId: DEFAULT_GROUP data-type: json rule-type: flow
3、添加Nacos業務規則配置
內容解析
測試接口:
@RestController public class RateLimitController { @GetMapping("/byResource") @SentinelResource(value = "byResource", blockHandler = "handleException") public CommonResult byResource() { return new CommonResult(200, "按資源名稱限流測試OK", new Payment(2020L, "serial001")); } public CommonResult handleException(BlockException exception) { return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服務不可用"); } }
4、測試
停止8401,發現規則消失了,啟動8401,發現還是沒有,但是調用幾次接口后,規則又出現了