Nginx极少产生僵尸进程,因其Master仅fork长期运行的Worker进程,并在SIGCHLD信号处理中调用waitpid非阻塞回收;僵尸仅可能源于自定义模块或外部脚本误用fork未wait。

Nginx 的 Master 进程本身并不主动监控或清理僵尸进程,因为它不直接 fork 出可能产生僵尸子进程的短期任务型子进程。Nginx 的进程模型决定了僵尸进程在其正常运行中极少出现,也无需专门的“清理策略”。
为什么 Nginx 很少产生僵尸进程
Nginx 采用预派生(prefork)+ 事件驱动模型:
- Master 进程只负责启动、配置重载、平滑升级、信号管理,以及 fork 出固定数量的 Worker 进程;
- Worker 进程是长期运行的,不频繁创建/退出子进程;
- Nginx 自身不调用外部程序(如 CGI、fastcgi_pass 后端由独立服务托管),也不在 Worker 中 fork/exec 短命子进程;
- 所有子进程(主要是 Worker)均由 Master 显式 wait 或 waitpid 回收——Master 在收到 SIGCHLD 信号后,会调用
waitpid(-1, &status, WNOHANG)非阻塞地回收已退出的 Worker。
Master 对 SIGCHLD 的处理机制
当 Worker 异常退出(如段错误、被 kill)时,内核向 Master 发送 SIGCHLD。Nginx Master 注册了该信号的处理函数 ngx_signal_handler,其核心逻辑是:
- 遍历所有已知的子进程 PID(保存在
ngx_processes数组中); - 对每个已退出的子进程,调用
waitpid(pid, &status, WNOHANG)获取退出状态并清除僵尸; - 若子进程是 Worker 且非预期退出,Master 会按配置决定是否重新 fork 新 Worker(例如
worker_processes auto下保持数量); - 整个过程是轻量、非阻塞的,不会遗漏或堆积僵尸。
什么情况下可能出现僵尸?如何避免
真正产生僵尸的场景,往往源于外部扩展或误用**,而非 Nginx 原生行为:
- 在自定义模块中调用 fork() + exec() 但未在父进程中 wait;
- 使用第三方模块(如某些 Lua 模块)执行 system() 或 os.execute() 后未正确处理子进程生命周期;
- 将 Nginx 与 shell 脚本混用(如用 rewrite + proxy_pass 到本地脚本服务),而脚本自身产生子进程后未 wait;
- 系统级限制:如 ulimit -n 过低导致 fork 失败,或 init 进程异常(极罕见),使子进程无法被及时回收。
防范建议:避免在模块或配置中引入不可控的子进程;若必须调用外部程序,确保使用异步回调、进程池或交由独立守护进程(如 supervisord)管理。
验证与排查方法
可通过以下方式确认是否存在僵尸:
-
ps aux | grep 'Z'查看 Z 状态进程,检查其 PPID 是否为 nginx master(PID); -
ps -o pid,ppid,stat,comm -C nginx区分 master / worker 及其状态; - 检查
/proc/<master-pid>/status</master-pid>中的Children:行,正常应为 0 或与当前 worker 数一致; - 启用 Nginx debug 日志(
error_log ... debug;),观察是否有reaping children或waitpid() failed相关记录。
若发现僵尸持续存在,重点审查自定义代码或集成逻辑,而非怀疑 Nginx 内置机制失效。

















