SpringCloud Alibaba Sentinel實(shí)現(xiàn)熔斷與限流
官網(wǎng):https://github.com/alibaba/sentinel
中文網(wǎng):https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
Sentinel 是什么然痊?
隨著微服務(wù)的流行熄赡,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來越重要。Sentinel 以流量為切入點(diǎn),從流量控制腾啥、熔斷降級、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度保護(hù)服務(wù)的穩(wěn)定性晰赞。
Sentinel 具有以下特征:
- 豐富的應(yīng)用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景括儒,例如秒殺(即突發(fā)流量控制在系統(tǒng)容量可以承受的范圍)、消息削峰填谷肮韧、集群流量控制融蹂、實(shí)時(shí)熔斷下游不可用應(yīng)用等。
- 完備的實(shí)時(shí)監(jiān)控:Sentinel 同時(shí)提供實(shí)時(shí)的監(jiān)控功能岛宦。您可以在控制臺中看到接入應(yīng)用的單臺機(jī)器秒級數(shù)據(jù)认境,甚至 500 臺以下規(guī)模的集群的匯總運(yùn)行情況左权。
- 廣泛的開源生態(tài):Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud意乓、Dubbo、gRPC 的整合约素。您只需要引入相應(yīng)的依賴并進(jìn)行簡單的配置即可快速地接入 Sentinel届良。
- 完善的 SPI 擴(kuò)展點(diǎn):Sentinel 提供簡單易用、完善的 SPI 擴(kuò)展接口业汰。您可以通過實(shí)現(xiàn)擴(kuò)展接口來快速地定制邏輯伙窃。例如定制規(guī)則管理、適配動態(tài)數(shù)據(jù)源等样漆。
Sentinel 的主要特性:
Sentinel 分為兩個(gè)部分:
- 核心庫(Java 客戶端)不依賴任何框架/庫为障,能夠運(yùn)行于所有 Java 運(yùn)行時(shí)環(huán)境,同時(shí)對 Dubbo / Spring Cloud 等框架也有較好的支持。
- 控制臺(Dashboard)基于 Spring Boot 開發(fā)鳍怨,打包后可以直接運(yùn)行呻右,不需要額外的 Tomcat 等應(yīng)用容器。
Docker 安裝 Sentinel
#拉取sentinel鏡像
docker pull bladex/sentinel-dashboard
#運(yùn)行sentinel(docker里的sentinel是8858端口)
docker run --name sentinel -d -p 8858:8858 bladex/sentinel-dashboard
#把nacos和mysql也啟動起來
訪問: http://120.92.164.250:8858/#/login
賬號和密碼都是sentinel
演示
- 新建模塊 cloudalibaba-sentinel-service8401
- pom
<dependencies>
<!-- SpringCloud ailibaba nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud ailibaba sentinel-datasource-nacos 持久化需要用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!-- SpringCloud ailibaba sentinel-->
<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>
<!--監(jiān)控-->
<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>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>
- yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinal-service
cloud:
nacos:
discovery:
#Nacos服務(wù)注冊中心地址(改成自己的服務(wù)器ip地址鞋喇,本地用localhost?)
server-addr: 120.92.164.250:8848
sentinel:
transport:
#配置Sentin dashboard地址(改成自己的服務(wù)器ip地址声滥,本地用localhost?)
dashboard: 120.92.164.250:8858
# 默認(rèn)8719端口,假如被占用了會自動從8719端口+1進(jìn)行掃描侦香,直到找到未被占用的 端口
port: 8719
management:
endpoints:
web:
exposure:
include: '*'
- 啟動類
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401 {
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}
}
- 測試落塑,啟動8401,然后刷新sentinel后臺頁面(因?yàn)閟entinel采用懶加載策略罐韩,所以需要調(diào)用服務(wù)后才在后臺顯示)
在瀏覽器分別輸入憾赁,然后刷新sentinel后臺頁面:
規(guī)則的種類
Sentinel 的所有規(guī)則都可以在內(nèi)存態(tài)中動態(tài)地查詢及修改,修改之后立即生效散吵。同時(shí) Sentinel 也提供相關(guān) API龙考,供您來定制自己的規(guī)則策略。
Sentinel 支持以下幾種規(guī)則:流量控制規(guī)則矾睦、熔斷降級規(guī)則晦款、系統(tǒng)保護(hù)規(guī)則、來源訪問控制規(guī)則 和 熱點(diǎn)參數(shù)規(guī)則枚冗。
流量控制規(guī)則 (FlowRule)
同一個(gè)資源可以同時(shí)有多個(gè)限流規(guī)則缓溅,檢查規(guī)則時(shí)會依次檢查。
每秒請求數(shù)超過1個(gè)就會限流官紫。
閥值類型
QPS與線程數(shù)的區(qū)別
: QPS(每秒請求的數(shù)量):當(dāng)調(diào)用該api的QPS達(dá)到閥值的時(shí)候肛宋,進(jìn)行限流
: 線程數(shù):當(dāng)調(diào)用該API的線程數(shù)達(dá)到閥值的時(shí)候,進(jìn)行限流
QPS是直接擋在外面束世,而線程數(shù)是有多少個(gè)線程在處理酝陈,放進(jìn)來后,有線程是空閑狀態(tài)就對請求進(jìn)行處理毁涉,都沒空閑沉帮,就限流
QPS流量控制
直接 : 快速失敗
關(guān)聯(lián):當(dāng)關(guān)聯(lián)的資源達(dá)到閥值時(shí),就限流自己贫堰,當(dāng)與A關(guān)聯(lián)的資源B達(dá)到閥值后穆壕,就限流A自己
鏈路:Sentinel 允許只根據(jù)某個(gè)入口的統(tǒng)計(jì)信息對資源限流。
當(dāng) QPS 超過某個(gè)閾值的時(shí)候其屏,則采取措施進(jìn)行流量控制喇勋。流量控制的效果包括以下幾種:直接拒絕、Warm Up偎行、勻速排隊(duì)川背。對應(yīng) FlowRule 中的 controlBehavior 字段贰拿。
注意:若使用除了直接拒絕之外的流量控制效果,則調(diào)用關(guān)系限流策略(strategy)會被忽略熄云。
直接拒絕
- 直接拒絕(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默認(rèn)的流量控制方式膨更,當(dāng)QPS超過任意規(guī)則的閾值后,新的請求就會被立即拒絕缴允,拒絕方式為拋出FlowException荚守。這種方式適用于對系統(tǒng)處理能力確切已知的情況下,比如通過壓測確定了系統(tǒng)的準(zhǔn)確水位時(shí)练般。
Warm Up
- Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式矗漾,即預(yù)熱/冷啟動方式。當(dāng)系統(tǒng)長期處于低水位的情況下踢俄,當(dāng)流量突然增加時(shí)缩功,直接把系統(tǒng)拉升到高水位可能瞬間把系統(tǒng)壓垮晴及。通過"冷啟動"都办,讓通過的流量緩慢增加,在一定時(shí)間內(nèi)逐漸增加到閾值上限虑稼,給冷系統(tǒng)一個(gè)預(yù)熱的時(shí)間琳钉,避免冷系統(tǒng)被壓垮。
勻速排隊(duì)
- 勻速排隊(duì)(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會嚴(yán)格控制請求通過的間隔時(shí)間蛛倦,也即是讓請求以均勻的速度通過歌懒,對應(yīng)的是漏桶算法
降級規(guī)則
- RT : (平均響應(yīng)時(shí)間,秒級) 平均響應(yīng)時(shí)間 超出閥值 且 在時(shí)間窗口內(nèi)通過的請求 >=5 溯壶,兩哥條件同時(shí)滿足后觸發(fā)降級窗口期后關(guān)閉斷路器
- 異常比例 : (秒級) QPS >=5 且異常比例(秒級統(tǒng)計(jì))超過閥值時(shí)及皂,觸發(fā)降級;時(shí)間窗口結(jié)束后且改,關(guān)閉降級
- 異常數(shù) :(分鐘統(tǒng)計(jì)) 超過閥值時(shí)验烧,觸發(fā)降級;時(shí)間窗口結(jié)束后又跛,關(guān)閉降級
系統(tǒng)規(guī)則
系統(tǒng)保護(hù)規(guī)則是從應(yīng)用級別的入口流量進(jìn)行控制碍拆,從單臺機(jī)器的load 、cpu使用率慨蓝、平均RT感混、入口QPS和并發(fā)線程數(shù)幾個(gè)緯度監(jiān)控應(yīng)用指標(biāo),讓系統(tǒng)盡可能的跑在最大吞吐量的同時(shí)保證系統(tǒng)整體的穩(wěn)定性
系統(tǒng)保護(hù)規(guī)則則是應(yīng)用整體緯度的礼烈,而不是資源緯度的弧满,并且僅對入口流量生效。入口流量指的是進(jìn)入應(yīng)用的流量此熬,比如Web 服務(wù)或Dubbo 服務(wù)端接收的請求庭呜,都屬于入口流量洽蛀。
系統(tǒng)則支持以下的模式
- Load 自適應(yīng) : 系統(tǒng)的load1作為啟發(fā)指標(biāo),精細(xì)自適應(yīng)系統(tǒng)保護(hù)疟赊。當(dāng)系統(tǒng)load1超過啟發(fā)值郊供,且系統(tǒng)當(dāng)前的并發(fā)數(shù)超過估算的系統(tǒng)容量時(shí)才會觸發(fā)系統(tǒng)保護(hù)
- CPU usage :當(dāng)系統(tǒng)CPU使用率超過閥值即觸發(fā)系統(tǒng)保護(hù)
- 平均RT:當(dāng)單臺機(jī)器上所有入口流量的平均RT達(dá)到閥值時(shí)觸發(fā),單位是毫秒
- 并發(fā)線程數(shù) : 當(dāng)單臺機(jī)器上所有入口流量的并發(fā)線程數(shù)達(dá)到閥值時(shí)觸發(fā)系統(tǒng)保護(hù)
- 入口 QPS : 當(dāng)單臺機(jī)器上所有入口流量的QPS 達(dá)到閥值即觸發(fā)系統(tǒng)保護(hù)
針對系統(tǒng):
熱點(diǎn)key限流
何為熱點(diǎn):熱點(diǎn)即經(jīng)常訪問的數(shù)據(jù)近哟。很多時(shí)候我們希望統(tǒng)計(jì)某個(gè)熱點(diǎn)數(shù)據(jù)中訪問頻率最高的Top Key 數(shù)據(jù)驮审,并且對其訪問進(jìn)行限制:
比如:
- 商品ID作為參數(shù),針對一段時(shí)間內(nèi)最常購買的商品ID進(jìn)行限制
- 商品ID作為參數(shù)吉执,針對一段時(shí)間內(nèi)頻繁訪問的用戶ID進(jìn)行限制
方法:
@GetMapping("/testB")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testB() {
return "----testB";
}
//兜底方法
public String deal_testHotKey(String p1, String p2, BlockException exception) {
// sentinel的默認(rèn)提示都是: Blocked by Sentinel (flow limiting)
return "----deal_testHotKey, o(╥﹏╥)o";
}
設(shè)置限流 1秒
[圖片上傳失敗...(image-cf3ec3-1600587602916)]
服務(wù)熔斷降級
- 除了流量控制以外疯淫,對調(diào)用鏈路中不穩(wěn)定的資源進(jìn)行熔斷降級也是保障高可用的重要措施之一。一個(gè)服務(wù)常常會調(diào)用別的模塊戳玫,可能是另外的一個(gè)遠(yuǎn)程服務(wù)熙掺、數(shù)據(jù)庫,或者第三方 API 等咕宿。例如币绩,支付的時(shí)候,可能需要遠(yuǎn)程調(diào)用銀聯(lián)提供的 API府阀;查詢某個(gè)商品的價(jià)格缆镣,可能需要進(jìn)行數(shù)據(jù)庫查詢。然而试浙,這個(gè)被依賴服務(wù)的穩(wěn)定性是不能保證的董瞻。如果依賴的服務(wù)出現(xiàn)了不穩(wěn)定的情況,請求的響應(yīng)時(shí)間變長田巴,那么調(diào)用服務(wù)的方法的響應(yīng)時(shí)間也會變長钠糊,線程會產(chǎn)生堆積,最終可能耗盡業(yè)務(wù)自身的線程池壹哺,服務(wù)本身也變得不可用抄伍。
@SentineResource
- 按資源名稱限流
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(200,"按照資源名稱限流測試",new Payment(2020L,"serial001"));
}
//兜底方法
public CommonResult handleException(BlockException exception) {
return new CommonResult(444,exception.getClass().getCanonicalName() + "\t 服務(wù)不可用");
}
}
- 按URL地址限流
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl",blockHandler = "handleException")
public CommonResult byUrl() {
return new CommonResult(200,"按照byUrl限流測試",new Payment(2020L,"serial002"));
}
- 自定義限流
添加自定義類
public class CustomerBlockHandler {
public static CommonResult handlerException(BlockException exception) {
return new CommonResult(444,"按照客戶自定義限流測試,Glogal handlerException ---- 1");
}
public static CommonResult handlerException2(BlockException exception) {
return new CommonResult(444,"按照客戶自定義限流測試斗躏,Glogal handlerException ---- 2");
}
}
新增接口
//CustomerBlockHandler
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2")
public CommonResult customerBlockHandler() {
return new CommonResult(200,"按照客戶自定義限流測試",new Payment(2020L,"serial003"));
}
-
更多注解的方式
在這里插入圖片描述
規(guī)則持久化
yml 添加對 datasource
datasource:
ds1:
nacos:
server-addr: 10.211.55.26:8848 #nacos
dataId: ${spring.application.name}
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
feign:
sentinel:
enabled: true #激活Sentinel 對Feign的支持
實(shí)現(xiàn)sentinel配置的持久化逝慧。
- 個(gè)人博客:http://blog.yanxiaolong.cn/