一次 nginx 服务停止不当引起的问题

存储架构 Alex (源链)

昨天下午的时候,线上一台机器的一个 ngx_lua 服务突然出现了一波 HTTP 500,从错误日志打印的堆栈来看,是不久前新发布的版本里添加的一个 Lua table 不存在,而有代码向其进行索引导致的。这令人百思不得其解,如果是版本回退导致的,那么为什么使用这个 Lua table 的代码没有被回退,偏偏定义这个 table 的代码被回退了呢?

后来运维老大说该机器有重启过,之后主管去查看了该服务的启动和关闭脚本,并注意到不久前新发布的版本有过 nginx 二进制的热更新,值得一提的是,旧的 nginx master 进程在当时还运行着,没有退出。

之后排查到问题是由于关闭 nginx 的操作不当导致的。关闭脚本只是简单的使用了下面这条命令:

/path/to/nginx -s stop

这直接导致业务出现了问题。

场景复现

下面我将使用一个原生的 nginx,在我的安装了 fedora26 的虚拟机上复现这个过程,我使用的 nginx 版本是目前最新的 1.13.4

首先启动 nginx

# alex@Fedora26-64: ~/bin_install/nginx
ζ ./sbin/nginx
# alex@Fedora26-64: ~/bin_install/nginx
ζ ps auxf | grep nginx
alex      6174  0.0  0.0  28876   428 ?        Ss   14:35   0:00 nginx: master process ./sbin/nginx
alex      6175  0.0  0.2  29364  2060 ?        S    14:35   0:00  _ nginx: worker process

可以看到 master 和 worker 都已经在运行。

接着我们向 master 发送一个 SIGUSR2
信号,当 nginx 核心收到这个信号后,就会触发热更新。需要注意的是,当热更新完成之后, nginx.pid
文件里记录将是最新的 master 进程的 pid,也就是这里的 6209 进程,旧 master 的 pid 文件则被移到了 nginx.pid.oldbin

# alex@Fedora26-64: ~/bin_install/nginx                                                                                                                                                                (14:35:15)
ζ kill -USR2 6174
# alex@Fedora26-64: ~/bin_install/nginx
ζ ps auxf | grep nginx
alex      6174  0.0  0.1  28876  1996 ?        Ss   14:35   0:00 nginx: master process ./sbin/nginx
alex      6175  0.0  0.2  29364  2060 ?        S    14:35   0:00  _ nginx: worker process
alex      6209  0.0  0.2  28876  2804 ?        S    14:37   0:00  _ nginx: master process ./sbin/nginx
alex      6213  0.0  0.1  29364  2004 ?        S    14:37   0:00      _ nginx: worker process
alex      6214  0.0  0.1  29060  1800 ?        S    14:37   0:00

可以看到新的 master 和该 master fork 出来的 worker 已经在运行了,此时我们接着向旧 master 发送一个 SIGWINCH
信号,旧 master 收到这个信号后,会向它的 worker 发送 SIGQUIT
,于是旧 master 的 worker 进程就会退出:

# alex@Fedora26-64: ~/bin_install/nginx
ζ kill -WINCH 6174
# alex@Fedora26-64: ~/bin_install/nginx
ζ ps auxf | grep nginx
alex      6174  0.0  0.1  28876  1996 ?        Ss   14:35   0:00 nginx: master process ./sbin/nginx
alex      6209  0.0  0.2  28876  2804 ?        S    14:37   0:00  _ nginx: master process ./sbin/nginx
alex      6213  0.0  0.1  29364  2004 ?        S    14:37   0:00      _ nginx: worker process

此时只剩下旧的 master、新的 master 和新 master 的 worker 在运行,这和当时线上运行的情况类似。

接着我们使用 stop 命令:

# alex@Fedora26-64: ~/bin_install/nginx                                                                                                                                                                
ζ ./sbin/nginx -s stop
# alex@Fedora26-64: ~/bin_install/nginx                                                                                                                                                               
ζ ps auxf | grep nginx
alex      6174  0.0  0.1  28876  1996 ?        Ss   14:35   0:00 nginx: master process ./sbin/nginx
alex      6301  0.0  0.2  29364  2124 ?        S    14:49   0:00  _ nginx: worker process

我们发现,新的 master 和它的 worker 都已经退出,而旧的 master 还在运行,并产生了 worker 出来。这就是当时线上的情况了。

原因

更不巧的是,我们上面提到的这个 Lua table,定义它的 Lua 文件早在 init_by_lua 的时候,就已经被 LuaJIT 加载到内存并编译成字节码了,那么显然旧的 master 必然没有这个 Lua table 的信息,因为它加载那部分 Lua 代码是旧的。

而索引该 table 的 Lua 代码并没有在 init_by_lua 的时候使用到,这些代码都是在 worker 进程里被加载起来的,当然这时候项目目录里的代码都是最新的,所以 worker 加载的都是最新的代码,而当时那台机器流量也并没有切干净,于是就出现了一些 Lua 运行时错误,外部表现则是对应的 HTTP 500。

吸收了这个教训之后,我们意识到需要更加合理地关闭我们的 nginx 服务。我们总是应该先查看下是否有 nginx.pid.oldbin
这个文件,或者总是应该判断下 master 进程的父进程是否是 init 进程,如果旧 master 还存在,我们应该向旧 master 发送 SIGQUIT
信号让它退出,确保它退出后,再使用 nginx -s stop
,此时服务便可安全地退出了。当然,我们再做这些操作前,更应该确保这台机器的流量已经被切干净。

您可能感兴趣的

WEB服务器-Nginx之虚拟主机、日志、认证及优化... WEB服务器-Nginx之虚拟主机、日志、认证及优化 概述 Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 服务器 。 Nginx 是由 Igor Sysoev 为 俄罗斯 ...
HAProxy+Nginx实现负载均衡PDF 一、什么是Haproxy HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万...
Nginx Inside Docker – Website Root Configuration “What the mind can conceive and believe, and the heart desire, you can achieve.” ― Norman Vincent Peale Contents 2. Copy Files fro...
LNMP下使用Jemalloc来优化MySQL、Nginx内存管理... 由于 FaceBook 而火起来的 Jemalloc 广为人之,但殊不知,它在 malloc 界里面很早就出名了。 Jemalloc 的创始人 Jason Evans 也是在 FreeBSD 很有名的开发人员。此人就在2006年为提高低性能的 malloc 而写的 Jemalloc 。 Je...
日志服务(原SLS)2017-12 月功能发布 美东(弗吉尼亚)访问入口 嵌入式/物联网IoT日志客户端(C-Producer) 文档 , 使用案例 面向嵌入式、物联网(IoT)客户端C-Producer Library定位为一个“轻量级Logtail”,虽没有实时配置管理机制,但具备除此之外70%功能,包括: 多...
Alex责编内容来自:Alex (源链) | 更多关于

阅读提示:酷辣虫无法对本内容的真实性提供任何保证,请自行验证并承担相关的风险与后果!
本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 一次 nginx 服务停止不当引起的问题



专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录