基於分散式環境下限流系統的設計

前提

業務背景

就拿前些天的雙十一的 「搶券活動」 來說,一般是設置整點開始搶的,你想想,淘寶的用戶群體非常大,可以達到億級別,而服務介面每秒能處理的量是有限的,那麼這個時候問題就會出現,我們如何通過程序來控制用戶搶券呢,於是就必須加上這個限流功能了。

生產環境

1、服務介面所能提供的服務上限(limit)假如是 500次/s

2、用戶請求介面的次數未知,QPS可能達到 800次/s,1000次/s,或者更高

3、當服務介面的訪問頻率超過 500次/s,超過的量將拒絕服務,多出的信息將會丟失

4、線上環境是多節點部署的,但是調用的是同一個服務介面

於是,為了保證服務的可用性,就要對服務介面調用的速率進行限制(介面限流)。

什麼是限流?

限流是對系統的出入流量進行控制,防止大流量出入,導致資源不足,系統不穩定。

限流系統是對資源訪問的控制組件,控制主要的兩個功能:限流策略熔斷策略,對於熔斷策略,不同的系統有不同的熔斷策略訴求,有的系統希望直接拒絕、有的系統希望排隊等待、有的系統希望服務降級、有的系統會定製自己的熔斷策略,這裡只針對限流策略這個功能做詳細的設計。

限流演算法

1、限制瞬時並發數

Guava RateLimiter 提供了令牌桶演算法實現:平滑突發限流(SmoothBursty)和平滑預熱限流(SmoothWarmingUp)實現。

2、限制某個介面的時間窗最大請求數

即一個時間窗口內的請求數,如想限制某個介面/服務每秒/每分鐘/每天的請求數/調用量。如一些基礎服務會被很多其他系統調用,比如商品詳情頁服務會調用基礎商品服務調用,但是怕因為更新量比較大將基礎服務打掛,這時我們要對每秒/每分鐘的調用量進行限速;一種實現方式如下所示:

LoadingCache<Long, AtomicLong> counter =n CacheBuilder.newBuilder()n .expireAfterWrite(2, TimeUnit.SECONDS)n .build(new CacheLoader<Long, AtomicLong>() {n @Overriden public AtomicLong load(Long seconds) throws Exception {n return new AtomicLong(0);n }n });nlong limit = 1000;nwhile(true) {n //得到當前秒n long currentSeconds = System.currentTimeMillis() / 1000;n if(counter.get(currentSeconds).incrementAndGet() > limit) {n System.out.println("限流了:" + currentSeconds);n continue;n }n //業務處理n}n

使用Guava的Cache來存儲計數器,過期時間設置為2秒(保證1秒內的計數器是有的),然後我們獲取當前時間戳然後取秒數來作為KEY進行計數統計和限流,這種方式也是簡單粗暴,剛才說的場景夠用了。

3、令牌桶

演算法描述:

  • 假如用戶配置的平均發送速率為r,則每隔1/r秒一個令牌被加入到桶中
  • 假設桶中最多可以存放b個令牌。如果令牌到達時令牌桶已經滿了,那麼這個令牌會被丟棄
  • 當流量以速率v進入,從桶中以速率v取令牌,拿到令牌的流量通過,拿不到令牌流量不通過,執行熔斷邏輯

屬性

  • 長期來看,符合流量的速率是受到令牌添加速率的影響,被穩定為:r
  • 因為令牌桶有一定的存儲量,可以抵擋一定的流量突發情況
    • M是以位元組/秒為單位的最大可能傳輸速率。 M>r
    • T max = b/(M-r) 承受最大傳輸速率的時間
    • B max = T max * M 承受最大傳輸速率的時間內傳輸的流量

優點:流量比較平滑,並且可以抵擋一定的流量突發情況

4、GOOGLE GUAVA 提供的工具庫中 RATELIMITER 類(內部也是採用令牌桶演算法實現)

最快的方式是使用 RateLimit 類,但是這僅限制在單節點,如果是分散式系統,每個節點的 QPS 是一樣的,請求量到服務介面那的話就是 QPS * 節點數 了。所以這種方案在分散式的情況下不適用!

5、基於 REDIS 實現,存儲兩個 KEY,一個用於計時,一個用於計數。請求每調用一次,計數器增加 1,若在計時器時間內計數器未超過閾值,則可以處理任務。

這種能夠很好地解決了分散式環境下多實例所導致的並發問題。因為使用redis設置的計時器和計數器均是全局唯一的,不管多少個節點,它們使用的都是同樣的計時器和計數器,因此可以做到非常精準的流控。

代碼就不公布了,畢竟涉及公司隱私了。

最後

參考文章:

基於Redis的限流系統的設計

感興趣的可以看看別人的代碼是怎麼寫的:github.com/wukq/rate-li

原文作者:zhisheng

原文地址:基於分散式環境下限流系統的設計

版權說明:本文由極樂科技合作博主原創,轉載請註明作者與出處,謝謝!

一元搶購微信小程序>>>鏈接地址

推薦閱讀:

超級乾貨:Word2Vec課堂筆記(內附教學視頻)
聊聊一致性哈希
分散式系統理論基礎 - CAP
未來已來,Google Cloud Spanner 展開 NewSQL 時代
理解這兩點,也就理解了paxos協議的精髓

TAG:分布式服务器 | 分布式存储 | 分布式系统 |