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

时间:2016-04-12 05:10:31

标签: php nginx

运行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

有什么建议吗?我希望尽可能地使这个系统尽可能无缝。谢谢!

1 个答案:

答案 0 :(得分:3)

在经历了一段时间的同样情况之后,我相信我已经找到了神奇的配置设置,让子进程在死前完成处理请求。

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

  

<强> 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一样好。