Nginx Master进程通过显式忽略SIGCHLD信号,使内核自动回收直系子进程(Worker)资源,从根本上避免僵尸进程产生;仅当Worker派生子进程未处理退出、第三方模块失控或Master异常崩溃时才可能绕过该机制。

Nginx 的 Master 进程本身不处理、也不需要“恢复”僵死进程——因为正常情况下,Nginx 架构中几乎不会产生僵尸进程(Zombie Process)。它通过内核机制主动规避,而非事后清理。
真正要厘清的,是两个常被混淆的概念:
- ❌ “僵死连接”(Zombie Connection):指 TCP 层已失效但未关闭的连接(如 CLOSE_WAIT 堆积、空闲超时未断),属于网络连接生命周期管理问题,由
proxy_read_timeout、keepalive_timeout等控制; - ❌ “僵尸进程”(Zombie Process):指子进程已终止、父进程未回收其退出状态,导致进程表项残留(
ps显示STAT=Z)。这是 Unix 进程模型中的资源回收问题。
而 Nginx 的 Master 进程,恰恰从设计上杜绝了自身成为僵尸制造者。
Master 进程如何避免产生僵尸进程?
它不靠轮询或手动 wait,而是用一个简洁可靠的系统级约定:
- 启动早期,Master 显式设置:
signal(SIGCHLD, SIG_IGN);
并配合sigprocmask(SIG_BLOCK, &set, NULL)阻塞信号(防止竞态)。 - 根据 POSIX 规范:当父进程将
SIGCHLD设为SIG_IGN时,内核会在子进程终止后自动回收其 PCB,不留下僵尸。 - 所有 Worker 进程均由 Master 直接 fork,是其直系子进程 → 完全适用该机制。
✅ 效果:Worker 正常或异常退出后,内核直接清理,Master 不需干预,也不会看到 Z 状态的 nginx 进程。
什么情况下仍可能出现僵尸?怎么应对?
仅在以下非标准、扩展性场景中可能绕过自动回收:
- Worker 进程自己又 fork 出子进程(例如执行
system()、os.execute()或调用外部脚本),但没处理子进程退出; - 第三方模块(如某些 Lua 模块)创建了脱离 Master 管理的子进程链;
- Master 进程崩溃后残留 Worker —— 此时 Worker 成为 init(PID 1)的子进程;若 init 暂未回收,会有极短暂僵尸(实际极少发生)。
排查方式:
ps aux | grep 'Z' | grep nginx # 或更精准: ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/ && $4 ~ /nginx/'
若发现僵尸:
- 先看其 PPID:是 1?→ 系统 init 正在接管,无需操作;
- 是 Nginx Master PID?→ 说明
SIGCHLD被意外覆盖,需检查是否加载了冲突模块或自定义代码。
建议:
- 避免在配置中使用
perl、lua_spawn_process等易派生子进程且不自动回收的指令; - 升级至 Nginx 1.19.0+,其对子进程生命周期管理更严谨;
- 如确需 Worker 创建子进程,应在代码中显式
waitpid(-1, &status, WNOHANG)循环回收。
补充:Master 对 Worker 异常退出的响应 ≠ 清理僵尸
当 Worker 因段错误、OOM 或 kill -9 退出时:
- Master 通过
waitpid()检测到非零退出码,记录日志,立即 fork 新 Worker 补位; - 这个动作是“补员”,不是“清僵尸”——因为旧 Worker 的资源早已被内核自动回收(得益于
SIG_IGN); - 若 1 秒内连续异常退出 ≥10 次,Master 会自我终止,防止雪崩,此时需人工介入查配置或模块。
不复杂但容易忽略。


















