php连接不上MySQL问题排查

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

现象
在PHP error log里发现:
PHP Warning: mysqli::mysqli(): (HY000/2003): Can’t connect to MySQL server on ‘XXX.XXX.XXX.XXX’ (99) in /u1/www/XXXX.php on line 10
PHP Warning: mysqli::close(): Couldn’t fetch mysqli in /u1/www/XXXX.php on line 11
推断:只有在高并发的环境下出现

诊断分析:
通过MySQL数据库上抓包,没发现异常。又把目标转到php 服务器上。
BTW:
linux开着selinux连接MySQL在测试中基本上属于1ms+,禁掉selinux后在0.96左右。selinux还是要禁掉的。
既然又怀疑是PHP的问题就写一个程序测试(禁掉selinux后):
cat tconn.php

function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}

$time_start = microtime_float();
for ( $i=0; $i<30000; $i++){  
$dbh=new mysqli("XXX.XXX.XXX.XXX", "wubx", "wubxwubx", "userdb", 3308);
$dbh->close();
}
$time_end= microtime_float();
$time_use= ($time_end - $time_start)/30000;
print "$time_use\n";

#php tconn.php
0.00090954260031382
再次运行就开始大量的报错。

PHP Warning: mysqli::mysqli(): (HY000/2003): Can't connect to MySQL server on 'XXX.XXX.XXX.XXX' (99) in /u1/www/XXXX.php on line 10
PHP Warning: mysqli::close(): Couldn't fetch mysqli in /u1/www/XXXX.php on line 11

中止该程序后,通过
#strace php tconn.php 运行
得到:

connect(3, {sa_family=AF_INET, sin_port=htons(3308), sin_addr=inet_addr("XXX.XXX.XXX.XXX")}, 16) = -1 EADDRNOTAVAIL (Cannot assign requested address)
shutdown(3, 2 /* send and receive */) = -1 ENOTCONN (Transport endpoint is not connected)

看到这个大概明白是本地的网络可能注册不上了,也难怪在MySQL抓包看也正常。
参考:http://www.unixguide.net/network/socketfaq/4.5.shtml

看样子是本地tcp不能重用造成的。改一下在测试
sysctl -w net.ipv4.tcp_tw_reuse=1;
在次测试问题不存在了。在这个上面碰了一下后顺便改一下/etc/sysctl.conf添加:

net.ipv4.tcp_max_syn_backlog = 819200
net.core.netdev_max_backlog = 400000
net.core.somaxconn = 4096
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=0

#sysctl -p

总结:
php连接MySQL的原因有很多,这个只是一个高并发环境会出现的问题也比较难查。其它连不上只要好重现都比较好查,一般通过抓包都能分析出来。 这个同样适用于做为App的Server大量和中间层交互的也需要注意。