专栏首页屈定‘s Blog关于大量CLOSE_WAIT连接分析

关于大量CLOSE_WAIT连接分析

问题场景

某日线上登录出现故障,排查日志发现HttpClient请求时随机分配到的端口被占用,导致第三方登录拉取信息时无法拉取成功,错误如下:

java.net.BindException: Address already in use (Bind failed)
	at java.net.PlainSocketImpl.socketBind(Native Method) ~[na:1.8.0_111]
	at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387) ~[na:1.8.0_111]
	at java.net.Socket.bind(Socket.java:644) ~[na:1.8.0_111]
	at sun.reflect.GeneratedMethodAccessor2044.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
	at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:139) ~[commons-httpclient-3.1.jar:na]
	at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:125) ~[commons-httpclient-3.1.jar:na]
	at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707) ~[commons-httpclient-3.1.jar:na]
.....

这个问题很奇怪,linux端口分配会避免端口冲突的,然后检查服务器发现大量tcp连接处于CLOSE_WAIT状态,不过对应的是另外一个项目.

统计信息如下(命令netstat -nat | awk 'FNR>2{print $NF}' | sort | uniq -c),简直恐怖.

CLOSE_WAIT

TCP关闭连接时四次挥手的过程,如下图所示(图来自网络):

有图可知,主动方发起关闭请求也就是FIN包后,被动方接收到包,被动方接着进入CLOSE_WAIT状态,接着被动方发送FIN包告知主动方自己已关闭后进入LAST_ACK状态. 那么当被动方这个FIN包没有发送成功,那么其就一直处于CLOSE_WAIT状态.那么问题成功转换为以下几个小问题:

  • 大量CLOSE_WAIT有什么危害? CLOSE_WAIT状态不会自己消失,除非对应的应用进程死掉,不会消失就意味着一直占用服务器资源,端口总数又只有65535,因此这里的服务器作为连接的发起者就会造成大量端口被占用,一旦占用完就导致后面的请求都发不出去,也就是一开始图上另一个项目发请求出现的Address already in use (Bind failed)错误.
  • 被动方什么情况下FIN包会发送失败?
    • 程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 也永远执行不到。
    • 响应太慢或者超时设置过小:如果连接双方不和谐,一方不耐烦直接 timeout,另一方却还在忙于耗时逻辑,就会导致 close 被延后。响应太慢是首要问题,不过换个角度看,也可能是 timeout 设置过小。
    • BACKLOG 太大:此处的 backlog 不是 syn backlog,而是 accept 的 backlog,如果 backlog 太大的话,设想突然遭遇大访问量的话,即便响应速度不慢,也可能出现来不及消费的情况,导致多余的请求还在队列里就被对方关闭了。

解决问题

知道了产生的原因,自然好解决,根据netstat给出的信息包括pid定位到具体的应用,然后通过git查看最近代码改动,最终找到之前上线的一段代码使用了python的httplib,使用完却没有主动close释放连接,因此出现了这个问题.

那么为什么HttpClient访问时端口会分配到CLOSE_WAIT对应的端口? Linux会为每一次请求分配临时端口,这个分配范围在/proc/sys/net/ipv4/ip_local_port_range中有记录,在我这台服务器上其值是20000-65535,大量的CLOSE_WAIT就会导致可分配的端口数减少,因此系统会在指定范围内选择一个没有冲突的端口,一旦端口消耗完毕就会造成冲突.也就是上面的错误Address already in use (Bind failed).

TIME_WAIT

上面结果图中TIME_WAIT也有几百个,这个是什么原因? 对于四次挥手过程中,当主动方接收到被动放的关闭确认信号FIN后,主动方会回复一个ACK信号,然后会进入TIME_WAIT状态,此时会等待2MLS,在Linux中也就是60s,因此相对上述2000多个活跃tcp来说,这100多的TIME_WAIT是正常现象. 然后为什么TCP主动方关闭后需要等待2MLS? 因为TCP是可靠的通信,在主动方回复ACK时如果由于网络问题该包发送失败,那么被动方就会进行FIN重传,此时重传会遇到两个场景:

  • 主动方已关闭,旧的TCP连接已经消失,那么系统只能回复RST包.
  • 主动方已关闭,然后利用此端口建立了新的连接.也就是旧的TCP关闭,新的TCP已建立,那么就会造成信道的不可靠.

因此超时等待机制是必要的,

参考

浅谈CLOSE_WAIT

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • (转)JAVA拾遗--关于SPI机制

    JDK提供的SPI(Service Provider Interface)机制,可能很多人不太熟悉,因为这个机制是针对厂商或者插件的,也可以在一些框架的扩展中看...

    屈定
  • (转)你写的代码,是别人的噩梦吗

    自从工作后写了大半年代码了,公司由于历史原因项目中充斥着各种不合理设计,写着写着就很容易烦躁,影响心情,写代码本来是快乐而富有创造的事情,面对这样的噩梦需要找到...

    屈定
  • Java--Java中的四种引用

    Java中存在四种引用,StrongReference(强引用) 、SoftReferenc(软引用) 、WeakReferenc(弱引用)、PhantomRe...

    屈定
  • 445端口如何正确的修改和关闭

    我们都知道,有些专业的黑客可以通过开放端口对windows系统进行攻击,但是很多状况下我们忘了把用不到的端口关闭,特别是一些程序调用了该端口过后没有及时关闭。下...

    it妹
  • H3CSE笔记系列 | 带你走进园区网,一篇能让你知道侧重点(可用于知识点复习)

    1,协议,MAC,子网VLAN划分端口类型都是hybrid端口 2,isolate-user-vlan会用到hybrid端口{运行商} 都是hybrid端口 角...

    网络技术联盟站
  • 3389 Windows 远程端口修改工具

    https://pan.baidu.com/s/1Rt3ZFXY0sOD5okeb9VI3_A

    我爱你的一诺
  • H3C-限速

    h3c s3610的端口限速如何配置 对端口入方向的报文限速,也就是端口下的PC机上传的速率: # 进入系统视图。

    py3study
  • 一条命令实现端口复用后门

    说到端口复用,大部分人第一反应肯定是想到内核驱动,需要对网络接口进行一些高大上的操作才能实现。但只要合理利用操作系统提供的功能,就能以简单的方式实‍现这...

    洛米唯熊
  • python对象和类

    py3study
  • ASP.NET Core 如何在运行Docker容器时指定容器外部端口

    晓晨

扫码关注云+社区

领取腾讯云代金券