Java常見的限流方案及實(shí)現(xiàn)方法
在高并發(fā)場景中,限流(Rate Limiting) 是一種重要的保護(hù)機(jī)制,用于控制系統(tǒng)的請求流量,避免系統(tǒng)過載。以下是常見的限流方案及其 Java 實(shí)現(xiàn)。
1. 限流的常見算法
1.1 計(jì)數(shù)器算法
原理:在固定時間窗口內(nèi)統(tǒng)計(jì)請求次數(shù),超過閾值則拒絕請求。
優(yōu)點(diǎn):實(shí)現(xiàn)簡單。
缺點(diǎn):無法應(yīng)對突發(fā)流量。
1.2 滑動窗口算法
原理:將時間窗口劃分為多個小窗口,統(tǒng)計(jì)最近一段時間內(nèi)的請求次數(shù)。
優(yōu)點(diǎn):比計(jì)數(shù)器算法更平滑。
缺點(diǎn):實(shí)現(xiàn)復(fù)雜。
1.3 漏桶算法
原理:請求以固定速率流出,超過桶容量的請求被丟棄或等待。
優(yōu)點(diǎn):平滑流量。
缺點(diǎn):無法應(yīng)對突發(fā)流量。
1.4 令牌桶算法
原理:以固定速率生成令牌,請求需要獲取令牌才能被處理。
優(yōu)點(diǎn):支持突發(fā)流量。
缺點(diǎn):實(shí)現(xiàn)復(fù)雜。
2. 限流方案的 Java 實(shí)現(xiàn)
以下是基于 計(jì)數(shù)器算法 和 令牌桶算法 的 Java 實(shí)現(xiàn)示例。
2.1 計(jì)數(shù)器算法實(shí)現(xiàn)
import java.util.concurrent.atomic.AtomicInteger; public class CounterRateLimiter { private final int limit; // 限流閾值 private final long interval; // 時間窗口(毫秒) private final AtomicInteger counter; // 計(jì)數(shù)器 private long lastResetTime; // 上次重置時間 public CounterRateLimiter(int limit, long interval) { this.limit = limit; this.interval = interval; this.counter = new AtomicInteger(0); this.lastResetTime = System.currentTimeMillis(); } public boolean tryAcquire() { long now = System.currentTimeMillis(); if (now - lastResetTime > interval) { // 重置計(jì)數(shù)器 counter.set(0); lastResetTime = now; } // 判斷是否超過閾值 return counter.incrementAndGet() <= limit; } public static void main(String[] args) throws InterruptedException { CounterRateLimiter limiter = new CounterRateLimiter(10, 1000); // 每秒限流 10 次 for (int i = 0; i < 20; i++) { System.out.println("請求 " + i + ": " + (limiter.tryAcquire() ? "通過" : "被限流")); Thread.sleep(100); // 模擬請求間隔 } } }
2.2 令牌桶算法實(shí)現(xiàn)
import java.util.concurrent.atomic.AtomicLong; public class TokenBucketRateLimiter { private final long capacity; // 桶容量 private final long rate; // 令牌生成速率(令牌/毫秒) private final AtomicLong tokens; // 當(dāng)前令牌數(shù)量 private long lastRefillTime; // 上次補(bǔ)充令牌時間 public TokenBucketRateLimiter(long capacity, long rate) { this.capacity = capacity; this.rate = rate; this.tokens = new AtomicLong(capacity); this.lastRefillTime = System.currentTimeMillis(); } public boolean tryAcquire() { refillTokens(); // 補(bǔ)充令牌 long currentTokens = tokens.get(); if (currentTokens > 0) { return tokens.decrementAndGet() >= 0; } return false; } private void refillTokens() { long now = System.currentTimeMillis(); long elapsedTime = now - lastRefillTime; long newTokens = elapsedTime * rate; // 計(jì)算新增令牌數(shù) if (newTokens > 0) { lastRefillTime = now; tokens.updateAndGet(old -> Math.min(capacity, old + newTokens)); // 更新令牌數(shù) } } public static void main(String[] args) throws InterruptedException { TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(10, 1); // 桶容量 10,每秒生成 1 個令牌 for (int i = 0; i < 20; i++) { System.out.println("請求 " + i + ": " + (limiter.tryAcquire() ? "通過" : "被限流")); Thread.sleep(100); // 模擬請求間隔 } } }
3. 使用 Guava 的 RateLimiter
Google Guava 提供了 RateLimiter
類,基于令牌桶算法實(shí)現(xiàn)限流。
3.1 添加依賴
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> </dependency>
運(yùn)行 HTML
3.2 使用示例
import com.google.common.util.concurrent.RateLimiter; public class GuavaRateLimiterExample { public static void main(String[] args) throws InterruptedException { RateLimiter limiter = RateLimiter.create(1.0); // 每秒限流 1 次 for (int i = 0; i < 10; i++) { System.out.println("請求 " + i + ": " + (limiter.tryAcquire() ? "通過" : "被限流")); Thread.sleep(300); // 模擬請求間隔 } } }
4. 限流方案的選擇
算法 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場景 |
---|---|---|---|
計(jì)數(shù)器 | 實(shí)現(xiàn)簡單 | 無法應(yīng)對突發(fā)流量 | 簡單限流場景 |
滑動窗口 | 比計(jì)數(shù)器更平滑 | 實(shí)現(xiàn)復(fù)雜 | 需要平滑限流的場景 |
漏桶 | 平滑流量 | 無法應(yīng)對突發(fā)流量 | 需要嚴(yán)格控制流量的場景 |
令牌桶 | 支持突發(fā)流量 | 實(shí)現(xiàn)復(fù)雜 | 需要支持突發(fā)流量的場景 |
Guava | 簡單易用,功能強(qiáng)大 | 依賴第三方庫 | 需要快速實(shí)現(xiàn)限流的場景 |
5. 總結(jié)
限流是保護(hù)系統(tǒng)的重要手段,常見的限流算法包括計(jì)數(shù)器、滑動窗口、漏桶和令牌桶。
Java 中可以通過自定義實(shí)現(xiàn)或使用 Guava 的
RateLimiter
實(shí)現(xiàn)限流。根據(jù)業(yè)務(wù)需求選擇合適的限流方案,確保系統(tǒng)的穩(wěn)定性和高可用性。
通過以上內(nèi)容,可以輕松掌握限流的實(shí)現(xiàn)方法!
到此這篇關(guān)于Java常見的限流方案及實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java限流方案內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java多線程中的ThreadPoolExecutor使用解析
這篇文章主要介紹了Java多線程中的ThreadPoolExecutor使用解析,作為線程池的緩沖,當(dāng)新增線程超過maximumPoolSize時,會將新增線程暫時存放到該隊(duì)列中,需要的朋友可以參考下2023-12-12關(guān)于mybatis-plus插件使用時的一些問題小結(jié)
這篇文章主要給大家介紹了關(guān)于mybatis-plus插件使用時的一些問題的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-03-03Eclipse maven項(xiàng)目lombok安裝配置圖解
這篇文章主要介紹了Eclipse maven項(xiàng)目lombok安裝配置圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-05-05初識Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運(yùn)算符
Java是一種強(qiáng)類型語言,每個變量都必須聲明其數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運(yùn)算符的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10