Nginx不停机升级:实现零停机更新的终极指南

引言

在本指南中,我们将演示如何在不中断客户端连接的情况下,直接原地升级Nginx可执行文件。Nginx是一个强大的网页服务器和反向代理,被用于服务全球最流行的许多网站。

前提条件

在开始本指南之前,您应在您的服务器上具备一个非root用户,并配置有sudo权限。您还需要安装Nginx。

您可以按照我们的Ubuntu 22.04初始服务器设置指南进行操作,然后在该服务器上安装Nginx。

升级如何运作

当Nginx服务启动时,它通过生成一个主进程来工作。主进程再生成一个或多个工作进程来处理实际的客户端连接。Nginx被设计成在接收到系统特定的低级信号时执行特定的操作。使用这些信号可以在不丢失客户端连接的情况下升级Nginx或其配置。

Nginx提供的安装和升级脚本旨在在启动、停止和重新启动Nginx时发送这些信号。然而,手动发送这些信号可以让您在升级过程中进行审核,并在出现问题时快速恢复。如果您从源码安装了Nginx或不依赖软件包管理器来配置服务,这也将提供一种优雅升级的选择。

将使用以下信号:

  • USR2: 这会生成一组新的主/工作进程,而不影响旧的进程。
  • WINCH: 这会告诉Nginx主进程优雅地停止其关联的工作实例。
  • HUP: 这会告诉Nginx主进程重新读取其配置文件,并用符合新配置的工作进程替换旧的工作进程。如果旧的和新的主进程都在运行,向旧的主进程发送此信号将使用其原始配置生成工作进程。
  • QUIT: 这会优雅地关闭主进程及其工作进程。
  • TERM: 这会启动主进程及其工作进程的快速关闭。
  • KILL: 这会立即杀死主进程及其工作进程,不进行任何清理。

找到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安装方式,通过软件包管理器或源码安装来完成更新。

在新的二进制文件准备就绪后,你可以生成一组第二个主/工作进程,使用这个新的可执行文件。

你可以通过直接向查询到的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

  1. tail -n +1 /run/nginx.pid*
输出

==> /run/nginx.pid <== 16699

==> /run/nginx.pid.oldbin <== 16653

你现在可以使用这些文件中包含的PID向任意一个主进程发送信号。

目前,主/工作进程集都是可操作并能够处理客户端请求的。第一组使用原始的Nginx可执行文件和配置,而第二组使用更新版本。它们可以并行运行,但为了保持一致性,我们应该开始过渡到新的组。

关闭第一个主进程的工作进程

为了开始向新的设置过渡,首先要做的是停止原主进程的工作进程。原始工作进程将完成处理所有当前连接的任务,然后退出。

通过向原始集合的主进程发出WINCH信号来停止其工作进程。

  1. sudo kill -s WINCH `cat /run/nginx.pid.oldbin`

这将使新的主进程的工作进程独立处理新的客户端连接。旧的主进程仍在运行,但没有工作进程。

  1. 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信号。

  1. sudo kill -s QUIT `cat /run/nginx.pid.oldbin`

老的主进程将会优雅地退出,只留下你的新的一组 Nginx 主/工作进程。此时,你已成功地进行了一次原地二进制更新的 Nginx,而不会中断客户端连接。

如果您的升级没有成功

如果你的新工作进程似乎遇到问题,你可以回到旧的配置和二进制程序。只要你还没有退出旧的主进程,这是可能的。

最佳的方法是通过发送HUP信号重新启动您旧的主进程的工作进程。通常,当您向Nginx主进程发送HUP信号时,它会重新读取配置文件并启动新的工作进程。然而,当目标是老旧的主进程时,它将使用其原始可用的配置产生新的工作进程。

  1. sudo kill -s HUP `cat /run/nginx.pid.oldbin`

你现在应该恢复了两组主/工作进程。

  1. ps aux | grep nginx
输出

这是文章《如何在不断开客户端连接的情况下升级Nginx》的第3部分(共3部分)。

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信号停止已更新但有缺陷的主进程及其工作进程。

  1. sudo kill -s QUIT `cat /run/nginx.pid`

你应该回到你的主进程和工作进程身边。

  1. 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能够处理两组主/工作进程并保持它们之间关系的信息,使我们能够在无需使服务器机器离线的情况下升级服务器软件。

bannerAds