分佈式三大利器之限流

一、什麼是服務限流

什麼是服務限流呢?限流即限制併發量,限制某一段時間只有指定數量的請求進入後臺服務器,遇到流量高峯期或者流量突增時,把流量速率限制在系統所能接受的合理範圍之內,不至於讓系統被高流量擊垮。限流與緩存、降級統稱爲分佈式系統的三大利器,最終目的都是用來保護系統穩定運行。

二、如何實現服務限流

怎麼實現服務限流呢?開發過程中或多或少會接觸到服務限流,比如tomcat限制最大連接數、數據庫連接池限制連接數、nginx限制ip訪問數、秒殺、搶購等。這些都是通過限制一個時間窗口內的請求數,當達到設置的最大請求數後,會讓後續請求進入等待隊列或直接拒絕,防止系統過載。這些限流是怎麼做到的呢,或者說限流主要有哪些方式呢?很多人把限流歸納成4種場景,其實也不外乎這4種場景,它們分別是:

1)限制總併發數或請求數

從系統層面維護一個計數器,每來一個請求就將計數器加1,請求處理完後將計數器減1,當計數器大於設定的閥值時,拒絕請求或將請求放入等待隊列。這是最簡單粗暴的限流方式,實現起來比較簡單,但它有個很明顯的缺陷是如果某一時間段系統受到惡意攻擊(即突發請求),若併發數大於閥值時,後續有效的請求都會被拒絕,因而這種方法在現實中的使用並不常見

2)限制接口的總併發或請求數

針對每個接口維護一個計數器,每來一個請求就將對應接口的計數器加1,請求處理完後將計數器減1,當計數器大於設定的閥值時,拒絕請求或將請求放入等待隊列。這種方式較之第一種稍複雜些,如果要用aop去實現的話,則需要定義多個切面,維護成本也隨之加大,它雖然不能應對接口受到惡意攻擊(即突發請求),但較之第一種方式有個好處是,即使遭到攻擊,也只會造成某個接口不可用,影響面小很多。實現同場景1。

3)限制接口每秒的請求數

     這種方式和第二種很相似,只是它把時間窗口縮小到1秒,故而影響範圍更小,實現如下:

// 存放令牌的緩存,失效時間爲1s,緩存的key爲當前時間秒值,value爲這一秒對應的請求數,以當前時間秒值作爲key的好處是方 
// 便統計一秒產生的請求總數,且下一秒到來時,數據會被自動清空
LoadingCache<Long, AtomicLong> tokenCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {
      @Override
      public AtomicLong load(Long seconds) throws Exception {
           return new AtomicLong(0);
      }
});
// 每秒最大請求數
long limit = 200;
while(true) {
    Long currentSeconds = System.currentTimeMillis() / 1000;
    if(tokenCache.get(currentSeconds).incrementAndGet() > limit) {
        log.info("該請求被限流了");
        continue;
    }
    //do-business
}

作者:有讚美業商家經營組技術博客
鏈接:https://juejin.im/post/5c34892be51d45521315edab
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

4)平滑限流接口的請求數 

平滑限流接口是爲了對突發請求進行整形,以平均速率處理請求,故而可以應對突發請求,也是目前用的較多的限流方式。其分爲平滑突發限流(SmoothBursty)、平滑預熱限流(SmoothWarmingUp)兩種模式,限流算法有令牌桶法、漏桶法。Google對Guava工具包提供了令牌桶的算法實現,使用起來也很簡單、方便,下面會介紹令牌桶法、漏桶法。

三:限流算法

1)令牌桶法

令牌桶法是以固定速率往桶裏添加令牌,當令牌數達到上限時,便會丟棄或拒絕,其流程圖如下:

令牌以固定速率放入桶中,如每秒放入r個; 桶中最多存放b個令牌,當桶中令牌數達到上限時,便丟棄或拒絕; 當需從桶中獲取n個令牌時,若桶中令牌數大於n,便會刪除桶裏的n個令牌,否則請求等待。

 

2)漏桶法

漏桶法允許以任意速率流入桶內,但流出速率是恆定的,桶滿了則丟棄令牌,桶內沒有令牌時則阻塞,其流程圖如下:

 

令牌以任意速率流入桶中; 以固定速率流出令牌,如果桶是空的,則不用流出; 若流入的令牌數超出了桶的容量,則令牌被丟棄。 由於令牌桶算法是以恆定速率流入桶中,令牌可以以任意速率流出,因而只需調整令牌流入速率便可解決流量突發情況,同時也支持預先消費,而漏桶算法是令牌以任意速率流入桶中,以恆定速率流出,從而不能解決流量突發情況(如常用的隊列),如此對比令牌桶法相對漏桶法更優,但業務上不能一味的追求使用令牌桶法去實現,主要還需根據業務需求來斷定使用那個限流算法。

 

四:總結

限流做爲保護系統的一種常用方式,以限制系統的輸入和輸出流量已達到保護系統,業界也提供了很多現有的框架可直接使用,如jdk提供的Semaphore、google提供的Guava、Netflix提供的hystrix等,Semaphore是最簡單粗暴的,直接使用計數器來控制。guava則採用了令牌桶法,可以平滑的進行限流。hystrix則提供了多種限流策略,使用起來更靈活,同時使用複雜度相對大一些,後續會介紹Semaphore、Guava、hystrix的實現原理。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章