【技术求助帖】大量tcp time_wait 异常连接

环境 radhat6.9

S1 和 S2 为业务服务器(weblogic)A1 为负载服务器,代理 S1 和 S2,

线上发现 S1 和 S2 出现大量 close_wait 状态,通常发生在整点,如4点整,但是10分钟后这些 close_wait 状态就没了,负载侧time wait 超时为2分钟, 正常来说客户端已经超时关闭tcp链接了,这时候服务器应该一直处于 close_wait 状态,为什么 10分钟多这些异常链接就会关闭,应用没有重启,我想知道这些异常状态为什么会关闭,或者说是什么回收了这些异常进程,

我的理解是,如果服务端请求没有正常调用close,就应该一直处于 close wait,而不是过一阵关闭,即使一段时间后处理完成向客户端发送第三个包 也就是 fin,但是客户端已经超时退出了,也是不正常的吧, 求助各位大佬解惑。

2 Likes

常规话题快问快答

太高深了,顶一下帖子,让佬看见

22 Likes

水神啊?

插个眼

close wait 可能是程序没有正常关闭tcp链接,需要检查一下程序日志或者代码编写。

time wait是由于短链接造成的,本身并不是什么坏事,只是性能上会慢一些,可以考虑负载 与 后端app程序使用长链接 keepalive通信。

代码问题可以确认,但是为什么处于close wait的人状态持续10分钟左右就没有了, 这个状态应该是不会回收的吧,是有什么内核参数控制吗?

我认为是tcp keepalive过期了,然后自动回收了。
影响keepalive的指标有三个:

- tcp_keepalive_time: 该参数定义了系统如何经常(以秒为单位)发送TCP keepalive漫游,用于检测死连接。默认值通常是7200秒(2小时)。

- tcp_keepalive_intvl: 确定在前一个keepalive探针后系统应发送下一个探针的频率。 默认值通常是75秒。

- tcp_keepalive_probes: 定义了在放弃并标记链接为死链接之前系统应发送多少个keepalive漫游。默认值通常是9。

但是,跟你说的10分钟有点出入。
按照默认参数,怎么也得2hour+75*9,没有10分钟这么快。

具体这三个参数可以看下是否动过?

这几个参数是默认的,应该不是这个影响的,这个超时时间太长了, 奇怪是客户端已经超时退出了,就算服务端处理完了以后调用 close,发送4次握手的第三个报文的时候也得不到回应了,应该还是要处于close_wait, 但是10分钟多一点这些异常连接都没了。。。很奇怪

可能还有一种可能性。

就是中间的NAT设备,一般指客户和服务器之间的路由器设备并开启了NAT功能。

当客户端发送fin并收到ack后,NAT设备认为该tcp链接已经不存在了。当服务端尝试发送包的时候,NAT设备会回复Reset。

有这个可能,中间有负载均衡设备。

有可能。

如果有lb的话,client与lb交互,lb向backend交互,client发送fin,为啥lb不向backend发送fin呢?或者lb发送了fin,但是backend没有响应。

是的,lb的确会向backend发送fin。

还有一个疑点,backend是如何在close_wait后发起了一次tcp包?而后收到了reset

上面有朋友提到我比较认同的,这种状态只是因为短连接在等待退出,如果你整点有瞬时大量并发的短连接,比如api调用,这样情况就能重现。
wls上的服务器如果瞬时有大量的tcp请求发起和关闭,这是需要cpu片来完成,os认为处理其他线程的更加优先,就不处理close_wait这种状态的socket连接也是可以讲得过去的,如果没有实际上的问题产生,这可以不用管它

还有一种可能性,就是大量的并发且使用短连接情况下,使得lb在选则本地端口的时候会重复使用之前用过的,而backend程序还停留在close_wait状态的端口,触发tcp异常使得close_wait消失。

1 Like

是的我们发现出现大量 closewait 是因为突然的大量并发,这样有好的处理方案吗

大佬很专业,

太高深了

插个眼

这个问题其实不碍事儿,顶多在效率上有些延迟而已。timewait 多了也没啥事儿,系统有 bucket 会自动回收。

只是如果并发再多些,延迟大到一定程度,可能就雪崩了。麻烦就大了。

终极解决方案:

  1. 修复程序,实现正常 tcp 关闭。
  2. 考虑系统瓶颈,及时扩容。比如多跑几个 app 实例。

临时解决方案:

  1. 扩大 net.ipv4.ip_local_port_range=10000 60000,扩大随机端口范围,方便负载均衡选取端口想后端应用程序发起短链接请求,降低 colsewait 端口被重复选中的概率。
  2. 负载均衡与后端应用之间尽量还是要开长连接,避免反复 tcp 三次握手,以及 closewait 异常状态,提高负载均衡与后端应用之间的通信效率。

首先确定的是 程序在收到 fin 并发送ack 的时候,tcp 进入 close_wait 然后程序某种原因导致tcp链接没有及时释放导致的。(应该是可以确定的吧)

  1. 如果负载均衡侧和后端,使用长链接,而他们发送一次数据就不进行通信的话,长链接也会占用大量网络资源,并发上来可能导致服务雪崩。这里有待测试一下

感谢王总,耐心解答本菜鸡问题,您的回答十分有帮助。