Fatal Error: Cannot assign requested address

问题

在执行一个PHP cli 常驻进程程序时,报致命错误:Cannot assign requested address,打开调试模式,具体错误可看到是 redis 建立连接语句导致。

这个错误 “Cannot assign requested address” 是由于 linux 分配的客户端连接端口用尽,客户端无法分配出新的端口,则会出现“Cannot assign requested address”问题。并发量较大的情况下,处于 TIME_WAIT状态下的TCP连接数较多无法建立新的连接所致。php redis 连接数过多解决办法。

虽然连接可以正常关闭,但是端口不是立即释放,而是处于 TIME_WAIT 状态,默认等待 60s 后才释放。

分析

该应用程序是会频繁消耗 redis 队列消息,本身是使用了 supervisor 进行多进程执行的。手动启用调试时报的错误,所以直接查看 redis 的连接看看

netstat -apn | grep :6379

不得了不得了,输出根本停不下来。统计了下,有22w个处于 TIME_WAIT 状态的。

处理

经过查看程序中 redis 默认使用了 connect 短连接方式,更换为 pconnect 持久连接即可。而且处理完成后系统CPU消耗由49%左右下降为14%左右,负载也明显降低。

顺便调整下系统参数

# 查看系统参数
sysctl net.ipv4.tcp_max_tw_buckets net.ipv4.ip_local_port_range net.ipv4.tcp_fin_timeout

我的机器 4C8G 输出如下信息

# 系统 tcp 最大 time wait 的包大小
net.ipv4.tcp_max_tw_buckets = 262144
# 系统本地端口号范围
net.ipv4.ip_local_port_range = 32768  61000
# 系统 tcp 超时
net.ipv4.tcp_fin_timeout = 60

临时修改 sysctl -w net.ipv4.tcp_max_tw_buckets=10000

永久修改需修改配置文件 /etc/sysctl.conf,并找到对应参数修改即可。我这里仅把 tcp 超时由 60 秒修改为了 30 秒,系统级参数请务必小心修改!

# 使配置文件立即生效
sysctl -p

参考文章:
使用短连接访问Redis出现“Cannot assign requested address”错误_分布式缓存服务 DCS_常见问题_客户端和网络连接_华为云 (huaweicloud.com)
linux下常见的网络相关参数简介 – ExzaiTin – 博客园 (cnblogs.com)

Author: thinkwei

1 thought on “Fatal Error: Cannot assign requested address

  1. 短连接类的程序都会有类似问题,MySQL也不例外,保持持久连接或者连接池才是正确解法~

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注