现在的位置: 首页 > 综合 > 正文

php连接mysql错误Lost connection to MySQL server during query

2016年05月06日 ⁄ 综合 ⁄ 共 1211字 ⁄ 字号 评论关闭

昨天晚上,有个业务出现异常,现象是:

1、nginx无法连接上游的php-fpm(nginx和php-fpm之间是本地的unix domain socket);

2、php-fpm进程跑满了,strace进程发现所有的子进程都阻塞在read系统调用上,lsof发现read的fd是一个和mysql的连接;

3、通过日志发现执行sql语句出错,错误码是2013,错误信息是Lost connection to MySQL server during query,并且每个请求的处理时间都在7875秒左右。

因此这里有3个疑问:

1、为什么php-fpm不能建立新的连接了?

2、php.ini里设置了max_execution_time是30秒,为什么每个请求的处理时间超过了7875秒?max_execution_time没有生效?

3、每个请求的处理时间为什么是7875秒,这个时间太长了,都干嘛了?

结论:

1、第一问题很好解释,因为php-fpm配置了进程上限,然后每个子进程都阻塞在了read系统调用上,所有无法接受新的连接请求了;

2、查了下资料发现php的max_execution_time不包括mysql请求处理的时间,这里感觉php太坑了:

http://php.net/manual/en/function.set-time-limit.php

3、为什么每个请求处理的时间是7875秒左右呢?这是由于网络原因导致的,php给mysql发送一个查询请求,然后php阻塞在read系统调用上,这时候如果php和mysql之间的网络断了、网络拥塞导致丢包或mysql server所在服务器内核panic了,那么php和mysql之间的网络连接就断开了,但是由于php阻塞在了read系统调用上,php对网络连接的异常是没有感知的,所以php会一直阻塞。直到tcp keepalive机制探测后才会发现网络的异常,read才会返回。tcp
keepalive相关的有三个配置:

配置项 默认值 含义
tcp_keepalive_time 7200 tcp开始进行keealive探测的秒数
tcp_keepalive_probes 9 探测失败时的重试次数
tcp_keepalive_intvl 75 每次重试的间隔

这3个配置的详细信息也可以通过man 7 tcp查看。

7200 + 75 * 9 = 7875

所以,php阻塞在read系统调用后,要7875秒左右之后才能根据tcp的keepalive机制探测到连接的丢失,read系统调用才会返回,所以请求的处理时间会是7875秒左右。

规避措施:

1、业务和mysql server最好不要跨机房部署;

2、由于max_execution_time并不包含mysql query的时间,因此在做数据库查询等相关的操作时,一定要设置连接、读写的超时时间;

3、跨机房拷贝文件的时候一定要限速,防止网络拥塞进而影响业务。

以上,感谢您的阅读,欢迎评论。


抱歉!评论已关闭.