摘要:本文主要介紹SpringBoot項目的介面限流方案,市面上常用有2種限流方案漏桶和令牌桶,大家常用的都是令牌桶,本文也只實現了令牌桶的方案。
漏桶和令牌桶說明
漏桶和令牌桶是最常用的兩種限流演算法,核心差異如下:
特性 | 漏桶限流(Leaky Bucket) | 令牌桶限流(Token Bucket) |
核心邏輯 | 固定速率處理請求(「漏水」),桶緩衝突發請求 | 固定速率生成令牌,請求需獲取令牌才能處理 |
輸出速率 | 嚴格固定(等於漏水速率) | 允許突發(最大為桶容量 + 新生成的令牌數) |
突發容忍度 | 不允許突發(超過桶容量的請求直接拒絕) | 允許突發(桶中令牌足夠時,可一次性處理多個請求) |
資源利用率 | 可能較低(即使系統空閑,也需按固定速率處理) | 較高(系統空閑時可積累令牌,突發時快速處理) |
典型場景 | 嚴格要求速率穩定(如網路流量整形) | 允許一定突發(如 API 介面限流) |
項目基礎配置
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的令牌桶
在分散式系統中,使用 Redisson 實現並發限流是一種常見且高效的方式
RateType限流鍵(key)的設計
- OVERALL模式:限流鍵需全局唯一(如 global_api_limit),確保所有請求共享同一個桶。
- PER_CLIENT模式:限流鍵需能唯一標識客戶端(如 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;
}
}測試結果
我單線程請求了8S,請求成功40個

Guava的實現
Guava 的 RateLimiter是單機環境下基於令牌桶演算法的輕量級限流工具,適用於控制介面請求頻率、資源訪問速率或任務執行頻率等場景。以下是不同場景下的使用案例,包含基礎用法、高級特性及實際業務集成。
介面說明
- RateLimiter.create(10.0):創建一個每秒生成 10 個令牌的限流器(即允許每秒 10 個請求)。
- RateLimiter rateLimiter = RateLimiter.create(20.0, 5, TimeUnit.SECONDS): //創建預熱限流器:目標速率 20 個/秒,預熱時間 5 秒(從 2 個/秒逐步提升到 20 個/秒)
- rateLimiter.acquire(1):阻塞等待獲取 1 個令牌(若當前無令牌,會等待直到新令牌生成)。返回值為等待時間(秒)
- 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("請求太火爆");
}
}結果
8s內成功訪問45個請求

基於nginx的限流
Nginx 限流核心模塊:ngx_http_limit_req_module
Nginx 內置的 ngx_http_limit_req_module基於漏桶演算法實現限流,通過以下兩個核心指令控制:
- limit_req_zone:定義限流的共享內存區和基礎速率。
- limit_req:在具體 location或 server塊中應用限流規則。
(1)定義限流共享內存區(limit_req_zone)
在 Nginx 主配置文件(nginx.conf)的 http塊中,定義共享內存區存儲限流狀態:
http {
# 定義限流共享內存區(名稱=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:共享內存區名稱為 one,大小為 10MB(根據客戶端數量調整,10MB 約支持 16 萬 IP)。
- rate=10r/s:基礎速率(每秒允許 10 個請求)。
(2)在 server或 location中應用限流規則
在需要限流的站點配置(如 server塊)中,使用 limit_req指令應用規則,並設置被限流時的響應:
server {
listen 80;
server_name example.com;
location /api/ {
# 應用限流規則(使用上面定義的 zone=one)
limit_req zone=one burst=20 nodelay; # burst=突發容量,nodelay=不等待直接拒絕
# 被限流時返回 429 狀態碼,並跳轉到自定義錯誤頁
limit_req_status_code 429;
error_page 429 /custom_limit_msg;
# 正常請求的反向代理(示例)
proxy_pass http://backend_server;
}
# 自定義限流消息體(返回 JSON)
location = /custom_limit_msg {
internal; # 僅內部訪問,禁止外部直接請求
add_header Content-Type application/JSON;
return 429 '{"code": 429, "message": "請求過於頻繁,請稍後再試"}';
}
}關鍵參數說明
參數/指令 | 含義 |
limit_req_zone | 定義限流的共享內存區、鍵(如 IP)和基礎速率(rate=10r/s表示每秒 10 個請求)。 |
burst | 突發容量(允許短時間內超過基礎速率的請求數),例如 burst=20表示最多允許 20 個突發請求。 |
nodelay | 若啟用,被限流的請求直接拒絕(不等待);若禁用(默認),請求會等待直到令牌可用。 |
limit_req_status_code | 設置被限流時的 HTTP 狀態碼(如 429 Too Many Requests)。 |
error_page | 自定義限流時的響應內容(如返回 JSON 消息體)。 |
高級限流場景
1. 按用戶 ID 限流
若需按用戶 ID 限流(如防止惡意用戶高頻請求),可將限流鍵改為用戶 ID(需前端傳遞 X-User-ID頭):
nginx
複製
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";
}
# 應用限流(鍵為用戶 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;
}
}
}