限流有哪些方案?¶
一、为什么要限流¶
保护系统不被突发流量打挂。常见场景:秒杀、接口防刷、第三方调用配额。
二、常见算法¶
1. 固定窗口计数器¶
每分钟 100 个请求,到了就拒绝。
- 优点:简单。
- 缺点:窗口边界突刺(59s 来 100 个,0s 又来 100 个,1 秒内 200 个)。
2. 滑动窗口¶
把窗口切成小格,统计过去 N 小格。比固定窗口平滑,但仍有边界问题。
3. 漏桶(Leaky Bucket)¶
请求像水进桶,桶以固定速率出水。超出桶容量拒绝。
- 特点:输出速率恒定。
- 缺点:突发流量不能及时处理。
4. 令牌桶(Token Bucket)¶
以固定速率往桶里放令牌,请求要拿到令牌才能通过。桶满了新令牌丢弃。
- 特点:允许一定程度的突发(桶里攒了令牌,一次可以拿多个)。
- Guava
RateLimiter就是令牌桶。
RateLimiter limiter = RateLimiter.create(100); // 100 QPS
if (limiter.tryAcquire()) {
// 处理请求
} else {
// 限流
}
5. 信号量(Semaphore)¶
限制并发数,不是速率。适合限制同时处理的请求数。
三、分布式限流¶
单机限流不够,多台机器要统一计数。
1. Redis + Lua¶
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call('INCR', key)
if current == 1 then
redis.call('EXPIRE', key, window)
end
if current > limit then
return 0
end
return 1
Lua 保证原子性。
2. Sentinel¶
阿里开源,支持:
- 限流(QPS、线程数)。
- 熔断降级。
- 系统负载保护。
- 控制台动态规则。
3. Gateway 层限流¶
在 Nginx / Spring Cloud Gateway 层做限流,挡住大部分流量。
四、限流后处理¶
- 直接拒绝:返回 429。
- 排队等待:请求进入队列,慢慢处理。
- 降级:返回兜底数据。
五、常见维度¶
- 用户 ID 限流:防刷。
- IP 限流:防爬虫。
- 接口维度:保护核心接口。
- 全局限流:保护整个系统。
高频追问
- 令牌桶 vs 漏桶:令牌桶允许突发,漏桶强制匀速。
- 单机 vs 分布式:单机用 Guava,分布式用 Redis+Lua 或 Sentinel。