Sentinel 發布裏程碑版本,添加集群流控功能
自去年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 集群流控可以在更多場景下使用。
Sentinel 發布裏程碑版本,添加集群流控功能