PHP MySQLi连接随机失败,返回“0”;无法分配请求的地址";

PHP MySQLi连接随机失败,返回“0”;无法分配请求的地址";,php,mysql,debian,Php,Mysql,Debian,大约两个星期以来,我一直在处理灯堆中最奇怪的问题之一。 长故事短随机连接到MySQL服务器失败,错误消息: Warning: mysqli::real_connect(): (HY000/2002): Cannot assign requested address in .. MySQL位于不同的“盒子”上,托管在Rackspace云上 今天我们将它的版本降级为 Ver 14.14 Distrib 5.1.42, for debian-linux-gnu (x86_64). 根据DB服务器

大约两个星期以来,我一直在处理灯堆中最奇怪的问题之一。 长故事短随机连接到MySQL服务器失败,错误消息:

Warning:  mysqli::real_connect(): (HY000/2002): Cannot assign requested address in ..
MySQL位于不同的“盒子”上,托管在Rackspace云上 今天我们将它的版本降级为

Ver 14.14 Distrib 5.1.42, for debian-linux-gnu (x86_64).
根据DB服务器的状态变量,它非常忙于处理每秒的查询平均值:5327.957

MySQL在日志中警告=9,但未记录连接被拒绝的情况。 site和gearman workers脚本都以1%的概率出现错误。 在我们监视时,没有服务器负载似乎不是一个因素。(CPU负载、IO负载或MySQL负载) 最大DB连接(max_连接)设置为200,但我们从未处理过超过100个到数据库的同时连接

无论是否使用防火墙软件,都会发生这种情况

我怀疑是TCP网络问题,而不是PHP/MySQL配置问题

有人能告诉我怎么找到它吗

更新:

连接代码为:

$this->_mysqli = mysqli_init(); 
$this->_mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 120); 
$this->_mysqli->real_connect($dbHost,$dbUserName, $dbPassword, $dbName); 

if (!is_null($this->_mysqli->connect_error)) {
    $ping = $this->_mysqli->ping(); 

    if(!$ping){
        $error = 'HOST: {'.$dbHost.'};MESSAGE: '. $this->_mysqli->connect_error ."\n"; 
        DataStoreException::raiseHostUnreachable($error);
    }
} 

频繁连接有什么危险?
除了一些极端情况外,它运行良好。如果每秒从同一个框中连接数百个,则可能会耗尽本地端口号。修复此问题的方法可能是:在linux上减少“/proc/sys/net/ipv4/tcp\u fin\u timeout”(这违反了tcp/IP标准,但您可能不关心本地网络),在客户端上增加“/proc/sys/net/ipv4/IP\u local\u port\u range”。其他操作系统也有类似的设置。您还可以为同一数据库主机使用更多的web框或多个IP来解决此问题。我真的在生产中看到了这一点

关于这个问题的一些背景:

TCP/IP连接由localip:localport-remoteip:remote-port标识。在这种情况下,我们有固定的MySQL IP和端口以及客户端IP,因此我们只能改变具有有限范围的本地端口。注意即使在关闭连接后,TCP/IP堆栈也必须将端口保留一段时间,这就是TCP\u fin\u超时的原因。

对于Vicidial,我经常遇到同样的问题,由于使用的编程类型,必须建立新的MYSQL连接(非常)我们的系统经常通过许多虚拟组件以每秒超过10000个连接的速度敲打数据库服务器,其中大多数连接在几毫秒内完成,并且在一秒钟或更短的时间内关闭。根据经验,我可以告诉您,在本地网络中,几乎没有丢失的包,tcp\u fin\u超时可以一直减少到3,而不会出现任何问题

用于诊断等待关闭的连接是否是您的问题的典型linux命令有:

netstat -anlp | grep :3306 | grep TIME_WAIT -wc
这将显示等待完全关闭的连接数

netstat -nat | awk {'print $5'} | cut -d ":" -f1 | sort | uniq -c | sort -n
这将显示每个已连接主机的连接,允许您在存在多个候选主机时识别正在折叠系统的其他主机

要测试修复,您可以

cat /proc/sys/net/ipv4/tcp_fin_timeout
echo "3" > /proc/sys/net/ipv4/tcp_fin_timeout
这将临时将tcp_fin_超时设置为3秒,并告诉您之前的时间,以便您可以恢复到旧值进行测试

作为永久性修复,我建议您将以下行添加到/etc/sysctl.conf

net.ipv4.tcp_fin_timeout=3
在一个良好的本地网络中,如果您遇到问题,例如由于数据包丢失,您可以尝试

net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_fin_timeout=10
它允许有更多的时间关闭连接,并尝试将相同的ip:端口组合重新用于到相同主机:服务组合的新连接

这将更积极地尝试重用连接,但会给其他应用程序(例如Web服务器)带来新问题。因此,你应该先尝试一下简单的解决方案,在大多数情况下,它已经可以解决你的问题,而且没有任何不良副作用


祝你好运

Vicidial服务器经常需要增加MySQL中的连接限制。许多安装(我们已经看到并处理过很多安装)都必须通过修改限制来实现这一点

此外,有报告称conntract_Max需要增加

/sbin/sysctl -w net.netfilter.nf_conntrack_max=196608
当问题被证明与网络有关时

还要注意,Vicidial有一些特定的建议设置,甚至还有一些mysql配置的企业设置。请查看/usr/src/astguiclient/conf中的my-bigvici.cnf,了解一些可能会打开mysql服务器的配置思想


到目前为止,增加连接限制并没有导致任何问题,只是使用了额外的资源。由于服务器的目的是使此应用程序工作,因此将资源专用于此应用程序似乎不是问题。LOL

我遇到了这个问题,并使用持久连接模式解决了这个问题,可以在mysqli中通过使用“p:”预先修复数据库主机名来激活持久连接模式

$link = mysqli_connect('p:localhost', 'fake_user', 'my_password', 'my_db');
发件人: :

持久连接背后的思想是 客户端进程可以重用客户端进程和数据库, 而不是被多次创建和破坏。这减少了 每次需要新连接时创建新连接的开销, 因为未使用的连接会被缓存并准备好重新使用。

打开一个持久的窗口 连接连接时,必须在主机名前加上p:


我们也有同样的问题。尽管“tcp_fin_timeout”和“ip_local_port_range”解决方案行之有效,但真正的问题是编写得很差的PHP脚本,它几乎每查询一次数据库,就创建一个新的连接。重写脚本连接一次就解决了所有问题。
请注意,降低“tcp\u fin\u timeout”值可能是危险的,因为某些代码可能依赖于连接后一段时间数据库连接仍然存在。这是一条脏兮兮的管道胶带和泡泡糖路径,而不是真正的解决方案。

我们可以看看您的连接代码吗?如果失败,请尝试连接到127.0.0
$link = mysqli_connect('p:localhost', 'fake_user', 'my_password', 'my_db');