云主机访问对象存储时偶发“Cannot assign requested address”错误排查
问题说明
本文针对一类连接失败问题:在 ZStack Cloud 上的云主机(VM Instance)访问外部对象存储时,应用侧日志中反复出现 Cannot assign requested address 错误。
同一类问题也会影响任何在 Linux 云主机中频繁建立短 TCP 连接的工作负载(例如,对 S3 兼容对象存储进行轮询的应用服务器)。
现象
应用日志中出现类似如下的连接失败:
2024-11-06 11:33:07 Unable to execute HTTP request: Connect to 169.169.32.177:8060 [/169.169.32.177] failed: Cannot assign requested address (connect failed)
ZStack 控制面、物理主机以及网络路径均正常。错误仅出现在云主机操作系统中,且仅在高并发场景下出现。
适用环境
- 产品:ZStack Cloud;问题来源于云主机操作系统,而非 ZStack 平台本身。
- 版本:4.x、5.x。
- 组件:云主机内的 Linux 内核网络栈。
- 部署形态:向对象存储等单一目标发起高频、短生命周期的出向 HTTP/HTTPS 连接。
可能原因
- Linux 云主机中积累了大量
TIME_WAIT套接字。 - 临时端口范围不足以支撑当前连接速率。
- 应用频繁建立短连接,未使用 keep-alive 或持久连接池。
排查步骤
1. 确认临时端口耗尽
- 在云主机中执行
netstat -ant | grep -c TIME_WAIT。若数量较高(数千以上)且持续增长,说明云主机的临时端口池已被耗尽。 - 在云主机中执行
sysctl net.ipv4.ip_local_port_range。若端口范围较窄(默认为32768 60999,约 28 000 个端口),高并发工作负载可能将其占满。 - 确认目标服务(对象存储)可从另一台相同配置的主机访问。若可以,则问题位于受影响云主机的本地,而非存储平台。
2. 按需应用缓解措施
以下三种措施彼此独立,可按需组合使用。所有操作均在受影响的云主机(VM Instance)的客户机操作系统中执行,不要在管理节点或物理主机上执行。
方案 1 — 缩短 TIME_WAIT 窗口并启用端口复用
sysctl -w net.ipv4.tcp_fin_timeout=30
sysctl -w net.ipv4.tcp_timestamps=1
sysctl -w net.ipv4.tcp_tw_reuse=1
tcp_fin_timeout=30—— 将 TIME_WAIT 套接字的释放时间由 60 s 缩短为 30 s。tcp_timestamps=1——tcp_tw_reuse生效的前提条件。tcp_tw_reuse=1—— 允许将 TIME_WAIT 套接字用于新的出向连接。
Note:
不要启用 tcp_tw_recycle。该参数已在较新内核中弃用或移除,且在 NAT 环境下可能引发问题。
方案 2 — 扩大临时端口范围
sysctl -a | grep port_range
# 默认:net.ipv4.ip_local_port_range = 32768 60999 (约 28 000 个端口)
vi /etc/sysctl.conf
# 新增或替换为:
net.ipv4.ip_local_port_range = 10000 65000 # 约 55 000 个端口
sysctl -p
无需重启。
方案 3 — 将短连接改造为长连接(keep-alive)
如果应用协议支持,改为使用长连接(HTTP keep-alive、持久连接池)。这是最可持续的修复,因为它直接消除根因,而非单纯提高端口上限。
3. 验证处理结果
- 应用方案 1 后,在工作负载运行期间重新执行
netstat -ant | grep -c TIME_WAIT。计数应当趋于稳定,而非持续单调增长。 - 应用方案 2 后,
sysctl net.ipv4.ip_local_port_range应显示新的端口范围。 - 在相同工作负载下,应用错误日志中应不再出现新的
Cannot assign requested address。
