Java常見的限流方案及實(shí)現(xiàn)方法
在高并發(fā)場(chǎng)景中,限流(Rate Limiting) 是一種重要的保護(hù)機(jī)制,用于控制系統(tǒng)的請(qǐng)求流量,避免系統(tǒng)過載。以下是常見的限流方案及其 Java 實(shí)現(xiàn)。
1. 限流的常見算法
1.1 計(jì)數(shù)器算法
原理:在固定時(shí)間窗口內(nèi)統(tǒng)計(jì)請(qǐng)求次數(shù),超過閾值則拒絕請(qǐng)求。
優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單。
缺點(diǎn):無法應(yīng)對(duì)突發(fā)流量。
1.2 滑動(dòng)窗口算法
原理:將時(shí)間窗口劃分為多個(gè)小窗口,統(tǒng)計(jì)最近一段時(shí)間內(nèi)的請(qǐng)求次數(shù)。
優(yōu)點(diǎn):比計(jì)數(shù)器算法更平滑。
缺點(diǎn):實(shí)現(xiàn)復(fù)雜。
1.3 漏桶算法
原理:請(qǐng)求以固定速率流出,超過桶容量的請(qǐng)求被丟棄或等待。
優(yōu)點(diǎn):平滑流量。
缺點(diǎn):無法應(yīng)對(duì)突發(fā)流量。
1.4 令牌桶算法
原理:以固定速率生成令牌,請(qǐng)求需要獲取令牌才能被處理。
優(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; // 時(shí)間窗口(毫秒)
private final AtomicInteger counter; // 計(jì)數(shù)器
private long lastResetTime; // 上次重置時(shí)間
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("請(qǐng)求 " + i + ": " + (limiter.tryAcquire() ? "通過" : "被限流"));
Thread.sleep(100); // 模擬請(qǐng)求間隔
}
}
}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ǔ)充令牌時(shí)間
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 個(gè)令牌
for (int i = 0; i < 20; i++) {
System.out.println("請(qǐng)求 " + i + ": " + (limiter.tryAcquire() ? "通過" : "被限流"));
Thread.sleep(100); // 模擬請(qǐng)求間隔
}
}
}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("請(qǐng)求 " + i + ": " + (limiter.tryAcquire() ? "通過" : "被限流"));
Thread.sleep(300); // 模擬請(qǐng)求間隔
}
}
}4. 限流方案的選擇
| 算法 | 優(yōu)點(diǎn) | 缺點(diǎn) | 適用場(chǎng)景 |
|---|---|---|---|
| 計(jì)數(shù)器 | 實(shí)現(xiàn)簡(jiǎn)單 | 無法應(yīng)對(duì)突發(fā)流量 | 簡(jiǎn)單限流場(chǎng)景 |
| 滑動(dòng)窗口 | 比計(jì)數(shù)器更平滑 | 實(shí)現(xiàn)復(fù)雜 | 需要平滑限流的場(chǎng)景 |
| 漏桶 | 平滑流量 | 無法應(yīng)對(duì)突發(fā)流量 | 需要嚴(yán)格控制流量的場(chǎng)景 |
| 令牌桶 | 支持突發(fā)流量 | 實(shí)現(xiàn)復(fù)雜 | 需要支持突發(fā)流量的場(chǎng)景 |
| Guava | 簡(jiǎn)單易用,功能強(qiáng)大 | 依賴第三方庫(kù) | 需要快速實(shí)現(xiàn)限流的場(chǎng)景 |
5. 總結(jié)
限流是保護(hù)系統(tǒng)的重要手段,常見的限流算法包括計(jì)數(shù)器、滑動(dòng)窗口、漏桶和令牌桶。
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring 使用 feign時(shí)設(shè)置header信息的操作
這篇文章主要介紹了Spring 使用 feign時(shí)設(shè)置header信息的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Spring實(shí)現(xiàn)上拉刷新和下拉加載效果
這篇文章主要為大家詳細(xì)介紹了Spring實(shí)現(xiàn)上拉刷新和下拉加載效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
SpringBoot--- SpringSecurity進(jìn)行注銷權(quán)限控制的配置方法
這篇文章主要介紹了SpringBoot--- SpringSecurity進(jìn)行注銷,權(quán)限控制,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
mybatis 使用jdbc.properties文件設(shè)置不起作用的解決方法
這篇文章主要介紹了mybatis 使用jdbc.properties文件設(shè)置不起作用的解決方法,需要的朋友可以參考下2018-03-03
基于Feign實(shí)現(xiàn)異步調(diào)用
近期,需要對(duì)之前的接口進(jìn)行優(yōu)化,縮短接口的響應(yīng)時(shí)間,但是springcloud中的feign是不支持傳遞異步化的回調(diào)結(jié)果的,因此有了以下的解決方案,記錄一下,需要的朋友可以參考下2021-05-05
Mybatis如何使用ognl表達(dá)式實(shí)現(xiàn)動(dòng)態(tài)sql
這篇文章主要介紹了Mybatis使用ognl表達(dá)式實(shí)現(xiàn)動(dòng)態(tài)sql的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
java實(shí)現(xiàn)統(tǒng)計(jì)字符串中字符及子字符串個(gè)數(shù)的方法示例
這篇文章主要介紹了java實(shí)現(xiàn)統(tǒng)計(jì)字符串中字符及子字符串個(gè)數(shù)的方法,涉及java針對(duì)字符串的遍歷、判斷及運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-01-01

