Redis滑动窗口限流最可靠:用ZSET存时间戳,ZREMRANGEBYSCORE清理旧记录,ZCARD统计数量,EVAL封装Lua保证原子性;文件计数仅适用于单机低频场景。
用 Redis 实现滑动窗口限流最可靠
第三方 API 通常有每分钟/每秒调用次数限制,硬 sleep 或简单计数器容易被并发绕过。滑动窗口是平衡精度与性能的常用方案,Redis 的 ZSET + 过期时间能天然支持。
实操建议:
- 用
ZADD存储每次调用的时间戳(score = microtome()),key 为服务标识(如"api:wechat:send") - 用
ZREMRANGEBYSCORE清理窗口外请求(如time() - 60秒前的记录) - 用
ZCARD判断当前窗口内请求数是否超限(如 > 100) - 整个操作用
EVAL封装成 Lua 脚本,保证原子性,避免竞态
file_put_contents 本地文件计数只适合单机低频场景
没有 Redis 时可用文件暂代,但仅限开发或单机部署、QPS flock 锁粒度粗、I/O 延迟高,极易堆积失败。
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
- 多个进程同时读到旧计数值,一起写入导致超限
- 忘记设置
LOCK_EX,或锁后未fclose导致后续请求永久阻塞 - 文件路径没加绝对路径,不同 worker 进程写到不同位置,限流失效
若必须用文件,至少用 tempnam(sys_get_temp_dir(), 'rate_') 生成唯一路径,并在每次写入前 file_get_contents + flock + file_put_contents 三步闭环。