天天看點

java程式化交易軟體_Java高并發系統的限流政策

Guava中開源工具類RateLimiter是基于令牌桶算法的實作類,可以簡單的實作限流的工作,并根據系統實際情況調整生成token速率。RateLimiter 對簡單的令牌桶算法做了一些工程上的優化,具體的實作是 SmoothBursty。需要注意的是,RateLimiter 的另一個實作 SmoothWarmingUp,就不是令牌桶了,而是漏桶算法。也許是出于簡單起見,RateLimiter 中的時間視窗能且僅能為 1s,如果想搞其他時間機關的限流,隻能另外造輪子。

RateLimiter 有一個有趣的特性是「前人挖坑後人跳」,也就是說 RateLimiter 允許某次請求拿走超出剩餘令牌數的令牌,但是下一次請求将為此付出代價,一直等到令牌虧空補上,并且桶中有足夠本次請求使用的令牌為止。這裡面就涉及到一個權衡,是讓前一次請求幹等到令牌夠用才走掉呢,還是讓它先走掉後面的請求等一等呢?Guava 的設計者選擇的是後者,先把眼前的活幹了,後面的事後面再說。

RateLimiter rateLimiter = RateLimiter.create(2);

System.out.println(rateLimiter.acquire(5));

System.out.println(rateLimiter.acquire(2));

System.out.println(rateLimiter.acquire(1));

輸出

0.0

2.496889

0.992149

可以看出,令牌桶每秒隻能産生2個令牌,我們可以第一次取出5個,但是第二個再去取令牌的時候,需要等2.5s,也就是第一次令牌取完後,需要等2.5s才能取到令牌。同樣的,第三次取1個令牌的時候,也需要等待第二次的1s的時間。也就是,取的速率可以超過令牌産生的速率,但是下一次再次去取的時候,需要阻塞等待。

當然也可以使用tryAcquire來非阻塞的擷取,可以實時傳回結果。另外tryAcquire也可以傳入參數,也就是等待的時間,逾時直接傳回false。這點等同于常見的lock,tryLock。

漏桶算法

漏桶算法即leaky bucket是一種非常常用的限流算法,可以用來實作流量整形(Traffic Shaping)和流量控制(Traffic Policing)。貼了一張維基百科上示意圖幫助大家了解:

java程式化交易軟體_Java高并發系統的限流政策
java程式化交易軟體_Java高并發系統的限流政策

漏桶算法的主要概念如下:

一個固定容量的漏桶,按照常量固定速率流出水滴;

如果桶是空的,則不需流出水滴;

可以以任意速率流入水滴到漏桶;

如果流入水滴超出了桶的容量,則流入的水滴溢出了(被丢棄),而漏桶容量是不變的。

它的主要目的是控制資料注入到網絡的速率,平滑網絡上的突發流量,資料可以以任意速度流入到漏桶中。漏桶算法提供了一種機制,通過它,突發流量可以被整形以便為網絡提供一個穩定的流量。 漏桶可以看作是一個帶有常量服務時間的單伺服器隊列,如果漏桶為空,則不需要流出水滴,如果漏桶(包緩存)溢出,那麼水滴會被溢出丢棄。

漏桶算法比較好實作,在單機系統中可以使用隊列來實作(.Net中TPL DataFlow可以較好的處理類似的問題,你可以在這裡找到相關的介紹),在分布式環境中消息中間件或者Redis都是可選的方案。

令牌桶算法

令牌桶算法的原理是系統會以一個恒定的速度往桶裡放入令牌,而如果請求需要被處理,則需要先從桶裡擷取一個令牌,當桶裡沒有令牌可取時,則拒絕服務。 當桶滿時,新添加的令牌被丢棄或拒絕。

令牌桶算法是一個存放固定容量令牌(token)的桶,按照固定速率往桶裡添加令牌。令牌桶算法基本可以用下面的幾個概念來描述:

令牌将按照固定的速率被放入令牌桶中。比如每秒放10個。

桶中最多存放b個令牌,當桶滿時,新添加的令牌被丢棄或拒絕。

當一個n個位元組大小的資料包到達,将從桶中删除n個令牌,接着資料包被發送到網絡上。

如果桶中的令牌不足n個,則不會删除令牌,且該資料包将被限流(要麼丢棄,要麼緩沖區等待)。

java程式化交易軟體_Java高并發系統的限流政策
java程式化交易軟體_Java高并發系統的限流政策

令牌算法是根據放令牌的速率去控制輸出的速率,也就是上圖的to network的速率。to network我們可以了解為消息的處理程式,執行某段業務或者調用某個RPC。

漏桶和令牌桶的比較

令牌桶可以在運作時控制和調整資料處理的速率,處理某時的突發流量。放令牌的頻率增加可以提升整體資料處理的速度,而通過每次擷取令牌的個數增加或者放慢令牌的發放速度和降低整體資料處理速度。而漏桶不行,因為它的流出速率是固定的,程式處理速度也是固定的。

整體而言,令牌桶算法更優,但是實作更為複雜一些。