Nginx / PHP FPM 优雅停止(SIGQUIT):不太优雅

问题描述 投票:0回答:2

运行 nginx 1.9.* / PHP 7.0.*(但在 5.6.* 中也有完全相同的行为)

尝试优雅地停止 PHP-FPM / nginx 组合以在维护期间关闭节点。为此,我将 SIGQUIT 发送到 php-fpm,这应该提供正常关闭。

为了测试这一点,我制作了一个愚蠢的脚本

<?php sleep(5); echo 'done';

使用以下curl在本地进行测试

curl -I x.x.x.x:8080

通常会产生输出:

HTTP/1.1 200 OK
Server: nginx
Date: Tue, 12 Apr 2016 04:48:00 GMT
Content-Type: text/html; charset=UTF-8
Connection: close

期望:在任何正在进行的请求中间,当请求正常关闭时,当前请求应该完成,但任何其他请求都应该失败。

不幸的是,当我尝试触发此行为时,通过向 PHP-FPM 主进程发送 SIGQUIT (http://manpages.ubuntu.com/manpages/precise/man8/php5-fpm.8.html):

kill -s SIGQUIT $FPMPID

连接立即断开,导致 ngnix 502

HTTP/1.1 502 Bad Gateway
Server: nginx
Date: Tue, 12 Apr 2016 04:48:07 GMT
Content-Type: text/html
Content-Length: 166
Connection: close

有什么建议吗?我很想让系统的这一部分尽可能无缝。谢谢!

php nginx
2个回答
4
投票

在与同样的情况苦苦挣扎一段时间后,我相信我已经找到了神奇的配置设置,可以使子进程在死亡之前完成处理请求。

http://php.net/manual/en/install.fpm.configuration.php#process-control-timeout

进程控制超时

子进程等待主进程信号反应的时间限制

基本上,通过将其设置为

10s
之类的值,子进程将等待那么长时间,同时在退出之前处理现有请求。

不幸的是,似乎

php-fpm
主进程立即退出,因此,受代码here的启发,我编写了一个包装脚本:

#!/bin/bash

PHP_FPM_PID='/php-fpm.pid'

wait_for_pid () {
    try=0

    while test $try -lt 35 ; do
        if [ ! -f "$1" ] ; then
            try=''
            break
        fi

        echo -n .
        try=`expr $try + 1`
        sleep 1
    done
}

function clean_up {

    echo "Killing $(cat $PHP_FPM_PID)"

    kill -QUIT `cat $PHP_FPM_PID`
    wait_for_pid $PHP_FPM_PID

    echo "Done!"

    exit 0
}

trap clean_up EXIT

nohup php-fpm --daemonize --pid $PHP_FPM_PID 2>&1 &

while true; do sleep 1; done
# ^ do nothing forever

等待 35 秒或直到 pid 文件被删除(大概是由子进程之一删除?我仍然不清楚 如何删除它)。

无论如何,这个包装器脚本与我们使用 Kubernetes 运行的

CMD
docker 容器的
php-fpm
配合得很好。


0
投票

Nginx 还会对 SIGWINCH 做出反应,以优雅地关闭工作线程。所以这可以用来在 php-fpm 之前停止 nginx。就我而言,在部署过程中,我收到了 502 错误,因为 php-fpm 立即停止处理请求,但 nginx 有一些请求要处理队列。虽然时间很短,但足以在负载下产生错误。只需在 docker-compose.yml 中设置 stop_signal: SIGWINCH 即可帮助解决此问题。当然,可以创建捕获 SIGWINCH 的自定义脚本,并在 NGINX 停止后优雅地终止其他进程。

© www.soinside.com 2019 - 2024. All rights reserved.