Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景
本文介紹阿里開源限流熔斷方案Sentinel功能、原理、架構、快速入門以及相關框架比較
基本介紹
1 名詞解釋
- 服務限流 :當系統資源不夠,不足以應對大量請求,對系統按照預設的規則進行流量限制或功能限制
- 服務熔斷:當調用目標服務的請求和調用大量超時或失敗,服務調用方為避免造成長時間的阻塞造成影響其他服務,后續對該服務接口的調用不再經過進行請求,直接執行本地的默認方法
- 服務降級:為了保證核心業務在大量請求下能正常運行,根據實際業務情況及流量,對部分服務降低優先級,有策略的不處理或用簡單的方式處理
服務降級的實現可以基于人工開關降級(秒殺、電商大促等)和自動檢測(超時、失敗次數、故障),熔斷可以理解為一種服務故障降級處理
2 為什么需要限流降級
系統承載的訪問量是有限的,如果不做流量控制,會導致系統資源占滿,服務超時,從而所有用戶無法使用,通過服務限流控制請求的量,服務降級省掉非核心業務對系統資源的占用,最大化利用系統資源,盡可能服務更多用戶
3 Sentinel簡介
Sentinel: 分布式系統的流量防衛兵,是阿里中間件團隊2018年7月開源的,面向分布式服務架構的輕量級流量控制產品,主要以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度來保護系統服務的穩定性
Sentinel 的開源生態:
功能特性
1 總體介紹
Sentinel 具有以下特征:
豐富的應用場景:秒殺限流,消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等
完備的實時監控:Sentinel 同時提供實時的監控功能。可以在控制臺中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集群的匯總運行情況
廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。只需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel
完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。可以通過實現擴展接口來快速地定制邏輯。例如定制規則管理、適配動態數據源等
Sentinel 分為兩個部分:
控制臺(Dashboard) 基于 Spring Boot 開發,打包后可以直接運行,不需要額外的 Tomcat 等應用容器
核心庫(JAVA 客戶端) 不依賴任何框架/庫,能夠運行于所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持
2 控制臺特性
- 實時監控
- 支持自動發現集群機器列表、服務健康狀態、服務調用通過/拒絕QPS、調用耗時、圖表統計
- 規則管理及推送
- 支持在界面配置流控、降級、熱點規則,并實時推送
- 鑒權
- 控制臺支持自定義鑒權接口,提供基本登錄功能
3 核心庫功能特性
(1) 應用流控
針對指定應用實例的流量控制,監控應用流量QPS或并發線程數,當達到指定的閾值時對流量進行控制,以避免被瞬時的流量高峰沖垮,從而保障應用的高可用性
流量控制的手段包括:
- 直接拒絕
- Warm Up,即預熱/冷啟動方式,讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被瞬間壓垮
- 勻速排隊,嚴格控制請求通過的間隔時間,讓請求以均勻的速度通過
(2) 集群流控
不同于應用流控根據單個應用實例閾值執行限流檢查,集群流控只對整個集群調用總量進行限流,例如以下場景:
- 限制某個用戶調用某個API的總QPS,提供API的應用在多個機器上部署了多個實例
- 因為多個應用實例流量不均勻,導致集群調用總量沒有到的情況下某些機器就開始限流
僅靠單機維度去限制的話會無法精確地限制總體流量,通過集群精確地控制整個集群的調用總量,結合單機限流兜底,可以更好地發揮流量控制的效果
(3) 網關流控
Sentinel 支持對 Spring Cloud Gateway、Zuul 等主流的 API Gateway 進行限流
網關流控針對 API網關的場景定制的限流規則,可以針對不同 route 或自定義的 API 分組進行限流,支持針對請求中的路徑、參數、Header、來源 IP 等進行定制化的限流
(4) 熔斷降級
如果調用鏈路中的某個資源不穩定,最終會導致請求發生堆積,通過熔斷降級能在調用鏈路中某個資源出現不穩定狀態時(包括調用超時、異常比例升高、異常數升高),對這個資源的調用進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯錯誤
當資源被降級后,在接下來的降級時間窗口之內,對該資源的調用都自動熔斷(默認行為是拋出 DegradeException),經過時間窗口之后,退出熔斷,并在下一次資源出現不穩定狀態再次自動熔斷
(5) 熱點參數限流
熱點即經常訪問的數據,熱點參數限流會統計傳入參數中的熱點參數,并根據配置的限流閾值與模式,對包含熱點參數的資源調用進行限流例如以下場景:
- 用戶ID為參數,限制用戶對接口的范圍QPS
- 商品ID為參數,限制商品下單接口頻率
(6) 系統自適應限流
為了解決傳統方案:基于操作系統負載(load1,linux下用uptime查看)做進行自適應限流,帶來的存在延時、系統性能恢復慢的問題,Sentinel采用新的思路:根據系統能夠處理的請求,和允許進來的請求,來做平衡,而不是根據一個間接的指標(系統 load)來做限流
目標在于:在系統不被拖垮的情況下,盡可能提高系統的吞吐率,而不是 負載 一定要到低于某個閾值
系統保護規則是從應用級別的入口流量進行控制,從單臺機器的總體 Load、RT、入口 QPS 和線程數四個維度監控應用數據,當實際運行達到限定閾值進行限流保護,支持的閾值類型:
- Load:當系統 load1 超過閾值,且系統當前的并發線程數超過系統容量時才會觸發系統保護。系統容量由系統時間運行監測到的的 maxQps * minRt (最小響應時間)計算得出
- RT:當單臺機器上所有入口流量的平均 RT(響應時間)
- 線程數:當單臺機器上所有入口流量的并發線程數
- 入口 QPS:當單臺機器上所有入口流量的 QPS
(7) 黑白名單控制
Sentinel黑白名單根據資源的請求來源(origin)限制資源是否通過,若配置白名單則只有請求來源位于白名單內時才可通過;若配置黑名單則請求來源位于黑名單時不通過,其余的請求通過
快速入門
1 安裝控制臺
從github release頁面(https://github.com/alibaba/Sentinel/releases)下載最新控制臺jar包
命令行啟動控制臺:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
2 應用接入Sentinel
Sentinel適配了常見主流框架,包括Dubbo、Spring Boot、Spring WebFlux、gRPC、Zuul、Spring Cloud Gateway、RocketMQ、Web Servlet,對于需要限流的資源,支持用原生Java的try-catch 接入或者使用注解
下面以常見的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指定控制臺地址:
spring: cloud: sentinel: transport: dashboard: IP:端口號
定義需要限流的資源:
@RestController public class TestController { @GetMapping(value = "/hello") // 定義需要限流的資源名稱為hello @SentinelResource("hello") public String hello() { return "Hello Sentinel"; } }
請求一次上面的http hello接口后,觸發Sentinel客戶端初始化,才能在控制臺看到接口
添加流控規則:
頻繁請求接口,可以看到部分請求被拒絕:
注意:上面的配置方式是沒有做持久化的,生產環境不建議使用
3 規則配置
Sentinel 提供 動態規則數據源 支持來動態地管理、讀取配置的規則。Sentinel 提供的 ReadableDataSource 和 WritableDataSource 接口簡單易用,非常方便使用。
Sentinel 動態規則源針對常見的配置中心和遠程存儲進行適配,目前已支持 Nacos、ZooKeeper、Apollo、redis 等多種動態規則源,可以覆蓋到很多的生產場景
實現原理
下面介紹Sentinel客戶端基本原理
1 基本概念
- Resource 資源
- Sentinel中,需要被流量保護的方法、代碼塊都可以稱為資源,每個資源都需要定義一個唯一的資源名詞,用于匹配相關規則
- Entry
- Sentinel功能入口類,Entry 可以通過對主流框架的適配自動創建,也可以通過注解的方式或調用 SphU API 顯式創建,創建后執行資源和規則匹配和校驗
- Slot
- 功能插槽,由Enty類創建,每個資源對應一系列Slot,Slot實現資源信息收集、規則匹配、校驗的,多個Slot通過組成Slot Chain,在進入資源和退出資源時分別基于責任鏈模式調用entry()和exit()方法
2 工作原理
一個簡單的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(); } }
主要流程如下:
- 進入資源方法之前,基于SphU創建Entry,Entry獲取查找資源關聯的Slot Chain信息,如果找不到則創建,并基于責任鏈模式調用Slot的entry()方法
- 資源方法調用
- 資源方法調用完成后,通過Entry觸發Slot的exit()邏輯
框架比較
Sentinel Hystrix resilience4j 隔離策略 信號量隔離(并發線程數限流) 線程池隔離/信號量隔離 信號量隔離 熔斷降級策略 基于響應時間、異常比率、異常數 基于異常比率 基于異常比率、響應時間 實時統計實現 滑動窗口(LeapArray) 滑動窗口(基于 RxJava) Ring Bit Buffer 動態規則配置 支持多種數據源 支持多種數據源 有限支持 擴展性 多個擴展點 插件的形式 接口的形式 基于注解的支持 支持 支持 支持 限流 基于 QPS,支持基于調用關系的限流 有限的支持 Rate Limiter 流量整形 支持預熱模式、勻速器模式、預熱排隊模式 不支持 簡單的 Rate Limiter 模式 系統自適應保護 支持 不支持 不支持 控制臺 提供開箱即用的控制臺,可配置規則、查看秒級監控、機器發現等 簡單的監控查看 不提供控制臺,可對接其它監控系統 值得補充的是:相比Hystrix基于線程池隔離進行限流,這種方案雖然隔離性比較好,但是代價就是線程數目太多,線程上下文切換的 overhead 比較大,特別是對低延時的調用有比較大的影響。
Sentinel 并發線程數限流不負責創建和管理線程池,而是簡單統計當前請求上下文的線程數目,如果超出閾值,新的請求會被立即拒絕,效果類似于信號量隔離
參考
《Sentinel官方文檔》
https://github.com/alibaba/Sentinel/wiki
《從 Hystrix 遷移到 Sentinel》
https://github.com/alibaba/Sentinel/wiki/Guideline:-從-Hystrix-遷移到-Sentinel
更多精彩,歡迎關注公眾號【分布式系統架構】