一分鐘告訴面試官TIME_WAIT

我們只知道在四次揮手的過程中,先發起關閉的一方會進入TIME_WAIT狀態,爲什麼會出現TIME_WAIT狀態以及TIME_WAIT狀態過多,是什麼原因?

1 出現的場景

客戶端在TCP建立連接對外提供服務的過程中,每個鏈接會佔用一個本地端口,如在高併發的情況下,TIME_WAIT狀態過多,勢必會佔用大量的端口,端口又有限,以致於耗盡端口,所以會出現偶爾鏈接的上,偶爾斷開的情況

這麼多的TIME_WAIT哪裏來的呢?先複習下四次揮手

四次揮手

[FIN_WAIT1] :FIN_WAIT1和FIN_WAIT2均爲等待對方的FIN報文。兩者區別爲,當SOCKET在ESTABLISHED狀態時,想主動關閉連接從而想對方發送FIN報文,此時進入FIN_WAIT1狀態。當收到ACK報文進入FIN_WAIT2狀態。

[FIN_WAIT_2]:此狀態下的socket實際上表示半連接的狀態。什麼是半連接,是一方想要關閉連接,另一方說稍等下,我還有點數據給你

[FIN_WAIT] :表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了

[CLOSE_WAIT] : 反過來讀比較好,WAIT_CLOSE即「等待關閉」。在被動關閉連接情況下,在已經接收到FIN,但是還沒有發送自己的FIN的時刻,連接處於CLOSE_WAIT狀態。

[LAST_ACK] :被動關閉乙方發送FIN後,等待對方的ACK,收到ACK即進入CLOSED狀態

在TCP/IP協議棧中,假設主機A想要進行鏈接終止操作,於是發送FIN報文給主機B,主機B收到從而進入CLOSE_WAIT狀態併發送ACK作爲應答,同時主機B會告訴應用程序也要關閉操作,於是發送FIN報文。主機A收到FIN報文發送ACK表示收到並進入TIME_WAIT

在Linux系統中有一個字段,名稱爲TCP_TIME_WAIT_LEN,其數值爲60s,也就是需要在TIME_WAIT階段停留60s

2 TIME_WAIT什麼作用

從上圖我們知道TIME_WAIT過後還有CLOSE狀態,爲什麼不直接進入CLOSED狀態,而是要過一會呢?

第一點,在TIME_WAIT後,爲了確保ACK能讓被動方接收並輔助其關閉。假設這樣的情況

如果主機A的ACK報文傳輸失敗,那麼在TCP/IP協議棧設計中,主機B會重傳FIN報文,但是此時主機A沒有維護好TIME_WAIT狀態而是CLOSED狀態,此時主機A只好發送RST,從而被動關閉失敗。

第二點,爲了讓就連接的重複節點在網絡中自然消失。怎麼理解?

我們知道,在網絡傳輸的過程中,總會因爲各種故障導致報文不能準時到達目的地。現在我們假設使用[源IP,源端口,目的IP,目的端口]代表連接A,在通信的過程中,鏈接A因爲某種原因中斷,暫時迷路,從而創建了類似於A的連接B,可是迷路的連接A此時到達了,勢必就會對TCP通信產生影響。所以設置了2MSL,足夠的時間讓兩個方向的分組都消失,使得下一個新的連接不會出現舊的連接請求報文

3 TIME_WAIT哪些危害

  • 內存資源佔用

  • 端口占用。端口資源有限,一般可開啓端口爲32768~61000,可以通過修改net.ipv4.ip_local_port_range指定,如果TIME_WAIT太多將無法建立連接

你可以通過下面命令查看當前TIME_WAIT數量

這裏爲什麼是28233呢,取決於內核參數net.ipv4.ip_local_range

因爲端口範圍是一個閉區間,所以實際可用的端口數量是:

shell> echo $((61000-32768+1)) 28233

4 TIME_WAIT如何優化

  • 暴力執法------net.ipv4.tcp_max_tw_buckets

一旦TIME_WAIT狀態過多就重置,方法是使用sysctl將系統值減小,太粗魯不推薦

  • 調低 TCP_TIMEWAIT_LEN

瞭解內核編譯即可操作

  • SO_LINGER設置,不推薦,因爲它直接跳過TIME_WAIT

int setsockopt(int sockfd, int level, int optname, const void *optval,socklen_t optlen);

  • 調整tcp_tw_recycle

我們先看看RFC1323中怎麼描述的

An additional mechanism could be added to the TCP, a per-hostcache of the last timestamp received from any connection.This value could then be used in the [PAWS] mechanism to rejectold duplicate segments from earlier incarnations of theconnection, if the timestamp clock can be guaranteed to haveticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT togethermust be at least one tick of the sender’s timestamp clock.Such an extension is not part of the proposal of this RFC.

  • net.ipv4.tcp_tw_reuse 複用連接

使用這個選項有個前提,需要打開TCP時間戳的支持net.ipv4.tcp_time stamps=1,在RFC1323中,爲了保證TCP的高可用,引入了兩個4字節的時間戳選項,用於記錄 TCP 發送方的當前時間戳和從對端接收到的最新時間戳。這就有意思了,之前說的2MSL就不存在了,因爲如果重複的數據包會因爲時間戳的過期而被丟棄

  1. 只適用於連接發起方(C/S 模型中的客戶端),這裏爲什麼強調是客戶端,我們看看源碼;

其調用路徑僅僅出現在tcp_v4_connect->inet_hash_connect->__inet_check_established->twsk_unique->twsk_unique。 也就是說tcp_tw_reuse僅在TCP套接字作爲客戶端調用connect時起作用。作爲服務端很少主動發起鏈接,所以對於服務端而言不用打開此選項

  1. 對應的 TIME_WAIT 狀態的連接創建時間超過 1 秒纔可以被複用。

最後引用一下W. Richard Stevens在《UNIX網絡編程》的一句話

The TIME_WAIT state is our friend and is there to help us (i.e., to let old duplicate segments expire in the network). Instead of trying to avoid the state, we should understand it.

譯者:存在即合理,勇敢面對,而不是逃避。

巨人的肩膀

  • 《Coping with the TCP TIME-WAIT state on busy Linux servers》

  • Tuning TCP and nginx on ec2 -p30

  • TIME_WAIT and its design implications for protocols and scalable client server systems

  • tcp_tw_recycle和tcp_timestamps導致connect失敗問題

  • https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

  • tcp_tw_recycle參數引發的系統問題 - http://blog.csdn.net/zhuyiquan/article/details/68925707

本文分享自微信公衆號 - 匠心Java(code-the-world)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章