繁体   English   中英

PHP activerecord mysql服务器已经消失了

[英]PHP activerecord mysql server has gone away

我现在正在使用php-activerecord一段时间,我非常喜欢它。 Php-activerecord是一个基于ActiveRecord模式的开源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一直保持mysql连接在websocket服务器运行时保持打开状态,如果它自动尝试重新连接并再次运行查询,那么这个问题应该不是问题。 但它没有。

我已经阅读了有关设置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

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

您可以尝试使用以下代码段影响 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。 立即切换,实现对断开连接和重新连接的真正控制。

MySQL服务器消失的最常见原因是服务器超时并关闭了连接。

尝试进行以下更改。

max_allowed_packet=64M

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

max_connections=1000

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

阅读更多关于MySQL服务器的消息已经消失

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

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

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

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

  • 在执行期间定期执行SELECT 1查询
  • 在查询周围创建一个包装器,在执行之前检查连接是否有效
  • 使用这篇文章的答案

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

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

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

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

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

  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来处理它。 一旦注册,工人将等待运行/被叫。 如有必要,您必须从websocket应用程序中调用Worker以及必要的工作负载参数(有关此工作负载术语解释,请参阅Gearman网站)。

在Worker中,将其设置为在已完成守护程序请求的作业时停止/退出。 有了这个,你将不会有“mysql服务器已经消失的问题”因为连接立即关闭。

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

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

另一个有趣的事情是你可以添加尽可能多的工人,让你活着等待。 只需添加以下配置:

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

由于我们告诉主管自动重启每个进程,我们总是在后台运行常量Worker。

以下是有关此策略的另一种解释: http//www.masnun.com/2011/11/02/gearman-php-and-supervisor-processing-background-jobs-with-sanity.html

希望有所帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM