Redis实现限流(滑动窗口/令牌桶/漏桶算法)
请介绍如何使用Redis实现高并发接口限流的三种常用算法:固定窗口、滑动窗口(ZSet实现),以及令牌桶和漏桶算法。每种算法的优缺点分别是什么?如何选择?
回答
编译有声
1. 固定窗口
- 如:1分钟内最多100个请求
- 实现:INCR key,设置过期时间,计数超限拒绝
- 缺点:临界突变问题(59秒999个请求,第60秒1个请求,两秒合计1000个)
2. 滑动窗口(ZSet实现)
- 原理:每个请求的时间戳作为score存入ZSet
- 实现:
ZADD rate_limit:api 当前时间戳 当前时间戳-随机后缀
ZREMRANGEBYSCORE rate_limit:api 0 当前时间戳-窗口大小
ZCARD rate_limit:api
// 如果 > 100 则拒绝
- 优点:精确控制窗口内请求数,无临界问题
- 缺点:记录所有请求时间戳,内存开销较大
3. 令牌桶
- 原理:以固定速率向桶中添加令牌,请求消耗令牌
- Redis实现:存储上次更新时间+令牌数,每次请求时计算新令牌
- 优点:允许突发流量(桶内令牌可积累),平滑限流
- 缺点:实现较复杂
4. 漏桶
- 原理:请求以固定速率出水(处理),桶满则丢弃
- Redis实现:使用List存储请求,后台定时消费
- 优点:严格保证处理速率,适合保护下游
- 缺点:不能处理突发流量(相比令牌桶)
选型建议:
- 一般限流(允许突发):令牌桶
- 严格保护下游:漏桶
- 简单精确限流:滑动窗口(推荐ZSet实现)
- 固定窗口只适合非严格要求场景