轮询本身不导致内存泄漏,而是暴露模块缺陷的放大器;关键在确认同一worker rss是否随轮询请求线性增长,并通过valgrind聚焦ngx_palloc调用栈定位第三方模块泄漏源。

轮询模式本身不直接导致内存泄漏,但它是暴露模块级泄漏的“放大器”——请求持续打到同一 worker 进程,若模块中存在 ngx_palloc 分配未释放、pool 生命周期误用或循环引用等问题,内存会随请求量线性增长。排查关键不在轮询配置本身,而在它背后运行的 worker 进程与所加载模块。
确认是否真为轮询引发的泄漏迹象
轮询只是分发策略,不会额外分配内存。真正要盯的是:同一 worker 进程 RSS 是否在持续轮询流量下稳定上涨(如每小时涨 100MB+ 且不回落),同时其他 worker 内存平稳。可用以下命令快速比对:
-
ps -o pid,rss,comm -C nginx | sort -k2n—— 查看各 worker 实际物理内存(RSS)排序 -
watch -n 5 'ps -o pid,rss -C nginx | grep -v PID'—— 每 5 秒刷新观察趋势 - 配合
netstat -ant | grep :80 | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -5确认流量是否真被轮询打到固定后端,再反推对应 worker 是否承压
聚焦轮询场景下的模块与配置风险点
轮询常搭配 upstream 使用,而 upstream 的 proxy 缓冲、keepalive 和 SSL 会显著影响单 worker 内存占用。需重点检查:
-
upstream keepalive 连接池未回收:若配置
keepalive 32但后端响应慢或连接空闲超时未触发清理,连接对象及其关联 pool 可能滞留 -
proxy_buffering 开启但缓冲区过大:例如
proxy_buffers 32 16k(512KB/连接),千并发即占 512MB,易被误判为泄漏 -
SSL session cache 全局共享却重复定义:在多个 server 块中重复写
ssl_session_cache shared:SSL:64m,会导致实际分配远超预期 - 第三方模块在 init_process 或 init_worker 阶段注册全局资源但未 cleanup:轮询长期运行下,这类一次性初始化缺陷会被充分暴露
用 Valgrind 锁定轮询路径中的泄漏源头
不能只跑一次请求就退出——轮询需模拟真实调用链。正确做法是:
- 启用
master_process off; worker_processes 1;,让 Valgrind 跟踪唯一前台 worker - 用
ab -n 1000 -c 50 http://nginx-host/或 curl 循环,确保至少 200+ 请求经由轮询落到该 worker - 用
nginx -s quit或 Ctrl+C 优雅退出,触发 Valgrind 输出完整报告 - 重点过滤含
ngx_palloc、ngx_pcalloc、ngx_create_pool的调用栈,定位来自哪个模块的 .c 文件第几行
验证与收口:关闭轮询后对比是否仍泄漏
这不是为了改负载策略,而是做控制变量:
- 临时将 upstream 改为
server 127.0.0.1:8080 max_fails=0;(单节点,绕过轮询逻辑) - 保持相同请求压力,观察同一 worker RSS 是否依然上涨
- 若上涨停止,说明问题与轮询无直接关系,而是 upstream 交互或后端响应特征(如长连接、大 header)触发了模块缺陷;若仍上涨,则泄漏源在模块自身,与分发方式无关











