常見的限流方法:
- 固定窗口計數(shù)器:按照時間段劃分窗口,有一次請求就+1,最為簡單的算法,但這個算法有時會讓通過請求量允許為限制的兩倍。
- 滑動窗口計數(shù)器:通過將窗口再細(xì)分,并且按照時間“滑動”來解決突破限制的問題,但是時間區(qū)間的精度越高,算法所需的空間容量就越大。
- 漏桶:請求類似水滴,先放到桶里,服務(wù)的提供方則按照固定的速率從桶里面取出請求并執(zhí)行。缺陷也很明顯,當(dāng)短時間內(nèi)有大量的突發(fā)請求時,即便此時服務(wù)器沒有任何負(fù)載,每個請求也都得在隊(duì)列中等待一段時間才能被響應(yīng)。
- 令牌桶:往桶里面發(fā)放令牌,每個請求過來之后拿走一個令牌,然后只處理有令牌的請求。令牌桶滿了則多余的令牌會直接丟棄。令牌桶算法既能夠?qū)⑺械恼埱笃骄植嫉綍r間區(qū)間內(nèi),又能接受服務(wù)器能夠承受范圍內(nèi)的突發(fā)請求,因此是目前使用較為廣泛的一種限流算法。Google的開源項(xiàng)目guava提供了RateLimiter類,實(shí)現(xiàn)了單點(diǎn)的令牌桶限流。分布式環(huán)境下,可以考慮用Redis+Lua腳本實(shí)現(xiàn)令牌桶。 如果請求量太大了,Redis也撐不住怎么辦?我覺得可以類似于分布式ID的處理方式,Redis前面在增加預(yù)處理,比如每臺及其預(yù)先申請一部分令牌,只有令牌用完之后才去 Redis。如果還是太大,是否可以垂直切分?按照流量的來源,比如地理位置、IP 之類的再拆開。