今天觀看QCon大會講述了阿里線上管控體系,其中主要使用了令牌桶算法來實現限流的目的。表示很是好奇,故此學習一下什麼是令牌桶算法。算法
1. 簡介api
令牌桶算法最初來源於計算機網絡。在網絡傳輸數據時,爲了防止網絡擁塞,需限制流出網絡的流量,使流量以比較均勻的速度向外發送。令牌桶算法就實現了這個功能,可控制發送到網絡上數據的數目,並容許突發數據的發送。緩存
令牌桶算法是網絡流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一種算法。典型狀況下,令牌桶算法用來控制發送到網絡上的數據的數目,並容許突發數據的發送。網絡
大小固定的令牌桶可自行以恆定的速率源源不斷地產生令牌。若是令牌不被消耗,或者被消耗的速度小於產生的速度,令牌就會不斷地增多,直到把桶填滿。後面再產生的令牌就會從桶中溢出。最後桶中能夠保存的最大令牌數永遠不會超過桶的大小。學習
傳送到令牌桶的數據包須要消耗令牌。不一樣大小的數據包,消耗的令牌數量不同。優化
令牌桶這種控制機制基於令牌桶中是否存在令牌來指示何時能夠發送流量。令牌桶中的每個令牌都表明一個字節。若是令牌桶中存在令牌,則容許發送流量;而若是令牌桶中不存在令牌,則不容許發送流量。所以,若是突發門限被合理地配置而且令牌桶中有足夠的令牌,那麼流量就能夠以峯值速率發送。計算機網絡
2.算法過程設計
算法描述:隊列
假如用戶配置的平均發送速率爲r,則每隔1/r秒一個令牌被加入到桶中(每秒會有r個令牌放入桶中);it
假設桶中最多能夠存放b個令牌。若是令牌到達時令牌桶已經滿了,那麼這個令牌會被丟棄;
當一個n個字節的數據包到達時,就從令牌桶中刪除n個令牌(不一樣大小的數據包,消耗的令牌數量不同),而且數據包被髮送到網絡;
若是令牌桶中少於n個令牌,那麼不會刪除令牌,而且認爲這個數據包在流量限制以外(n個字節,須要n個令牌。該數據包將被緩存或丟棄);
算法容許最長b個字節的突發,但從長期運行結果看,數據包的速率被限制成常量r。對於在流量限制外的數據包能夠以不一樣的方式處理:(1)它們能夠被丟棄;(2)它們能夠排放在隊列中以便當令牌桶中累積了足夠多的令牌時再傳輸;(3)它們能夠繼續發送,但須要作特殊標記,網絡過載的時候將這些特殊標記的包丟棄。
注意:
令牌桶算法不能與另一種常見算法漏桶算法相混淆。這兩種算法的主要區別在於漏桶算法可以強行限制數據的傳輸速率,而令牌桶算法在可以限制數據的平均傳輸速率外,還容許某種程度的突發傳輸。在令牌桶算法中,只要令牌桶中存在令牌,那麼就容許突發地傳輸數據直到達到用戶配置的門限,所以它適合於具備突發特性的流量。
3.Java實現
咱們可使用Guava 的 RateLimiter 來實現基於令牌桶的流控,RateLimiter 令牌桶算法是單桶實現。RateLimiter 對簡單的令牌桶算法作了一些工程上的優化,具體的實現是 SmoothBursty。須要注意的是,RateLimiter 的另外一個實現SmoothWarmingUp,就不是令牌桶了,而是漏桶算法。也許是出於簡單起見,RateLimiter 中的時間窗口能且僅能爲 1s。
SmoothBursty 有一個能夠放 N 個時間窗口產生的令牌的桶,系統空閒的時候令牌就一直攢着,最好狀況下能夠扛 N 倍於限流值的高峯而不影響後續請求。RateLimite容許某次請求拿走超出剩餘令牌數的令牌,可是下一次請求將爲此付出代價,一直等到令牌虧空補上,而且桶中有足夠本次請求使用的令牌爲止。當某次請求不能獲得所須要的令牌時,這時涉及到一個權衡,是讓前一次請求乾等到令牌夠用才走掉呢,仍是讓它先走掉後面的請求等一等呢?Guava 的設計者選擇的是後者,先把眼前的活幹了,後面的過後面再說。