自去年10月底釋出GA版本後,Sentinel在近期釋出了另一個裡程碑版本v1.4(最新的版本号是v1.4.1),加入了開發者關注的叢集流控功能。
叢集流控簡介
為什麼要使用叢集流控呢?假設我們希望給某個使用者限制調用某個 API 的總 QPS 為 50,但機器數可能很多(比如有 100 台)。這時候我們很自然地就想到,找一個 server 來專門來統計總的調用量,其它的執行個體都與這台 server 通信來判斷是否可以調用。這就是最基礎的叢集流控的方式。
那麼這個 server 如何部署呢?最直覺的方式就是作為獨立的 token server 程序啟動,獨立部署:

另一種就是嵌入模式(Embedded),即作為内置的 token server 與服務在同一程序中啟動,無需單獨部署:
另外叢集流控還可以解決流量不均勻導緻總體限流效果不佳的問題。假設叢集中有 10 台機器,我們給每台機器設定單機限流門檻值為 10 QPS,理想情況下整個叢集的限流門檻值就為 100 QPS。不過實際情況下流量到每台機器可能會不均勻,會導緻總量沒有到的情況下某些機器就開始限流:
是以僅靠單機次元去限制的話會無法精确地限制總體流量。而叢集流控可以精确地控制整個叢集的調用總量,結合單機限流兜底,可以更好地發揮流量控制的效果。
Sentinel 1.4.0 開始引入了叢集流控子產品,主要分為兩個部分:Token Client 和 Token Server:
- Token Client 即叢集流控用戶端,用于向所屬 Token Server 通信請求 token。叢集限流服務端會傳回給用戶端結果,決定是否限流。Sentinel 叢集流控的通信底層采用 Netty 實作。
- Token Server 即叢集流控服務端,處理來自 Token Client 的請求,根據配置的叢集規則判斷是否應該發放 token(是否允許通過)。
Sentinel 叢集流控支援限流規則和熱點規則兩種規則。叢集流控支援兩種形式的門檻值計算方式:
- 叢集總體模式:即限制整個叢集内的某個資源的總體 QPS 不超過此門檻值。
- 單機均攤模式:單機均攤模式下配置的門檻值等同于單機能夠承受的限額,Token Server 會根據連接配接數來計算總的門檻值(比如獨立模式下有 3 個 client 連接配接到了 token server,然後配的單機均攤門檻值為 10,則計算出的叢集總量就為 30),按照計算出的總的門檻值來進行限制。這種方式根據目前的連接配接數實時計算總的門檻值,對于機器經常進行變更的環境非常适合。
部署方式
Sentinel 叢集流控服務端支援獨立模式(Alone)以及嵌入模式(Embedded)。兩者的優缺點對比:
- 獨立模式作為獨立的 token server 程序啟動,獨立部署,隔離性好,但是需要額外的部署操作。獨立模式适合作為 Global Rate Limiter 給整個叢集提供流控服務。
-
嵌入模式作為内置的 token server 嵌入到應用程序中。嵌入模式下叢集中各個執行個體都是對等的,token server 和 client 可以随時進行轉變,無需單獨部署,靈活性比較好。但缺點就是隔離性不佳,
需要限制 token server 的總 QPS,防止影響應用本身。嵌入模式适合某個應用叢集内部的流控。
Sentinel 提供 API 來對 client / server 進行配置以及指定模式,但是機器多的時候不友善進行管理。一般我們需要通過 Sentinel 控制台的叢集流控管理功能來統一管理某個應用叢集下所有的 token server 和 token client,靈活進行配置設定。
配置
配置是叢集流控中比較重要的一部分。Sentinel 叢集流控的配置主要包含幾部分:
叢集規則配置
叢集規則配置需要借助動态規則源。以叢集流控規則為例,對于用戶端,我們可以用之前的方式向
FlowRuleManager
注冊動态規則源。而對于 Token Server,我們需要向叢集規則管理器
ClusterFlowRuleManager
注冊規則源。我們推薦的方式是在應用端注冊動态規則源,然後在 Sentinel 控制台直接推送規則到配置中心,即 push 模式:
Token Server / Client 的配置設定
以嵌入模式為例,一個比較好的實踐是:結合流量分布和實時負載情況來在服務叢集中選取幾台較為空閑的機器作為 Token Server,其它的機器作為 Token Client,劃分成幾組,分别歸屬各自的 Token Server 管理。最後組成一個映射表,類似于:
// ip: token server IP, port: token server port, clientSet: 所管轄的 token client 集合
[{"clientSet":["112.12.88.66@8729","112.12.88.67@8727"],"ip":"112.12.88.68","machineId":"112.12.88.68@8728","port":11111}]
然後像 Token Client / Token Server 通信配置、叢集流控模式等配置源都可以監聽這個配置設定映射表對應的資料源,來解析自己的身份和相關通信配置。當配置設定映射表變更時每台機器對應的身份和配置也會實時變更,實時生效。Sentinel 1.4.1 改進了 Sentinel 控制台叢集流控的管理頁面,可以直接以應用次元來配置設定 Token Server。可以參考本文後面的指引來使用。
其它配置
其它的配置比如 Token Server 的命名空間集合(namespace set,用于指定該 Token Server 可以為哪些應用/分組服務)、最大允許的總 QPS 等,既可以通過 Sentinel 預留的 HTTP API 來變更配置,也可以通過注冊動态配置源來進行配置。
快速使用叢集流控
下面我們來看一下如何快速使用叢集流控功能。接入叢集流控子產品的步驟如下:
(1)引入叢集流控依賴
這裡我們以嵌入模式來運作 token server,即在應用叢集中指定某台機器作為 token server,其它的機器指定為 token client。
首先我們引入叢集流控相關依賴:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-client-default</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>1.4.1</version>
</dependency>
(2)配置動态規則源
要想使用叢集流控功能,我們需要在應用端配置動态規則源,并通過 Sentinel 控制台實時進行推送。流程如下所示:
以流控規則為例,假設我們使用 ZooKeeper 作為配置中心,則可以向用戶端
FlowRuleManager
注冊 ZooKeeper 動态規則源:
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new ZookeeperDataSource<>(remoteAddress, path, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
另外我們還需要針對 Token Server 注冊叢集規則資料源。由于嵌入模式下 token server 和 client 可以随時變換,是以我們隻需在每個執行個體都向叢集流控規則管理器
ClusterFlowRuleManager
注冊動态規則源即可。Token Server 抽象出了命名空間(namespace)的概念,可以支援多個應用/服務,是以我們需要注冊一個自動根據 namespace 建立動态規則源的生成器:
// Supplier 會根據 namespace 生成的動态規則源,類型為 SentinelProperty<List<FlowRule>>,針對不同的 namespace 生成不同的規則源(監聽不同 namespace 的 path).
// 預設 namespace 為應用名(project.name)
// ClusterFlowRuleManager 針對叢集限流規則,ClusterParamFlowRuleManager 針對叢集熱點規則,配置方式類似
ClusterFlowRuleManager.setPropertySupplier(namespace -> {
return new SomeDataSource(address, dataIdPrefix + namespace).getProperty();
});
(3)控制台進行改造适配動态規則源
我們隻需簡單對 Sentinel 控制台進行改造即可直接将流控規則推送至配置中心。從 Sentinel 1.4.0 開始,Sentinel 控制台提供
DynamicRulePublisher
和
DynamicRuleProvider
接口用于實作應用次元的規則推送和拉取,并提供了 Nacos 推送的示例(位于 test 目錄下)。我們隻需要實作自己的
DynamicRulePublisher
DynamicRuleProvider
接口并在
FlowControllerV2
類中相應位置通過
@Qualifier
注解指定對應的 bean name 即可,類似于:
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
Sentinel 控制台提供應用次元推送的頁面(
/v2/flow
)。在上述配置完成後,我們可以在此頁面向配置中心推送規則:
(4)控制台配置設定 Token Server
當上面的步驟都完成後,我們就可以在 Sentinel 控制台的“叢集流控” Token Server 清單頁面管理配置設定 token server 了。假設我們啟動了三個應用執行個體,我們選擇一個執行個體為 token server,其它兩個為 token client:
頁面上機器的顯示方式為
ip@commandPort
,其中
commandPort
為應用端暴露給 Sentinel 控制台的端口。選擇好以後,點選 儲存 按鈕,重新整理頁面即可以看到 token server 配置設定成功:
并且我們可以在頁面檢視 token server 的連接配接情況:
(5)配置規則,觀察效果
接下來我們配置一條叢集限流規則,限制
com.alibaba.csp.sentinel.demo.cluster.app.service.DemoService:sayHello(java.lang.String)
資源的叢集總 QPS 為 10,選中“是否叢集”選項,門檻值模式選擇總體門檻值:
模拟流量同時請求這三台機器,過一段時間後觀察效果。可以在監控頁面看到對應資源的叢集次元的總 QPS 穩定在 10:
總結
叢集流控能夠精确地控制整個叢集的 QPS,結合單機限流兜底,可以更好地發揮流量控制的效果。還有更多的場景等待大家發掘,比如:
- 在 API Gateway 處統計某個 API 的總通路量,并對某個 API 或服務的總 QPS 進行限制
- Service Mesh 中對服務間的調用進行全局流控
- 叢集内對熱點商品的總通路頻次進行限制
盡管叢集流控比較好用,但它不是萬能的,隻有在确實有必要的場景下才推薦使用叢集流控。
另外若在生産環境使用叢集限流,管控端還需要關注以下的問題:
- Token Server 自動管理(配置設定/選舉 Token Server)
- Token Server 高可用,在某個 server 不可用時自動 failover 到其它機器
未來我們還計劃實作叢集流控多語言版本的用戶端,并對接 Service Mesh,讓 Sentinel 叢集流控可以在更多場景下使用。