在TCP斷開鏈接四次揮手時, 主動發起關閉方會產生 TIME_WAIT, TIME_WAIT 是 TCP 協議可靠性設計的重要一個環節, 雖然說加強了可靠性, 可是對於高併發場景下, 會產生大量的 TIME_WAIT, 致使高峯時段無故口能夠使用.html
本文只作簡單學習測試, 不保證內容的全面性及正確性, 不要輕易修改正式環境內核配置linux
今天主要對兩個 Linux 內核的配置 tcp_tw_reuse 和 tcp_tw_recycle 進行測試講解nginx
爲了方面模擬網絡狀況, 咱們設置可用端口區間僅爲81安全
sysctl -w "net.ipv4.ip_local_port_range=81 81"
複製代碼
訪問本地nginx服務bash
curl http://127.0.0.1
curl http://127.0.0.1
curl: (7) Failed to connect to 127.0.0.1: Cannot assign requested address
複製代碼
查看網絡狀態服務器
netstat -napo |grep 127.0.0.1
複製代碼
咱們能夠看到, 第一次正常, 在 2MSL 時間內, 再次訪問將會出現沒法分配請求地址錯誤. 在 Linux 中TIME_WAIT時間爲60s,而且還沒法修改網絡
TIME_WAIT過時時間宏定義併發
//include/net/tcp.h
/* how long to wait to destroy TIME-WAIT
* state, about 60 seconds */
#define TCP_TIMEWAIT_LEN (60*HZ)
複製代碼
驗證時間 curl
能夠看到標紅線的地方爲 time_wait 的倒計時,到時間後將會自動釋放端口.socket
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
複製代碼
進行測試
咱們能夠觀測到, 在 TIME_WAIT 狀態的端口也能夠繼續完成請求, 但不會改變 TIME_WAIT 自己的狀態和計時.
此結論證實, 當本地端口將耗盡時, 能夠嘗試開啓 tcp_tw_reuse 進行端口重用.
It's not SO_REUSEADDR socket option. SO_REUSEADD is used for binding socket to LISTEN state even if it is in TIME_WAIT state.
開啓 tcp_tw_recycle
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
複製代碼
進行測試
結果很好, 一樣完成了請求測試. 可是彷佛跟 tcp_tw_reuse 哪裏不太同樣?
對比開啓 tcp_tw_reuse 的netstat檢測結果, 看看有什麼差別.
咱們發現這裏簡直就是暴力美學, 根本沒有 TIME_WAIT 的狀態呀
linux內核斷定代碼
當開啓回收時,咱們的 timeout 值爲 rto, 這是一個很是短的一個時間, 不然爲 TCP_TIMEWAIT_LEN , 還記得文章開頭提到的宏定義的時間嗎, 沒錯, 這裏指的就是那個60s.
彷佛這兩個參數都可以很好的工做, 至少測試結果是很理想的.
參數 | 功能 |
---|---|
tcp_tw_reuse | 複用(reuse),不改變 TIMEWAIT 狀態 |
tcp_tw_recycle | 回收(recycle),最快時間回收 |
net.ipv4.tcp_timestamps 默認開啓, 他是記錄標記時間戳
若是開啓了 tcp_tw_reuse, 若是客戶端發來的時間戳大於先前鏈接內核記錄的最新時間戳, 則 Linux 將從新使用狀態中的現有鏈接以 TIME-WAIT 用於新的對外請求鏈接, 狀態中的傳出鏈接 TIME-WAIT可在僅一秒以後重複使用.
若是開啓了 tcp_tw_recycle, 則內核會記住客戶端上次發來數據包的時間戳, 若是發來的數據包時間戳小於內核記錄的最後發來的數據包時間戳, 那麼將會丟棄此數據包, 這種狀況在 NAT 模式下多機器時間滯後或同時發送, 會有很大危險, 會形成難以排查的異常狀況.
網上說 設置net.ipv4.tcp_timestamps=0, 能夠再也不檢測時間戳, 未找到官方出處, 真實性沒法保證.
在服務器端,請勿啓用net.ipv4.tcp_tw_recycle 除非你很是肯定你的服務中永遠不會有NAT設備。 啓用net.ipv4.tcp_tw_reuse 對於發送請求 (outgoing connection) 的鏈接有效。
在客戶端,啓用 net.ipv4.tcp_tw_reuse 是另外一個幾乎安全的解決方案
並且,在設計協議時,不要先讓客戶關閉。客戶端沒必要處理將TIME-WAIT狀態推向更適合處理此問題的服務器的狀態。
因此最終建議能夠開啓 tcp_tw_reuse, 禁用 tcp_tw_recycle.
參考文檔:
vincent.bernat.ch/en/blog/201…
linuxsyseng.blogspot.com/2017/03/the…