nginx中master与worker通过socketpair单向管道、ngx_channel_t命令结构体及事件驱动实现高效通信:master为每个worker创建专属管道并发送命令,worker监听管道接收指令后置位标志位触发对应动作。

Nginx 中 Master 进程与 Worker 进程通过单向管道(socketpair)+ 命令结构体 + 事件驱动监听实现高效、轻量的交互,不依赖共享内存或复杂 IPC 机制,整个过程由内核级系统调用支撑,稳定且低开销。
通信通道:每个 Worker 都有专属 socketpair 管道
Master 在 fork 出每个 Worker 前,先调用 socketpair(AF_UNIX, SOCK_STREAM, 0, sv) 创建一对已连接的匿名套接字(sv[0] 和 sv[1])。随后:
- 在 Master 进程中关闭
sv[1],保留sv[0]作为向该 Worker 发送指令的写端; - 在 Worker 进程中关闭
sv[0],保留sv[1]作为接收指令的读端; - 这个管道被封装进
ngx_processes[n].channel[2]数组,成为进程表中对应 slot 的通信信道。
指令封装:用 ngx_channel_t 结构体传递控制命令
Master 向 Worker 发送的所有操作都打包成 ngx_channel_t 结构体,包含四个关键字段:
-
command:命令类型,如
NGX_CMD_QUIT(优雅退出)、NGX_CMD_REOPEN(重开日志)、NGX_CMD_OPEN_CHANNEL(初始化通信); - pid:目标 Worker 的进程 ID;
-
slot:该 Worker 在
ngx_processes[]数组中的下标,便于 Master 快速索引; -
fd:仅在
OPEN_CHANNEL场景下携带,用于传递额外文件描述符(如日志文件句柄)。
Worker 收到后,只解析 command 字段并置位对应标志(如 ngx_quit = 1),不回传响应。
指令接收:Worker 在事件循环中主动轮询管道
Worker 启动后,会调用 ngx_add_channel_event() 将自己的 channel[1] 加入 epoll/kqueue 监听集合,注册为可读事件。此后:
- 每次事件循环末尾,Worker 检查是否有新指令到达;
- 若可读,调用
ngx_channel_handler()解析ngx_channel_t并设置内部标志位; - 后续循环中,Worker 根据标志位执行动作——例如检测到
ngx_quit为真,就进入“停止 accept、处理完现存请求后退出”流程。
典型交互场景示例
以 nginx -s reload 为例:
- Shell 执行命令 → 向 Master PID 发送
SIGHUP; - Master 捕获信号 → 重新校验配置 → 成功后向所有旧 Worker 发送
NGX_CMD_QUIT; - 各 Worker 收到指令 → 设置
ngx_quit→ 下次循环检查时触发优雅关闭逻辑; - 同时 Master fork 新 Worker,并向其发送
NGX_CMD_OPEN_CHANNEL初始化通信通道。
整个过程无阻塞、无竞态,旧连接不断,新配置即时生效。











