為什么要限流?
由于Web服務(wù)無法控制調(diào)用方的行為,當(dāng)遇到請求并發(fā)量超過系統(tǒng)的容量閾值,會導(dǎo)致服務(wù)器資源耗盡從而導(dǎo)致服務(wù)異?;蝈礄C(jī),而且某個服務(wù)的請求量突增還會影響到上游的服務(wù),如DB或者是其他的公共服務(wù),導(dǎo)致整個系統(tǒng)癱瘓。
可能導(dǎo)致流量突增的原因有以下幾點:
- 熱點業(yè)務(wù)的突發(fā)請求(如大型活動)
- 調(diào)用方bug導(dǎo)致的請求量倍增
- 惡意攻擊的請求
為了對服務(wù)進(jìn)行保護(hù),就需要對請求進(jìn)行限流。
常見算法
固定窗口計數(shù)器算法

算法思路:
- 將時間劃分為多個窗口
- 每個窗口內(nèi)每有一次請求計數(shù)器加1
- 如果計數(shù)器超過了限制數(shù)量,則本窗口內(nèi)的所有請求都被丟棄,當(dāng)時間到達(dá)下一個窗口時,計數(shù)器重置。
特點:原理和實現(xiàn)都比較簡單,但是這種算法可能會讓通過的請求量為閾值的兩倍。比如當(dāng)閾值是100時,第一個窗口在0-0.5秒期間沒有請求,0.5-1.0秒期間有100個請求,然后到了第二個窗口計數(shù)器已經(jīng)重置,在1.0-1.5秒期間有100個請求,這樣看來在0.5-1.5秒的1秒內(nèi)通過了200個請求。
滑動窗口計數(shù)器算法
該方法就是對固定窗口計數(shù)算法的窗口時間細(xì)分更多的區(qū)間,并且按照時間在區(qū)間上滑動,如下圖所示:

算法思路:
- 將時間劃分多個區(qū)間,維護(hù)一個包含多個區(qū)間的窗口
- 每個區(qū)間內(nèi)每有一次請求就將該區(qū)間的計數(shù)器加1
- 每經(jīng)過一個區(qū)間時間,丟棄最老的一個區(qū)間,加入最新的一個區(qū)間
- 如果當(dāng)前窗口內(nèi)區(qū)間的請求計數(shù)總和超過了限制數(shù)量則本窗口內(nèi)所有新的請求都被丟棄。
特點:
將時間劃分為更小單位的區(qū)間,按時間滑動,避免了固定窗口計數(shù)器會產(chǎn)生雙倍請求的問題,但是時間區(qū)間的精度越高,算法需要的空間容量就越大。
漏桶算法

算法思路:
- 將每個請求視作“水滴”放入“漏桶”進(jìn)行存儲
- 漏桶以固定的速率(通常是服務(wù)的最大容量)向外漏出請求交給服務(wù)器執(zhí)行
- 如果漏桶空了則停止漏水,如果漏桶滿了則丟棄新來的請求
特點:通常使用消息隊列來實現(xiàn)漏桶。該算法能良好的保證瞬時請求量不會超過閾值,但是當(dāng)短時間內(nèi)有大量的突發(fā)請求時,即使服務(wù)器沒有負(fù)載,每個請求也都需要在隊列中等待一段時間才能被響應(yīng)。
令牌桶算法

算法思路:
- 令牌以固定速錄添加到桶中,如果桶滿了直接丟棄
- 請求到達(dá)時從桶中取令牌,取到了令牌的請求交給服務(wù)器執(zhí)行
- 如果桶空了,嘗試取令牌的請求就會被拒絕
特點:令牌桶算法既能將流量均勻的分布,又能接受服務(wù)器承受的容量范圍內(nèi)的突發(fā)請求,因此是目前使用比較廣泛的一種限流算法。缺點是突發(fā)流量時第一個周期會多放過一些請求。