在高併發的系統中,往往需要在系統中做限流,一方面是為了防止大量的請求使伺服器過載,導致服務不可用,另一方面是為了防止網路攻擊。
常見的限流方式,比如hystrix適用執行緒池隔離,超過執行緒池的負載,走熔斷的邏輯。在一般應用伺服器中,比如tomcat容器也是通過限制它的執行緒數來控制併發的;也有通過時間視窗的平均速度來控制流量。常見的限流緯度有比如通過ip來限流、通過uri來限流、通過使用者訪問頻次來限流。
一般限流都是在閘道器這一層做,比如nginx、openresty、kong、zuul、spring cloud gateway等;也可以在應用層通過aop這種方式去做限流。
本文詳細**在 spring cloud gateway 中如何實現限流。
計數器演算法採用計數器實現限流有點簡單粗暴,一般我們會限制一秒鐘的能夠通過的請求數,比如限流qps為100,演算法的實現思路就是從第乙個請求進來開始計時,在接下去的1s內,每來乙個請求,就把計數加1,如果累加的數字達到了100,那麼後續的請求就會被全部拒絕。等到1s結束後,把計數恢復成0,重新開始計數。具體的實現可以是這樣的:對於每次服務呼叫,可以通過atomiclong#incrementandget()方法來給計數器加1並返回最新值,通過這個最新值和閾值進行比較。這種實現方式,相信大家都知道有乙個弊端:如果我在單位時間1s內的前10ms,已經通過了100個請求,那後面的990ms,只能眼巴巴的把請求拒絕,我們把這種現象稱為「突刺現象」。
漏桶演算法為了消除"突刺現象",可以採用漏桶演算法實現限流,漏桶演算法這個名字就很形象,演算法內部有乙個容器,類似生活用到的漏斗,當請求進來時,相當於水倒入漏斗,然後從下端小口慢慢勻速的流出。不管上面流量多大,下面流出的速度始終保持不變。不管服務呼叫方多麼不穩定,通過漏桶演算法進行限流,每10毫秒處理一次請求。因為處理的速度是固定的,請求進來的速度是未知的,可能突然進來很多請求,沒來得及處理的請求就先放在桶裡,既然是個桶,肯定是有容量上限,如果桶滿了,那麼新進來的請求就丟棄。
在演算法實現方面,可以準備乙個佇列,用來儲存請求,另外通過乙個執行緒池(scheduledexecutorservice)來定期從佇列中獲取請求並執行,可以一次性獲取多個併發執行。
這種演算法,在使用過後也存在弊端:無法應對短時間的突發流量。
從某種意義上講,令牌桶演算法是對漏桶演算法的一種改進,桶演算法能夠限制請求呼叫的速率,而令牌桶演算法能夠在限制呼叫的平均速率的同時還允許一定程度的突發呼叫。在令牌桶演算法中,存在乙個桶,用來存放固定數量的令牌。演算法中存在一種機制,以一定的速率往桶中放令牌。每次請求呼叫需要先獲取令牌,只有拿到令牌,才有機會繼續執行,否則選擇選擇等待可用的令牌、或者直接拒絕。放令牌這個動作是持續不斷的進行,如果桶中令牌數達到上限,就丟棄令牌,所以就存在這種情況,桶中一直有大量的可用令牌,這時進來的請求就可以直接拿到令牌執行,比如設定qps為100,那麼限流器初始化完成一秒後,桶中就已經有100個令牌了,這時服務還沒完全啟動好,等啟動完成對外提供服務時,該限流器可以抵擋瞬時的100個請求。所以,只有桶中沒有令牌時,請求才會進行等待,最後相當於以一定的速率執行。
實現思路:可以準備乙個佇列,用來儲存令牌,另外通過乙個執行緒池定期生成令牌放到佇列中,每來乙個請求,就從佇列中獲取乙個令牌,並繼續執行。
常見的限流演算法
計數器演算法採用計數器實現限流有點簡單粗暴,一般我們會限制一秒鐘的能夠通過的請求數,比如限流qps為100,演算法的實現思路就是從第乙個請求進來開始計時,在接下去的1s內,每來乙個請求,就把計數加1,如果累加的數字達到了100,那麼後續的請求就會被全部拒絕。等到1s結束後,把計數恢復成0,重新開始計...
幾種常見的限流演算法
1 令牌桶演算法 令牌桶演算法是比較常見的限流演算法之一,大概描述如下 1 所有的請求在處理之前都需要拿到乙個可用的令牌才會被處理 2 根據限流大小,設定按照一定的速率往桶裡新增令牌 3 桶設定最大的放置令牌限制,當桶滿時 新新增的令牌就被丟棄活著拒絕 4 請求達到後首先要獲取令牌桶中的令牌,拿著令...
三種常見的限流演算法
在開發高併發系統時,有三把利器用來保護系統 快取 降級和限流。那麼何為限流呢?顧名思義,限流就是限制流量,就像你寬頻包了1個g的流量,用完了就沒了。通過限流,我們可以很好地控制系統的qps,從而達到保護系統的目的。本篇文章將會介紹一下常用的限流演算法以及他們各自的特點。1 計數器演算法 計數器演算法...