MySQL"走了"持久PHP连接出错

时间:2014-10-29 00:02:59

标签: php mysql pdo

我在WAMP堆栈上本地托管网站。我最近通过将array(PDO::ATTR_PERSISTENT => true)添加到PDO构造函数选项参数来将PHP连接切换为持久性。我注意到响应时间因此下降了(万岁!)。

当机器醒来时,缺点似乎是一个消失的错误。在更改连接样式之前从未发生这种情况。

缓存连接是否可能已关闭,但仍会继续返回?是否可以通过catch块内的PDO重置PHP连接或重置连接池?

3 个答案:

答案 0 :(得分:3)

我已经将这个问题踢了几天,并且基于网络上类似问题的普遍存在,这似乎是PDO的一个缺陷,阻碍了对持久连接的有效管理。

回答明显的问题:

  • PHP 5.4.22
  • php.ini中的驱动程序设置已打开持久连接
  • 会话限制不受限制(设置为-1)
  • 池限制不受限制(设置为-1)

我可以通过执行以下操作重新创建问题:

在MySQL数据库上发出以下语句。

set @@GLOBAL.interactive_timeout := 10;
set @@GLOBAL.wait_timeout := 10;

针对服务器发出一些请求以生成一些缓存连接。与使用非持久连接执行此操作相比,您可以看到线程数增加:

echo $conn->getAttribute(PDO::ATTR_SERVER_INFO);

等待至少10秒钟并开始发出更多请求。你应该开始接受'离开'消息。

问题是SQL关闭连接并且后续调用PDO构造函数返回这些已关闭的连接,而不重新连接它们

这是PDO缺乏的地方。没有办法强制连接打开,甚至没有办法检测状态。

我目前正在解决这个问题(不可否认的是有点黑客攻击)是发布这些MySQL语句

set @@GLOBAL.interactive_timeout := 86400;

set @@GLOBAL.wait_timeout := 86400;

These variables are set to 28800sec (8 hours) by default。请注意,您将要重新启动Apache以清除缓存的连接,或者在池中的所有连接都已循环之前您不会注意到差异(我不知道如何/何时发生这种情况)。我选择86400这是24小时,我每天都在这台机器上,所以这应该满足基本需求。

在这次更新之后,我让我的机器至少停留了12个小时,这是我以前在我开始消失的时间里走了多长时间的消息'。看起来问题已经解决了。

我一直在想,虽然我无法强行打开连接,但可能会从池中删除错误的连接。我没有试过这个,但稍微更优雅的解决方案可能是检测到“消失了”#39;然后将对象设置为NULL,告诉PHP销毁资源。如果数据库逻辑做了这样的一些尝试(如果发生更严重的错误,则必须有限制),这可能有助于将这些错误保持在最低限度。

答案 1 :(得分:1)

对于什么值,我正在研究在nginx之后的php-fpm 7.3上使用持久连接,并尝试使用1个孩子的静态池重现该行为,到目前为止,我还不能。

我可以在单独的终端上通过SHOW PROCESSLIST看到数据库如何在执行SELECT的请求5秒钟后关闭持久连接,但是下一个只是打开一个新的并且同样有效。另一方面,如果我用负载测试工具轰炸API,则将维持相同的连接,并且所有请求都将成功。

也许是因为您使用的是Apache + mod_php而不是php-fpm工作池,或者也许是在5.4和7.3之间进行了真正的修复

测试版本:

PHP-FPM: 7.3.13
mysqlnd (underlying PDO_MYSQL driver): 5.0.12-dev - 20150407
MySQL Server: 5.7.29 and 8.0.19
MariaDB Server (MySQL drop-in replacement): 10.1.43

PD感谢您安排复制步骤和您的思考过程,这非常宝贵。

答案 2 :(得分:0)

是的,如果连接关闭,您将需要重新连接。

http://brady.lucidgene.com/2013/04/handling-pdo-lost-mysql-connection-error/