流量控制:高并發(fā)系統(tǒng)中我們?nèi)绾尾倏v流量?
限流是一種保護(hù)系統(tǒng)免受過載的策略,通過限制系統(tǒng)處理請求的速率來確保系統(tǒng)穩(wěn)定運(yùn)行。常見的限流策略包括控制并發(fā)連接數(shù)、基于時間窗口的限流算法(如令牌桶算法)、動態(tài)調(diào)整限流策略、服務(wù)降級和故障熔斷、以及優(yōu)先級隊列等方法。在微服務(wù)架構(gòu)中,可以在服務(wù)入口處或關(guān)鍵組件處部署限流策略,同時在RPC客戶端中引入限流策略,以保護(hù)系統(tǒng)的穩(wěn)定性和可靠性。
其實,無論在實際工作生活中還是在之前學(xué)習(xí)過的知識中,你都可能對限流策略有過應(yīng)用,我給你舉幾個例子。
限流策略就像是景區(qū)限制每天售賣門票數(shù)量或者地鐵限制進(jìn)站人數(shù)一樣,通過控制一段時間內(nèi)的流量,來避免系統(tǒng)或者場所因為擁擠而影響服務(wù)質(zhì)量或者安全。這種策略可以確保系統(tǒng)或者場所在高峰時段不會被過多的用戶或者游客擠爆,保證了服務(wù)的穩(wěn)定性和可靠性。
TCP協(xié)議中的滑動窗口就像接收方的一個緩沖區(qū),用來控制發(fā)送方發(fā)送數(shù)據(jù)的速度。如果接收方處理速度慢,滑動窗口就變小,限制發(fā)送方發(fā)送數(shù)據(jù)的量,避免數(shù)據(jù)堆積和網(wǎng)絡(luò)擁塞。
在TCP協(xié)議中,接收方回復(fù)發(fā)送方的ACK消息中會攜帶滑動窗口的大小。這個滑動窗口大小告訴發(fā)送方,接收方目前的處理能力和緩沖區(qū)的剩余空間。發(fā)送方根據(jù)這個窗口大小來決定發(fā)送數(shù)據(jù)的速率。如果接收方處理了部分緩沖區(qū)的數(shù)據(jù),滑動窗口就會增大,發(fā)送方可以加快發(fā)送數(shù)據(jù)的速率。反之,如果接收方的緩沖區(qū)快滿了,滑動窗口就會減小,發(fā)送方會減慢發(fā)送數(shù)據(jù)的速率,以避免數(shù)據(jù)丟失或網(wǎng)絡(luò)擁塞。
圖片
你應(yīng)該知道的限流算法
固定窗口與滑動窗口的算法
我們知道,限流的目的是限制一段時間內(nèi)發(fā)向系統(tǒng)的總體請求量,比如,限制一分鐘之內(nèi)系統(tǒng)只能承接 1 萬次請求,那么最暴力的一種方式就是記錄這一分鐘之內(nèi)訪問系統(tǒng)的請求量有多少,如果超過了 1 萬次的限制,那么就觸發(fā)限流的策略返回請求失敗的錯誤。如果這一分鐘的請求量沒有達(dá)到限制,那么在下一分鐘到來的時候先重置請求量的計數(shù),再統(tǒng)計這一分鐘的請求量是否超過限制。
圖片
粗粒度控制: 固定窗口算法在限流時只考慮了一個固定的時間窗口,例如每秒或每分鐘,這種粗粒度的控制可能會導(dǎo)致在時間窗口開始的瞬間發(fā)生突發(fā)的流量,而在窗口結(jié)束時沒有流量的情況,無法靈活應(yīng)對。
突發(fā)請求問題: 固定窗口算法無法很好地處理突發(fā)性的請求,在窗口期開始時可能會集中出現(xiàn)大量請求,導(dǎo)致瞬間達(dá)到限流閾值,而在接下來的時間段內(nèi)無法再接受新的請求,造成了資源的浪費(fèi)和服務(wù)的不公平性。
漏桶算法與令牌筒算法
漏桶算法的原理很簡單,它就像在流量產(chǎn)生端和接收端之間增加一個漏桶,流量會進(jìn)入和暫存到漏桶里面,而漏桶的出口處會按照一個固定的速率將流量漏出到接收端(也就是服務(wù)接口)。
令牌桶算法是一種流量控制算法,其基本原理如下:
圖片
定義一個令牌桶,用來存放令牌。
每隔固定時間間隔(1/N秒),向令牌桶中放入一個令牌,直到達(dá)到令牌桶的最大容量。
處理請求時,需要從令牌桶中獲取一個令牌,如果令牌桶中沒有令牌,則拒絕服務(wù)或者等待直到有令牌可用。
如果令牌桶中的令牌數(shù)量超過了最大容量,新的令牌將不再被放入令牌桶中。
通過令牌桶算法,可以限制請求的處理速率,避免系統(tǒng)突發(fā)流量造成的問題。由于令牌桶中令牌的數(shù)量有限,因此可以有效控制系統(tǒng)的總體請求量。
圖片
在分布式環(huán)境下使用令牌桶算法進(jìn)行限流時,確實需要解決多臺機(jī)器之間共享令牌數(shù)量的問題。通常可以借助分布式緩存或者分布式鎖來實現(xiàn)。
對于使用Redis來存儲令牌數(shù)量的情況,每次請求都需要向Redis請求令牌,可能會增加一定的延遲。為了減少請求Redis的次數(shù),可以采取一些優(yōu)化策略,比如在每次請求時一次性獲取一批令牌,而不是逐個獲取。這樣可以減少與Redis的交互次數(shù),提高性能。
另外,還可以通過合理設(shè)置令牌桶的容量和填充速率,以及調(diào)整令牌獲取的頻率,來平衡系統(tǒng)的穩(wěn)定性和性能損耗。需要根據(jù)具體場景和性能需求進(jìn)行合理的設(shè)計和調(diào)優(yōu)。
總結(jié):
限流是一種常見的服務(wù)保護(hù)策略,你可以在整體服務(wù)、單個服務(wù)、單個接口、單個 IP 或者單個用戶等多個維度進(jìn)行流量的控制;
基于時間窗口維度的算法有固定窗口算法和滑動窗口算法,兩者雖然能一定程度上實現(xiàn)限流的目的,但是都無法讓流量變得更平滑;
令牌桶算法和漏桶算法則能夠塑形流量,讓流量更加平滑,但是令牌桶算法能夠應(yīng)對一定的突發(fā)流量,所以在實際項目中應(yīng)用更多。