高併發處理思路與手段(五):應用限流
限流就是通過對併發訪問/請求進行限速或一個時間視窗內的請求進行限速,從而達到保護系統的目的。一般系統可以通過壓測來預估能處理的峰值,一旦達到設定的峰值閥值,則可以拒絕服務(定向錯誤頁或告知資源沒有了)、排隊或等待(例如:秒殺、評論、下單)、降級(返回預設資料)。
限流不能亂用,否則正常流量會出現一些奇怪的問題,從而導致使用者抱怨。
假設有130W到140W的資料插入到資料庫中,如果沒有做限流,資料庫的主庫會突然接收到130w的插入操作。
首先是網路上的開銷,很可能直接把頻寬佔滿,導致其他請求無法正常傳輸和處理,其次會是資料庫的負載突然增高,導致無法處理某些資料庫的操作,也有可能資料庫沒有足夠的連線導致某些資料庫插入查詢失敗;
還有一點就是現在資料庫都做了主從設計,主資料庫的資料還要同步給從庫,這時瞬間插入了大量的資料,會帶來從庫和主庫的延遲特別大,這時從庫查詢不準確的概率也會跟著提升。
如果我們放慢插入資料庫的速度,這時插入資料庫主庫的速率會很正常,同步到從庫也很正常。網路消耗也可以接收不會影響其他服務。
1.計數器法
有時我們還會使用計數器來進行限流,主要用來限制一定時間內的總併發數,比如資料庫連線池、執行緒池、秒殺的併發數;計數器限流只要一定時間內的總請求數超過設定的閥值則進行限流,是一種簡單粗暴的總數量限流,而不是平均速率限流。
這個方法有一個致命問題:臨界問題——當遇到惡意請求,在0:59時,瞬間請求100次,並且在1:00請求100次,那麼這個使用者在1秒內請求了200次,使用者可以在重置節點突發請求,而瞬間超過我們設定的速率限制,使用者可能通過演算法漏洞擊垮我們的應用。
2.滑動視窗演算法
在上圖中,整個紅色矩形框是一個時間視窗,在我們的例子中,一個時間視窗就是1分鐘,然後我們將時間視窗進行劃分,如上圖我們把滑動視窗
劃分為6格,所以每一格代表10秒,每超過10秒,我們的時間視窗就會向右滑動一格,每一格都有自己獨立的計數器,例如:一個請求在0:35到達,
那麼0:30到0:39的計數器會+1,那麼滑動視窗是怎麼解決臨界點的問題呢?如上圖,0:59到達的100個請求會在灰色區域格子中,而1:00到達的請求
會在紅色格子中,視窗會向右滑動一格,那麼此時間視窗內的總請求數共200個,超過了限定的100,所以此時能夠檢測出來觸發了限流。
回頭看看計數器演算法,會發現,其實計數器演算法就是視窗滑動演算法,只不過計數器演算法沒有對時間視窗進行劃分,所以是一格。
由此可見,當滑動視窗的格子劃分越多,限流的統計就會越精確。
3.漏銅演算法
這個演算法很簡單。首先,我們有一個固定容量的桶,有水進來,也有水出去。對於流進來的水,我們無法預計共有多少水流進來,也無法預計流水速度,但
對於流出去的水來說,這個桶可以固定水流的速率,而且當桶滿的時候,多餘的水會溢位來。
4.令牌桶演算法
從上圖中可以看出,令牌演算法有點複雜,桶裡存放著令牌token。桶一開始是空的,token以固定的速率r往桶裡面填充,直到達到桶的容量,多餘的token會
被丟棄。每當一個請求過來時,就會嘗試著移除一個token,如果沒有token,請求無法通過。