高並發處理思路與手段(五):應用限流
限流就是通過對並發訪問/請求進行限速或一個時間窗口內的請求進行限速,從而達到保護系統的目的。一般系統可以通過壓測來預估能處理的峰值,一旦達到設定的峰值閥值,則可以拒絕服務(定向錯誤頁或告知資源沒有了)、排隊或等待(例如:秒殺、評論、下單)、降級(返回默認數據)。
限流不能亂用,否則正常流量會出現一些奇怪的問題,從而導致用戶抱怨。
假設有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,請求無法通過。
高並發處理思路與手段(五):應用限流