SpringBoot實現(xiàn)接口限流的常用方案
漏桶和令牌桶說明
漏桶和令牌桶是最常用的兩種限流算法,核心差異如下:
| ?特性? | ?漏桶限流(Leaky Bucket)?? | ?令牌桶限流(Token Bucket)?? |
|---|---|---|
| ?核心邏輯? | 固定速率處理請求(“漏水”),桶緩沖突發(fā)請求 | 固定速率生成令牌,請求需獲取令牌才能處理 |
| ?輸出速率? | 嚴格固定(等于漏水速率) | 允許突發(fā)(最大為桶容量 + 新生成的令牌數(shù)) |
| ?突發(fā)容忍度? | 不允許突發(fā)(超過桶容量的請求直接拒絕) | 允許突發(fā)(桶中令牌足夠時,可一次性處理多個請求) |
| ?資源利用率? | 可能較低(即使系統(tǒng)空閑,也需按固定速率處理) | 較高(系統(tǒng)空閑時可積累令牌,突發(fā)時快速處理) |
| ?典型場景? | 嚴格要求速率穩(wěn)定(如網(wǎng)絡(luò)流量整形) | 允許一定突發(fā)(如 API 接口限流) |
項目基礎(chǔ)配置
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.48.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.8-jre</version>
</dependency>
</dependencies>
application.yml
spring:
data:
redis:
host: redis
port: 6379
啟動類
@SpringBootApplication
public class RateLimitApplication {
public static void main(String[] args) {
SpringApplication.run(RateLimitApplication.class, args);
}
}
基于Redisson的令牌桶
在分布式系統(tǒng)中,使用 Redisson 實現(xiàn)并發(fā)限流是一種常見且高效的方式
RateType限流鍵(key)的設(shè)計
OVERALL模式?:限流鍵需全局唯一(如global_api_limit),確保所有請求共享同一個桶。PER_CLIENT模式?:限流鍵需能唯一標(biāo)識客戶端(如user:${userId}、ip:${clientIp}),確保每個客戶端獨立使用自己的桶。
@Slf4j
@RestController
@RequestMapping(value = "redisson/rate-limit")
public class RedissonRateLimitController {
@Autowired
private RedissonClient redissonClient;
@PostMapping("create-order")
public Object createOrder(String info){
RRateLimiter rateLimiter = getLimiter();
boolean b = rateLimiter.tryAcquire();
if(b) {
log.info("允許訪問");
return "SUCCESS";
}
log.warn("限流了");
throw new RuntimeException("請求太火爆");
}
/**
* 獲取限流器
* @return
*/
private RRateLimiter getLimiter() {
RRateLimiter rateLimiter = redissonClient.getRateLimiter("create-order");
rateLimiter.trySetRate(RateType.PER_CLIENT, 20, Duration.ofSeconds(5L));
return rateLimiter;
}
}
測試結(jié)果
我單線程請求了8S,請求成功40個

Guava的實現(xiàn)
Guava 的 RateLimiter是單機環(huán)境下基于令牌桶算法的輕量級限流工具,適用于控制接口請求頻率、資源訪問速率或任務(wù)執(zhí)行頻率等場景。以下是不同場景下的使用案例,包含基礎(chǔ)用法、高級特性及實際業(yè)務(wù)集成。
接口說明
RateLimiter.create(10.0):創(chuàng)建一個每秒生成 10 個令牌的限流器(即允許每秒 10 個請求)。RateLimiter rateLimiter = RateLimiter.create(20.0, 5, TimeUnit.SECONDS): //創(chuàng)建預(yù)熱限流器:目標(biāo)速率 20 個/秒,預(yù)熱時間 5 秒(從 2 個/秒逐步提升到 20 個/秒)rateLimiter.acquire(1):阻塞等待獲取 1 個令牌(若當(dāng)前無令牌,會等待直到新令牌生成)。返回值為等待時間(秒)rateLimiter.tryAcquire(long permits, long timeout, TimeUnit unit):非阻塞獲取
具體代碼
@Slf4j
@RestController
@RequestMapping(value = "guava/rate-limit")
public class GuavaRateLimitController {
private static final RateLimiter rateLimiter = RateLimiter.create(5);
@PostMapping("create-order")
public Object createOrder(String info){
boolean b = rateLimiter.tryAcquire();
if(b) {
log.info("允許訪問");
return "SUCCESS";
}
log.warn("限流了");
throw new RuntimeException("請求太火爆");
}
}
結(jié)果
8s內(nèi)成功訪問45個請求

基于nginx的限流
Nginx 限流核心模塊:ngx_http_limit_req_module
Nginx 內(nèi)置的 ngx_http_limit_req_module基于漏桶算法實現(xiàn)限流,通過以下兩個核心指令控制:
limit_req_zone:定義限流的共享內(nèi)存區(qū)和基礎(chǔ)速率。limit_req:在具體location或server塊中應(yīng)用限流規(guī)則。
(1)定義限流共享內(nèi)存區(qū)(limit_req_zone)
在 Nginx 主配置文件(nginx.conf)的 http塊中,定義共享內(nèi)存區(qū)存儲限流狀態(tài):
http {
# 定義限流共享內(nèi)存區(qū)(名稱=one,大小=10MB,速率=10請求/秒)
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
# 其他全局配置...
include mime.types;
default_type application/octet-stream;
}
$binary_remote_addr:限流的鍵(基于客戶端 IP 地址)。zone=one:10m:共享內(nèi)存區(qū)名稱為one,大小為 10MB(根據(jù)客戶端數(shù)量調(diào)整,10MB 約支持 16 萬 IP)。rate=10r/s:基礎(chǔ)速率(每秒允許 10 個請求)。
(2)在 server或 location中應(yīng)用限流規(guī)則
在需要限流的站點配置(如 server塊)中,使用 limit_req指令應(yīng)用規(guī)則,并設(shè)置被限流時的響應(yīng):
server {
listen 80;
server_name example.com;
location /api/ {
# 應(yīng)用限流規(guī)則(使用上面定義的 zone=one)
limit_req zone=one burst=20 nodelay; # burst=突發(fā)容量,nodelay=不等待直接拒絕
# 被限流時返回 429 狀態(tài)碼,并跳轉(zhuǎn)到自定義錯誤頁
limit_req_status_code 429;
error_page 429 /custom_limit_msg;
# 正常請求的反向代理(示例)
proxy_pass http://backend_server;
}
# 自定義限流消息體(返回 JSON)
location = /custom_limit_msg {
internal; # 僅內(nèi)部訪問,禁止外部直接請求
add_header Content-Type application/json;
return 429 '{"code": 429, "message": "請求過于頻繁,請稍后再試"}';
}
}
關(guān)鍵參數(shù)說明
| 參數(shù)/指令 | 含義 |
|---|---|
| limit_req_zone | 定義限流的共享內(nèi)存區(qū)、鍵(如 IP)和基礎(chǔ)速率(rate=10r/s表示每秒 10 個請求)。 |
| burst | 突發(fā)容量(允許短時間內(nèi)超過基礎(chǔ)速率的請求數(shù)),例如 burst=20表示最多允許 20 個突發(fā)請求。 |
| nodelay | 若啟用,被限流的請求直接拒絕?(不等待);若禁用(默認),請求會等待直到令牌可用。 |
| limit_req_status_code | 設(shè)置被限流時的 HTTP 狀態(tài)碼(如 429 Too Many Requests)。 |
| error_page | 自定義限流時的響應(yīng)內(nèi)容(如返回 JSON 消息體)。 |
高級限流場景
1. 按用戶 ID 限流
若需按用戶 ID 限流(如防止惡意用戶高頻請求),可將限流鍵改為用戶 ID(需前端傳遞 X-User-ID頭):
http {
# 限流鍵為 X-User-ID 頭的值(需確保頭存在)
limit_req_zone $http_x_user_id zone=user_limit:10m rate=5r/s;
server {
location /api/user/ {
# 校驗 X-User-ID 頭是否存在,不存在則拒絕
if ($http_x_user_id = "") {
return 400 "Missing X-User-ID header";
}
# 應(yīng)用限流(鍵為用戶 ID)
limit_req zone=user_limit burst=10 nodelay;
limit_req_status_code 429;
error_page 429 /custom_limit_msg;
proxy_pass http://backend_server;
}
}
}
以上就是SpringBoot實現(xiàn)接口限流的常用方案的詳細內(nèi)容,更多關(guān)于SpringBoot接口限流的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
postman中參數(shù)和x-www-form-urlencoded傳值的區(qū)別及說明
在Postman中,參數(shù)傳遞有多種方式,其中params和x-www-form-urlencoded最為常用,Params主要用于URL中傳遞查詢參數(shù),適合GET請求和非敏感數(shù)據(jù),其特點是將參數(shù)作為查詢字符串附加在URL末尾,適用于過濾和排序等操作2024-09-09
idea2023創(chuàng)建JavaWeb教程之右鍵沒有Servlet的問題解決
最近在寫一個javaweb項目,但是在IDEA中創(chuàng)建好項目后,在搭建結(jié)構(gòu)的時候創(chuàng)建servlet文件去沒有選項,所以這里給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于idea2023創(chuàng)建JavaWeb教程之右鍵沒有Servlet問題的解決方法,需要的朋友可以參考下2023-10-10
Java如何實現(xiàn)kaptcha網(wǎng)頁驗證碼驗證
在做關(guān)于SSM項目之商鋪系統(tǒng)時,了解到了kaptcha實現(xiàn)網(wǎng)頁驗證碼驗證,感覺就很有趣,所以便開始學(xué)習(xí)記錄了起來,復(fù)制粘貼即可用2025-01-01
Spring Boot 項目設(shè)置網(wǎng)站圖標(biāo)的方法
這篇文章主要介紹了Spring Boot 項目設(shè)置網(wǎng)站圖標(biāo)的方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02

