基于系統(tǒng)負載的動態(tài)限流組件 dynamic-limiter

基于系統(tǒng)負載的動態(tài)限流組件 dynamic-limiter

來源:Qunar 技術沙龍

背景

一個系統(tǒng)的處理能力是有限的,當請求量超過處理能力時,通常會引起排隊,造成響應時間迅速提升。如果對服務占用的資源量沒有約束,還可能因為系統(tǒng)資源占用過多而宕機。因此,為了保證系統(tǒng)在遭遇突發(fā)流量時,能夠正常運行,需要為你的服務加上限流。

通常限流可以分為兩類:單機限流、全局限流。常見的單機限流工具有 Guava RateLimiter 和 Java Semaphore,全局限流可以用 Redis 做全局計數(shù)器來實現(xiàn),基礎架構(gòu)組也提供了一個靈活的全局限流組件 common-blocking。這些限流工具有一個共同的缺點:都需要手動設置一個固定的限流閾值。

首先,手動設置固定閾值需要做容量評估,準確的容量評估是比較難的。其次,在每次系統(tǒng)更新升級后,閾值會變得不再準確,需要重新調(diào)整,比較繁瑣。再次,固定閾值也不能應對服務器性能波動的情況,對于一些日志量比較大的應用,整點日志壓縮時,會消耗較多性能,此時系統(tǒng)的處理能力肯定比其他時候要稍差一些。最后,應用大多運行在虛擬機上,同一個實體機上的虛擬機之間也會相互影響,這個體現(xiàn)在監(jiān)控上就是 CPU 使用率里的 steal 值了。

既然固定閾值有這么多缺點,我們就想有沒有什么辦法能夠自動計算限流閾值呢?下面介紹一下:基于系統(tǒng)負載的動態(tài)限流。

動態(tài)限流原理

為什么叫動態(tài)限流呢?因為我們希望在系統(tǒng)運行時,限流閾值能夠根據(jù)實際情況做動態(tài)調(diào)整。具體根據(jù)什么來調(diào)整呢?系統(tǒng)負載,這里我們使用了最常見的三種監(jiān)控指標:CPU 使用率、Load 和服務的響應時間。

動態(tài)限流的目標是,計算一個合理的閾值,讓系統(tǒng)在提供最大處理能力的同時,保持健壯,不被壓垮。

動態(tài)限流的基本思路可以看下面這幅圖,系統(tǒng)負載反過來說就是系統(tǒng)的健康程度。當系統(tǒng)負載較低,處于健康狀態(tài)時不限流。當系統(tǒng)負載稍高,處于不健康狀態(tài)時,以最近幾秒處理請求的 QPS 計算限流閾值。當系統(tǒng)負載過高,狀態(tài)惡化時,讓限流閾值以一定的系數(shù)進行衰減,直到系統(tǒng)負載降低,系統(tǒng)狀態(tài)由惡化變?yōu)椴唤】担罱K讓系統(tǒng)負載收斂在兩個負載閾值之間。

動態(tài)限流基本思路

前面提到在健康狀態(tài)下不限流,那么系統(tǒng)在從健康狀態(tài)變?yōu)椴唤】祷驉夯癄顟B(tài)時,就需要計算一個初始限流閾值,初始限流閾值的計算參考了健康狀態(tài)的 QPS 和當前處理請求的 QPS。具體的計算公式如下圖所示,其中 H 表示健康狀態(tài)下的 QPS,C 表示當前處理請求的 QPS。

限流初始閾值的計算公式

其中的重點是系統(tǒng)狀態(tài)從健康變成惡化時的閾值計算,限流閾值等于 H 乘以一個系數(shù),這個系數(shù)是 C 除以 H 的二分之一次方,也就是流量暴漲倍數(shù)的二分之一次方。這樣計算的目的,是避免像下圖這樣的情況,初始閾值設置的不合理時,限流閾值收斂到合理區(qū)間太慢,浪費系統(tǒng)資源。

初始限流閾值不合理的情況

初始閾值設定之后,還需要根據(jù)系統(tǒng)負載進行動態(tài)調(diào)整,如何動態(tài)調(diào)整呢?可以先看下面這幅閾值調(diào)整示意圖,相比之前的基本思路圖,這里多了一個負載閾值 0,設置它的目的是希望當初始閾值設置不合理導致系統(tǒng)負載變得很低時,能夠快速提升閾值。當系統(tǒng)負載接近收斂區(qū)間時,進行細微調(diào)整,避免步子邁得太大,把系統(tǒng)搞垮了。簡單說就是當系統(tǒng)負載低的時候,快速調(diào)整,當系統(tǒng)負載高的時候,細微調(diào)整。

閾值動態(tài)調(diào)整示意圖

在實際中,負載閾值 1 和 2 可以靈活配置,為了減少配置工作量,負載閾值 0 固定為負載閾值 1 的 70%。

最后再說一下,何時不再限流,恢復正常呢?當突發(fā)流量消失,系統(tǒng)能夠處理全部請求,并且處于健康狀態(tài)時,不再限流。

到這里動態(tài)限流的原理就講完了,下面我們看一下線上測試效果。

測試效果

最初我們做了基于 Load 的動態(tài)限流,服務器 CPU 是 4 核的,所以兩個負載閾值分別設置成 3 和 5,限流閾值更新頻率為 1 秒一次。

實際效果請看下面的監(jiān)控圖,左邊是 10 倍流量壓測而未開限流的情況,未開限流時 CPU 使用率高達 99%,Load 也高達 20。中間打開限流之后,Load 降到 5 左右,CPU 使用率也降了下去,但是波動很大,為什么呢?想到之前看過的文章里提到 Load 是 5 秒采樣一次,而這里閾值 1 秒更新一次,更新太快了,更新之后還沒有體現(xiàn)在 Load 計算上就又更新了。

基于 Load 的動態(tài)限流測試 1

當我們將閾值更新頻率改為 10 秒一次時,從下圖可以看出來,CPU 和 Load 的波動小了很多。

基于 Load 的動態(tài)限流測試 2

看監(jiān)控我們發(fā)現(xiàn) Load 在 3 到 5 之間波動時,CPU 使用率才 60%,還有提高的空間。我們知道 Load 和 CPU 不同步的原因是,Load 不僅和計算有關,也和 IO 有關。而報價是計算密集型的應用,所以我們又試驗了基于 CPU 使用率的動態(tài)限流。

我們將閾值設定為 70 到 90,看下面的監(jiān)控圖,CPU 使用率基本穩(wěn)定在 70 到 90 之間,Load 稍微高一些。壓測之后搜索耗時從 70 漲到了 150 并保持穩(wěn)定,穩(wěn)定就表示服務是正常的。

基于 CPU 的動態(tài)限流壓測效果

下面我們再看一下,基于 CPU 和基于 Load 限流時搜索成功量的對比,分別是 164 和 134,說明基于 CPU 的限流的確提升了系統(tǒng)處理能力,提高了資源利用效率。

Load 和 CPU 動態(tài)限流對比

一些服務可能對響應時間比較敏感,所以我們又做了基于時間的動態(tài)限流,當我們將閾值設定在 140 到 200 之間時,看監(jiān)控壓測之后搜索耗時也基本穩(wěn)定在這個 140 到 200 之間,CPU 和 Load 監(jiān)控也保持穩(wěn)定。

基于 TIME 的動態(tài)限流壓測效果

總結(jié)

我們將上述講的基于負載的動態(tài)限流封裝到了一個 API dynamic-limiter 中,供各個系統(tǒng)使用。最后總結(jié)一下,動態(tài)限流適合什么樣的場景呢?

  1. 如果你的系統(tǒng)內(nèi)單個服務占用大部分資源,就可以使用基于 CPU 或 Load 的動態(tài)限流。
  2. 如果你的服務對響應時間要求比較高,可以使用基于時間的動態(tài)限流。

實際中,也可以同時參考多種因素來進行動態(tài)限流,起到一個多重約束的作用。比如同時使用 CPU 和 TIME 時,表示既對 CPU 使用率有一個硬約束,又對服務響應時間有一個硬約束。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 當資源成為瓶頸時,服務框架需要對消費者做限流,啟動流控保護機制。流量控制有多種策略,比較常用的有:針對訪問速率的靜...
    c84f3109853b閱讀 5,978評論 0 2
  • [TOC] 系統(tǒng)設計:關于高可用系統(tǒng)的一些技術方案 可靠的系統(tǒng)是業(yè)務穩(wěn)定、快速發(fā)展的基石。那么,如何做到系統(tǒng)高可靠...
    albon閱讀 2,012評論 0 14
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 操蛋的人生, 有時候真是無法預料。 悲歡離合,酸甜苦辣,人生百態(tài)。 你始終不知道生活下一刻會迎來什么樣的滋味。 你...
    元氣滿滿的慧慧醬閱讀 480評論 0 2
  • Frank Sinatra的曲子回蕩在開著暖氣的房間 我聽到了,往烈酒杯子里,加冰塊的聲音 記起了童年的冬天 爐子...
    很深的綠閱讀 146評論 0 0

友情鏈接更多精彩內(nèi)容