天天看點

高并發限流

突然發現自己的接口請求量突然漲到之前的10倍,帶寬被占滿,沒多久該接口幾乎不可使用,并引發連鎖反應導緻整個系統崩潰。

計數器算法是使用計數器在周期内累加通路次數,當達到設定的限流值時,觸發限流政策。下一個周期開始時,進行清零,重新計數。

此算法在單機還是分布式環境下實作都非常簡單,使用redis的incr原子自增性和線程安全即可輕松實作。

高并發限流

這個算法通常用于qps限流和統計總通路量,對于秒級以上的時間周期來說,會存在一個非常嚴重的問題,那就是臨界問題,如下圖:

高并發限流

假設1min内伺服器的負載能力為100,是以一個周期的通路量限制在100,然而在第一個周期的最後5秒和下一個周期的開始5秒時間段内,分别湧入100的通路量,雖然沒有超過每個周期的限制量,但是整體上10秒内已達到200的通路量,已遠遠超過伺服器的負載能力,由此可見,計數器算法方式限流對于周期比較長的限流,存在很大的弊端。

滑動視窗算法是将時間周期分為n個小周期,分别記錄每個小周期内通路次數,并且根據時間滑動删除過期的小周期。

如下圖,假設時間周期為1min,将1min再分為2個小周期,統計每個小周期的通路數量,則可以看到,第一個時間周期内,通路數量為75,第二個時間周期内,通路數量為100,超過100的通路則被限流掉了

高并發限流

由此可見,當滑動視窗的格子劃分的越多,那麼滑動視窗的滾動就越平滑,限流的統計就會越精确。

此算法可以很好的解決固定視窗算法的臨界問題。

使用redis中zset方法可以實作滑動視窗,在一個清單中,value可以是随機值,但是score是時間戳,zset中range方法可以拿到兩個時間戳間隔内的個數,如果超過則直接傳回。

漏桶算法是通路請求到達時直接放入漏桶,如目前容量已達到上限(限流值),則進行丢棄(觸發限流政策)。漏桶以固定的速率進行釋放通路請求(即請求通過),直到漏桶為空。

高并發限流

一個存放固定容量令牌的桶,按照固定速率(每秒/或者可以自定義時間)往桶裡添加令牌,然後每次擷取一個令牌,當桶裡沒有令牌可取時,則拒絕服務

令牌桶分為2個動作,動作1(固定速率往桶中存入令牌)、動作2(用戶端如果想通路請求,先從桶中擷取token)

高并發限流

<code>create(double permitspersecond)</code>根據指定的穩定吞吐率建立ratelimiter,這裡的吞吐率是指每秒多少許可數(通常是指qps,每秒多少查詢)

<code>create(double permitspersecond, long warmupperiod, timeunit unit)</code>根據指定的穩定吞吐率和預熱期來建立ratelimiter,這裡的吞吐率是指每秒多少許可數(通常是指qps,每秒多少個請求量),在這段預熱時間内,ratelimiter每秒配置設定的許可數會平穩地增長直到預熱期結束時達到其最大速率。(隻要存在足夠請求數來使其飽和)

兩個方法差別:第一個方法固定速率生成令牌數,第二個方法有預熱時間段,在預熱階段内不超過設定的令牌數,超過預熱期後以固定時間速率生成令牌,當出現突然出現大量資料。

明顯差別:使用第一種方法可能會使消費方(背景服務)沒有消費完成,一直往系統塞資料導緻伺服器不可用,使用第二種方法将流量比較平滑的過渡,進而降低背景服務down掉的風險(就是預熱期内設定的令牌數少,不容易一下子把系統攻破)

ratelimiter是一個抽象類,限流器有兩個實作類:1、smoothbursty;2、smoothwarmingup

smoothbursty是以穩定的速度生成permit。smoothwarmingup是漸進的生成,最終達到最大值趨于穩定。

償還機制:目前請求的債務(請求的令牌大于限流器存儲的令牌數)由下一個請求來償還(上個請求虧欠的令牌,下個請求需要等待虧欠令牌生産出來以後才能被授權)acquire多個token時生效。

高并發限流

漏桶的出水速度是恒定的,那麼意味着如果瞬時大流量的話,将有大部分請求被丢棄掉(也就是所謂的溢出)。

生成令牌的速度是恒定的,而請求去拿令牌是沒有速度限制的。這意味,面對瞬時大流量,該算法可以在短時間内請求拿到大量令牌,而且拿令牌的過程并不是消耗很大的事情。

最後,不論是對于令牌桶拿不到令牌被拒絕,還是漏桶的水滿了溢出,都是為了保證大部分流量的正常使用,而犧牲掉了少部分流量,這是合理的,如果因為極少部分流量需要保證的話,那麼就可能導緻系統達到極限而挂掉,得不償失。

并不能說明令牌桶一定比漏洞好,她們使用場景不一樣。令牌桶可以用來保護自己,主要用來對調用者頻率進行限流,為的是讓自己不被打垮。是以如果自己本身有處理能力的時候,如果流量突發(實際消費能力強于配置的流量限制),那麼實際處理速率可以超過配置的限制。

而漏桶算法,這是用來保護他人,也就是保護他所調用的系統。主要場景是,當調用的第三方系統本身沒有保護機制,或者有流量限制的時候,我們的調用速度不能超過他的限制,由于我們不能更改第三方系統,是以隻有在主調方控制。這個時候,即使流量突發,也必須舍棄。因為消費能力是第三方決定的。

如果要讓自己的系統不被打垮,用令牌桶。如果保證别人的系統不被打垮,用漏桶算法。

這是單機(單程序)的限流,是jvm級别的的限流,所有的令牌生成都是在記憶體中,在分布式環境下不能直接這麼用。

如果我們能把permit放到redis中就可以在分布式環境中用了。

令牌桶算法限流

令牌桶限流總結

高并發系統限流-漏桶算法和令牌桶算法

繼續閱讀