Nginx 生产环境平滑升级指南:从二进制热部署到健康检查配置

7

在Nginx生产环境中实现不停机(平滑)升级版本的关键,是充分利用其支持热替换(Hot Replacement)的特性。以下是详细操作流程和注意事项:


一、关键原理

  • 主进程:管理配置、绑定端口、控制子进程
  • 工作进程:处理实际请求(worker_processes
  • 信号控制
    • USR2:启动新版本二进制
    • WINCH:优雅停止旧工作进程
    • QUIT:完全退出旧主进程

二、详细操作步骤

1. 预检与备份

# 备份配置文件、二进制文件和日志
cp -r /usr/local/nginx /usr/local/nginx_backup_$(date +%F)

# 查看当前版本和编译参数
nginx -V

2. 编译新版本(以这次静态编译为例)

# 下载新版源码
wget https://tengine.taobao.org/download/tengine-3.1.0.tar.gz
tar -xvf ./tengine-3.1.0.tar.gz
cd tengine-3.1.0
# 使用docker创建临时环境,这个退出docker时就会自动删除
docker run -it --rm -v $(pwd):/work alpine:latest sh
# 安装必要依赖
apk add --no-cache gcc g++ make perl linux-headers curl gnupg  pcre-dev zlib-dev openssl-dev openssl-libs-static git

# 下载zlib依赖
wget https://zlib.net/zlib-1.3.1.tar.gz
tar xf zlib-1.3.1.tar.gz
# 设置编译参数,--prefix=/opt/nginx 表示默认运行目录为/opt/nginx,如tms
./configure --prefix=/opt/nginx  --with-http_v2_module --with-http_ssl_module --add-module=./modules/ngx_http_upstream_check_module --with-cc-opt='-static-libgcc' --with-ld-opt='-static' --with-zlib=/work/tengine/zlib-1.3.1

# 也可以配置时保持与原版一致(注意输出参数)
# ./configure <原版参数> --with-http_stub_status_module...

# 四线程编译
make -j4

# 编译完的二进制在./objs/nginx

3. 替换二进制文件(热部署)

# 替换二进制文件(不要make install!)
cp objs/nginx /usr/sbin/nginx

4. 发送信号启动热更新

# 检测新版本是否正确(重要)
nginx -t

# 向旧主进程发送USR2信号(启动新实例)
kill -USR2 $(cat /usr/local/nginx/logs/nginx.pid)

# 此时会生成新旧两个主进程PID文件:
# /usr/local/nginx/logs/nginx.pid          # 新主进程
# /usr/local/nginx/logs/nginx.pid.oldbin   # 旧主进程

PixPin_2025-02-11_12-58-01

5. 逐步关闭旧进程

# 发送WINCH信号让旧进程停止接受新连接,处理完现有请求后退出
kill -WINCH $(cat /usr/local/nginx/logs/nginx.pid.oldbin)

# 观察旧进程状态(此时旧进程还在但不处理请求)
ps aux | grep nginx

PixPin_2025-02-11_13-00-47

6. 最终切换确认

# 如果新版本运行正常,彻底退出旧主进程
kill -QUIT $(cat /usr/local/nginx/logs/nginx.pid.oldbin)

# 如果发现问题需要回滚,立即发送HUP重启旧进程,TERM新进程:
kill -HUP $(cat /usr/local/nginx/logs/nginx.pid.oldbin)
kill -TERM $(cat /usr/local/nginx/logs/nginx.pid)

PixPin_2025-02-11_13-02-17


三、关键注意事项

  1. 编译参数一致性

    • 使用 nginx -V获取旧版本的编译参数,确保模块(如 --with-http_ssl_module)和依赖库一致。
  2. 验证环节

    • 升级前在生产环境的测试沙盒中验证:
      nginx -t -c /usr/local/nginx/conf/nginx.conf
      
  3. 依赖项兼容性

    • 检查新版本是否依赖更高的OpenSSL、PCRE等库版本。
  4. 会话保持

    • 当使用长连接(如WebSocket)时,确保升级前通过配置 worker_shutdown_timeout合理超时。
  5. 回滚预案

    # 快速回滚方法
    cp /usr/local/nginx/sbin/nginx_old /usr/local/nginx/sbin/nginx
    kill -USR2 <新主进程PID>  # 启动旧版本
    
  6. 监控指标

    • 升级后监控:
      • nginx -s status(需配置 stub_status模块)
      • 系统负载、错误日志(tail -f /usr/local/nginx/log/error.log

四、NGINX配置相关

本次升级配置修改部分主要是使用了 ngx_http_upstream_check_module模块,用来自动检查 upstream节点的可用性,配置文档可参考:https://tengine.taobao.org/document_cn/http_upstream_check_cn.html

  1. 添加自动替换参数,以 oms服务为例:
upstream omsserver{
        server 172.16.3.134:8088 max_fails=30 weight=1;
        server 172.16.3.134:8089 max_fails=30 weight=1; #上面这两行不动,添加下面三行
  
        check interval=10000 rise=2 default_down=false fall=3 timeout=1000 type=http;
        check_http_send "GET /kj/keepAlive HTTP/1.0\r\n\r\n";
        check_http_expect_alive http_2xx http_3xx;
}

配置格式为:

Syntax: check interval=milliseconds [fall=count] [rise=count] [timeout=milliseconds] [default_down=true|false] [type=tcp|http|ssl_hello|mysql|ajp] [port=check_port]

interval :向后端发送的健康检查包的间隔。

rise(rise_count): 如果连续成功次数达到rise_count,服务器就被认为是up。

default_down: 设定初始时服务器的状态,如果是true,就说明默认是down的,如果是false,就是up的。默认值是true,也就是一开始服务器认为是不可用,要等健康检查包达到一定成功次数以后才会被认为是健康的。

fall(fall_count): 如果连续失败次数达到fall_count,服务器就被认为是down。

timeout: 后端健康请求的超时时间。

type:健康检查包的类型,现在支持以下多种类型:

  • tcp:简单的tcp连接,如果连接成功,就说明后端正常。
  • ssl_hello:发送一个初始的SSL hello包并接受服务器的SSL hello包。
  • http:发送HTTP请求,通过后端的回复包的状态来判断后端是否存活。
  • mysql: 向mysql服务器连接,通过接收服务器的greeting包来判断后端是否存活。
  • ajp:向后端发送AJP协议的Cping包,通过接收Cpong包来判断后端是否存活。

我们使用的配置 check interval=10000 rise=2 default_down=false fall=3 timeout=1000 type=http; 含义为:每10s检测一次,如果连续两次都成功说明服务正常,nginx启动后默认所有节点都是成功的状态,连续测试失败三次表明服务不可用,检测检测请求超1s没响应就是失败。

check_http_send "GET /kj/keepAlive HTTP/1.0\r\n\r\n";check_http_expect_alive http_2xx http_3xx; 含义为使用 GET请求 /kj/keepAlive ,如果返回2xx和3xx状态码说明服务正常,一般情况下建议使用 HEAD请求,因为 HEAD 方法只请求服务器返回 HTTP 头部信息,而 不返回响应体 (body),对服务器没有压力,oms这个是使用 HEAD一直报错才换成 GET

  1. 添加节点状态查看配置:
        location /status {
                auth_basic "Restricted Area";
                auth_basic_user_file /usr/local/nginx/auth/htpasswd; #添加访问密码
                check_status;

                access_log   off;
                allow 10.0.0.0/8;  #设置允许的网段,除了10.0.0.0/8和172.16.0.0/16其他都不允许访问
                allow 172.16.0.0/16;
                deny all;
        }

认证账号密码使用 htpasswd 命令创建,指定用户名后需要输入两次密码:

htpasswd -c ./htpasswd ks # 创建用户名为ks

PixPin_2025-02-11_13-16-54

可以使用 http://example.com/status 输入密码查看状态,同时支持不同的格式输出,默认是html格式:

/status?format=html
/status?format=csv
/status?format=json

认证界面:

PixPin_2025-02-11_13-31-28

节点监控界面:

PixPin_2025-02-11_13-33-10

通过遵循上述步骤,可以在生产环境中实现Nginx版本的无缝升级,确保服务持续可用。