如何在不断开客户端连接的情况下升级Nginx
引言
在这个指南中,我们将演示如何在不丢失客户端连接的情况下,直接在原地升级Nginx可执行文件。Nginx是一个强大的网页服务器和反向代理,被用于服务全球最流行的许多网站。
前提条件
在开始本指南之前,您应在您的服务器上具备一个非root用户,并配置有sudo权限。您还需要安装Nginx。
您可以按照我们的Ubuntu 22.04初始服务器设置指南进行操作,然后在该服务器上安装Nginx。
升级如何运作
当Nginx服务启动时,它通过生成一个主进程来工作。主进程再生成一个或多个工作进程来处理实际的客户端连接。Nginx被设计成在接收到系统特定的低级信号时执行特定的操作。使用这些信号可以在不丢失客户端连接的情况下升级Nginx或其配置。
Nginx提供的安装和升级脚本旨在在启动、停止和重新启动Nginx时发送这些信号。然而,手动发送这些信号可以让您在升级过程中进行审核,并在出现问题时快速恢复。如果您从源码安装了Nginx或不依赖软件包管理器来配置服务,这也将提供一种优雅升级的选择。
将使用以下信号:
- USR2: This spawns a new set of master/worker processes without affecting the old set.
- WINCH: This tells the Nginx master process to gracefully stop its associated worker instances.
- HUP: This tells an Nginx master process to re-read its configuration files and replace worker processes with those adhering to the new configuration. If an old and new master are running, sending this to the old master will spawn workers using their original configuration.
- QUIT: This shuts down a master and its workers gracefully.
- TERM: This initiates a fast shutdown of the master and its workers.
- KILL: This immediately kills a master and its workers without any cleanup.
找到Nginx进程的PID
为了给各个进程发送信号,我们需要知道目标进程的进程标识码(PID)。寻找进程标识码有两种方法。
首先,你可以使用ps命令行工具,然后在结果中使用grep命令搜索Nginx。这样可以看到主进程和工作进程。
- ps aux | grep nginx
root 16653 0.0 0.2 119160 2172 ? Ss 21:48 0:00 nginx: master process /usr/sbin/nginx nginx 16654 0.0 0.9 151820 8156 ? S 21:48 0:00 nginx: worker process sammy 16688 0.0 0.1 221928 1164 pts/0 S+ 21:48 0:00 grep –color=auto nginx
第二列被突出显示的是所选进程的进程ID(PID)。最后一列解释了第一个结果是一个Nginx主进程。
另一种找到主Nginx进程的PID的方法是打印出/run/nginx.pid文件的内容。
- cat /run/nginx.pid
16653
如果有两个Nginx主进程在运行,则旧进程将被移动到/run/nginx.pid.oldbin位置。
生成一个新的Nginx主/工作组合
优雅更新的第一步是实际更新您的Nginx软件包和/或二进制文件。根据您的Nginx安装方式,通过软件包管理器或源码安装来完成更新。
在新的二进制文件准备就绪后,你可以生成一组第二个Master/Worker进程,使用这个新的可执行文件。
你可以通过直接向查询到的 PID 号发送 USR2 信号来做到这一点(确保用你自己的 Nginx 主进程的 PID 替换这里的 PID)。
- sudo kill -s USR2 16653
或者,你可以直接阅读并替换你的PID文件中存储的值到命令中,就像这样:
- sudo kill -s USR2 `cat /run/nginx.pid`
如果你查看你的运行进程,你会发现你现在有两组Nginx的主进程和工作进程。
- ps aux | grep nginx
root 16653 0.0 0.2 119160 2172 ? Ss 21:48 0:00 nginx: master process /usr/sbin/nginx nginx 16654 0.0 0.9 151820 8156 ? S 21:48 0:00 nginx: worker process root 16699 0.0 1.5 119164 12732 ? S 21:54 0:00 nginx: master process /usr/sbin/nginx nginx 16700 0.0 0.9 151804 8008 ? S 21:54 0:00 nginx: worker process sammy 16726 0.0 0.1 221928 1148 pts/0 R+ 21:55 0:00 grep –color=auto nginx
你还可以看到原来的/run/nginx.pid文件已被移动到/run/nginx.pid.oldbin,而新的主进程的PID已被写入到/run/nginx.pid。
- tail -n +1 /run/nginx.pid*
==> /run/nginx.pid <== 16699 ==> /run/nginx.pid.oldbin <== 16653
你现在可以使用这些文件中包含的PID向任意一个主进程发送信号。
目前,主/工作集都是可操作并能够处理客户请求的。第一组使用原始的Nginx可执行文件和配置,而第二组使用更新版本。它们可以并行运行,但为了保持一致性,我们应该开始过渡到新的组。
关闭第一主人的工人
为了开始向新的设置过渡,首先要做的是停止原主进程的工作进程。原始工作者将完成处理所有当前连接的任务,然后退出。
通过向原始集合的主进程发出WINCH信号来停止其工作人员。
- sudo kill -s WINCH `cat /run/nginx.pid.oldbin`
这将使新的主进程的工作人员独立处理新的客户端连接。旧的主进程仍在运行,但没有工作人员。
- ps aux | grep nginx
root 16653 0.0 0.2 119160 2172 ? Ss 21:48 0:00 nginx: master process /usr/sbin/nginx root 16699 0.0 1.5 119164 12732 ? S 21:54 0:00 nginx: master process /usr/sbin/nginx nginx 16700 0.0 0.9 151804 8008 ? S 21:54 0:00 nginx: worker process sammy 16755 0.0 0.1 221928 1196 pts/0 R+ 21:56 0:00 grep –color=auto nginx
这使您能够在新员工接受连接时单独审计他们。
评估结果并采取下一步行动
你应该在这个时候测试并审核你的系统,确保没有任何问题的迹象。你可以保持配置处于这个状态,以确保新的Nginx可执行文件是无bug的且能够处理你的流量。
你接下来的步骤将完全取决于你是否遇到问题。
如果您的升级成功了
如果您的新设置的工人没有遇到任何问题,您可以安全地关闭旧的主进程。要做到这一点,向旧的主进程发送QUIT信号。
- sudo kill -s QUIT `cat /run/nginx.pid.oldbin`
老的主进程将会优雅地退出,只留下你的新的一组 Nginx 主/工作进程。此时,你已成功地进行了一次原地二进制更新的 Nginx,而不会中断客户端连接。
如果您的升级没有成功。
如果你的新员工似乎遇到问题,你可以回到旧的配置和二进制程序。只要你还没有退出旧的主进程,这是可能的。
最佳的方法是通过发送HUP信号重新启动您旧的主进程的工作者。通常,当您向Nginx主进程发送HUP信号时,它会重新读取配置文件并启动新的工作者。然而,当目标是老旧的主进程时,它将使用其原始可用的配置产生新的工作者。
- sudo kill -s HUP `cat /run/nginx.pid.oldbin`
你现在应该恢复了两组主/工作进程。
- ps aux | grep nginx
root 16653 0.0 0.2 119160 2172 ? Ss 21:48 0:00 nginx: master process /usr/sbin/nginx nginx 16654 0.0 0.9 151820 8156 ? S 21:48 0:00 nginx: worker process root 16699 0.0 1.5 119164 12732 ? S 21:54 0:00 nginx: master process /usr/sbin/nginx nginx 16700 0.0 0.9 151804 8008 ? S 21:54 0:00 nginx: worker process sammy 16726 0.0 0.1 221928 1148 pts/0 R+ 21:55 0:00 grep –color=auto nginx
最新的工人与老大师有关联。此时,两组工人都将接受客户端连接。现在,通过发送QUIT信号停止更新且有缺陷的主进程及其工人。
- sudo kill -s QUIT `cat /run/nginx.pid`
你应该回到你的老师和工作伙伴身边。
- ps aux | grep nginx
root 16653 0.0 0.2 119160 2172 ? Ss 21:48 0:00 nginx: master process /usr/sbin/nginx nginx 16654 0.0 0.9 151820 8156 ? S 21:48 0:00 nginx: worker process sammy 16688 0.0 0.1 221928 1164 pts/0 S+ 21:48 0:00 grep –color=auto nginx
原始主进程将重新获取/run/nginx.pid文件的进程ID。
如果由于任何原因这种方法不起作用,您可以尝试只向新的主服务器发送TERM信号,这将引发关闭操作。这将停止新的主服务器以及所有的工作节点,同时自动启动旧的主服务器的工作进程。如果存在严重问题,并且有问题的工作节点无法退出,您可以向每个工作节点发送一个KILL信号来清理。然而,这应该是最后的手段,因为它会中断连接。
当切换回旧的二进制文件后,请记住您的系统上仍然安装着新版本。您应该删除有问题的版本,并回滚到以前的版本,以便在重启时 Nginx 可以无故障运行。
结论:
到目前为止,您应该能够无缝地将您的机器从一个Nginx二进制文件过渡到另一个。Nginx能够处理两组主/工作进程并保持它们之间关系的信息,使我们能够在无需使服务器机器离线的情况下升级服务器软件。