解決netstat TIME_WAIT狀態過多問題(轉)


在實際生產過程中,遇到過tcp連接有十幾萬個TIME_WAIT的連接,通過設置相關參數解決,這里直接引用這個連接。

 

轉自:https://www.cnblogs.com/even160941/p/15180216.html

通過命令查看所有狀態的個數:

netstat -antlp|awk '/tcp/ {print $6}'|sort|uniq -c
     16 CLOSING
    130 ESTABLISHED
    298 FIN_WAIT1
     13 FIN_WAIT2
      9 LAST_ACK
      7 LISTEN
    103 SYN_RECV
   5204 TIME_WAIT
各個狀態的含義解釋:

狀態	描述
CLOSED	無連接是活動的或正在進行
LISTEN	服務器在等待進入呼叫
SYN_RECV	一個連接請求已經到達,等待確認
SYN_SENT	應用已經開始,打開一個連接
ESTABLISHED	正常數據傳輸狀態
FIN_WAIT1	應用說它已經完成
FIN_WAIT2	另一邊已同意釋放
ITMED_WAIT	等待所有分組死掉
CLOSING	兩邊同時嘗試關閉
TIME_WAIT	另一邊已初始化一個釋放
LAST_ACK	等待所有分組死掉
如發現系統存在大量TIME_WAIT狀態的連接,通過調整內核參數解決,編輯內核文件,加入以下內容:

vim /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后執行 /sbin/sysctl -p 讓參數生效。

參數含義解釋:

net.ipv4.tcp_syncookies = 1 表示開啟SYN cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉。
net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉。
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間。
下面附上TIME_WAIT狀態的意義:

客戶端與服務器端建立TCP/IP連接后關閉SOCKET后,服務器端連接的端口狀態為TIME_WAIT,是不是所有執行主動關閉的socket都會進入TIME_WAIT狀態呢?有沒有什么情況使主動關閉的socket直接進入CLOSED狀態呢?主動關閉的一方在發送最后一個 ack 后就會進入 TIME_WAIT 狀態 停留2MSL(max segment lifetime報文最大生存時間)時間這個是TCP/IP必不可少的,也就是"解決"不了的。也就是TCP/IP設計者本來是這么設計的。

主要有兩個原因:

1.防止上一次連接中的包,迷路后重新出現,影響新連接(經過2MSL,上一次連接中所有的重復包都會消失)。
2.可靠的關閉TCP連接。
在主動關閉方發送的最后一個 ack(fin) ,有可能丟失,這時被動方會重新發fin, 如果這時主動方處於 CLOSED 狀態 ,就會響應 rst 而不是 ack。所以主動方要處於 TIME_WAIT 狀態,而不能是 CLOSED。TIME_WAIT 並不會占用很大資源的,除非受到攻擊。還有,如果一方 send 或 recv 超時,就會直接進入 CLOSED 狀態。

這樣修改完內核參數完,再去netstat查看網絡連接,發現time_wait狀態的連接基本都消失了。

netstat -antlp|awk '/tcp/{print $6}'|sort|uniq -c
      8 ESTABLISHED
     19 LISTEN
      3 SYN_SENT
      3 TIME_WAIT

有圖片的:https://blog.csdn.net/yangshengwei230612/article/details/115165095



另一個詳細的:
https://www.jianshu.com/p/42918db85f19 :

在開發網絡服務器應用系統的時候,有時會碰到服務器有大量的socket處於CLOSE_WAIT狀態,也無法關閉,導致服務器無法接受新的用戶請求,最終導致服務器奔潰,系統重啟才能解決。

為什么會出現大量的CLOSE_WAIT狀態呢?

要解決這個問題,我們得先介紹一下socket斷開過程中的四次揮手。

終止TCP連接的四次揮手

由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。
假設終止命令由client端發起。

 

 

 

當clien端傳輸完成數據,或者需要斷開連接時:

  1. Client端發送一個FIN報文給Server端。(序號為M)
    1.1. 表示要終止Client到Server這個方向的連接。
    1.1. 通過調用close(socket) API。
    1.3 表示Client不再會發送數據到Server端。(但Server還能繼續發給Client端)
    1.4 Client狀態變為FIN_WAIT_1
  2. Server端收到FIN后,發送一個ACK報文給Client端。(序號為M+1)
    2.1 Server狀態變為CLOSE_WAIT
    2.2 Client收到序號為(M+1)的ACK后狀態變為FIN_WAIT_2
    。。。
  3. Server端也發送一個FIN報文給Client端。(序號為N)
    3.1 表示Server也要終止到Client端這個方向的連接。
    3.2. 通過調用close(socket) API。
    3.3 Server端狀態變為LAST_ACK
  4. Client端收到報文FIN后,也發送一個ACK報文給服務器。(序號N+1)
    4.1 Client狀態變為TIME_WAIT
  5. Server端收到序號為(N+1)的ACK
    5.1 Server的狀態變為CLOSED.
  6. 等帶2MSL之后
    6.1 Client的狀態也變為CLOSE.
  7. 至此,一個完整的TCP連接就關閉了。

兩個基本問題:

  1. Q: 我們看到CLOSE_WAIT出現在什么時候呢?
    A: 在Sever端收到Client的FIN消息之后。
  2. Q: 狀態CLOSE_WAIT在什么時候轉換成下一個狀態呢?
    A: 在Server端向Client發送FIN消息之后。

至此似乎明白了為什么會出現CLOSE_WAIT的狀態:如果Server端一直沒有向client端發送FIN消息(調用close() API),那么這個CLOSE_WAIT會一直存在下去。

原因分析

從上面我們看到出現CLOSE_WAIT,說明Server端沒有發起close()操作,這基本上是用戶server端程序的問題了;通常情況下,Server都是等待Client訪問,如果Client退出請求關閉連接,server端自覺close()對應的連接。

當然這也可能是業務實現上的需要,暫時不發送FIN,因為服務器可能還有數據要發往客戶端,等發送完所有應用數據最后再發送FIN消息了;這個場景並不是這里我們討論的大量COLSE_WAIT的問題了,因為這個還是可控的。

我們要討論的場景是什么?我們先介紹兩個系統調用,前面也提到並且用到的close(socket)和shutdown(socket,HOW)接着往下分析。

我們知道一個進程打開一個socket,然后此進程fork出子進程的時候,父進程已打開的socket是會被繼承的,即子進程能夠繼續訪問這個socket。其結果就是,一個socket被兩個進程打開,一個父進程和一個子進程,此時socket的引用計數會變成2。

  • 調用close(socket)時,內核先檢查socket上的引用計數器:如果引用計數大於1,那么將這個引用計數減1,然后直接返回。如果引用計數等於1,那么內核才會真正關閉此socket。(通過發送FIN到對端來關閉TCP連接)
  • 調用shutdown(socket,HOW)時,內核不會檢查此socket對應的引用計數器,直接向對端發送FIN來關閉TCP連接。

據此分析,很大可能性是用戶服務器的程序實現有問題導致的大量CLOSE_WAIT的socket,比如父進程打開了socket,然后通過fork出子進程來處理業務,父進程繼續對網絡請求進行監聽,永遠不會終止;當客戶端發FIN過來的時候,處理業務的子進程處理此FIN消息,調用close()對本端進行關閉,然而這個close()調用只是把socket的引用計數器減1,因為父進程還在運行,socket並沒關閉,這樣就導致系統中又多了一個CLOSE_WAIT的socket,長此以往,就這樣了。

關於TIME_WAIT狀態

多說兩句關於TIME_WAIT的狀態,這個發生在client端,而且是不可避免的,其時間長度是固定的2MSL,到期自動轉為CLOSED,不會導致系統資源耗盡的問題。

MSL是一個系統級參數,可調。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM