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. 進程在退出的時候,可能是會把申請的連接資源標記爲不可用的(和真正釋放可能有差別,不釋放的原因肯能是複用網絡資源)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章