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

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

來源:Qunar 技術(shù)沙龍

背景

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

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

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

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

動(dòng)態(tài)限流原理

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

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

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

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

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

限流初始閾值的計(jì)算公式

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

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

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

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

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

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

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

測(cè)試效果

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

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

基于 Load 的動(dòng)態(tài)限流測(cè)試 1

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

基于 Load 的動(dòng)態(tài)限流測(cè)試 2

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

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

基于 CPU 的動(dòng)態(tài)限流壓測(cè)效果

下面我們?cè)倏匆幌?,基?CPU 和基于 Load 限流時(shí)搜索成功量的對(duì)比,分別是 164 和 134,說明基于 CPU 的限流的確提升了系統(tǒng)處理能力,提高了資源利用效率。

Load 和 CPU 動(dòng)態(tài)限流對(duì)比

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

基于 TIME 的動(dòng)態(tài)限流壓測(cè)效果

總結(jié)

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

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

實(shí)際中,也可以同時(shí)參考多種因素來進(jìn)行動(dòng)態(tài)限流,起到一個(gè)多重約束的作用。比如同時(shí)使用 CPU 和 TIME 時(shí),表示既對(duì) CPU 使用率有一個(gè)硬約束,又對(duì)服務(wù)響應(yīng)時(shí)間有一個(gè)硬約束。

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

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

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

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