Nginx请求限流内存清理机制及持续限流异常问题咨询
问题背景
Nginx官方文档对limit_req_zone的zone参数说明如下:
Zone——定义用于存储每个IP地址状态及其访问受限URL频率的共享内存区域。将信息存储在共享内存中意味着它可以在NGINX工作进程之间共享。该定义包含两部分:由
zone=关键字标识的区域名称,以及冒号后的大小。约16000个IP地址的状态信息占用1MB内存,因此我们的区域可存储约160000个地址。
核心疑问
- Nginx需要多久才会清理存储IP地址的内存?
- Nginx会将这些IP地址存储多久,以及它是如何清理的?
测试场景与异常情况
配置限流规则:
limit_req_zone $binary_remote_addr zone=mylimit:1m rate=2r/s;
创建仅含单个请求的简单html页面,理论上每秒可刷新2次,第3次刷新应触发503或429错误,这一步符合预期。但等待15秒不操作后,再次刷新仍收到503/429错误;执行systemctl reload nginx、systemctl restart nginx后问题依旧。
更新后的完整配置
limit_req_zone $binary_remote_addr zone=front_limit:100m rate=50r/s; limit_req_zone $binary_remote_addr zone=saeed:1m rate=1r/s; server { listen 80; server_name example.com; location / { root /var/www/html/; index index.html; try_files /$uri /$uri/ /index.html; limit_req zone=front_limit burst=50 delay=50; limit_req_status 429; error_page 429 /home/custom_429.html; } location /saeed.html { root /home/; limit_req zone=saeed; limit_req_status 500; } }
关联错误日志
2024/05/16 22:16:57 [error] 16531#16531: *4866 limiting requests, excess: 0.500 by zone "saeed", client: my_ip_v4, server: example.com, request: "GET /saeed.html HTTP/1.1", host: "example.com"
问题解答
1. IP状态的存储时长与清理机制
Nginx的limit_req_zone中IP状态的默认过期时间是60秒,你也可以通过limit_req_zone的timeout参数手动配置,比如:
limit_req_zone $binary_remote_addr zone=saeed:1m rate=1r/s timeout=30s;
清理逻辑:Nginx会自动移除timeout时间段内没有新请求的IP状态记录;如果共享内存区域被占满,会优先移除最久未被访问的IP记录,为新IP腾出空间。
2. 测试异常的原因分析
从错误日志看,你访问的是/saeed.html,对应saeed zone的限流规则是rate=1r/s(每秒仅允许1次请求)。日志里的excess: 0.500说明两次请求的间隔小于1秒(比如0.5秒),直接触发了限流。
至于重启Nginx后问题依旧,大概率是你重启后的刷新频率仍超过了1r/s的限制——比如重启后第一次刷新正常,但马上第二次刷新(间隔不足1秒),就会触发500错误,和日志记录完全匹配。
3. 验证与调整建议
- 重启Nginx后,等待几秒再单次刷新
/saeed.html,此时应该能正常访问; - 若要调整IP状态的过期时间,给
saeedzone加上timeout参数,比如设置为10秒,这样10秒无请求后IP状态会被清理,再次请求会重新计数; - 测试时严格控制刷新间隔,确保两次请求间隔超过1秒,验证是否还会触发限流。
内容的提问来源于stack exchange,提问作者Saeed

