当前位置:首页 >  IDC >  服务器 >  正文

连接数未满却无法连接?排查 TIME_WAIT 是否占用本地端口

 2026-10-29 09:15  来源: 互联网   我来投稿 撤稿纠错

  一键部署OpenClaw

业务高峰的时候接口开始报错,日志里是Can't connect to MySQL server on 127.0.0.1 (99)。括号里那个99是EADDRNOTAVAIL,既不是连接被拒绝,也不是超时。报错集中在晚上八点到十点,别的时段一条都没有,重启一次php-fpm能好十分钟,然后原样再犯。重启清掉的是进程里的连接,内核里的端口占用一点没动。进库看SHOW STATUS LIKE 'Threads_connected',四十几个,max_connections配的是500。连接数离上限差着十倍,端口却分配不出来了。

短连接一建立就关,主动关闭的那一方会在TIME_WAIT状态里待满60秒。这个时间由2MSL决定,Linux上基本就是60秒。每个这样的连接占掉本地端口范围里的一个坑,坑不释放,新的连接就开不出来。

cat /proc/sys/net/ipv4/ip_local_port_range看一眼,通常是32768到60999,两万八千个左右。要是每秒新建五百个连接,乘60秒就是三万,正好把这批端口吃干净。ss -s的输出里timewait那一行会给个总数,跟这个算出来的量级对得上,基本就定了。把峰值QPS乘60秒再乘短连接比例估一遍,估出来的数跟ss -s里的timewait比,同一个量级就是在端口上出的问题。

ss -tan state time-wait再数一遍,看两侧的地址。全是同一个本地端口连着同一个远端端口,说明程序在短连接上狂刷;地址散得很开,那是正常的业务流量,不至于这么快堆满。按本地端口分组排一遍,前几个端口重复出现几百次的,就是被反复连的那一处。

处理有几种,治本的是换长连接或者连接池。一个连接复用几百次,TIME_WAIT自然就没了,PHP的pconnect、MySQL的连接池、Redis的pconnect都是这个思路。pconnect在php-fpm里够用,但进程数开得多的时候,每个进程各拿一条,池子的意义就打折了。第二种是把主动关闭的一方换掉,TIME_WAIT只出现在主动关闭方,让服务端关、客户端等,端口压力就挪到端口更多的那一侧。第三种是内核参数,net.ipv4.tcp_tw_reuse设成1,允许复用在TIME_WAIT里的连接,但它只对出向连接有效,还要求开了tcp_timestamps。还有一种情况更难缠:程序连的是外网地址,本地端口用完得更早,因为四元组里能变的只剩本地端口这一个位置。

tcp_tw_recycle你别碰。它在NAT后面会丢包,4.12之后的内核已经把它删了。网上还有老文章在教这个参数,照着抄一定踩坑。它按来源IP判断时间戳,同一个NAT后面的机器时间戳不同步,包会被当成旧的丢掉,表现是随机连不上,特别难复现。

tcp_max_tw_buckets调大只是把报错推后,端口该用完还是用完。真正的解法在连接复用上,参数只是缓冲。改完再压一次,看ss -s的timewait有没有降下来,没降就是复用没生效。sysctl改完要-p写进配置文件,只在命令行上改的,重启一次就回去了。

申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!

相关文章

热门排行

信息推荐