Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL代码导致PHP脚本在popen/exec上崩溃_Php_Mysql_Linux_Ubuntu_Pdo - Fatal编程技术网

MySQL代码导致PHP脚本在popen/exec上崩溃

MySQL代码导致PHP脚本在popen/exec上崩溃,php,mysql,linux,ubuntu,pdo,Php,Mysql,Linux,Ubuntu,Pdo,我在ubuntu14.04服务器上有以下php5.6.19代码。这段代码只是连接到一个MySQL 5.6.28数据库,等待一分钟,启动自己的另一个进程,然后退出 注意:这是完整的脚本,它的目的是演示问题-它没有做任何有用的事情 class DatabaseConnector { const DB_HOST = 'localhost'; const DB_NAME = 'database1'; const DB_USERNAME = 'root'; const DB

我在
ubuntu14.04
服务器上有以下
php5.6.19
代码。这段代码只是连接到一个
MySQL 5.6.28
数据库,等待一分钟,启动自己的另一个进程,然后退出

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

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&
启动脚本的第一个进程

这个过程循环应该永远持续下去,但是。。。根据多次测试,在一天内(但不是瞬间),服务器上的进程会无缘无故地“消失”。我发现
MySQL
代码导致
popen
代码失败(脚本退出时没有任何错误或输出)

这里发生了什么


注释

  • 服务器全天候运行
  • 记忆不是问题
  • 数据库连接正确
  • 文件路径不包含空格
  • 使用
    shell\u exec
    exec
    而不是
    popen
    (和
    pclose
    )时也存在同样的问题

我还知道,
popen
是一行失败的代码,因为我通过在脚本中的某些点登录到文件进行了进一步调试(上面没有显示)。

分叉后父进程肯定会退出吗?我原以为
pclose
会等到孩子退出后再回来

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

编辑1

我只是想复制一下。我将你的脚本改为每半秒一次,而不是每分钟一次,并且能够在大约10分钟内完成

子进程的重复创建似乎正在生成越来越多的FD,直到最终无法再生成:

$ 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
...
这是因为在分叉时,子节点继承了父节点的FDs(在本例中是mySQL连接)

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

这个问题有望解决

脚本退出时没有任何错误或输出

当代码中没有错误检查时,这并不奇怪。然而,如果它真的是“崩溃”,那么:

  • 如果原因被PHP运行时捕获,那么它将尝试记录错误。您是否尝试过谨慎地创建一个错误场景,以确定重新排序/日志记录是否按预期工作

  • 如果PHP运行时没有捕获错误,那么操作系统应该转储一个corefile,是吗?查找核心文件

$cmd=“nohup php$filePath>/tmp/1.log 2>&1&”

这可能不像你想象的那样。当您使用大多数版本的nohup在后台运行进程时,它仍然与父进程保持关系;在子进程退出之前,父进程无法收获,而子进程总是在退出之前生成另一个子进程

这不是使代码作为守护进程在后台运行的有效方法。正确的方法取决于你想要达到的目标。尝试每60秒更新一次流程是否有特定原因

(您从不显式关闭数据库连接-这不是一个问题,因为调用
exit
时PHP应该这样做)


您可能需要阅读,我在使用和MySQL连接时遇到了类似的情况。这里的原因可能是相同的

背景信息 创建一个子进程。对的调用关闭通信通道,子进程继续运行,直到退出。这是事情开始失控的时候

当子进程完成时,父进程将收到一条消息。这里的父进程是运行您发布的代码的PHP解释器。子进程是使用
popen()
启动的进程(不管运行什么命令)

这里有一件小事情您可能不知道,或者您在文档中找到了,并忽略了它,因为当您使用PHP编程时,它没有多大意义。以下文件中提到了这一点:

如果调用被信号中断,
sleep()
返回一个非零值

sleep()

PHP文档中未说明的内容在系统调用文档中有明确说明:

sleep()

回到你的代码。 PHP解释器在代码中有两个地方调用
usleep()
Linux系统函数。其中一个是清晰可见的:PHP代码调用它。另一个是隐藏的(见下文)

发生了什么(可见部分) 从第二次迭代开始,如果一个子进程(在上一次迭代中使用
popen()
创建)在父程序位于
usleep(100000)
调用中时恰好退出,PHP解释器进程将收到
sigchd
信号,并在超时之前恢复执行。
usleep()
返回的时间早于预期。由于超时时间较短,肉眼无法观察到这种效果。用10秒代替0.1秒,你会注意到的

但是,除了中断的超时之外,这不会以致命的方式影响代码的执行

为什么会崩溃(看不见的部分) 第二个输入信号影响程序执行的地方隐藏在PHP解释器代码的深处。出于某些协议原因,MySQL客户端库使用DatabaseConnector::$db = null;
pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD));
pcntl_wait($status, WNOHANG);