【问题标题】:"MySQL gone away" in PHP daemon, using pcntl_fork使用 pcntl_fork 在 PHP 守护程序中“MySQL 消失”
【发布时间】:2014-09-09 20:28:18
【问题描述】:

我正在尝试使用 PHP 守护程序检索数据库值,并为检索到的每个 id 分配一个实例(使用 pcntlfork)。

每个 fork 都应该做一些工作,然后更改数据库值,因此不会再次检索它。

但是,例如,当我 fork 一个孩子并让它休眠 10 秒(实际处理时间)时,MySQL 连接似乎超时。我该如何防止这种情况发生? try/catch 似乎无法阻止错误。

#!/usr/bin/php
<?php
ini_set('memory_limit','256M');
gc_enable();

function sig_handler($signo) {
  global $child;
  switch ($signo) {
   case SIGCHLD:
     echo "SIGCHLD received\n";
     $child--;
  }
}

// install signal handler for dead kids
pcntl_signal(SIGCHLD, "sig_handler");

global $PIDS; $PIDS = array();
global $maxforks; $maxforks = 5;
global $child; $child = 1;

global $boot; $boot = true;
date_default_timezone_set('Europe/Brussels');

// figure command line arguments
if($argc > 0){
    foreach($argv as $arg){
        $args = explode('=',$arg);
        switch($args[0]){
            case '--log':
                $log = $args[1];
                break;
            case '--msgtype':
                $msgtype = $args[1];
                break;
        } //end switch
    } //end foreach
} //end if

// Daemonizen
$daemon_start = date('j/n/y H:i', time());
$pid = pcntl_fork();
if($pid == -1){
    return 1; // error
} else if($pid) {
    return 0;
} else {    
    while(true){

    try {
        $host = 'localhost';
    $dbname = 'bla';
    $dbuser = 'bla';
    $dbpass = 'bla';
        $db = new PDO('mysql:host='.$host.';dbname='.$dbname.';charset=utf8', $dbuser, $dbpass, array(PDO::ATTR_TIMEOUT => 2));
        //$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
    } catch (PDOException $e){
        echo $e->getMessage();
    }

    $read_messages = $db->query("SELECT * blablabla");
    while($read_message_row = $read_messages->fetch(PDO::FETCH_ASSOC)){
        $id = $read_message_row['id'];

        $pid1 = pcntl_fork();
        if ($pid1 == -1){
                die('could not fork');
        } else { #START ELSE COULD FORK
            $PIDS[$pid1] = $pid1; //KEEP TRACK OF SPAWNED PIDS
            if ($pid1){
                // parent
                if ($child++ >= $maxforks){
                        pcntl_wait($status);
                        $child++;
                }

                echo "Forking child with PID $pid1 voor $id.\n";

                //PARENT THREAD : $ch is a copy that we don't need in this thread
                // child forken
            } else {
                include_once "test_worker.php";
            } // einde child thread
        } //if-else-forked


    }
}
}
?>

【问题讨论】:

  • 根据我的经验,fork() 不能很好地连接数据库。我会尝试读取所有行,关闭 PDO 对象,然后进行分叉,然后重新打开连接并在它们进入时处理结果。

标签: php mysql pdo daemon pcntl


【解决方案1】:

解决方案很简单。分叉后连接(或重新连接)。

分叉进程是其父进程的精确镜像,并共享资源句柄。当您的分叉进程之一关闭数据库连接时,树中的所有其他进程都会关闭它 - 即使在查询中间也是如此。然后您会收到诸如“MySQL 服务器已消失”或“在查询期间丢失与 MySQL 服务器的连接”之类的错误。

【讨论】:

    【解决方案2】:

    当您打开数据库句柄时不要使用pcntl_fork()。数据库句柄最终被两个子进程共享,使连接处于不一致状态。

    事实上,如果您能提供帮助,请完全避免使用pcntl_fork()。使用它的代码往往非常脆弱,并且在命令行 SAPI 之外无法正常工作。

    【讨论】:

      猜你喜欢
      • 2012-07-01
      • 2011-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 2012-07-28
      相关资源
      最近更新 更多