大量TIME_WAIT問題的解決


netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

會得到類似下面的結果,具體數字會有所不同:

LAST_ACK 1

SYN_RECV 14

ESTABLISHED 79

FIN_WAIT1 28

FIN_WAIT2 3

CLOSING 5

TIME_WAIT 1669

狀態:描述

CLOSED:無連接是活動的或正在進行

LISTEN:服務器在等待進入呼叫

SYN_RECV:一個連接請求已經到達,等待確認

SYN_SENT:應用已經開始,打開一個連接

ESTABLISHED:正常數據傳輸狀態

FIN_WAIT1:應用說它已經完成

FIN_WAIT2:另一邊已同意釋放

ITMED_WAIT:等待所有分組死掉

CLOSING:兩邊同時嘗試關閉

TIME_WAIT:另一邊已初始化一個釋放

LAST_ACK:等待所有分組死掉

也就是說,這條命令可以把當前系統的網絡連接狀態分類匯總。

下面解釋一下為啥要這樣寫:

一個簡單的管道符連接了netstat和awk命令。

------------------------------------------------------------------

每個TCP報文在網絡內的最長時間,就稱為MSL(Maximum Segment Lifetime),它的作用和IP數據包的TTL類似。

RFC793指出,MSL的值是2分鍾,但是在實際的實現中,常用的值有以下三種:30秒,1分鍾,2分鍾。

注意一個問題,進入TIME_WAIT狀態的一般情況下是客戶端,大多數服務器端一般執行被動關閉,不會進入TIME_WAIT狀態,當在服務

器端關閉某個服務再重新啟動時,它是會進入TIME_WAIT狀態的。

舉例:

1.客戶端連接服務器的80服務,這時客戶端會啟用一個本地的端口訪問服務器的80,訪問完成后關閉此連接,立刻再次訪問服務器的

80,這時客戶端會啟用另一個本地的端口,而不是剛才使用的那個本地端口。原因就是剛才的那個連接還處於TIME_WAIT狀態。

2.客戶端連接服務器的80服務,這時服務器關閉80端口,立即再次重啟80端口的服務,這時可能不會成功啟動,原因也是服務器的連

接還處於TIME_WAIT狀態。


檢查net.ipv4.tcp_tw當前值,將當前的值更改為1分鍾:

[root@aaa1 ~]# sysctl -a|grep net.ipv4.tcp_tw

net.ipv4.tcp_tw_reuse = 0

net.ipv4.tcp_tw_recycle = 0

[root@aaa1 ~]#

vi /etc/sysctl

增加或修改net.ipv4.tcp_tw值:

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

使內核參數生效:

[root@aaa1 ~]# sysctl -p

[root@aaa1 ~]# sysctl -a|grep net.ipv4.tcp_tw

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

用netstat再觀察正常


這里解決問題的關鍵是如何能夠重復利用time_wait的值,我們可以設置時檢查一下time和wait的值

#sysctl -a | grep time | grep wait

net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120

net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60

net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120

問一下TIME_WAIT有什么問題,是閑置而且內存不回收嗎?

是的,這樣的現象實際是正常的,有時和訪問量大有關,設置這兩個參數: reuse是表示是否允許重新應用處於TIME-WAIT狀態的

socket用於新的TCP連接; recyse是加速TIME-WAIT sockets回收


Q: 我正在寫一個unix server程序,不是daemon,經常需要在命令行上重啟它,絕大

多數時候工作正常,但是某些時候會報告"bind: address in use",於是重啟失

敗。


A: Andrew Gierth

server程序總是應該在調用bind()之前設置SO_REUSEADDR套接字選項。至於

TIME_WAIT狀態,你無法避免,那是TCP協議的一部分。


Q: 如何避免等待60秒之后才能重啟服務


A: Erik Max Francis


使用setsockopt,比如


--------------------------------------------------------------------------

int option = 1;


if ( setsockopt ( masterSocket, SOL_SOCKET, SO_REUSEADDR, &option,

sizeof( option ) ) < 0 )

{

die( "setsockopt" );

}

--------------------------------------------------------------------------


Q: 編寫 TCP/SOCK_STREAM 服務程序時,SO_REUSEADDR到底什么意思?


A: 這個套接字選項通知內核,如果端口忙,但TCP狀態位於 TIME_WAIT ,可以重用

端口。如果端口忙,而TCP狀態位於其他狀態,重用端口時依舊得到一個錯誤信息,

指明"地址已經使用中"。如果你的服務程序停止后想立即重啟,而新套接字依舊

使用同一端口,此時 SO_REUSEADDR 選項非常有用。必須意識到,此時任何非期

望數據到達,都可能導致服務程序反應混亂,不過這只是一種可能,事實上很不

可能。


一個套接字由相關五元組構成,協議、本地地址、本地端口、遠程地址、遠程端

口。SO_REUSEADDR 僅僅表示可以重用本地本地地址、本地端口,整個相關五元組

還是唯一確定的。所以,重啟后的服務程序有可能收到非期望數據。必須慎重使

用 SO_REUSEADDR 選項。


Q: 在客戶機/服務器編程中(TCP/SOCK_STREAM),如何理解TCP自動機 TIME_WAIT 狀

態?


A: W. Richard Stevens <1999年逝世,享年49歲>


下面我來解釋一下 TIME_WAIT 狀態,這些在<>

中2.6節解釋很清楚了。


MSL(最大分段生存期)指明TCP報文在Internet上最長生存時間,每個具體的TCP實現

都必須選擇一個確定的MSL值。RFC 1122建議是2分鍾,但BSD傳統實現采用了30秒。


TIME_WAIT 狀態最大保持時間是2 * MSL,也就是1-4分鍾。


IP頭部有一個TTL,最大值255。盡管TTL的單位不是秒(根本和時間無關),我們仍需

假設,TTL為255的TCP報文在Internet上生存時間不能超過MSL。


TCP報文在傳送過程中可能因為路由故障被迫緩沖延遲、選擇非最優路徑等等,結果

發送方TCP機制開始超時重傳。前一個TCP報文可以稱為"漫游TCP重復報文",后一個

TCP報文可以稱為"超時重傳TCP重復報文",作為面向連接的可靠協議,TCP實現必須

正確處理這種重復報文,因為二者可能最終都到達。


一個通常的TCP連接終止可以用圖描述如下:


client server

FIN M

close -----------------> (被動關閉)

ACK M+1

<-----------------

FIN N

<----------------- close

ACK N+1

----------------->


為什么需要 TIME_WAIT 狀態?


假設最終的ACK丟失,server將重發FIN,client必須維護TCP狀態信息以便可以重發

最終的ACK,否則會發送RST,結果server認為發生錯誤。TCP實現必須可靠地終止連

接的兩個方向(全雙工關閉),client必須進入 TIME_WAIT 狀態,因為client可能面

臨重發最終ACK的情形。


{

scz 2001-08-31 13:28


先調用close()的一方會進入TIME_WAIT狀態

}


此外,考慮一種情況,TCP實現可能面臨先后兩個同樣的相關五元組。如果前一個連

接處在 TIME_WAIT 狀態,而允許另一個擁有相同相關五元組的連接出現,可能處理

TCP報文時,兩個連接互相干擾。使用 SO_REUSEADDR 選項就需要考慮這種情況。


為什么 TIME_WAIT 狀態需要保持 2MSL 這么長的時間?


如果 TIME_WAIT 狀態保持時間不足夠長(比如小於2MSL),第一個連接就正常終止了。

第二個擁有相同相關五元組的連接出現,而第一個連接的重復報文到達,干擾了第二

個連接。TCP實現必須防止某個連接的重復報文在連接終止后出現,所以讓TIME_WAIT

狀態保持時間足夠長(2MSL),連接相應方向上的TCP報文要么完全響應完畢,要么被

丟棄。建立第二個連接的時候,不會混淆。


A: 小四


在Solaris 7下有內核參數對應 TIME_WAIT 狀態保持時間


# ndd -get /dev/tcp tcp_time_wait_interval

240000

# ndd -set /dev/tcp tcp_time_wait_interval 1000


缺省設置是240000ms,也就是4分鍾。如果用ndd修改這個值,最小只能設置到1000ms,

也就是1秒。顯然內核做了限制,需要Kernel Hacking。


# echo "tcp_param_arr/W 0t0" | adb -kw /dev/ksyms /dev/mem

physmem 3b72

tcp_param_arr: 0x3e8 = 0x0

# ndd -set /dev/tcp tcp_time_wait_interval 0


我不知道這樣做有什么災難性后果,參看<>的聲明。


Q: TIME_WAIT 狀態保持時間為0會有什么災難性后果?在普遍的現實應用中,好象也

就是服務器不穩定點,不見得有什么災難性后果吧?


D: rain@bbs.whnet.edu.cn


Linux 內核源碼 /usr/src/linux/include/net/tcp.h 中


#define TCP_TIMEWAIT_LEN (60*HZ)  


最好不要改為0,改成1。端口分配是從上一次分配的端口號+1開始分配的,所以一般

不會有什么問題。端口分配算法在tcp_ipv4.c中tcp_v4_get_port中。


关注微信公众号

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com