Nginx Master进程不直接实现信号通信,而是作为信号接收与分发中心,通过标准Unix信号(如SIGHUP、SIGUSR2)与外部及Worker进程协同;细粒度控制依赖socketpair构建的channel通道,Worker向Master反馈主要依靠SIGCHLD和共享内存。

Nginx 的 Master 进程不直接“实现”信号通信,而是作为信号接收与分发中心,依托 Linux 原生信号机制完成进程协同。它本身不创建新信号,也不封装底层 syscall,而是通过标准 Unix 信号(如 SIGHUP、SIGUSR2)与外部及 Worker 进程建立轻量、异步的控制通道。
Master 进程接收外部信号并响应
外部操作(如 nginx -s reload)本质是启动一个临时进程,读取 pid 文件(默认 /var/run/nginx.pid),再调用 kill() 向 Master 发送对应信号:
-
SIGHUP→ 触发配置重载:Master 验证新配置,平滑启动新 Worker,通知旧 Worker 优雅退出 -
SIGUSR2→ 启动新版本二进制:Master fork 新 Worker 使用新版可执行文件,旧 Worker 继续服务直至空闲 -
SIGQUIT→ 优雅关闭:Master 发送NGX_CMD_QUIT命令给所有 Worker,等待连接处理完毕后退出 -
SIGTERM→ 强制终止:Master 发送NGX_CMD_TERMINATE,Worker 立即中止当前请求并退出 -
SIGUSR1→ 重新打开日志文件:Master 通知 Worker 关闭并重开 access/error 日志句柄
这些信号由 Master 的 ngx_signal_handler() 统一捕获,不做阻塞处理,仅设置标志位或触发后续非阻塞动作。
Master 向 Worker 进程下发控制指令
信号本身不用于 Master → Worker 的细粒度控制(如“暂停 accept”或“刷新缓存”)。这部分靠 socketpair 构建的 channel 通道完成:
- 每次 fork Worker 前,Master 调用
socketpair(AF_UNIX, SOCK_STREAM, 0, sv)创建一对双向套接字 - Master 保留
sv[0],Worker 继承sv[1]并关闭sv[0] - Master 向
sv[0]写入ngx_channel_t结构体(含command、pid、slot等字段) - Worker 在事件循环中监听
sv[1],收到后解析命令并执行对应逻辑(如NGX_CMD_QUIT就开始清理连接)
这种设计避免了信号不可靠、无法携带结构化数据的问题,也规避了信号中断系统调用带来的复杂性。
Worker 进程向 Master 的反馈不依赖信号
Worker 不主动向 Master 发送信号来汇报状态。Master 主要通过以下方式感知 Worker 行为:
-
SIGCHLD:Worker 退出时内核自动发送,Master 捕获后检查waitpid()获取退出码,决定是否重启异常子进程 - 共享内存 + 原子计数:例如
limit_req_zone中的计数器,Worker 自行更新,Master 无需干预 - channel 反向通信极少使用:Worker 一般不向 Master 发送
ngx_channel_t,channel 是单向(Master→Worker)为主
关键约束:不引入阻塞同步
Nginx 明确回避在 Worker 中使用互斥锁、条件变量等阻塞原语。所有跨进程协作(包括共享内存读写)都基于:
- 原子操作(如
ngx_atomic_fetch_add) - 自旋锁(
ngx_shmtx_t,优先用共享内存模拟) - 文件锁(仅当原子操作不可用时降级使用)
这确保每个 Worker 始终保持高并发响应能力,不会因 IPC 等待而挂起。
不复杂但容易忽略


















