springboot tomcat 性能调优(SpringBoot内置Tomcat出现大量CLOSEWAIT导致应用假死深入分析)

通常情况下,一个正常的TCP连接,都会有三个阶段:

  • TCP三次握手;
  • 数据传送;
  • TCP四次挥手;

具体流程可以看下面的状态图。

一、分析CLOSE_WAIT现象和问题定位

Spring Boot应用内置Tomcat服务出现大量CLOSE_WAIT的现象,主要原因是某种情况下对方关闭了Socket链接,但是我方(Server)忙于读或者写,没有关闭连接。

关于CLOSE_WAIT的产生大部分都是资源没释放导致的,有httpclient导致的,也有数据库或者其他中间件服务器(如Redis、MQ等等)连接导致的。

springboot tomcat 性能调优(SpringBoot内置Tomcat出现大量CLOSEWAIT导致应用假死深入分析)(1)

CLOSE_WAIT状态是由于客户端关闭了socket连接,发送了FIN报文,服务端也发送了ACK报文,此时客户端处于FIN_WAIT_2状态,服务端处于CLOSE_WAIT状态。

下面回顾一下问题的定位:

1. 首先,我这边的大部分请求都需要查询数据库,数据库连接池设置的最大连接数是100,所以每一个请求创建了一个连接,等到100个请求就把连接池占满了,但是处理servlet的那个线程并没有释放这个连接,于是接下来的请求再去创建数据库连接的时候就会一直阻塞在那里,这里我所用的是DBCP作为连接池的。

2. 如果没有可用的连接对象会导致线程等待。好了,servlet由于得不到数据库连接而阻塞了,这个客户端的请求就一直等待。

3. 客户端使用httpclient设置了5s的请求超时时间,那么超时之后就会抛出异常,关闭连接。

4. 关闭连接时,客户端发送了FIN(终结)报文,Server端TCP/IP返回了ACK报文,但是由于处理请求的线程还处于阻塞的状态,所以当前的连接状态是CLOSE_WAIT。

二、终止TCP连接的四次挥手

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。

假设终止FIN命令由Client端发起。

springboot tomcat 性能调优(SpringBoot内置Tomcat出现大量CLOSEWAIT导致应用假死深入分析)(2)

当Client端传输完成数据,或者需要断开连接时:

1. Client端发送一个FIN报文给Server端。(序号为m)

  • 表示要终止Client到Server这个方向的连接。
  • 通过调用close(socket) API。
  • 表示Client不再会发送数据到Server端。(但Server还能继续发给Client端)。
  • Client状态变为FIN_WAIT_1。

2. Server端收到FIN后,发送一个ACK报文给Client端。(序号为m 1)

  • Server状态变为CLOSE_WAIT。
  • Client收到序号为(m 1)的ACK后状态变为FIN_WAIT_2。

3. Server端也发送一个FIN报文给Client端。(序号为n)

  • 表示Server也要终止到Client端这个方向的连接。
  • 通过调用close(socket) API。
  • Server端状态变为LAST_ACK。

4. Client端收到报文FIN后,也发送一个ACK报文给服务器。(序号n 1)

  • Client状态变为TIME_WAIT。

5. Server端收到序号为(n 1)的ACK

  • Server的状态变为CLOSED。

6. Client等待2MSL之后

  • Client的状态也变为CLOSE.

至此,一个完整的TCP连接就关闭了。

两个基本问题:

Q: 我们看到CLOSE_WAIT出现在什么时候呢?

A: 在Sever端收到Client的FIN消息之后。

Q: 状态CLOSE_WAIT在什么时候转换成下一个状态呢?

A: 在Server端向Client发送FIN消息之后。

至此似乎明白了为什么会出现CLOSE_WAIT的状态:如果Server端一直没有向Client端发送FIN消息(调用close() API),那么这个CLOSE_WAIT会一直存在下去。

从上面我们看到出现CLOSE_WAIT,说明Server端没有发起close()操作,这基本上是用户Server端程序的问题了,比如存在耗时的操作、访问DB超时或无法获取连接等等。

通常情况下,Server都是等待Client访问,如果Client退出请求关闭连接,Server端自觉close()对应的连接。

三、SYN,ACK,RST和FIN都是什么的缩写?

连接过程是通过一系列状态表示的,这些状态有:LISTEN,SYN-SENT,SYN-RECEIVED,ESTABLISHED,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT和 CLOSED。

各个状态的意义如下:

LISTEN - 侦听来自远方TCP端口的连接请求;

SYN-SENT - 在发送连接请求后等待匹配的连接请求;

SYN-RECEIVED - 在收到和发送一个连接请求后等待对方对连接请求的确认(ACK);

ESTABLISHED - 代表一个打开的连接,数据可以传送给用户;

FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;

FIN-WAIT-2 - 从远程TCP等待连接中断请求;

CLOSE-WAIT - 等待从本地用户发来的连接中断请求;

CLOSING - 等待远程TCP对连接中断的确认;

LAST-ACK - 等待Client端TCP的连接中断请求的确认;

TIME-WAIT - 等待足够的时间以确保远程TCP接收到连接中断请求的确认;

CLOSED - 没有任何连接状态;

英文单词缩写:

SYN(Synchronize)同步;该标志仅在三次握手建立TCP连接时有效,表示一个新的TCP连接请求。

ACK(ACKnowledge)确认;对TCP请求的确认标志,同时表示对方系统已经成功接收所有数据。

RST(Reset)重置;

FIN(Finish)终结;用来结束一个TCP会话。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页