MySQL代码导致PHP脚本在popen/exec时崩溃 [英] MySQL code causes PHP script to crash at popen/exec

查看:94
本文介绍了MySQL代码导致PHP脚本在popen/exec时崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Ubuntu 14.04服务器上具有以下PHP 5.6.19代码.这段代码只是连接到MySQL 5.6.28数据库,等待一分钟,本身启动另一个进程,然后退出.

I have the following PHP 5.6.19 code on a Ubuntu 14.04 server. This code simply connects to a MySQL 5.6.28 database, waits a minute, launches another process of itself, then exits.

注意:这是完整的脚本,目的是演示问题-它没有做任何有用的事情.

Note: this is the full script, and it's purpose is to demonstrate the problem - it doesn't do anything useful.

class DatabaseConnector {
    const DB_HOST = 'localhost';
    const DB_NAME = 'database1';
    const DB_USERNAME = 'root';
    const DB_PASSWORD = 'password';

    public static $db;

    public static function Init() {
        if (DatabaseConnector::$db === null) {
            DatabaseConnector::$db = new PDO('mysql:host=' . DatabaseConnector::DB_HOST . ';dbname=' . DatabaseConnector::DB_NAME . ';charset=utf8', DatabaseConnector::DB_USERNAME, DatabaseConnector::DB_PASSWORD);
        }
    }
}

$startTime = time();

// ***** Script works fine if this line is removed.
DatabaseConnector::Init();

while (true) {
    // Sleep for 100 ms.
    usleep(100000);

    if (time() - $startTime > 60) {
        $filePath = __FILE__;
        $cmd = "nohup php $filePath > /tmp/1.log 2>&1 &";

        // ***** Script sometimes exits here without opening the process and without errors.
        $p = popen($cmd, 'r');

        pclose($p);

        exit;
    }
}

我使用nohup php myscript.php > /tmp/1.log 2>&1 &开始脚本的第一个过程.

I start the first process of the script using nohup php myscript.php > /tmp/1.log 2>&1 &.

该进程循环应该永远持续下去,但是...基于一天内的多次测试(但不是立即),服务器上的进程会消失",没有任何理由.我发现MySQL代码导致popen代码失败(脚本退出,没有任何错误或输出).

This process loop should go on forever but... based on multiple tests, within a day (but not instantly), the process on the server "disappears" without reason. I discovered that the MySQL code is causing the popen code to fail (the script exits without any error or output).

这是怎么回事?

注释

  • 服务器运行24/7.
  • 内存不是问题.
  • 数据库正确连接.
  • 文件路径不包含空格.
  • 使用shell_execexec代替popen(和pclose)时,存在相同的问题.
  • The server runs 24/7.
  • Memory is not an issue.
  • The database connects correctly.
  • The file path does not contain spaces.
  • The same problem exists when using shell_exec or exec instead of popen (and pclose).

我还知道popen是失败的行,因为我通过在脚本中的某些位置登录到文件来进行了进一步的调试(未在上面显示).

I also know that popen is the line that fails because I did further debugging (not shown above) by logging to a file at certain points in the script.

推荐答案

父进程在分叉之后是否肯定退出?我以为pclose会等孩子离开后再返回.

Is the parent process definitely exiting after forking? I had thought pclose would wait for the child to exit before returning.

如果它没有退出,我推测是因为mySQL连接从未关闭,因此您在生成子进程树时最终会达到其连接限制(或其他限制).

If it isn't exiting, I'd speculate that because the mySQL connection is never closed, you're eventually hitting its connection limit (or some other limit) as you spawn the tree of child processes.

编辑1

我刚刚尝试复制此内容.我将您的脚本更改为每半秒而不是每分钟进行一次分叉,并能够在大约10分钟内将其杀死.

I've just tried to replicate this. I altered your script to fork every half-second, rather than every minute, and was able to kill it off within about 10 minutes.

子进程的重复创建似乎正在生成越来越多的FD,直到最终它不再具有更多的FD:

It looks like the the repeat creation of child processes is generating ever more FDs, until eventually it can't have any more:

$ lsof | grep type=STREAM | wc -l
240
$ lsof | grep type=STREAM | wc -l
242
...
$ lsof | grep type=STREAM | wc -l
425
$ lsof | grep type=STREAM | wc -l
428
...

那是因为孩子在派生时继承了父母的FD(在本例中为mySQL连接).

And that's because the child's inheriting the parent's FDs (in this case for the mySQL connection) when it forks.

如果在popen之前使用(在您的情况下)关闭mySQL连接:

If you close the mySQL connection before popen with (in your case):

DatabaseConnector::$db = null;

问题有望解决.

这篇关于MySQL代码导致PHP脚本在popen/exec时崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆