彻底弄懂TIME_WAIT 及 tcp_tw_reuse选项
徹底弄懂TIME_WAIT 及 tcp_tw_reuse選項
約等于這篇文章的摘選和翻譯
https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux
文章目錄
- 徹底弄懂TIME_WAIT 及 tcp_tw_reuse選項
- TIME_WAIT存在的兩個原因
- net.ipv4.tcp_tw_reuse —— 針對客戶端(發起連接的一方)優化TIME_WAIT
- net.ipv4.tcp_tw_reuse開啟后 特殊情況的分析
- 總結
TIME_WAIT是tcp釋放連接的四次揮手后的主動關閉連接方的狀態
TIME_WAIT存在的兩個原因
人盡皆知的是,防止上一個TCP連接的延遲的數據包(發起關閉,但關閉沒完成),被接收后,影響到新的TCP連接。(唯一連接確認方式為四元組:源IP地址、目的IP地址、源端口、目的端口),包的序列號也有一定作用,會減少問題發生的幾率,但無法完全避免。尤其是較大接收windows size的快速(回收)連接。
第一個理由和連接“化身”和報文迷走有關系,為了讓舊連接的重復分節在網絡中自然消失。
下一次新的連接中就肯定不會出現舊連接的報文段了。
- 我們知道,在網絡中,經常會發生報文經過一段時間才能到達目的地的情況,產生的原因是多種多樣的,如路由器重啟,鏈路突然出現故障等。
- 如果迷走報文到達時,發現 TCP 連接四元組(源 IP,源端口,目的 IP,目的端口)所代表的連接不復存在,那么很簡單,這個報文自然丟棄。
- 我們考慮這樣一個場景,在原連接中斷后,又重新創建了一個原連接的“化身”,說是化身其實是因為這個連接和原先的連接四元組完全相同,如果迷失報文經過一段時間也到達,那么這個報文會被誤認為是連接“化身”的一個 TCP 分節,這樣就會對 TCP 通信產生影響。
另外一個作用是,當最后一個ACK丟失時,遠程連接進入LAST-ACK狀態,它可以確保遠程已經關閉當前TCP連接。如果沒有TIME-WAIT狀態,當遠程仍認為這個連接是有效的,則會繼續與其通訊,導致這個連接會被重新打開。當遠程收到一個SYN 時,會回復一個RST包,因為這SEQ不對,那么新的連接將無法建立成功,報錯終止。
- 如果遠程因為最后一個ACK包丟失,導致停留在LAST-ACK狀態,將影響新建立具有相同四元組的TCP連接。
所以,TCP 就設計出了這么一個機制,經過 2MSL 這個時間,足以讓兩個方向上的分組都被丟棄,使得原來連接的分組在網絡中都自然消失,再出現的分組一定都是新化身所產生的。
2MSL 的時間是從主機 1 接收到 FIN 后發送 ACK 開始計時的;如果在 TIME_WAIT 時間內,因為主機 1 的 ACK 沒有傳輸到主機 2,主機 1 又接收到了主機 2 重發的 FIN 報文,那么 2MSL 時間將重新計時。道理很簡單,因為 2MSL 的時間,目的是為了讓舊連接的所有報文都能自然消亡,現在主機 1 重新發送了 ACK 報文,自然需要重新計時,以便防止這個 ACK 報文對新可能的連接化身造成干擾。
TIME_WAIT 的危害
- 對端口資源的占用,一個 TCP 連接至少消耗一個本地端口。要知道,端口資源也是有限的,一般可以開啟的端口為 32768~61000 ,也可以通過net.ipv4.ip_local_port_range指定,如果 TIME_WAIT 狀態過多,會導致無法創建新連接。這個也是我們在一開始講到的那個例子。
net.ipv4.tcp_tw_reuse —— 針對客戶端(發起連接的一方)優化TIME_WAIT
機器作為客戶端時起作用,開啟后time_wait在一秒內回收
對于服務端,打開tw_reuse無效
**TIME-WAIT狀態是為了防止不相關的延遲請求包被接受。**但在某些特定條件下,很有可能出現,新建立的TCP連接請求包,被老連接(同樣的四元組,暫時還是TIME-WAIT狀態,回收中)的連接誤處理。
RFC 1323 實現了TCP拓展規范,以保證網絡繁忙狀態下的高可用。除此之外,另外,它定義了一個新的TCP選項–兩個四字節的timestamp fields時間戳字段,第一個是TCP發送方的當前時鐘時間戳,而第二個是從遠程主機接收到的最新時間戳。
啟用net.ipv4.tcp_tw_reuse后,如果新的時間戳,比以前存儲的時間戳更大,那么linux將會從TIME-WAIT狀態的存活連接中,選取一個,重新分配給新的連接出去的TCP連接。
連出的TIME-WAIT狀態連接,僅僅1秒后就可以被重用了。
它如何安全?
- TIME-WAIT狀態的第一個目的是避免在不相關的連接中接受重復的段。由于使用了時間戳,此類重復段將帶有過時的時間戳,因此會被丟棄。
- 第二個目的是確保遠端 不會因為最后一個ACK丟失而處于LAST-ACK狀態。
遠端將重傳FIN段,直到(3種可能):- 它放棄(并斷開連接)
- 它收到正在等待的ACK(并斷開連接)
- 它收到一個RST(并斷開連接) —— 新連接會回復
- 它收到 連接請求(同四元組) —— 特殊情況
如果按時接收到FIN段,則本端套接字仍將處于該TIME-WAIT狀態,并會發送預期的ACK段。
net.ipv4.tcp_tw_reuse開啟后 特殊情況的分析
- 特殊情況
之前處于time_wait的機器 變為SYN_SENT狀態,向之前的 斷開連接的機器 重新 發送連接請求(四元組相同)
**一旦新連接(左邊的機器)替換了TIME-WAIT狀態,新連接的SYN 段將被忽略(感謝時間戳)并且不會由RST應答,而只會通過FIN段的重傳 。然后FIN段將用RST應答 (因為本地連接處于該SYN-SENT狀態),這將允許轉換出該LAST-ACK狀態。**最初的SYN 段最終將被重新發送(一秒后),因為沒有應答,并且連接將在沒有明顯錯誤的情況下建立,除了輕微的延遲:
如果遠端因為最后一個ACK丟失而一直處于LAST-ACK狀態,當本端轉換到SYN-SENT狀態時,遠端連接將被重置。
總結
通用的解決方案是通過使用更多的服務器端口來增加可能的四胞胎的數量。這將使您不會用盡可能的TIME-WAIT 狀態的連接。
在服務器端,啟用net.ipv4.tcp_tw_reuse對傳入連接無用(自己的time_wait不會被優化)。
在客戶端,啟用net.ipv4.tcp_tw_reuse是另一種幾乎安全的解決方案。啟用net.ipv4.tcp_tw_recycle除了net.ipv4.tcp_tw_reuse大部分是無用的。
此外,在設計協議時,不要讓客戶端先關閉。客戶端將不必處理TIME-WAIT將責任推給更適合處理此問題的服務器的狀態。
總結
以上是生活随笔為你收集整理的彻底弄懂TIME_WAIT 及 tcp_tw_reuse选项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信小程序的配置
- 下一篇: SpringBoot+Quartz+数据