1叽奥、漏桶限流算法
漏桶限流算法是一種常見的限流算法鉴裹,它的基本思想是模擬一個漏桶來控制流量。這個漏桶可以看作一個固定容量的桶廷没,所有的請求都先進(jìn)入到這個桶里糊饱,然后按照一定的速率流出,如果請求進(jìn)來的速度過快颠黎,超過了桶的容量另锋,那么多余的請求就會被直接丟棄或者排隊(duì)等待處理。
漏桶限流算法的實(shí)現(xiàn)方式也很簡單狭归,大致可以分為以下幾個步驟:
初始化一個固定容量的漏桶夭坪,并設(shè)置流出速率。
當(dāng)有請求進(jìn)來時过椎,先將其放入漏桶中室梅。
如果漏桶還有剩余容量,那么這個請求就可以被處理潭流,同時從漏桶中流出一個請求竞惋。
如果漏桶已經(jīng)滿了,那么這個請求就被丟棄或者排隊(duì)等待處理灰嫉。
在實(shí)際編程中,我們可以使用一個定時任務(wù)來模擬漏桶的流出速率嗓奢,每次定時任務(wù)執(zhí)行時讼撒,從漏桶中流出一個請求進(jìn)行處理。
以下是一個簡單的Java實(shí)現(xiàn)漏桶限流算法的示例代碼:
public class LeakyBucket {
private final int capacity; // 漏桶容量
private final int rate; // 流出速率股耽,單位為請求數(shù)/秒
private int water; // 當(dāng)前水量
private long timestamp; // 上次流出時間
public LeakyBucket(int capacity, int rate) {
this.capacity = capacity;
this.rate = rate;
this.water = 0;
this.timestamp = System.currentTimeMillis();
}
public boolean allowRequest() {
// 先計算當(dāng)前漏桶中的水量
long now = System.currentTimeMillis();
int out = (int) ((now - timestamp) / 1000 * rate);
water = Math.max(0, water - out);
// 檢查漏桶是否已經(jīng)滿了
if (water >= capacity) {
return false; // 漏桶已滿根盒,拒絕請求
}
// 漏桶還有剩余容量,將請求放入漏桶中物蝙,并更新時間戳和水量
timestamp = now;
water++;
return true;
}
}
在上面的代碼中炎滞,LeakyBucket類表示一個漏桶限流器,它包含漏桶的容量诬乞、流出速率册赛、當(dāng)前水量以及上次流出時間等屬性钠导。allowRequest方法用于處理請求,如果漏桶還有剩余容量森瘪,那么這個請求就可以被處理牡属,同時從漏桶中流出一個請求。否則扼睬,漏桶已滿逮栅,拒絕請求。
2窗宇、滑動窗口限流算法
滑動窗口限流算法是一種常見的限流算法措伐,用于控制請求流量,防止系統(tǒng)被過多的請求壓垮军俊。
該算法的基本思想是侥加,將時間劃分成固定大小的多個時間段,每個時間段稱為一個桶蝇完,將請求分配到不同的桶中官硝。如果某個桶中的請求數(shù)量超過了閾值,就拒絕該桶中多余的請求短蜕。
具體實(shí)現(xiàn)中氢架,我們可以使用一個固定大小的隊(duì)列來表示滑動窗口,隊(duì)列中的每個元素表示一個時間段對應(yīng)的桶朋魔。每當(dāng)有請求到來時岖研,就將其放入當(dāng)前時間段對應(yīng)的桶中,并計算當(dāng)前滑動窗口中所有桶的請求數(shù)量警检。如果總請求數(shù)量超過了閾值孙援,就拒絕該請求。同時扇雕,我們需要定期移除隊(duì)列中最老的元素拓售,以保證滑動窗口能夠不斷向前移動。
滑動窗口限流算法簡單易懂镶奉,適用于大多數(shù)場景础淤,但需要根據(jù)具體業(yè)務(wù)場景調(diào)整桶的大小和閾值的設(shè)定,以達(dá)到最佳的限流效果哨苛。
import java.util.LinkedList;
import java.util.Queue;
public class SlidingWindowRateLimiter {
private Queue<Long> window;
private final int limit;
private final long windowSize;
public SlidingWindowRateLimiter(int limit, long windowSize) {
this.window = new LinkedList<>();
this.limit = limit;
this.windowSize = windowSize;
}
public synchronized boolean tryAcquire() {
long now = System.currentTimeMillis();
if (window.size() >= limit) {
long oldest = window.peek();
if (now - oldest < windowSize) {
return false; // Reject request
}
window.poll();
}
window.offer(now);
return true; // Accept request
}
}