Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場(chǎng)景
本文介紹阿里開(kāi)源限流熔斷方案Sentinel功能、原理、架構(gòu)、快速入門以及相關(guān)框架比較
基本介紹
1 名詞解釋
- 服務(wù)限流 :當(dāng)系統(tǒng)資源不夠,不足以應(yīng)對(duì)大量請(qǐng)求,對(duì)系統(tǒng)按照預(yù)設(shè)的規(guī)則進(jìn)行流量限制或功能限制
- 服務(wù)熔斷:當(dāng)調(diào)用目標(biāo)服務(wù)的請(qǐng)求和調(diào)用大量超時(shí)或失敗,服務(wù)調(diào)用方為避免造成長(zhǎng)時(shí)間的阻塞造成影響其他服務(wù),后續(xù)對(duì)該服務(wù)接口的調(diào)用不再經(jīng)過(guò)進(jìn)行請(qǐng)求,直接執(zhí)行本地的默認(rèn)方法
- 服務(wù)降級(jí):為了保證核心業(yè)務(wù)在大量請(qǐng)求下能正常運(yùn)行,根據(jù)實(shí)際業(yè)務(wù)情況及流量,對(duì)部分服務(wù)降低優(yōu)先級(jí),有策略的不處理或用簡(jiǎn)單的方式處理
服務(wù)降級(jí)的實(shí)現(xiàn)可以基于人工開(kāi)關(guān)降級(jí)(秒殺、電商大促等)和自動(dòng)檢測(cè)(超時(shí)、失敗次數(shù)、故障),熔斷可以理解為一種服務(wù)故障降級(jí)處理
2 為什么需要限流降級(jí)
系統(tǒng)承載的訪問(wèn)量是有限的,如果不做流量控制,會(huì)導(dǎo)致系統(tǒng)資源占滿,服務(wù)超時(shí),從而所有用戶無(wú)法使用,通過(guò)服務(wù)限流控制請(qǐng)求的量,服務(wù)降級(jí)省掉非核心業(yè)務(wù)對(duì)系統(tǒng)資源的占用,最大化利用系統(tǒng)資源,盡可能服務(wù)更多用戶
3 Sentinel簡(jiǎn)介

Sentinel: 分布式系統(tǒng)的流量防衛(wèi)兵,是阿里中間件團(tuán)隊(duì)2018年7月開(kāi)源的,面向分布式服務(wù)架構(gòu)的輕量級(jí)流量控制產(chǎn)品,主要以流量為切入點(diǎn),從流量控制、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度來(lái)保護(hù)系統(tǒng)服務(wù)的穩(wěn)定性
Sentinel 的開(kāi)源生態(tài):

功能特性
1 總體介紹
Sentinel 具有以下特征:
豐富的應(yīng)用場(chǎng)景:秒殺限流,消息削峰填谷、集群流量控制、實(shí)時(shí)熔斷下游不可用應(yīng)用等
完備的實(shí)時(shí)監(jiān)控:Sentinel 同時(shí)提供實(shí)時(shí)的監(jiān)控功能。可以在控制臺(tái)中看到接入應(yīng)用的單臺(tái)機(jī)器秒級(jí)數(shù)據(jù),甚至 500 臺(tái)以下規(guī)模的集群的匯總運(yùn)行情況
廣泛的開(kāi)源生態(tài):Sentinel 提供開(kāi)箱即用的與其它開(kāi)源框架/庫(kù)的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。只需要引入相應(yīng)的依賴并進(jìn)行簡(jiǎn)單的配置即可快速地接入 Sentinel
完善的 SPI 擴(kuò)展點(diǎn):Sentinel 提供簡(jiǎn)單易用、完善的 SPI 擴(kuò)展接口。可以通過(guò)實(shí)現(xiàn)擴(kuò)展接口來(lái)快速地定制邏輯。例如定制規(guī)則管理、適配動(dòng)態(tài)數(shù)據(jù)源等

Sentinel 分為兩個(gè)部分:
控制臺(tái)(Dashboard) 基于 Spring Boot 開(kāi)發(fā),打包后可以直接運(yùn)行,不需要額外的 Tomcat 等應(yīng)用容器
核心庫(kù)(JAVA 客戶端) 不依賴任何框架/庫(kù),能夠運(yùn)行于所有 Java 運(yùn)行時(shí)環(huán)境,同時(shí)對(duì) Dubbo / Spring Cloud 等框架也有較好的支持
2 控制臺(tái)特性

- 實(shí)時(shí)監(jiān)控
- 支持自動(dòng)發(fā)現(xiàn)集群機(jī)器列表、服務(wù)健康狀態(tài)、服務(wù)調(diào)用通過(guò)/拒絕QPS、調(diào)用耗時(shí)、圖表統(tǒng)計(jì)
- 規(guī)則管理及推送
- 支持在界面配置流控、降級(jí)、熱點(diǎn)規(guī)則,并實(shí)時(shí)推送
- 鑒權(quán)
- 控制臺(tái)支持自定義鑒權(quán)接口,提供基本登錄功能
3 核心庫(kù)功能特性
(1) 應(yīng)用流控
針對(duì)指定應(yīng)用實(shí)例的流量控制,監(jiān)控應(yīng)用流量QPS或并發(fā)線程數(shù),當(dāng)達(dá)到指定的閾值時(shí)對(duì)流量進(jìn)行控制,以避免被瞬時(shí)的流量高峰沖垮,從而保障應(yīng)用的高可用性
流量控制的手段包括:
- 直接拒絕
- Warm Up,即預(yù)熱/冷啟動(dòng)方式,讓通過(guò)的流量緩慢增加,在一定時(shí)間內(nèi)逐漸增加到閾值上限,給冷系統(tǒng)一個(gè)預(yù)熱的時(shí)間,避免冷系統(tǒng)被瞬間壓垮
- 勻速排隊(duì),嚴(yán)格控制請(qǐng)求通過(guò)的間隔時(shí)間,讓請(qǐng)求以均勻的速度通過(guò)
(2) 集群流控
不同于應(yīng)用流控根據(jù)單個(gè)應(yīng)用實(shí)例閾值執(zhí)行限流檢查,集群流控只對(duì)整個(gè)集群調(diào)用總量進(jìn)行限流,例如以下場(chǎng)景:
- 限制某個(gè)用戶調(diào)用某個(gè)API的總QPS,提供API的應(yīng)用在多個(gè)機(jī)器上部署了多個(gè)實(shí)例
- 因?yàn)槎鄠€(gè)應(yīng)用實(shí)例流量不均勻,導(dǎo)致集群調(diào)用總量沒(méi)有到的情況下某些機(jī)器就開(kāi)始限流
僅靠單機(jī)維度去限制的話會(huì)無(wú)法精確地限制總體流量,通過(guò)集群精確地控制整個(gè)集群的調(diào)用總量,結(jié)合單機(jī)限流兜底,可以更好地發(fā)揮流量控制的效果
(3) 網(wǎng)關(guān)流控
Sentinel 支持對(duì) Spring Cloud Gateway、Zuul 等主流的 API Gateway 進(jìn)行限流

網(wǎng)關(guān)流控針對(duì) API網(wǎng)關(guān)的場(chǎng)景定制的限流規(guī)則,可以針對(duì)不同 route 或自定義的 API 分組進(jìn)行限流,支持針對(duì)請(qǐng)求中的路徑、參數(shù)、Header、來(lái)源 IP 等進(jìn)行定制化的限流
(4) 熔斷降級(jí)
如果調(diào)用鏈路中的某個(gè)資源不穩(wěn)定,最終會(huì)導(dǎo)致請(qǐng)求發(fā)生堆積,通過(guò)熔斷降級(jí)能在調(diào)用鏈路中某個(gè)資源出現(xiàn)不穩(wěn)定狀態(tài)時(shí)(包括調(diào)用超時(shí)、異常比例升高、異常數(shù)升高),對(duì)這個(gè)資源的調(diào)用進(jìn)行限制,讓請(qǐng)求快速失敗,避免影響到其它的資源而導(dǎo)致級(jí)聯(lián)錯(cuò)誤
當(dāng)資源被降級(jí)后,在接下來(lái)的降級(jí)時(shí)間窗口之內(nèi),對(duì)該資源的調(diào)用都自動(dòng)熔斷(默認(rèn)行為是拋出 DegradeException),經(jīng)過(guò)時(shí)間窗口之后,退出熔斷,并在下一次資源出現(xiàn)不穩(wěn)定狀態(tài)再次自動(dòng)熔斷
(5) 熱點(diǎn)參數(shù)限流
熱點(diǎn)即經(jīng)常訪問(wèn)的數(shù)據(jù),熱點(diǎn)參數(shù)限流會(huì)統(tǒng)計(jì)傳入?yún)?shù)中的熱點(diǎn)參數(shù),并根據(jù)配置的限流閾值與模式,對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用進(jìn)行限流例如以下場(chǎng)景:
- 用戶ID為參數(shù),限制用戶對(duì)接口的范圍QPS
- 商品ID為參數(shù),限制商品下單接口頻率

(6) 系統(tǒng)自適應(yīng)限流
為了解決傳統(tǒng)方案:基于操作系統(tǒng)負(fù)載(load1,linux下用uptime查看)做進(jìn)行自適應(yīng)限流,帶來(lái)的存在延時(shí)、系統(tǒng)性能恢復(fù)慢的問(wèn)題,Sentinel采用新的思路:根據(jù)系統(tǒng)能夠處理的請(qǐng)求,和允許進(jìn)來(lái)的請(qǐng)求,來(lái)做平衡,而不是根據(jù)一個(gè)間接的指標(biāo)(系統(tǒng) load)來(lái)做限流
目標(biāo)在于:在系統(tǒng)不被拖垮的情況下,盡可能提高系統(tǒng)的吞吐率,而不是 負(fù)載 一定要到低于某個(gè)閾值
系統(tǒng)保護(hù)規(guī)則是從應(yīng)用級(jí)別的入口流量進(jìn)行控制,從單臺(tái)機(jī)器的總體 Load、RT、入口 QPS 和線程數(shù)四個(gè)維度監(jiān)控應(yīng)用數(shù)據(jù),當(dāng)實(shí)際運(yùn)行達(dá)到限定閾值進(jìn)行限流保護(hù),支持的閾值類型:
- Load:當(dāng)系統(tǒng) load1 超過(guò)閾值,且系統(tǒng)當(dāng)前的并發(fā)線程數(shù)超過(guò)系統(tǒng)容量時(shí)才會(huì)觸發(fā)系統(tǒng)保護(hù)。系統(tǒng)容量由系統(tǒng)時(shí)間運(yùn)行監(jiān)測(cè)到的的 maxQps * minRt (最小響應(yīng)時(shí)間)計(jì)算得出
- RT:當(dāng)單臺(tái)機(jī)器上所有入口流量的平均 RT(響應(yīng)時(shí)間)
- 線程數(shù):當(dāng)單臺(tái)機(jī)器上所有入口流量的并發(fā)線程數(shù)
- 入口 QPS:當(dāng)單臺(tái)機(jī)器上所有入口流量的 QPS
(7) 黑白名單控制
Sentinel黑白名單根據(jù)資源的請(qǐng)求來(lái)源(origin)限制資源是否通過(guò),若配置白名單則只有請(qǐng)求來(lái)源位于白名單內(nèi)時(shí)才可通過(guò);若配置黑名單則請(qǐng)求來(lái)源位于黑名單時(shí)不通過(guò),其余的請(qǐng)求通過(guò)
快速入門
1 安裝控制臺(tái)
從github release頁(yè)面(https://github.com/alibaba/Sentinel/releases)下載最新控制臺(tái)jar包
命令行啟動(dòng)控制臺(tái):
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
2 應(yīng)用接入Sentinel
Sentinel適配了常見(jiàn)主流框架,包括Dubbo、Spring Boot、Spring WebFlux、gRPC、Zuul、Spring Cloud Gateway、RocketMQ、Web Servlet,對(duì)于需要限流的資源,支持用原生Java的try-catch 接入或者使用注解
下面以常見(jiàn)的Spring Boot注解的方式作為示例:引入sentinel適配Spring Cloud的依賴:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.1.0.RELEASE</version> </dependency>
Application.yml指定控制臺(tái)地址:
spring: cloud: sentinel: transport: dashboard: IP:端口號(hào)
定義需要限流的資源:
@RestController public class TestController { @GetMapping(value = "/hello") // 定義需要限流的資源名稱為hello @SentinelResource("hello") public String hello() { return "Hello Sentinel"; } }
請(qǐng)求一次上面的http hello接口后,觸發(fā)Sentinel客戶端初始化,才能在控制臺(tái)看到接口
添加流控規(guī)則:

頻繁請(qǐng)求接口,可以看到部分請(qǐng)求被拒絕:

注意:上面的配置方式是沒(méi)有做持久化的,生產(chǎn)環(huán)境不建議使用
3 規(guī)則配置
Sentinel 提供 動(dòng)態(tài)規(guī)則數(shù)據(jù)源 支持來(lái)動(dòng)態(tài)地管理、讀取配置的規(guī)則。Sentinel 提供的 ReadableDataSource 和 WritableDataSource 接口簡(jiǎn)單易用,非常方便使用。
Sentinel 動(dòng)態(tài)規(guī)則源針對(duì)常見(jiàn)的配置中心和遠(yuǎn)程存儲(chǔ)進(jìn)行適配,目前已支持 Nacos、ZooKeeper、Apollo、redis 等多種動(dòng)態(tài)規(guī)則源,可以覆蓋到很多的生產(chǎn)場(chǎng)景
實(shí)現(xiàn)原理
下面介紹Sentinel客戶端基本原理
1 基本概念
- Resource 資源
- Sentinel中,需要被流量保護(hù)的方法、代碼塊都可以稱為資源,每個(gè)資源都需要定義一個(gè)唯一的資源名詞,用于匹配相關(guān)規(guī)則
- Entry
- Sentinel功能入口類,Entry 可以通過(guò)對(duì)主流框架的適配自動(dòng)創(chuàng)建,也可以通過(guò)注解的方式或調(diào)用 SphU API 顯式創(chuàng)建,創(chuàng)建后執(zhí)行資源和規(guī)則匹配和校驗(yàn)
- Slot
- 功能插槽,由Enty類創(chuàng)建,每個(gè)資源對(duì)應(yīng)一系列Slot,Slot實(shí)現(xiàn)資源信息收集、規(guī)則匹配、校驗(yàn)的,多個(gè)Slot通過(guò)組成Slot Chain,在進(jìn)入資源和退出資源時(shí)分別基于責(zé)任鏈模式調(diào)用entry()和exit()方法
2 工作原理

一個(gè)簡(jiǎn)單的demo:
String resourceName = "resourceName"; Entry entry = null; try { entry = SphU.entry(resourceName); System.out.println("resource running"); } catch (BlockException e) { // 限流 throw e; } catch (Throwable e) { e.printStackTrace(); throw e; } finally { if (entry != null) { entry.exit(); } }
主要流程如下:
- 進(jìn)入資源方法之前,基于SphU創(chuàng)建Entry,Entry獲取查找資源關(guān)聯(lián)的Slot Chain信息,如果找不到則創(chuàng)建,并基于責(zé)任鏈模式調(diào)用Slot的entry()方法
- 資源方法調(diào)用
- 資源方法調(diào)用完成后,通過(guò)Entry觸發(fā)Slot的exit()邏輯
框架比較
Sentinel Hystrix resilience4j 隔離策略 信號(hào)量隔離(并發(fā)線程數(shù)限流) 線程池隔離/信號(hào)量隔離 信號(hào)量隔離 熔斷降級(jí)策略 基于響應(yīng)時(shí)間、異常比率、異常數(shù) 基于異常比率 基于異常比率、響應(yīng)時(shí)間 實(shí)時(shí)統(tǒng)計(jì)實(shí)現(xiàn) 滑動(dòng)窗口(LeapArray) 滑動(dòng)窗口(基于 RxJava) Ring Bit Buffer 動(dòng)態(tài)規(guī)則配置 支持多種數(shù)據(jù)源 支持多種數(shù)據(jù)源 有限支持 擴(kuò)展性 多個(gè)擴(kuò)展點(diǎn) 插件的形式 接口的形式 基于注解的支持 支持 支持 支持 限流 基于 QPS,支持基于調(diào)用關(guān)系的限流 有限的支持 Rate Limiter 流量整形 支持預(yù)熱模式、勻速器模式、預(yù)熱排隊(duì)模式 不支持 簡(jiǎn)單的 Rate Limiter 模式 系統(tǒng)自適應(yīng)保護(hù) 支持 不支持 不支持 控制臺(tái) 提供開(kāi)箱即用的控制臺(tái),可配置規(guī)則、查看秒級(jí)監(jiān)控、機(jī)器發(fā)現(xiàn)等 簡(jiǎn)單的監(jiān)控查看 不提供控制臺(tái),可對(duì)接其它監(jiān)控系統(tǒng) 值得補(bǔ)充的是:相比Hystrix基于線程池隔離進(jìn)行限流,這種方案雖然隔離性比較好,但是代價(jià)就是線程數(shù)目太多,線程上下文切換的 overhead 比較大,特別是對(duì)低延時(shí)的調(diào)用有比較大的影響。
Sentinel 并發(fā)線程數(shù)限流不負(fù)責(zé)創(chuàng)建和管理線程池,而是簡(jiǎn)單統(tǒng)計(jì)當(dāng)前請(qǐng)求上下文的線程數(shù)目,如果超出閾值,新的請(qǐng)求會(huì)被立即拒絕,效果類似于信號(hào)量隔離
參考
《Sentinel官方文檔》
https://github.com/alibaba/Sentinel/wiki
《從 Hystrix 遷移到 Sentinel》
https://github.com/alibaba/Sentinel/wiki/Guideline:-從-Hystrix-遷移到-Sentinel
更多精彩,歡迎關(guān)注公眾號(hào)【分布式系統(tǒng)架構(gòu)】