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

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

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_time7200tcp开始进行keealive探测的秒数
tcp_keepalive_probes9探测失败时的重试次数
tcp_keepalive_intvl75每次重试的间隔
这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、跨机房拷贝文件的时候一定要限速,防止网络拥塞进而影响业务。


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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值