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

标签 php mysql linux ubuntu pdo

我在 Ubuntu 14.04 服务器上有以下 PHP 5.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 代码失败(脚本退出时没有任何错误或输出)。

这里发生了什么?


注释

  • 服务器 24/7 全天候运行。
  • 内存不是问题。
  • 数据库连接正确。
  • 文件路径不包含空格。
  • 在使用 shell_execexec 而不是 popen(和 pclose)时存在同样的问题。<

我也知道 popen 是失败的行,因为我通过在脚本中的某些点记录到文件来进一步调试(上面未显示)。

最佳答案

fork后父进程肯定退出了吗?我原以为 pclose 会等 child 退出再返回。

如果它没有退出,我推测因为 mySQL 连接永远不会关闭,所以当您生成子进程树时,您最终会达到它的连接限制(或其他一些限制)。

编辑 1

我刚刚尝试复制这个。我将您的脚本更改为每半秒而不是每分钟 fork 一次,并且能够在大约 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
...

那是因为子进程在 fork 时继承了父进程的 FD(在本例中为 mySQL 连接)。

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

DatabaseConnector::$db = null;

这个问题有望消失。

关于php - MySQL 代码导致 PHP 脚本在 popen/exec 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36998023/

相关文章:

php - 为什么 PHP 字符串连接运算符是点 (.)?

php - 使用PDO搜索数据库

php - 如何过滤字符串中的 Just Number,然后如果数字以零开头,如何添加另一个数字

MySQL 关系和约束,我应该使用它们吗?

php - MySQL JOIN 具有 COUNT 性能

java - 无法添加或更新表

php - Laravel 护照 : Create access token manually

linux - 从一个进程创建多个共享内存

linux - 无法将 docker 镜像推/拉到经过证书身份验证的私有(private)注册表? (仅适用于 WSL,远程错误 : tls: alert(116))

linux - .net 核心一个代码,用于 Windows/Linux 的服务/守护程序