PHP 多进程下使用 PDO 丢失连接的问题

PHP 多进程加 PDO 丢失连接

PHP 的 pcntl 扩展实现了 PHP cli 模式下的多进程,但如果父进程创建或使用的对象,如果被子进程拿到可能会造成一些误导和错误

PDO

在使用 PDO 对 Mysql 进行操作的时候,如果在父进程实例化的 pdo 对象,在子类中继续使用,那么可能会造成 PHP warning 的警告,导致无法使用 pdo 对象对 mysql 进行操作,下面的代码可以复现这个场景:

环境

  1. Mysql 5.7.27
  2. PHP 7.3.9
<?php
$fork = 3;
$pdo = new PDO('mysql:host=127.0.0.1:3306;dbname=test', 'root', '******');
$childList = [];
for ($i = 0; $i < $fork; $i++) {
    $pid = pcntl_fork();
    if ($pid < 0) {
        exit('fork error.');
    } elseif ($pid == 0) {
        // 子进程
        $childId = getmypid();
        echo '子进程: ' . $childId . "\n";
        $sql = "select * from `t` where id = 1";
        $sth = $pdo->prepare($sql);
        $sth->execute();
        $res = $sth->fetchAll();
        echo $childId . ' 子进程查询结果: ' . "\n";
        var_dump($res);

        echo '子进程: ' . $childId . "结束 \n";

        exit();

    } else {
        // 父进程
        array_push($childList, $pid);
    }
}

while (count($childList) > 0) {
    foreach ($childList as $key => $pid) {
        $res = pcntl_waitpid($pid, $status, WNOHANG);
        if ($res == -1 || $res > 0) {
            unset($childList[$key]);
        }
    }
    sleep(1);
}

异常结果:

PHP Warning:  PDOStatement::execute(): MySQL server has gone away

Mysql 官方描述

Some other common reasons for the MySQL server has gone away error are:
- You tried to run a query after closing the connection to the server. This indicates a logic error in the application that should be corrected.

这一条大概能对应到此处的场景中。大致意思是程序正在尝试使用已经被关闭的链接进行查询,也就是说,我们的第一个子进程在查询完成后,进程退出,这时候使用的 Mysql 链接也被释放,此时这个链接被标记为已关闭,当第二个子进程再次使用这个链接去尝试查询的时候,Mysql 就会给出错误提示

结论

  1. 不要在此种情况下复用父进程的连接资源
  2. 进程在退出的时候,可能是会把申请的连接资源标记为不可用的(和真正释放可能有差别,不释放的原因肯能是复用网络资源)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章