在互聯(lián)網應用中,限流是非常重要的一個問題,它可以幫助我們保護系統(tǒng)免受惡意流量攻擊和突發(fā)流量沖擊。
Java通過兩種不同的限流算法來實現(xiàn)限流,一種是令牌桶算法,另一種是漏斗算法。
令牌桶算法: public class TokenBucket { private long lastTime = System.currentTimeMillis(); private long rate; //令牌產生速率 private long capacity; //桶的容量 private long tokens = 0; //桶里實際令牌數(shù)量 public TokenBucket(long rate, long capacity) { this.rate = rate; this.capacity = capacity; } public synchronized boolean getToken() { long now = System.currentTimeMillis(); tokens += (now - lastTime) * rate; //計算新產生的令牌數(shù)量 tokens = Math.min(tokens, capacity); //令牌桶的容量是有限的,不能超過容量 if (tokens< 1) { return false; //如果桶里已經沒有令牌,則不允許進入 } else { tokens--; lastTime = now; return true; } } }
令牌桶算法通過先定義令牌桶的容量,然后以一定的速率往桶里添加令牌,當需要限流時,從桶里取出一個令牌,如果桶里沒有令牌,則不允許通過。這種算法比較穩(wěn)定,令牌產生速率固定,限流效果比較理想。
漏斗算法: public class LeakyBucket { private long lastTime = System.currentTimeMillis(); private long rate; //漏出速率 private long capacity; //漏斗容量 private long water = 0; //漏斗實際存儲水量 public LeakyBucket(long rate, long capacity) { this.rate = rate; this.capacity = capacity; } public synchronized boolean leak() { long now = System.currentTimeMillis(); water = Math.max(0, water - (now - lastTime) * rate); //水流出的速度與速率成正比,計算漏斗實際存儲水量 lastTime = now; if (water< capacity) { water++; //如果漏斗還沒滿,則存儲一個單位的水 return true; } else { return false; //漏斗滿了,則不允許進入 } } }
漏斗算法通過定義漏斗容量,以一定的速率流出水,當需要限流時,判斷漏斗是否已經滿了,如果沒有滿,則允許通過,否則不允許通過。這種算法比較靈活,可以應對流量突發(fā)的情況。