阿里開源限流元件 Sentinel 叢集流控全解析

碼洞發表於2019-01-17

為什麼需要叢集流控功能?

假設我們希望給某個使用者限制呼叫某個 API 的總 QPS 為 50,但機器數可能很多(比如有 100 臺)。這時候我們很自然地就想到,找一個 server 專門用來統計總的呼叫量,其它的例項都與這臺 server 通訊以判斷是否可以呼叫。這就是最基礎的叢集流控的方式。

那麼這個 server 如何部署呢?最直觀的方式就是作為獨立的 token server 程式啟動,獨立部署:

阿里開源限流元件 Sentinel 叢集流控全解析


另一種就是嵌入模式(Embedded),即作為內建的 token server 與服務在同一程式中啟動,無需單獨部署:

阿里開源限流元件 Sentinel 叢集流控全解析


此外,叢集流控還可以解決流量不均勻導致總體限流效果不佳的問題。

假設叢集中有 10 臺機器,我們給每臺機器設定單機限流閾值為 10 QPS,理想情況下整個叢集的限流閾值就為 100 QPS。不過實際情況下流量到每臺機器可能會不均勻,會導致總量沒有到的情況下某些機器就開始限流:

阿里開源限流元件 Sentinel 叢集流控全解析

因此,僅靠單機維度去限制的話會無法精確地限制總體流量。而叢集流控可以精確地控制整個叢集的呼叫總量,結合單機限流兜底,可以更好地發揮流量控制的效果。

Sentinel的叢集流控功能是什麼?

Sentinel 1.4.0 開始引入了叢集流控模組,主要分為兩個部分:

  • Token Client: 即叢集流控客戶端,用於向所屬 Token Server 通訊請求 token。叢集限流服務端會返回給客戶端結果,決定是否限流。Sentinel 叢集流控的通訊底層採用 Netty 實現。

  • Token Server: 即叢集流控服務端,處理來自 Token Client 的請求,根據配置的叢集規則判斷是否應該發放 token(是否允許透過)。

Sentinel 叢集流控支援限流規則和熱點規則兩種規則,並支援兩種形式的閾值計算方式:

  • 叢集總體模式:即限制整個叢集內的某個資源的總體 QPS 不超過此閾值。

  • 單機均攤模式:單機均攤模式下配置的閾值等同於單機能夠承受的限額,Token Server 會根據連線數來計算總的閾值(比如獨立模式下有 3 個 client 連線到了 token server,然後配的單機均攤閾值為 10,則計算出的叢集總量就為 30),按照計算出的總的閾值來進行限制。這種方式根據當前的連線數實時計算總的閾值,對於機器經常進行變更的環境非常適合。

如何使用Sentinel的叢集流控功能?

部署方式

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 模式:

阿里開源限流元件 Sentinel 叢集流控全解析

  • 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}]

阿里開源限流元件 Sentinel 叢集流控全解析

然後像 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 控制檯實時進行推送。流程如下所示:

阿里開源限流元件 Sentinel 叢集流控全解析

以流控規則為例,假設我們使用 ZooKeeper 作為配置中心,則可以向客戶端 FlowRuleManager 註冊 ZooKeeper 動態規則源:

source FlowRuleManager

另外,我們還需要針對 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 目錄下)。我們只需要實現自己的 DynamicRulePublisherDynamicRuleProvider介面並在 FlowControllerV2類中相應位置透過 @Qualifier註解指定對應的 bean name 即可,類似於:

@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;

@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

Sentinel 控制檯提供應用維度推送的頁面(/v2/flow)。在上述配置完成後,我們可以在此頁面向配置中心推送規則:

阿里開源限流元件 Sentinel 叢集流控全解析

(4)控制檯分配 Token Server

當上面的步驟都完成後,我們就可以在 Sentinel 控制檯的“叢集流控” Token Server 列表頁面管理分配 token server 了。假設我們啟動了三個應用例項,我們選擇一個例項為 token server,其它兩個為 token client:

阿里開源限流元件 Sentinel 叢集流控全解析

頁面上機器的顯示方式為 ip@commandPort,其中 commandPort 為應用端暴露給 Sentinel 控制檯的埠。選擇好以後,點選 儲存 按鈕,重新整理頁面即可以看到 token server 分配成功:

阿里開源限流元件 Sentinel 叢集流控全解析

並且我們可以在頁面檢視 token server 的連線情況:

阿里開源限流元件 Sentinel 叢集流控全解析

(5)配置規則,觀察效果

接下來我們配置一條叢集限流規則,限制 com.alibaba.csp.sentinel.demo.cluster.app.service.DemoService:sayHello(java.lang.String)  資源的叢集總 QPS 為 10,選中“是否叢集”選項,閾值模式選擇總體閾值:

阿里開源限流元件 Sentinel 叢集流控全解析

模擬流量同時請求這三臺機器,過一段時間後觀察效果。可以在監控頁面看到對應資源的叢集維度的總 QPS 穩定在 10。

阿里開源限流元件 Sentinel 叢集流控全解析

還有哪些問題需要注意?

叢集流控能夠精確地控制整個叢集的 QPS,結合單機限流兜底,可以更好地發揮流量控制的效果。

還有更多的場景等待大家發掘,比如:

  • 在 API Gateway 處統計某個 API 的總訪問量,並對某個 API 或服務的總 QPS 進行限制

  • Service Mesh 中對服務間的呼叫進行全域性流控

  • 叢集內對熱點商品的總訪問頻次進行限制

儘管叢集流控比較好用,但它不是萬能的,只有在確實有必要的場景下才推薦使用叢集流控。

另外若在生產環境使用叢集限流,管控端還需要關注以下的問題:

  • Token Server 自動管理(分配/選舉 Token Server)

  • Token Server 高可用,在某個 server 不可用時自動 failover 到其它機器

未來我們還計劃實現叢集流控多語言版本的客戶端,並對接 Service Mesh,讓 Sentinel 叢集流控可以在更多場景下使用。

本文作者:宿何,社群暱稱sczyh30,阿里巴巴高可用架構組開發工程師,目前主要負責Sentinel 開源專案的開發和社群維護。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31561269/viewspace-2564053/,如需轉載,請註明出處,否則將追究法律責任。

相關文章