集群流量控制
介紹
為什么要使用集群流控呢灰伟?假設(shè)我們希望給某個用戶限制調(diào)用某個 API 的總 QPS 為 50木蹬,但機器數(shù)可能很多(比如有 100 臺)。
這時候我們很自然地就想到第步,找一個 server 來專門來統(tǒng)計總的調(diào)用量虏劲,其它的實例都與這臺 server 通信來判斷是否可以調(diào)用。
這就是最基礎(chǔ)的集群流控的方式演闭。
另外集群流控還可以解決流量不均勻?qū)е驴傮w限流效果不佳的問題。假設(shè)集群中有 10 臺機器颓帝,我們給每臺機器設(shè)置單機限流閾值為 10 QPS米碰,
理想情況下整個集群的限流閾值就為 100 QPS。不過實際情況下流量到每臺機器可能會不均勻购城,會導致總量沒有到的情況下某些機器就開始限流吕座。
因此僅靠單機維度去限制的話會無法精確地限制總體流量。
而集群流控可以精確地控制整個集群的調(diào)用總量瘪板,結(jié)合單機限流兜底吴趴,可以更好地發(fā)揮流量控制的效果。
集群流控中共有兩種身份:
- Token Client:集群流控客戶端侮攀,用于向所屬 Token Server 通信請求 token锣枝。集群限流服務(wù)端會返回給客戶端結(jié)果,決定是否限流兰英。
- Token Server:即集群流控服務(wù)端撇叁,處理來自 Token Client 的請求,根據(jù)配置的集群規(guī)則判斷是否應(yīng)該發(fā)放 token(是否允許通過)
項目模塊結(jié)構(gòu)
Sentinel 1.4.0 開始引入了集群流控模塊畦贸,主要包含以下幾部分:
- sentinel-cluster-common-default: 公共模塊陨闹,包含公共接口和實體
- sentinel-cluster-client-default: 默認集群流控 client 模塊,使用 Netty 進行通信薄坏,提供接口方便序列化協(xié)議擴展
- sentinel-cluster-server-default: 默認集群流控 server 模塊趋厉,使用 Netty 進行通信,提供接口方便序列化協(xié)議擴展胶坠;
同時提供擴展接口對接規(guī)則判斷的具體實現(xiàn)(TokenService)君账,默認實現(xiàn)是復用 sentinel-core 的相關(guān)邏輯
集群流控規(guī)則
規(guī)則
private boolean clusterMode; // 標識是否為集群限流配置
private ClusterFlowConfig clusterConfig; // 集群限流相關(guān)配置項
ClusterFlowConfig:
// 全局唯一的規(guī)則 ID,由集群限流管控端分配.
private Long flowId;
// 閾值模式涵但,默認(0)為單機均攤杈绸,1 為全局閾值.
private int thresholdType = ClusterRuleConstant.FLOW_THRESHOLD_AVG_LOCAL;
private int strategy = ClusterRuleConstant.FLOW_CLUSTER_STRATEGY_NORMAL;
// 在 client 連接失敗或通信失敗時,是否退化到本地的限流模式
private boolean fallbackToLocalWhenFail = true;
-
flowId
代表全局唯一的規(guī)則 ID矮瘟,Sentinel 集群限流服務(wù)端通過此 ID 來區(qū)分各個規(guī)則瞳脓,因此務(wù)必保持全局唯一。一般flowId
由統(tǒng)一的管控端進行分配澈侠,或?qū)懭胫?DB 時生成劫侧。 -
thresholdType
代表集群限流閾值模式。其中單機均攤模式下配置的閾值等同于單機能夠承受的限額,token server
會根據(jù)客戶端對應(yīng)的namespace
(默認為 project.name 定義的應(yīng)用名)下的連接數(shù)來計算總的閾值(比如獨立模式下有 3 個 client 連接到了 token server烧栋,然后配的單機均攤閾值為 10写妥,則計算出的集群總量就為 30);而全局模式下配置的閾值等同于整個集群的總閾值审姓。
ParamFlowRule 熱點參數(shù)限流相關(guān)的集群配置與 FlowRule 相似珍特。
配置方式
對于客戶端,我們可以動態(tài)設(shè)置來向 FlowRuleManager 和 ParamFlowRuleManager 注冊動態(tài)規(guī)則源魔吐,例如:
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId, parser);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
對于集群流控 token server扎筒,由于集群限流服務(wù)端有作用域(namespace)的概念,因此我們需要注冊一個自動根據(jù) namespace 生成動態(tài)規(guī)則源的 PropertySupplier:
// Supplier 類型:接受 namespace酬姆,返回生成的動態(tài)規(guī)則源嗜桌,類型為 SentinelProperty<List<FlowRule>>
// ClusterFlowRuleManager 針對集群限流規(guī)則,ClusterParamFlowRuleManager 針對集群熱點規(guī)則辞色,配置方式類似
ClusterFlowRuleManager.setPropertySupplier(namespace -> {
return new SomeDataSource(namespace).getProperty();
});
然后每當集群限流服務(wù)端 namespace set 產(chǎn)生變更時骨宠,Sentinel 會自動針對新加入的 namespace 生成動態(tài)規(guī)則源并進行自動監(jiān)聽,并刪除舊的不需要的規(guī)則源相满。
集群限流客戶端
要使用sentinel集群相關(guān)的功能层亿,引入最新的該依賴:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-client-default</artifactId>
<version>version</version>
</dependency>
用戶可以通過 API 將當前模式置為客戶端模式:
http://<ip>:<port>/setClusterMode?mode=<xxx>
其中 mode 為 0 代表 client,1 代表 server雳灵。設(shè)置成功后棕所,若已有客戶端的配置,集群限流客戶端將會開啟并連接遠程的 token server悯辙。我們可以在 sentinel-record.log 日志中查看連接的相關(guān)日志琳省。
若集群限流客戶端未進行配置,則用戶需要對客戶端進行基本的配置躲撰,比如指定集群限流 token server针贬。我們提供了 API 進行配置:
http://<ip>:<port>/cluster/client/modifyConfig?data=<config>
其中 data 是 JSON 格式的 ClusterClientConfig,對應(yīng)的配置項:
- serverHost: token server host
- serverPort: token server 端口![title]
- requestTimeout: 請求的超時時間(默認為 20 ms)
當然也可以通過動態(tài)配置源進行配置拢蛋。我們可以通過 ClusterClientConfigManager 的 register2Property 方法注冊動態(tài)配置源桦他。配置源注冊的相關(guān)邏輯可以置于 InitFunc 實現(xiàn)類中,并通過 SPI 注冊谆棱,在 Sentinel 初始化時即可自動進行配置源加載監(jiān)聽快压。
若用戶未引入集群限流 client 相關(guān)依賴,或者 client 未開啟/連接失敗/通信失敗垃瞧,則對于開啟了集群模式的規(guī)則:
- 集群熱點限流默認直接通過
- 普通集群限流會退化到 local 模式的限流蔫劣,即在本地按照單機閾值執(zhí)行限流檢查
當 token client 與 server 之間的連接意外斷開時,token client 會不斷進行重試个从,每次重試的間隔時間以 n * 2000 ms 的形式遞增
集群限流服務(wù)端
要想使用集群限流服務(wù)端脉幢,必須引入集群限流 server 相關(guān)依賴:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>1.4.1</version>
</dependency>
-
獨立模式(Alone)歪沃,即作為獨立的 token server 進程啟動,獨立部署嫌松,隔離性好沪曙,但是需要額外的部署操作。獨立模式適合作為 Global Rate Limiter 給集群提供流控服務(wù)萎羔。
title -
嵌入模式(Embedded)液走,即作為內(nèi)置的 token server 與服務(wù)在同一進程中啟動。在此模式下贾陷,集群中各個實例都是對等的育灸,token server 和 client 可以隨時進行轉(zhuǎn)變,因此無需單獨部署昵宇,靈活性比較好。但是隔離性不佳儿子,需要限制 token server 的總 QPS瓦哎,防止影響應(yīng)用本身。嵌入模式適合某個應(yīng)用集群內(nèi)部的流控
title
我們提供了 API 用于在 embedded 模式下轉(zhuǎn)換集群流控身份:
http://<ip>:<port>/setClusterMode?mode=<xxx>
其中 mode 為 0 代表 client柔逼,1 代表 server蒋譬,-1 代表關(guān)閉。注意應(yīng)用端需要引入集群限流客戶端或服務(wù)端的相應(yīng)依賴愉适。
在獨立模式下犯助,我們可以直接創(chuàng)建對應(yīng)的 ClusterTokenServer 實例并在 main 函數(shù)中通過 start 方法啟動 Token Server。
規(guī)則配置
屬性配置
我們推薦給集群限流服務(wù)端注冊動態(tài)配置源來動態(tài)地進行配置维咸。配置類型有以下幾種:
- namespace set: 集群限流服務(wù)端服務(wù)的作用域(命名空間)剂买,可以設(shè)置為自己服務(wù)的應(yīng)用名。集群限流 client 在連接到 token server 后會上報自己的命名空間(默認為 - project.name 配置的應(yīng)用名)癌蓖,token server 會根據(jù)上報的命名空間名稱統(tǒng)計連接數(shù)瞬哼。
- transport config: 集群限流服務(wù)端通信相關(guān)配置,如 server port
- flow config: 集群限流服務(wù)端限流相關(guān)配置租副,如滑動窗口統(tǒng)計時長坐慰、格子數(shù)目、最大允許總 QPS等
集群限流控制臺
整體擴展架構(gòu)
通用擴展接口
以下通用接口位于 sentinel-core
中:
-
TokenService
: 集群限流功能接口用僧,server / client 均可復用 -
ClusterTokenClient
: 集群限流功能客戶端 -
ClusterTokenServer
: 集群限流服務(wù)端接口 -
EmbeddedClusterTokenServer
: 集群限流服務(wù)端接口(embedded
嵌入模式)
以下通用接口位于 sentinel-cluster-common-default:
EntityWriter
EntityDecoder
Client 擴展接口
集群流控 Client 端通信相關(guān)擴展接口:
-
ClusterTransportClient
:集群限流通信客戶端 RequestEntityWriter
ResponseEntityDecoder
Server端擴展接口
集群流控 Server 端通信相關(guān)擴展接口:
ResponseEntityWriter
RequestEntityDecoder
集群流控 Server 端請求處理擴展接口:RequestProcessor
: 請求處理接口 (request -> response)