nginx 在平滑重载(reload)过程中,通过信号机制将正在处理的长连接请求完整处理完毕后才会关闭旧进程,从而确保客户端不会收到连接中断错误。具体做法是向 nginx 主进程发送 sighup 信号,主进程会启动新工作进程并等待所有旧工作进程完成当前请求后退出,期间新请求由新进程处理,而处于活跃状态的长连接(如 websocket 或 http keep-alive)会继续绑定在旧进程上直到其正常结束。

平滑重载的信号传递与进程状态变化
当执行 nginx -s reload 时,Nginx 主进程接收 SIGHUP 信号,随后进入配置验证与新进程启动阶段。此时旧的工作进程(Worker)并未立即终止,而是继续服务已有的连接。新启动的 Worker 进程开始接受新的连接请求。这种并行运行状态确保了服务的连续性,特别是对于尚未结束的长连接,它们依然由旧 Worker 处理,直到连接自然关闭或超时。

#!/bin/bash # 模拟 Nginx 平滑重载过程 # 假设已有 nginx 进程运行 # 1. 获取主进程 PID MASTER_PID=$(cat /var/run/nginx.pid) # 2. 发送 SIGHUP 触发重载 kill -HUP $MASTER_PID # 3. 检查新旧进程共存状态 ps aux | grep nginx # 预期结果: # 1. 主进程 PID 不变 # 2. 出现新的 worker 进程 (PID 不同) # 3. 旧的 worker 进程仍然存在,直到处理完所有连接后退出 # 4. 日志中会有 "signal 1 (SIGHUP) received" 记录
长连接在重载期间的生命周期管理
对于已经建立的长连接,Nginx 的策略是“不主动断开”。旧 Worker 进程在处理完最后一个数据包后,会正常关闭该连接的文件描述符。如果连接因空闲超时(Keep-Alive Timeout)而关闭,旧进程会在超时后释放资源。新 Worker 进程则负责处理在此之后发起的新连接。这意味着,在重载窗口期内,部分客户端可能仍连接到旧进程,但这不会影响连接的完整性,因为旧进程被允许完成其手头的工作。

# 验证长连接是否受影响
# 使用 curl 模拟长连接请求
while true; do
curl -s -o /dev/null -w "%{http_code}" http://localhost/
echo " - $(date)"
sleep 1
done &
# 在另一个终端执行重载
nginx -s reload
# 观察第一个终端的输出
# 预期结果:HTTP 状态码保持 200,无连接重置或超时错误
# 这表明长连接在重载期间未被强制中断
基于 keepalive_timeout 参数的具体影响分析
当 keepalive_timeout 设置较短时,长连接在重载期间更容易因超时而自动关闭,从而快速迁移到新进程。若设置较长,旧进程将维持这些连接更久,可能导致旧进程退出延迟。开发者应监控旧进程的存活时间,确保配置合理以避免资源滞留。例如,若 keepalive_timeout 为 60 秒,重载后最多需等待 60 秒旧进程才会完全退出,期间这些连接仍由旧进程服务。











