【问题标题】:pcntl_fork and the MySQL connection is gonepcntl_fork 和 MySQL 连接消失了
【发布时间】:2011-04-09 18:39:04
【问题描述】:

我有一个 foreach 循环,它在其中分叉。在进程分叉后,它访问数据库。我收到一个错误:

SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

问题是,我在分叉后 连接到数据库。

我的问题:为什么会这样?

如果发生这种情况,我实际上是在 分叉之前访问数据库吗?孩子会继承数据库连接吗?

(注意:我可以发布代码,但它相当大,因为它都在类中,这可能是导致我在访问数据库时感到困惑的原因。您应该知道的另一件事是我正在使用 ZF。 )

【问题讨论】:

  • 我没有玩过 Zend Framework,但我想知道它是否保留了某种内部数据库连接池。或者它正在做持久连接?除此之外,孩子不应该继承数据库连接或其他任何东西,因为它们是不同的 php 进程。
  • 确认,我的立场是正确的。我的上述答案是基于直觉,而不是基于个人经验,因为这还不是必需的。阅读更多内容,我看到分叉的孩子确实继承了他们父母的数据库连接,这是一个已知问题:php.net/manual/en/function.pcntl-fork.php#70721
  • @Fanis - 你能把你最后的评论变成一个答案,这样我就可以点击绿色的大检查了吗?感谢您挖掘此信息。我不会分叉,而是执行一个拥有自己的数据库连接的新进程。然后它将分叉,以免占用调用进程,然后在子进程中完成它的工作,将它的 pid 记录到另一个 cron-started-process 将出现并检查它是否已完成的日志中。嗯……这次可能就行了!谢谢!
  • 谢谢,祝你好运!再三考虑,看看gearman.org,当分叉变得如此复杂时,这是一个可行的选择。
  • 齿轮人看起来很有趣。我可以在大型装置上试一试。现在我希望代码尽可能便携。所以我不想引入太多的依赖。谢谢!

标签: php mysql zend-framework fork


【解决方案1】:

(评论 --> 根据发帖者的要求回答)

阅读更多内容后,我看到分叉的孩子确实继承了他们父母的数据库连接,这是一个已知问题:http://php.net/manual/en/function.pcntl-fork.php#70721

【讨论】:

  • 我只是想澄清一下:即使孩子继承了数据库连接,我也得到错误的原因是我正在分叉一堆都需要数据库连接的新进程。跨度>
  • 我想补充一点,这会影响所有资源,而不仅仅是 MySQL 连接。例如,如果一个孩子退出,所有在分叉之前打开的套接字都会死掉。所以总是在分叉后创建资源。此答案中的评论链接非常有价值。
【解决方案2】:

除非它不是一个问题。这是 pcntl_fork 的设计方式。任何维护它自己的文件描述符的扩展(如文档中明确指出的那样)都将具有损坏的描述符,因为父级的所有子级共享相同的文件描述符。

【讨论】:

    【解决方案3】:

    这对我有帮助:http://www.electrictoolbox.com/mysql-connection-php-fork/

    尤其是mysql_connect($server, $username, $password, true);

    【讨论】:

      【解决方案4】:

      如果您使用 SIGKILL 终止分叉进程,则可以避免在分叉进程退出时关闭连接。

      <?php
      $dbh = new PDO('pgsql:host=localhost', $username, $password);
      $pid = pcntl_fork();
      if($pid == 0){
              register_shutdown_function(function(){
                      posix_kill(getmypid(), SIGKILL);
              });
              exit;
      }
      sleep(1);
      $statement = $dbh->query('select 1');
      var_dump($statement);
      

      这种行为的原因是,当 PHP 进程退出时,PHP 会向数据库服务器发送“终止连接”命令。但是只有当所有到套接字的链接都关闭时,系统才会关闭套接字。使用 SIGKILL 可以帮助我们避免向数据库服务器发送“终止连接”命令。

      【讨论】:

        【解决方案5】:

        您需要关闭父进程上的 MySQL 连接,然后为每个子进程建立一个新连接。

        <?php
        $dbh = new PDO('pgsql:host=localhost', $username, $password);
        $pid = pcntl_fork();
        if(!$pid){
                // make new connection
                $newConnection = new PDO('pgsql:host=localhost', $username, $password);
                // do something in the child process.
                exit;
        }else{ 
                // parent node
                $dbh = null; // close PDO connection
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-16
          • 2013-08-28
          • 2018-12-31
          • 1970-01-01
          • 1970-01-01
          • 2012-03-27
          • 2023-03-24
          相关资源
          最近更新 更多