Redis怎样实现基于令牌桶的限流算法
正确做法是用 EVAL 执行 Lua 脚本保证原子性结合 PTTL 和 TIME 实现毫秒级令牌补充避免客户端时间依赖Redis 6.2 可用 CL.THROTTLE 简化实现。用 INCR EXPIRE 模拟令牌桶但要注意原子性问题Redis 本身没有原生令牌桶命令得靠多个命令组合实现。最常见写法是先 INCR 计数器再 EXPIRE 设置过期时间——但这不是原子操作高并发下可能漏设过期导致计数器永久残留。正确做法是用 EVAL 执行 Lua 脚本把“增、判、设过期”锁在一次请求里。比如当前令牌数不足时不增加足够则减一并保持 TTL 不变。脚本里用 redis.call(INCR, KEYS[1]) 获取新值再用 redis.call(TTL, KEYS[1]) 查剩余时间首次访问需同时设初始值和 TTL推荐用 SET key 1 EX 60 NX注意 NX 防覆盖别依赖客户端时间判断窗口所有逻辑必须在 Redis 端完成否则时钟不同步会出错PTTL 和 TTL 的区别影响重置逻辑令牌桶需要“定期补充”但 Redis 不支持定时回调。实际做法是每次请求时根据上次更新时间和当前时间差算出应补多少令牌。这时必须用 PTTL毫秒级而不是 TTL秒级否则在 1 秒内多次请求会误判为“没过期”导致补发失败。例如限流窗口 100ms补速率 10 token/s那每 100ms 补 1 个。如果只查 TTL两次请求间隔 50ms 但落在同一秒内TTL 返回值不变就无法触发补充。用 PTTL 获取精确剩余毫秒数再结合 TIME 或客户端传入时间戳推算流逝时间补令牌后要重设 PEXPIRE不能只改 value否则 TTL 会归零或错乱注意 Lua 脚本里 TIME 返回的是秒微秒数组要自己转成毫秒做计算用 CL.THROTTLERedis 6.2更省事但得确认服务端版本Redis 6.2 加了 CL.THROTTLE 命令底层就是令牌桶直接返回 [是否允许, 当前余量, 下次允许时间戳, 总容量, 重试等待毫秒] 五个值。不用手写 Lua也不用担心竞态。 Murf AI AI文本转语音生成工具