平滑重载(nginx -s reload)后限流计数器清零是设计使然,因共享内存区被重建导致漏桶状态归零;可通过比对重载时间与限流行为突变确认,并采用独立配置、burst缓冲、应用层兜底等方案规避。

平滑重载(nginx -s reload)后限流计数器被清零,是 Nginx 限流功能中一个典型但容易被忽略的行为——它不是故障,而是设计使然。关键在于理解 limit_req_zone 和 limit_conn_zone 的状态存储机制。
限流状态存在共享内存里,重载会重建内存区
Nginx 的漏桶限流依赖 zone(如 zone=mp4_req:10m)在 worker 进程间共享状态。这个 zone 实际是一块预分配的共享内存(shared memory segment),由 master 进程初始化、worker 进程共同访问。
执行 nginx -s reload 时:
- master 进程启动新 worker,同时加载新配置;
- 旧 worker 逐步退出,新 worker 启动并初始化自己的共享内存区;
- 旧 zone 内存被释放,新 zone 是一块空白内存,所有请求计数、burst 缓冲、当前“水位”全部归零。
所以你看到的“限流突然失效”“用户又可以猛刷”,本质是漏桶被重置,不是配置没生效或模块异常。
怎么确认确实是重载导致的计数器清零
不要只看日志或监控趋势,要抓两个关键证据:
-
查重载时间点:用
journalctl -u nginx --since "2 hours ago"或grep "reloading" /var/log/nginx/error.log定位 reload 精确时间; -
比对限流行为变化:在 reload 前后各发 10 个相同 IP 的请求(如
for i in {1..10}; do curl -sI http://your.site/video.mp4 | head -1; done),观察返回码是否从 503(被限)变成全 200(未限); - 若两者时间吻合、行为突变,基本可锁定为 zone 重建所致。
不想每次 reload 都清零?这些方案更实用
共享内存无法跨 reload 持久化,但业务上可以绕过这个问题:
-
避免高频 reload:把限流阈值、burst 值等参数抽到独立配置文件(如
rate_limit.conf),仅修改该文件时 reload;其他非限流相关变更(如日志路径、upstream)尽量用systemctl reload nginx或不 reload; -
用 burst + nodelay 缓冲突刺:配置如
limit_req zone=mp4_req burst=20 nodelay;,让突发请求先进入缓冲区,即使 reload 后清零,用户短时间内的体验也不会断崖式恶化; - 结合应用层兜底:Nginx 限流适合粗粒度防护,高敏感场景(如登录、下单)应在后端服务加 Redis 计数器,它不受 Nginx 重启影响;
- 不用 reload,改用热更新模块(进阶):部分商业版 Nginx 或 OpenResty 支持通过 Lua 动态修改限流参数,无需 reload;开源版暂不支持。
别误判成 bug 的几个常见干扰项
如果 reload 后限流完全不生效,先排除以下真问题:
-
配置未生效:执行
nginx -T | grep limit_req确认配置已加载,注意 location 块嵌套层级是否覆盖正确; -
IP 识别错误:若用了 CDN 或反向代理,
$binary_remote_addr可能是代理 IP,应改用$http_x_forwarded_for并配合set_real_ip_from; -
zone 大小不足:10m 内存最多存约 16 万个 IP 状态,高并发下可能因哈希冲突导致部分 IP 未被记录,可适当调大 zone(如
zone=mp4_req:32m); -
语法错误静默失败:reload 成功不代表限流生效,务必用
nginx -t验证后再 reload。











