通常情況下,一個正常的TCP連接,都會有三個階段:
具體流程可以看下面的狀态圖。
一、分析CLOSE_WAIT現象和問題定位Spring Boot應用内置Tomcat服務出現大量CLOSE_WAIT的現象,主要原因是某種情況下對方關閉了Socket鍊接,但是我方(Server)忙于讀或者寫,沒有關閉連接。
關于CLOSE_WAIT的産生大部分都是資源沒釋放導緻的,有httpclient導緻的,也有數據庫或者其他中間件服務器(如Redis、MQ等等)連接導緻的。
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端發起。
當Client端傳輸完成數據,或者需要斷開連接時:
1. Client端發送一個FIN報文給Server端。(序号為m)
2. Server端收到FIN後,發送一個ACK報文給Client端。(序号為m 1)
3. Server端也發送一個FIN報文給Client端。(序号為n)
4. Client端收到報文FIN後,也發送一個ACK報文給服務器。(序号n 1)
5. Server端收到序号為(n 1)的ACK
6. Client等待2MSL之後
至此,一個完整的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會話。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!