掌握四種常用限流算法,面試包過
在高并發(fā)訪問下,比如電商大促活動,流量持續(xù)不斷的涌入,服務(wù)之間的相互調(diào)用頻率突然增加,引發(fā)系統(tǒng)負(fù)載過高,這時(shí)系統(tǒng)所依賴的服務(wù)的穩(wěn)定性對系統(tǒng)的影響非常大,而且還有很多不確定因素引起雪崩,如網(wǎng)絡(luò)連接中斷,服務(wù)宕機(jī)等。一般微服務(wù)容錯組件提供了限流、隔離、降級、熔斷等手段,可以有效保護(hù)我們的微服務(wù)系統(tǒng)。本文主要說說限流。
限流,就是限制最大流量,防止操作頻率超過定義的限制。系統(tǒng)能提供的最大并發(fā)有限,同時(shí)請求又太多,這就就需要限流,比如秒殺、大促活動業(yè)務(wù),瞬時(shí)大量請求涌入,服務(wù)器服務(wù)不過來,就只好限流了。速率限制通過限制在給定時(shí)間段內(nèi)可以到達(dá) API 的請求數(shù)量來保護(hù)服務(wù)免受意外或惡意過度使用。在沒有速率限制的情況下,任何用戶都可以用請求轟炸您的服務(wù)器,從而導(dǎo)致其他用戶餓死的情況。
為什么要限速?
- 防止資源匱乏:速率限制的最常見原因是通過避免資源匱乏來提高基于 API 的服務(wù)的可用性。如果應(yīng)用速率限制,則可以防止基于負(fù)載的拒絕服務(wù) (doS) 攻擊。即使一個用戶用大量請求轟炸 API,其他用戶也不會挨餓。
- 安全性:速率限制可防止暴力破解登錄、促銷代碼等安全密集型功能。對這些功能的請求數(shù)量在用戶級別受到限制,因此暴力破解算法在這些場景中不起作用。
- 防止運(yùn)營成本:在按使用付費(fèi)模式自動擴(kuò)展資源的情況下,速率限制通過對資源擴(kuò)展設(shè)置虛擬上限來幫助控制運(yùn)營成本。如果不采用速率限制,資源可能會不成比例地?cái)U(kuò)展,從而導(dǎo)致指數(shù)級的賬單。
速率限制策略速率限制可應(yīng)用于以下參數(shù):
- 用戶:限制在給定時(shí)間段內(nèi)允許用戶的請求數(shù)?;谟脩舻乃俾氏拗剖亲畛R姾妥钪庇^的速率限制形式之一。
- 并發(fā)性:這里限制了在給定時(shí)間范圍內(nèi)用戶可以允許的并行會話數(shù)。并行連接數(shù)量的限制也有助于緩解 DDOS 攻擊。
- 位置/ID:這有助于運(yùn)行基于位置或以人口統(tǒng)計(jì)為中心的活動??梢韵拗撇皇莵碜阅繕?biāo)人口統(tǒng)計(jì)的請求,以提高目標(biāo)區(qū)域的可用性
- 服務(wù)器:基于服務(wù)器的速率限制是一種利基策略。這通常在特定服務(wù)器需要大部分請求時(shí)使用,即服務(wù)器與特定功能強(qiáng)耦合
下面介紹下四種常?的限流算法。
1、漏桶算法
漏桶算法的思路,是一種簡單直觀的算法,就是?個固定容量的漏桶,按照常量固定速率流出?滴。如果桶是空的,則不需流出水滴??梢砸匀我馑俾柿魅胨蔚铰┩?。如果流入水滴超出了桶的容量,則流入的水滴溢出了(被丟棄),而漏桶容量是不變的。
這種算法的優(yōu)點(diǎn)是它可以平滑請求的突發(fā)并以恒定的速率處理它們。它也很容易在負(fù)載均衡器上實(shí)現(xiàn),并且對每個用戶來說都是高效的內(nèi)存。無論請求的數(shù)量如何,都保持到服務(wù)器的恒定接近均勻的流量。
缺點(diǎn)是請求的爆發(fā)可能會填滿存儲桶,導(dǎo)致新請求的匱乏。它也不能保證請求在給定的時(shí)間內(nèi)完成。
優(yōu)點(diǎn):
- 平滑流量。由于漏桶算法以固定的速率處理請求,可以有效地平滑和整形流量,避免流量的突發(fā)和波動(類似于消息隊(duì)列的削峰填谷的作用)。
- 防止過載。當(dāng)流入的請求超過桶的容量時(shí),可以直接丟棄請求,防止系統(tǒng)過載。
缺點(diǎn):
- 無法處理突發(fā)流量:由于漏桶的出口速度是固定的,無法處理突發(fā)流量。例如,即使在流量較小的時(shí)候,也無法以更快的速度處理請求。
- 可能會丟失數(shù)據(jù):如果入口流量過大,超過了桶的容量,那么就需要丟棄部分請求。在一些不能接受丟失請求的場景中,這可能是一個問題。
2、令牌桶算法
令牌桶算法:假設(shè)限制2r/s,則按照500毫秒的固定速率往桶中添加令牌。桶中最多存放b個令牌,當(dāng)桶滿時(shí),新添加的令牌被丟棄或拒絕。當(dāng)一個n個字節(jié)大小的數(shù)據(jù)包到達(dá),將從桶中刪除n個令牌,接著數(shù)據(jù)包被發(fā)送到網(wǎng)絡(luò)上。如果桶中的令牌不足n個,則不會刪除令牌,且該數(shù)據(jù)包將被限流(要么丟棄,要么緩沖區(qū)等待)。令牌桶限流原理,如圖所示。
令牌桶限流服務(wù)器端可以根據(jù)實(shí)際服務(wù)性能和時(shí)間段改變生成令牌的速度和?桶的容量。 一旦需要提高速率,則按需提高放入桶中的令牌的速率。
生成令牌的速度是恒定的,而請求去拿令牌是沒有速度限制的。這意味著當(dāng)面對瞬時(shí)大流量,該算法可以在短時(shí)間內(nèi)請求拿到大量令牌,而且拿令牌的過程并不是消耗很大。
每次新請求到達(dá)服務(wù)器時(shí),都會發(fā)生兩個操作:
- 獲取令牌:獲取該用戶的當(dāng)前令牌數(shù)。如果它大于定義的限制,則丟棄請求。
- 更新令牌:如果獲取的令牌小于持續(xù)時(shí)間 d 的限制,則接受請求并附加令牌。
該算法具有內(nèi)存效率,因?yàn)槲覀優(yōu)槲覀兊膽?yīng)用程序?yàn)槊總€用戶節(jié)省了更少的數(shù)據(jù)量。這里的問題是它可能導(dǎo)致分布式環(huán)境中的競爭條件。當(dāng)來自兩個不同應(yīng)用程序服務(wù)器的兩個請求同時(shí)嘗試獲取令牌時(shí),就會發(fā)生這種情況。
優(yōu)點(diǎn):
- 可以處理突發(fā)流量:令牌桶算法可以處理突發(fā)流量。當(dāng)桶滿時(shí),能夠以最大速度處理請求。這對于需要處理突發(fā)流量的應(yīng)用場景非常有用。
- 限制平均速率:在長期運(yùn)行中,數(shù)據(jù)的傳輸率會被限制在預(yù)定義的平均速率(即生成令牌的速率)。
- 靈活性:與漏桶算法相比,令牌桶算法提供了更大的靈活性。例如,可以動態(tài)地調(diào)整生成令牌的速率。
缺點(diǎn):
- 可能導(dǎo)致過載:如果令牌產(chǎn)生的速度過快,可能會導(dǎo)致大量的突發(fā)流量,這可能會使網(wǎng)絡(luò)或服務(wù)過載。
- 需要存儲空間:令牌桶需要一定的存儲空間來保存令牌,可能會導(dǎo)致內(nèi)存資源的浪費(fèi)。
- 實(shí)現(xiàn)稍復(fù)雜:相比于計(jì)數(shù)器算法,令牌桶算法的實(shí)現(xiàn)稍微復(fù)雜一些。
3、固定時(shí)間窗?算法
在固定的時(shí)間窗口內(nèi),可以允許固定數(shù)量的請求進(jìn)入。超過數(shù)量就拒絕或者排隊(duì),等下一個時(shí)間段進(jìn)入。這種實(shí)現(xiàn)計(jì)數(shù)器限流方式由于是在一個時(shí)間間隔內(nèi)進(jìn)行限制,如果用戶在上個時(shí)間間隔結(jié)束前請求(但沒有超過限制),同時(shí)在當(dāng)前時(shí)間間隔剛開始請求(同樣沒超過限制),在各自的時(shí)間間隔內(nèi),這些請求都是正常的,但是將間隔臨界的一段時(shí)間內(nèi)的請求就會超過系統(tǒng)限制,可能導(dǎo)致系統(tǒng)被壓垮。
由于計(jì)數(shù)器算法存在時(shí)間臨界點(diǎn)缺陷,因此在時(shí)間臨界點(diǎn)左右的極短時(shí)間段內(nèi)容易遭到攻擊。比如設(shè)定每分鐘最多可以請求100次某個接口,如12:00:00-12:00:59時(shí)間段內(nèi)沒有數(shù)據(jù)請求,而12:00:59-12:01:00時(shí)間段內(nèi)突然并發(fā)100次請求,而緊接著跨入下一個計(jì)數(shù)周期,計(jì)數(shù)器清零,在12:01:00-12:01:01內(nèi)又有100次請求。那么也就是說在時(shí)間臨界點(diǎn)左右可能同時(shí)有2倍的閥值進(jìn)行請求,從而造成后臺處理請求過載的情況,導(dǎo)致系統(tǒng)運(yùn)營能力不足,甚至導(dǎo)致系統(tǒng)崩潰。
缺點(diǎn):
- 限流不夠平滑。例如:限流是每秒3個,在第一毫秒發(fā)送了3個請求,達(dá)到限流,窗口剩余時(shí)間的請求都將會被拒絕,體驗(yàn)不好。
- 無法處理窗口邊界問題。因?yàn)槭窃谀硞€時(shí)間窗口內(nèi)進(jìn)行流量控制,所以可能會出現(xiàn)窗口邊界效應(yīng),即在時(shí)間窗口的邊界處可能會有大量的請求被允許通過,從而導(dǎo)致突發(fā)流量。
例如:限流是每秒3個,在第一秒的最后一毫秒發(fā)送了3個請求,在第二秒的第一毫秒又發(fā)送了3個請求。在這兩毫米內(nèi)處理了6個請求,但是并沒有觸發(fā)限流。如果出現(xiàn)突發(fā)流量,可能會壓垮服務(wù)器。
4、滑動時(shí)間窗?算法
滑動窗?算法是把固定時(shí)間間進(jìn)行劃分,并且隨著時(shí)間移動,移動方式為開始時(shí)間點(diǎn)變?yōu)闀r(shí)間列表中的第二時(shí)間點(diǎn),結(jié)束時(shí)間點(diǎn)增加一個時(shí)間點(diǎn),不斷重復(fù),通過這種方式可以巧妙的避開計(jì)數(shù)器的臨界點(diǎn)的問題。
滑動窗口算法可以有效的規(guī)避計(jì)數(shù)器算法中時(shí)間臨界點(diǎn)的問題,但是仍然存在時(shí)間片段的概念。同時(shí)滑動窗口算法計(jì)數(shù)運(yùn)算也相對固定時(shí)間窗口算法比較耗時(shí)。
缺點(diǎn): 還是存在限流不夠平滑的問題。例如:限流是每秒3個,在第一毫秒發(fā)送了3個請求,達(dá)到限流,剩余窗口時(shí)間的請求都將會被拒絕,體驗(yàn)不好。
總結(jié)
介紹了四種常用的限流算法:固定窗口算法、滑動窗口算法、漏桶算法和令牌桶算法。每種算法都有其特點(diǎn)和適用場景,下面我們來對它們進(jìn)行簡單的總結(jié)和比較。
- 令牌桶算法既能平滑流量,又能處理突發(fā)流量,適用于需要處理突發(fā)流量的場景。
- 漏桶算法的優(yōu)點(diǎn)是流量處理更平滑,但是無法應(yīng)對突發(fā)流量,適用于需要平滑流量的場景。
- 固定窗口算法 實(shí)現(xiàn)簡單,但是限流不夠平滑,存在窗口邊界問題,適用于需要簡單實(shí)現(xiàn)限流的場景。
- 滑動窗口算法解決了窗口邊界問題,但是還是存在限流不夠平滑的問題,適用于需要控制平均請求速率的場景。