解决MySQL server has gone away错误的方案
阳光下的幸福 人气:0PHP中MySQL server has gone away问题
一.背景
之前在Codeigniter里面写过类似console命令行的脚本. 脚本里存在sleep语句时间比较久, 导致出现一个现象就是sleep之前的SQL都是操作成功的,但是sleep之后,再执行SQL操作竟然报错: MySQL server has gone away. 也就是mysql的这个连接失效. 后来分析才知道, MySQL中存在2个重要的配置参数:
interactive_timeout
wait_timeout
这2个参数的单位都是秒(s). 默认是8小时(28800). interactive_timeout从单词上看指的是交互超时时间. mysql的连接方式一般分为2种, 一种称之为"交互式", 一种称为"非交互式". 一般常见的使用mysql -u root xxx之类的或者主从复制的连接为"交互式连接", 使用如Java的JDBC、PHP的PDO驱动连接的方式一般是"非交互式连接". 然而interactive_timeout如果未修改的情况下,这个值是一直不会变的,但是wait_timeout在不同连接方式下,值是不一样的.
wait_timeout在"交互式连接"下, 其值是interactive_timeout的值. 如果在"非交互式连接"情况下, 则wait_timeout的值是原来mysql.cnf中配置的原始值.
最终起作用的只是wait_timeout的值.这配置项限定了处于sleep状态(通过 show processlist查看当前连接数情况)的连接,如果这个连接sleep休眠时间超过wait_timeout的值,则这个连接被断掉或者说被清理掉.
二.wait_timeout分析
1.首先查看mysql.conf配置
首先我们配置了interactive_timeout=10 wait_timeout=5, 此时通过mysql客户端(交互式连接)查看这2个配置项的值: show variables like ‘%timeout%';
2.交互式连接
客户端的结果: wait_timeout竟然不是我们msyql.conf配置的10s, 而是 5s.
那我们再来看看PHP连接MySQL(非交互式连接),执行相同的语句,得到什么结构:
3.非交互式连接
此时wait_timeout是我们原来在mysql.cnf配置的值了.
综上所述: wait_timeout这个值,在不同的"连接模式"下面,拿到的值是不一样的.
三.gone away原因分析
结合上面的情况,我们就知道了。 一开始某些SQL执行成功,但是后面的SQL执行失败报错gone away,大部分原因就是这个连接被闲置超过了wait_timeout,mysql服务器单方面断掉了这个连接。但是客户端代码,还是在用这个连接变量,以为连接还是ok的(其实mysql server端已经断开了,只是我们以为这个连接还有效),去执行SQL必然报错.
那么我们怎么解决这个情况呢?
1.可以适当调整wait_timeout的值, 调大一点,这样不容易触发这个gone away情况.但是弊端就是,sleep的长连接不被清理,资源白白浪费了.
2.通过try-cach如果抛出gone way msyql的连接问题, 先把之前的db调用close().在重新获取db连接open,然后再执行之前的代码. 不过代码看起来感觉很蛋疼.伪代码:
$db = db(); try { fun1$db); // 一开始执行成功 sleep(3600*10) // 假设sleep了10个小时 fun2($db); // 10小时之后 由于连接已经被mysql干掉 导致报错 gone away }catch(Exception $e) { // 报错后 我们把无效的连接close 在 open新的连接 $db->close(); $db->open(); // 再拿到新的连接执行 // fun2($db) }
3.如果是使用类似swoole或者easyswoole框架, 建议使用mysql pool连接池的形式.并且一般连接池都有关于心跳检查ping、连接存活检测间隔时间设置、最大闲置连接数等等设置, 只要配置一次就好了。 例如可以配置测活连接间隔时间短一点,来保证连接不会被msyql服务器干掉.例如 easyswoole配置:
例如之前我设置wait_timeout=10, 但是如果我没修改这个easyswoole的mysql连接池测活间隔时间变小, 同样会出现gone way的情况. 第一次访问接口成功返回SQL执行结果,但是超过10s以后我再次访问接口,报错mysql has gone away。修改setIntervalCheckTime()之后,就不会出现这个问题了. 我们通过mysql的show processlist;查看连接数情况:
这些都是easyswoole帮我们维护的连接数. 当sleep超过3秒时, 由于检查时间是3秒存活, 连接池帮我们保活检查, sleep的时间又从0开始计算.
下面是其他网友的补充
进入MySQL
cmd
mysql -u用户名 -p密码
在我们使用mysql导入大文件sql时可能会报MySQL server has gone away错误,该问题是max_allowed_packet配置的默认值设置太小,只需要相应调大该项的值之后再次导入便能成功。该项的作用是限制mysql服务端接收到的包的大小,因此如果导入的文件过大则可能会超过该项设置的值从而导致导入不成功!下面我们来看一下如何查看以及设置该项的值。
查看 max_allowed_packet 的值
show global variables like 'max_allowed_packet';
+--------------------+---------+
| Variable_name | Value |
+--------------------+---------+
| max_allowed_packet | 4194304 |
+--------------------+---------+
可以看到默认情况下该项的大小只有4M,接下来将该值设置成150M(1024*1024*150)
set global max_allowed_packet=157286400;
此时再查看大小
show global variables like 'max_allowed_packet';
通过调大该值,一般来说再次导入数据量大的sql应该就能成功了,如果任然报错,则继续再调大一些就行,请注意通过在命令行中进行设置只对当前有效,重启mysql服务之后则恢复默认值,但可以通过修改配置文件(可以在配置文件my.cnf中添加max_allowed_packet=150M即可)来达到永久有效的目的,可其实我们并不是经常有这种大量数据的导入操作,所以个人觉得通过命令行使得当前配置生效即可,没有必要修改配置文件。
以上就是本次介绍的全部相关知识点内容,希望整理的内容能够帮助到你。
加载全部内容