【问题标题】:Nginx / PHP FPM graceful stop (SIGQUIT): not so gracefulNginx / PHP FPM 优雅停止(SIGQUIT):不那么优雅
【发布时间】:2016-04-12 05:10:30
【问题描述】:

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

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

不幸的是,当我尝试通过向 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

有什么建议吗?我希望使系统的这一部分尽可能无缝。谢谢!

【问题讨论】:

  • 附加链接已失效 (503),此处总结的进程信号:forum.nginx.org/read.php?3,3485,template=head%3F%3F
  • 是的。 bugs.php.net/bug.php?id=41593,对我来说更重要的是,bugs.php.net/bug.php?id=60961。我不知道它们之间的关系到底如何(以及是否相关),但不幸的是 PHP-FPM 有它的小烦恼。
  • 我可以向您建议一些解决方法。它不是修复 php-fpm,而是帮助回答 200 :) 您只需要在具有 2-3 个后端的 nginx 配置中设置 upstream(它可以是相同的 php-fpm 池几次)。因此,如果其中一个请求失败,nginx 将尝试再次请求后端。

标签: php nginx


【解决方案1】:

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

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 文件被删除(可能是由其中一个子进程?我仍然不清楚 如何删除它)。

不管怎样,这个包装脚本和 CMD 一样适用于我们使用 Kubernetes 运行的 php-fpm docker 容器。

【讨论】:

  • 似乎是一个有用的设置,但这是否意味着它总是在响应之前等待 X 秒?我已经为我的 docker 容器 (github.com/bryanlatten/docker-php) 反转了这个过程,我没有立即发出 fpm 正常关闭的信号,而是优雅地关闭了它的转发 nginx 代理——这将是优雅的并等待连接完成。理论上,如果没有连接进来,并且传出连接等待关闭,PHP 可以像大象一样终止,并且飞行中的任何东西都不会受到影响。这有意义吗?
  • 当然,我认为在这里使用 nginx 作为优雅关闭代理是正确的解决方案。不幸的是,这对我们不起作用,但我认为这是未来的发展方向。
  • “很遗憾,好像php-fpm主进程马上退出了”这是什么废话。没有子进程就不能杀死主进程
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2019-11-10
  • 1970-01-01
相关资源
最近更新 更多