接口限流 5 种算法详解
接口被刷怎么办?限流方案全攻略——从最简单的计数器到分布式 Redis+Lua 原子限流,5 种算法覆盖不同场景。
一、计数器(最简单)
统计单位时间内的请求数,超过阈值则拒绝。
// 简单实现(生产用 Redis)
if (redis.incr("rate:user:123") > 100) {
return "请求太频繁,请稍后再试";
}
redis.expire("rate:user:123", 1); // 1 秒过期
⚠️ 缺点:临界点问题——0.9 秒时刷 100 次,1.1 秒时再刷 100 次,实际 1 秒内请求了 200 次。
二、滑动窗口(计数器升级版)
把时间切成多个小窗口,更精确地统计请求数。解决了计数器的临界点问题,但实现较复杂。
三、令牌桶(最推荐)
以固定速率往桶里放令牌,请求来了先拿令牌,拿到才放行。
- 优点: 可以应对突发流量(桶里有令牌就能用)
- 代表实现: Guava RateLimiter
RateLimiter limiter = RateLimiter.create(100); // 每秒 100 个令牌
if (!limiter.tryAcquire()) {
return "系统繁忙,请稍后再试";
}
四、漏桶
请求像水滴一样进入漏桶,以固定速度流出。
- 优点: 流量非常平滑
- 缺点: 无法应对突发流量
五、Redis + Lua(分布式限流)
Lua 脚本保证原子性执行,适用于分布式场景。
-- Lua 脚本:原子性执行限流
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local expire = tonumber(ARGV[2])
local current = tonumber(redis.call('get', key) or "0")
if current >= limit then
return 0
end
current = redis.call('incr', key)
if current == 1 then
redis.call('expire', key, expire)
end
return 1
限流维度选择
| 维度 | 适用场景 |
|---|---|
| IP 限流 | 防止单个 IP 刷接口 |
| 用户 ID 限流 | 防止登录用户刷接口 |
| 接口限流 | 保护重要接口 |
| 全局限流 | 保护整个系统 |
关联页面
| 页面 | 关联点 |
|---|---|
| high-concurrency-four-strategies | 高并发四大手段概览(缓存/限流/削峰/幂等)——限流在高并发系统中的定位与作用 |
| nginx-security-config-guide | Nginx 安全配置实战(连接层/请求层限流配置) |
| nginx-pre-launch-checklist | Nginx 上线前检查清单(限流/超时配置项) |