繁体   English   中英

PHP-MySQLi连接随机失败,并显示“无法分配请求的地址”

[英]PHP-MySQLi connection randomly fails with “Cannot assign requested address”

从大约2周开始,我正在处理LAMP堆栈中最奇怪的问题之一。 与MySQL服务器的长连接短连接失败,并显示错误消息:

Warning:  mysqli::real_connect(): (HY000/2002): Cannot assign requested address in ..

MySQL是在不同的“盒子”上,托管在Rackspace Cloud今天我们将它的版本降级为

Ver 14.14 Distrib 5.1.42, for debian-linux-gnu (x86_64).

根据它的状态变量,数据库服务器非常忙于处理每秒查询平均值:5327.957。

MySQL处于log-warnings = 9但没有记录连接拒绝的争用。 站点和齿轮工作者脚本都会因为错误而失败,假设概率为1%。 没有服务器负载似乎不是我们监控的因素。 (CPU负载,IO负载或MySQL负载)最大数据库连接数(max_connections)设置为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);
    }
} 

MySQL:使用巨大数量的连接

频繁连接有什么危险?
它运作良好,除了一些极端情况。 如果从同一个盒子中每秒获得数百个连接,则可能会耗尽本地端口号。 修复它的方法可能是 - 在linux上减少“/ proc / sys / net / ipv4 / tcp_fin_timeout”(这会打破TCP / IP标准,但你可能不关心你的本地网络),增加“/ proc / sys / net / ipv4 / ip_local_port_range“在客户端上 其他OS有类似的设置。 您也可以为同一个数据库主机使用更多Web框或多个IP来解决此问题。 我在制作中真的看到了这一点。

关于这个问题的一些背景:
TCP / IP连接由localip:localport remoteip:remote port标识。 在这种情况下,我们有MySQL IP和端口以及客户端IP固定,所以我们只能改变有限范围的本地端口。 注意, 即使在关闭连接之后,TCP / IP堆栈必须保留端口保留一段时间 ,这是tcp_fin_timeout来自的地方。

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

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

来自: http//php.net/manual/en/mysqli.persistconns.php

持久连接背后的想法是客户端进程和数据库之间的连接可以由客户端进程重用,而不是多次创建和销毁。 这样可以减少每次需要时创建新连接的开销,因为未使用的连接已缓存并可以重复使用。 ...

要打开持久连接,必须在连接时将p:添加到主机名。

使用Vicidial我经常遇到同样的问题,由于使用的编程类型,必须(非常)频繁地从许多vicidial组件建立新的MYSQL连接,我们有系统锤击数据库服务器每秒超过10000个连接,其中大部分都在几毫秒内完成服务,并在一秒或更短的时间内关闭。 根据经验,我可以告诉您,在本地网络中,几乎没有丢失的软件包,tcp_fin_timeout可以一直降低到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_timeout设置为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

Wiche允许更多时间连接关闭并尝试重用相同的ip:端口组合,以便与同一主机:服务组合的新连接。

要么

net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_fin_timeout=10

哪个会更积极地尝试重用连接,但是可以通过您的网络服务器为其他应用程序创建新问题。 所以你应该首先尝试简单的解决方案,在大多数情况下,它已经解决了你的问题没有任何不良副作用!

祝好运!

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

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

/sbin/sysctl -w net.netfilter.nf_conntrack_max=196608

当问题变成网络相关时。

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

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

我们遇到了同样的问题。 虽然“tcp_fin_timeout”和“ip_local_port_range”解决方案有效,但真正的问题是写得不好的PHP脚本,它几乎每隔一次查询就创建了新的连接数据库。 重写脚本连接只解决了一次麻烦。 请注意,降低“tcp_fin_timeout”值可能会有危险,因为某些代码可能依赖于连接后一段时间后仍然存在的DB连接。 这是一个相当脏的胶带和泡泡糖路径比真正的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM