TCP 有很多连接状态,每一个都够聊十块钱儿的,比如我们以前讨论过 TIME_WAIT 和 FIN_WAIT1,最近时不时听人提起 CLOSE_WAIT,感觉有必要梳理一下。 所谓 CLOSE_WAIT,借用某位大牛的话来说应该倒过来叫做 WAIT_CLOSE,也就是说「等待关闭」,如果你还不理解其含义,可以看看 TCP 关闭连接时的图例: TCP Close 不要被图中的 通常,CLOSE_WAIT 状态在服务器停留时间很短,如果你发现大量的 CLOSE_WAIT 状态,那么就意味着被动关闭的一方没有及时发出 FIN 包,一般有如下几种可能: 程序问题:如果代码层面忘记了 那么为什么我们总听说 CLOSE_WAIT 状态过多的故障,但是却相对少听说 FIN_WAIT2 状态过多的故障呢? 坏消息是 CLOSE_WAIT 没有类似的设置,如果不重启进程,那么 CLOSE_WAIT 状态很可能会永远持续下去;好消息是如果 socket 开启了 keepalive 机制,那么可以通过相应的设置来清理无效连接
CLOSE_WAIT和TIME_WAIT是如何产生的?大量的CLOSE_WAIT和TIME_WAIT又有何隐患?本文将通过实践角度来带你揭开CLOSE_WAIT和TIME_WAIT的神秘面纱! 什么时候出现CLOSE_WAIT? 所以可以看到原先ESTABLISHED的连接变成了CLOSE_WAIT。并且会持续下去。 通常情况下TIME_WAIT对服务端影响有限,而大量CLOSE_WAIT风险较高,但正确编写代码基本可以避免。为什么只说通常情况呢? TIME_WAIT和CLOSE_WAIT在一些异常条件下,还是会触发的。
热卖云产品年终特惠,2核2G轻量应用服务器7.33元/月起,更多上云必备产品助力您轻松上云
time_wait和close_wait tcp连接和关闭中常见的三种状态是: ESTABLISHED 表示正在通信 TIME_WAIT 表示主动关闭 CLOSE_WAIT 表示被动关闭。 有时服务器会在网络状态上出现异常,一半来说是以下两种情况: 服务器保持了大量TIME_WAIT状态 服务器保持了大量CLOSE_WAIT状态 服务器保持了大量TIME_WAIT状态 TIME_WAIT是主动关闭连接的一方 服务器保持了大量CLOSE_WAIT状态 TIME_WAIT状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源, 但是CLOSE_WAIT就不一样了,从上面的图可以看出来,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。 解决思路 将大量CLOSE_WAIT的解决办法总结为一句话那就是:查代码。因为问题出在服务器程序里头啊。
23 # 非常异常 TIME_WAIT 1 发现绝大部份的链接处于 CLOSE_WAIT 状态,这是非常不可思议情况。 图四:大量的CLOSE_WAIT CLOSED 表示socket连接没被使用。 LISTENING 表示正在监听进入的连接。 SYN_SENT 表示正在试着建立连接。 CLOSE_WAIT 表示远程计算器关闭连接,正在等待socket连接的关闭。 FIN_WAIT_1 表示socket连接关闭,正在关闭连接。 然后开始重点思考为什么会出现大量的mysql连接是 CLOSE_WAIT 呢?为了说清楚,我们来插播一点TCP的四次挥手知识。 TCP四次挥手 我们来看看 TCP 的四次挥手是怎么样的流程: ? 参考文章: 又见CLOSE_WAIT TCP 4-times close : https://wiki.wireshark.org/TCP%204-times%20close
面试中常问的问题 很多面试中,特别是后端岗位,特别是和服务器相关岗位的面试中喜欢问这两个状态,首先回忆下这两个状态出现的时间,下面是三次握手和四次挥手的状态图 TIME_WAIT TIME_WAIT 是出现在主动关闭的一端,一般是客户端,在收到服务端发来的FIN报文之后进入TIME_WAIT,TIME_WAIT的时间一般是2MSL,1MSL是30秒,主要是等待某些在网络延迟的报文到达,从而正确关闭 请求头没有设置keep_alive,而是close 第一种情况就是连接时长很短,导致连接关闭后进入TIME_WAIT状态,并且大量的短连接同时进行 第二种情况就是像某些爬虫服务器可能会主动断开连接,那这时候服务器会进入 个,端口不够用了会报错 CLOSE_WAIT 原因 CLOSE_WAIT是服务端收到FIN报文后,发出最后一个FIN报文前的状态,所以出现CLOSE_WAIT有很大可能是服务端没有及时发送出FIN报文, 也就是没有主动close或者shutdown,这种一般是代码写得有问题
我开发的某个服务出现这个状态 , 出现了大量的close_wait , 占满了单进程的连接数1024 ? tcp连接关闭的时候 , 会有几种状态转移 ? close_wait的大量出现 , 这个是说明我们是被动关闭 , 并且被动关闭后 , 我们的程序没有把连接关闭掉 , 造成连接泄露了 我在做gofly在线客服系统的时候 , 把连接关闭改成了前端来关闭 , 但是后端对关闭的连接没有进行close , 没有close就不会发送ACK和FIN标志 , 造成了连接泄露 所以遇到close_wait大量出现 , 需要检查下程序 time_wait的出现 , 说明是我们主动关闭 , 连接是我们关闭的 , 我们需要等2MSL时间 , 等对方把数据传完 , 这时就是time_wait , 才会发送ACK确认包 , 这个可以改系统参数 , 等系统回收就可以了
:39570 CLOSE_WAIT tcp6 0 0 localhost:synapse-nhttp localhost:55682 CLOSE_WAIT :43694 CLOSE_WAIT tcp6 0 0 localhost:synapse-nhttp localhost:32928 CLOSE_WAIT 我们发现一个有意思的现象,CLOSE_WAIT 是被动关闭连接的状态,主动关闭连接的状态应该是 FIN_WAIT1。 比较了两种状态连接数不是一个数量级,CLOSE_WAIT 将近1w个,而 FIN_WAIT1 只有几个,同时 FIN_WAIT2 只有几十个,TIME_WAIT一个没有。 合理情况下,sidecar 连接的 FIN_WAIT1 状态和本机程序连接的 CLOSE_WAIT 状态应该是一个数量级才对。
CLOSE_WAIT TCP关闭连接时四次挥手的过程,如下图所示(图来自网络): ? 那么当被动方这个FIN包没有发送成功,那么其就一直处于CLOSE_WAIT状态.那么问题成功转换为以下几个小问题: 大量CLOSE_WAIT有什么危害? 程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 那么为什么HttpClient访问时端口会分配到CLOSE_WAIT对应的端口? 因此超时等待机制是必要的, 参考 浅谈CLOSE_WAIT
:39570 CLOSE_WAIT tcp6 0 0 localhost:synapse-nhttp localhost:55682 CLOSE_WAIT :43694 CLOSE_WAIT tcp6 0 0 localhost:synapse-nhttp localhost:32928 CLOSE_WAIT 我们发现一个有意思的现象,CLOSE_WAIT 是被动关闭连接的状态,主动关闭连接的状态应该是 FIN_WAIT1。 比较了两种状态连接数不是一个数量级,CLOSE_WAIT 将近1w个,而 FIN_WAIT1 只有几个,同时 FIN_WAIT2 只有几十个,TIME_WAIT一个没有。 合理情况下,sidecar 连接的 FINWAIT1 状态和本机程序连接的 CLOSE_WAIT 状态应该是一个数量级才对。
什么是TIME-WAIT和CLOSE-WAIT? 所谓,要解决问题,就要先理解问题。 主动关闭连接的一方,调用close();协议层发送FIN包 被动关闭的一方收到FIN包后,协议层回复ACK;然后被动关闭的一方,进入CLOSE_WAIT状态,主动关闭的一方等待对方关闭,则进入FIN_WAIT 时间,主动关闭的一方,结束TIME_WAIT,进入CLOSED状态 通过上面的一次socket关闭操作,你可以得出以下几点: 主动关闭连接的一方 - 也就是主动调用socket的close操作的一方 ,最终会进入TIME_WAIT状态 被动关闭连接的一方,有一个中间状态,即CLOSE_WAIT,因为协议层在等待上层的应用程序,主动调用close操作后才主动关闭这条连接 TIME_WAIT 所以,这里凭你的直觉,TIME_WAIT并不可怕(not really,后面讲),CLOSE_WAIT才可怕,因为CLOSE_WAIT很多,表示说要么是你的应用程序写的有问题,没有合适的关闭socket
如下图所示: 为什么调用sokcet的close时只通过一次握手就终结连接了? 要分析这个原因那就得从关闭连接程的四次握手,有时也会是三次握手,说起。 如下所示: 在这四次握手状态中,有一个特别要注意的状态TIME_WAIT。 netstat命令查看系统将会发现机器上存在大量处于TIME_WAIT状态的socket连接,我这边曾经出现达到了2w多个,并且占用大量的本地端口号。 而此时机器上的可用本地端口号被占完,旧的大量处于TIME_WAIT状态的socket尚未被系统回收时,就会出现无法向服务端创建新的socket连接的情况。 设置为这个值的意思是当主动关闭方设置了setSoLinger(true,0)时,并调用close后,立该发送一个RST标志给对端,该TCP连接将立刻夭折,无论是否有排队数据未发送或未被确认。
has been performed and the local end-point needs to perform an active close to leave this state.CLOSE_WAIT No, needs to be added.Close_Wait引发的问题:Close_Wait数量过多会引起网络可用连接少、网络性能下降,并占用系统非换页内存。 解决CLOSE_WAIT的方法(在客户端执行,需要重启机器):https://blog.csdn.net/lgxzzz/article/details/124551824如果一直保持在CLOSE_WAIT 对象关闭,否则容易造成连接处于CLOSE_WAIT状态。 3、TCP的KeepLive功能,可以让操作系统替我们自动清理掉CLOSE_WAIT的连接。
Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”.2MSL在RFC 793协议中给出的建议是两分钟, 但是在Linux下一般时30秒, 也就是说2MSL就是60秒.CLOSE_WAIT 产生的原因CLOSE_WAIT是被动关闭连接是形成的,根据TCP状态机,服务器端收到客户端发送的FIN,TCP协议栈会自动发送ACK,连接进入CLOSE_WAIT状态。 但如果服务器端不执行SOCKET的CLOSE()操作,状态就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接.所以如果被动关闭端关闭SOCKET不及时, 例如: I/O线程被意外阻塞,或者I/O线程执行的用户自定义Task比例过高,导致I/O操作处理不及时,链路不能被及时释放.通常,CLOSE_WAIT 状态在服务器停留时间很短,如果你发现大量的 CLOSE_WAIT 状态,那么就意味着被动关闭的一方没有及时发出 FIN 包,一般有如下可能:(1) 程序问题:如果代码层面忘记了 CLOSE 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT
在服务器的日常维护过程中,会经常用到下面的命令: 它会显示例如下面的信息: TIME_WAIT 814 CLOSE_WAIT 1 FIN_WAIT1 1 ESTABLISHED 634 SYN_RECV 2 LAST_ACK 1 常用的三个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。 状态 休息一下,喘口气,一开始只是打算说说TIME_WAIT和CLOSE_WAIT的区别,没想到越挖越深,这也是写博客总结的好处,总可以有意外的收获。 但 是CLOSE_WAIT就不一样了,从上面的图可以看出来,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程 序自己没有进一步发出ack信号。 所以如果将大量CLOSE_WAIT的解决办法总结为一句话那就是:查代码。因为问题出在服务器程序里头啊。
线上大量CLOSE_WAIT的原因 为什么会出现大量的mysql连接是 CLOSE_WAIT 呢? 根据四次挥手,我们知道四次挥手有两个状态一个是Close_wait,一个是TimeWait; TimeWait 出现在最后,客户端向服务端发送ack,表示确认,请求服务端回ack, 这是客户端会等待2MSL (报文最大生存时间) Close_wait 出现在服务器向客户端第一次确认断开时,这是client无法向服务器发送消息,但是服务器还有消息向客户端发送; 大量的Close_wait 说明是服务器与客户端的连接没有断开 和 Close_Wait 产生原因与分析 Time_Wait 产生:调用close()发起主动关闭的一方,在发送最后一个ACK之后会进入time_wait的状态; 为什么要进行Time_wait? closeWait close_wait的危害在于,在一个端口上打开的文件描述符超过一定数量,(在linux上默认是1024,可修改),新来的socket连接就无法建立了。
前言 某机器上残留了很多CLOSE_WAIT状态的TCP连接,使用netstat却看不到是哪一个进程在使用。 通常的CLOSE_WAIT状态的TCP连接 ? 通常情况下,我们可以通过netstat -aptn来获取到TCP连接的信息,如上图,可以知道CLOSE_WAIT状态的TCP连接属于50871进程,大概率是用户逻辑处理有问题,没有执行close/shutdown 没有进程号的CLOSE_WAIT状态的TCP连接 ? 还有一种情况,没有进程归属的CLOSE_WAIT状态的TCP连接。 那么,能不能自动丢弃这种没有进程归属的CLOSE_WAIT状态的TCP连接?
-1状态 第二次挥手:服务器收到客户端的后,发出ACK=1确认标志和客户端的确认号ack=u+1,自己的序列号seq=v,进入CLOSE-WAIT状态 第三次挥手:客户端收到服务器确认结果后,进入FIN-WAIT 之前的python的那个连接,是TIME_WAIT状态 客户端(主动方)主动断开,进入TIME_WAIT状态,服务端(被动方)进去CLOSE状态,就是没有显示了 等待2MSL(1分钟)后,如下: ? TIME_WAIT状态的连接也消失了,TIME_WAIT回收机制,系统ing过一段时间会回收,资源重利用 CLOSE_WAIT情况 先建立连接,如下: ? 之前的redis-server的45370端口连接 进入了FIN_WAIT2状态,而python端(被动关闭方)就进去了CLOSE_WAIT状态 等待30s后,在看连接 ? 只有python的那条CLOSE_WAIT了 再次操作python端的脚本,再次get ? 关于6379端口(redis端口)的网络连接都没有了 ?
; CLOSE: 没有任何连接状态; 下面简单解释下什么是TIME-WAIT和CLOSE-WAIT ? 协议层回复ACK;然后被动关闭的一方,进入CLOSE_WAIT状态,主动关闭的一方等待对方关闭,则进入FIN_WAIT_2状态;此时,主动关闭的一方等待被动关闭一方的应用程序,调用close操作 ; 3 所以说这里凭直觉看,TIME_WAIT并不可怕,CLOSE_WAIT才可怕,因为CLOSE_WAIT很多,表示说要么是你的应用程序写的有问题,没有合适的关闭socket;要么是说,你的服务器CPU处理不过来 3) CLOSE_WAIT 对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭 4) TIME_WAIT 我方主动调用close 此问题的典型特征是:一端处于FIN_WAIT2 ,而另一端处于CLOSE_WAIT .
说起 CLOSE_WAIT,就不得不再复习一遍 TCP 的状态变迁: ? 出现 CLOSE_WAIT 本质上是因为服务端收到客户端的 FIN 后,仅仅回复了 ACK(由系统的 TCP 协议栈自动发出),并没有发 4 次断开的第二轮 FIN(由应用主动调用 Close() 或 而且观察到服务端的 CLOSE_WAIT 状态 RECV 缓冲区基本都有数据: ? 说明服务端还没有调用 recv 读取,并且在客户端关闭连接后,CLOSE_WAIT 依然不会消失,只能说明服务端 HANG 在了某处,没有调用 close。 无法被正常调用,产生大量的 CLOSE_WAIT 状态同时伴随大量的 goroutine 堆积。
由于TIME_WAIT的连接经过2MSL的时间(一般是2分钟)就会自动关闭。所以怀疑是有CLOSE_WAIT的连接。 分析对于TCP连接状态,遇事不决祭此图:图片这里先讲解一下CLOSE_WAIT,可能平时大家听说TIME_WAIT比较多,但TIME_WAIT并不是很严重的一个事情,CLOSE_WAIT才是。 CLOSE_WAIT都是出现在被动关闭的一方,即对端主动关闭了连接,发送了FIN。 所谓CLOSE_WAIT顾名思义,就是在等待close的函数,而如果被动关闭的一方没有调用close(),那么这个状态则会持续。 延伸keep_alive与CLOSE_WAIT回说前面提到的CLOSE_WAIT有超时时间吗?
扫码关注腾讯云开发者
领取腾讯云代金券