【问题标题】:PHP activerecord mysql server has gone awayPHP activerecord mysql 服务器已经消失
【发布时间】:2015-04-14 18:42:53
【问题描述】:

我现在使用php-activerecord 有一段时间了,我非常喜欢它。 php-activerecord 是一个基于ActiveRecord pattern 的开源ORM 库。但是,我最近尝试将它与基于 Wrench 的 websocket 应用程序结合使用。

这非常有效,但要启动脚本,应用程序必须在 linux 上作为守护进程运行,以使 websocket 始终可用。一段时间不使用该应用程序然后尝试再次使用它会引发一些数据库异常:

一开始它会发出警告:

PHP Warning: Error while sending QUERY packet. PID=XXXXX in /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Connection.php on line 322

然后它抛出一个致命错误:

PHP Fatal error: Uncaught exception 'ActiveRecord\DatabaseException' with message 'exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2006 MySQL server has gone away' in /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Connection.php:322

堆栈跟踪:

#0 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Connection.php(322): PDOStatement->execute(Array)

#1 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Table.php(218): ActiveRecord\Connection->query('SELECT * FROM ...', Array)

#2 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Table.php(209): ActiveRecord\Table->find_by_sql('SELECT * FROM `...', Array, false, NULL)

#3 /home/user/domains/example.com/public_html/vendor/php-activerecord/php-activerecord/lib/Model.php(1567): ActiveRecord\Table->find(Array)

#4 in /home/user/domains/example.com/public_html/vendor/php-activerecord/lib/Connection.php on line 325

似乎 php-activerecord 在 websocket 服务器运行时一直保持 mysql 连接打开,如果它随后自动尝试重新连接并再次运行查询,这当然不成问题。但事实并非如此。

我读过一些关于设置MYSQL_OPT_RECONNECT 的内容。但我不确定这是否有效或如何使用 php-activerecord 设置该选项。有人在这方面有经验吗?

编辑:这是我的全局超时配置变量

VARIABLE_NAME                   VARIABLE_VALUE  
DELAYED_INSERT_TIMEOUT          300
WAIT_TIMEOUT                    28800
CONNECT_TIMEOUT                 10
LOCK_WAIT_TIMEOUT               31536000
INNODB_ROLLBACK_ON_TIMEOUT      OFF
THREAD_POOL_IDLE_TIMEOUT        60
NET_WRITE_TIMEOUT               60
INNODB_LOCK_WAIT_TIMEOUT        50
INTERACTIVE_TIMEOUT             28800
DEADLOCK_TIMEOUT_LONG           50000000
SLAVE_NET_TIMEOUT               3600
DEADLOCK_TIMEOUT_SHORT          10000
NET_READ_TIMEOUT                30

【问题讨论】:

  • 您是否完全控制了数据库配置?你能列出你在配置中设置的所有超时吗?如果您的配置为空,请从 mysql 中选择您的全局变量并发布所有包含“超时”的行。
  • @Dimitri 是的,我有完全的控制权,我刚刚编辑了我的问题。
  • 你检查过how to enable database auto-reconnect in PHP?。根据它,不可能在 PDO 中设置MYSQL_OPT_RECONNECT(并且 php-activerecord 使用 PDO)。也许解决方法是每小时执行一次简单查询?
  • 您是否要让连接持续超过 8 小时?
  • IMO,MYSQL_OPT_RECONNECT 不是一个好的解决方案。在下面阅读我的答案。以实际实现为准。

标签: php mysql activerecord phpactiverecord wrench


【解决方案1】:

PHP ActiveRecord 使用 PDO。绝对没有办法关闭 PDO 连接,对于长时间运行的后台任务来说,这是错误的 DB 层。

您可以尝试影响使用以下 sn-p 断开 PDO 连接。

//if not using ZF2 libraries, disconnect in some other way
$db->getDriver()->getConnection()->disconnect()
$db = NULL;
gc_collect_cycles();

断开连接,将引用设置为 null,然后运行垃圾收集器。希望这将调用 PDO 的内部 __destruct 方法来实际关闭连接。

您必须在您自己的长时间运行的脚本中管理您的数据库连接。如果您的工作人员有一段时间不需要处理工作,您必须断开连接,并且您必须在有工作时重新连接。

真正的解决办法是不使用PDO,正常断开重连。

如果您只是将服务器和客户端库的超时设置为无限,您将遇到永远不会死机的失控脚本问题,迫使您重新启动整个服务器(搞砸超时不是一个好主意)。

编辑:我实际上遇到了这个确切的问题,并且去年在工作中使用了这个确切的解决方案。这解决了我 99% 的问题。但是,每隔一段时间就会出现一个我无法捕获并尝试重新连接的杂散连接异常。我只是每天重新启动一次进程,以摆脱那些杂散的连接错误。这就是为什么我的回答是,不要使用 PDO。立即切换并真正控制断开连接和重新连接。

【讨论】:

    【解决方案2】:

    MySQL server has gone away 错误最常见的原因是服务器超时并关闭了连接。

    尝试进行以下更改。

    max_allowed_packet=64M
    

    如果您有很多请求,请设置此选项,不要将其设置为更大,因为它与您的环境有关。

    max_connections=1000
    

    将此行添加到my.cnf 文件中可能会解决您的问题。完成更改后重新启动 MySQL 服务。

    阅读更多MySQL server has gone away

    如果它不起作用,请尝试this 自动重新连接功能。

    【讨论】:

    • 自动重新连接可能会因为丢失状态信息而导致麻烦。特别是,如果您处于事务中,则断开连接将回滚。重新连接后继续可能会导致数据丢失/修改。
    【解决方案3】:

    如前所述,PHP 脚本中的 MySQL 在一段时间内两者之间没有通信时会超时。 这是一件好事,因为空闲连接会占用您的服务器资源。

    “服务器已消失”错误主要发生在两个查询之间发生相对冗长的计算时。

    为了防止这种情况,你可以

    • 在执行期间定期执行SELECT 1 查询
    • 围绕您的查询创建一个包装器,在执行前检查连接是否有效
    • 使用来自this post的答案

    但是,我认为重新配置 MySQL 以使连接保持打开更长时间会鼓励粗心的编程,并且建议不要这样做。

    【讨论】:

      【解决方案4】:

      也可能是查询的大小,因为有时 ORM 会组合查询以提高性能。

      尝试设置 max_allowed_pa​​cket=128M,至少应该对诊断有用。

      【讨论】:

        【解决方案5】:

        如果您的数据库未处理多个并发连接和查询,您可以设置“无限”超时。这不会显着影响数据库资源。最好的方法是发送 ping 数据包(选择 1)来更新超时并保持连接。

        【讨论】:

          【解决方案6】:

          为了解决这个问题,我建议你:

          1. 使用 Gearman 作业服务器 (http://gearman.org/) 分发您的流程
          2. 使用 Supervisor (http://supervisord.org/) 轻松管理这些流程

          方法如下。

          将您的 Web 套接字应用程序作为守护程序运行,就像您现在所做的一样(可能使用 cron)。或者更好的是,使用 Supervisor 管理它。配置它,让 Supervisor 在 Supervisor 启动时启动它,如果守护进程死亡则自动重启。

          示例配置:

          [program:my-daemon]
          command=/usr/bin/php /path/to/your/daemon/script
          autostart=true
          autorestart=true
          

          接下来,不要在应用程序守护进程中运行查询处理,而是创建一个 Gearman Worker 来处理它。注册后,Worker 将等待运行/调用。您必须从您的 websocket 应用程序中调用 Worker,并在必要时连同必要的工作负载参数一起调用(有关此工作负载术语解释,请参阅 Gearman 网站)。

          在 Worker 中,将其设置为在它已经完成守护进程请求的作业时停止/退出。有了这个,你就不会因为连接立即关闭而出现“mysql server has gone away 问题”。

          最后,我们必须像守护进程一样让 Worker 始终可用。因此,与守护进程类似,将 Supervisor 配置为在 Worker 死亡/停止时自动启动和自动重启,如下所示:

          [program:my-worker]
          command=/usr/bin/php /path/to/your/worker/script
          autostart=true
          autorestart=true
          

          另一个有趣的事情是,您可以添加任意数量的 Worker 来等待。只需添加以下配置:

          numprocs=9 #change it to any number
          process_name=%(program_name)s_%(process_num)02d #to identity worker number
          

          由于我们告诉 Supervisor 自动重启每个进程,所以我们总是有恒定的 Worker 在后台运行。

          这里是关于这个策略的另一种解释:http://www.masnun.com/2011/11/02/gearman-php-and-supervisor-processing-background-jobs-with-sanity.html

          希望有帮助!

          【讨论】:

          • @ArunPoudel 为什么会这样?我在生产环境中实现了这些。 mysql服务器消失是因为连接打开时间过长,PHP不适合长期运行。
          • 反对者,请仔细阅读策略。阅读我发布的链接! “mysql server has gone away”问题看起来很容易解决,其实不然。
          • 是的,我做到了,这与帖子没有任何关系。 OP 遇到的问题与您要解决的问题完全不同。
          • @ArunPoudel 为什么不相关?解决了“mysql server has gone away”的问题。
          • 是的,使用疯狂的方法。这不仅仅是解决问题。但是以惯用的方式来做。还有其他处理此类问题的方法,重新连接标志就是其中之一。
          猜你喜欢
          • 2011-11-09
          • 2011-03-19
          • 2011-06-07
          • 2010-12-20
          • 2015-01-15
          • 2016-03-06
          • 2017-04-02
          • 2014-02-12
          相关资源
          最近更新 更多