先把当时的情况摆出来。CentOS 7.9 上的采集程序每分钟发起上千次 HTTP 请求,跑一阵就报 connect: cannot assign requested address,ss -s 里 timewait 三万多,ip_local_port_range 被前一个人改成了 30000 到 38000,重启进程只能顶几分钟,过一会儿又开始报同样的错。
排查方向其实有限,先把可能性排一排。本地端口范围只剩八千个,短连接一多就转不开。也可能是tcp_tw_reuse 关着,TIME_WAIT 的四元组要等两分钟才能复用。
还有一种情况,请求方没做连接复用,每个请求都新建一条 TCP。另外,容器用独立 netns,端口范围按命名空间各算一份,容器里更紧张。
上来先确认端口范围和当前占用
sysctl net.ipv4.ip_local_port_range net.ipv4.tcp_tw_reuse; ss -s
随后把范围改回默认的一半以上
sysctl -w net.ipv4.ip_local_port_range='10000 65000'
允许复用 TIME_WAIT 的出方向连接
sysctl -w net.ipv4.tcp_tw_reuse=1
剩下的就是统计当前 TIME_WAIT 的数量
ss -tan state time-wait | wc -l
恢复的判定其实很直接。ss -s 里 timewait 降到五千以内,采集程序连续跑一小时不再报 cannot assign,新建连接的耗时也稳定下来。
tcp_tw_reuse 只对主动发起连接的一方有效,服务端被动关闭的连接不受影响;端口范围开太大不是万能药,NAT 设备和 conntrack 表也会跟着吃紧。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
