轉載自http://blog.csdn.net/yusiguyuan/article/details/21445883
TIMEWAIT狀態本身和應用層的客戶端或者服務器是沒有關系的。僅僅是主動關閉的一方,在使用FIN|ACK|FIN|ACK四分組正常關閉TCP連接的時候會出現這個TIMEWAIT。服務器在處理客戶端請求的時候,如果你的程序設計為服務器主動關閉,那么你才有可能需要關注這個TIMEWAIT狀態過多的問題。如果你的服務器設計為被動關閉,那么你首先要關注的是CLOSE_WAIT。可以參考TCP協議
原則
TIMEWAIT並不是多余的。在TCP協議被創造,經歷了大量的實際場景實踐之后,TIMEWAIT出現了,因為TCP主動關閉連接的一方需要TIMEWAIT狀態,它是我們的朋友。這是《UNIX網絡編程》的作者----Steven對TIMEWAIT的態度。
TIMEWAIT是友好的
TCP要保證在所有可能的情況下使得所有的數據都能夠被正確送達。當你關閉一個socket時,主動關閉一端的socket將進入TIME_WAIT狀態,而被動關閉一方則轉入CLOSED狀態,這的確能夠保證所有的數據都被傳輸。當一個socket關閉的時候,是通過兩端四次握手完成的,當一端調用close()時,就說明本端沒有數據要發送了。這好似看來在握手完成以后,socket就都可以處於初始的CLOSED狀態了,其實不然。原因是這樣安排狀態有兩個問題, 首先,我們沒有任何機制保證最后的一個ACK能夠正常傳輸,第二,網絡上仍然有可能有殘余的數據包(wandering duplicates),我們也必須能夠正常處理。
TIMEWAIT就是為了解決這兩個問題而生的。
1.假設最后一個ACK丟失了,被動關閉一方會重發它的FIN。主動關閉一方必須維持一個有效狀態信息(TIMEWAIT狀態下維持),以便能夠重發ACK。如果主動關閉的socket不維持這種狀態而進入CLOSED狀態,那么主動關閉的socket在處於CLOSED狀態時,接收到FIN后將會響應一個RST。被動關閉一方接收到RST后會認為出錯了。如果TCP協議想要正常完成必要的操作而終止雙方的數據流傳輸,就必須完全正確的傳輸四次握手的四個節,不能有任何的丟失。這就是為什么socket在關閉后,仍然處於TIME_WAIT狀態的第一個原因,因為他要等待以便重發ACK。
2.假設目前連接的通信雙方都已經調用了close(),雙方同時進入CLOSED的終結狀態,而沒有走TIME_WAIT狀態。會出現如下問題,現在有一個新的連接被建立起來,使用的IP地址與端口與先前的完全相同,后建立的連接是原先連接的一個完全復用。還假定原先的連接中有數據報殘存於網絡之中,這樣新的連接收到的數據報中有可能是先前連接的數據報。為了防止這一點,TCP不允許新連接復用TIME_WAIT狀態下的socket。處於TIME_WAIT狀態的socket在等待兩倍的MSL時間以后(MSL為最大報文段生存時間,LWIP為1分鍾,windows為2分鍾。之所以是兩倍的MSL,是由於MSL是一個數據報在網絡中單向發出到認定丟失的時間,一個數據報有可能在發送途中或是其響應過程中成為殘余數據報,確認一個數據報及其響應的丟棄的需要兩倍的MSL),將會轉變為CLOSED狀態。這就意味着,一個成功建立的連接,必然使得先前網絡中殘余的數據報都丟失了。
大量TIMEWAIT在某些場景中導致的令人頭疼的業務問題
大量TIMEWAIT出現,並且需要解決的場景
在高並發短連接的TCP服務器上,當服務器處理完請求后立刻按照主動正常關閉連接。。。這個場景下,會出現大量socket處於TIMEWAIT狀態。如果客戶端的並發量持續很高,此時部分客戶端就會顯示連接不上。
我來解釋下這個場景。主動正常關閉TCP連接,都會出現TIMEWAIT。為什么我們要關注這個高並發短連接呢?有兩個方面需要注意:
1. 高並發可以讓服務器在短時間范圍內同時占用大量端口,而端口有個0~65535的范圍,並不是很多,刨除系統和其他服務要用的,剩下的就更少了。
2. 在這個場景中,短連接表示“業務處理+傳輸數據的時間 遠遠小於 TIMEWAIT超時的時間”的連接。這里有個相對長短的概念,比如,取一個web頁面,1秒鍾的http短連接處理完業務,在關閉連接之后,這個業務用過的端口會停留在TIMEWAIT狀態幾分鍾,而這幾分鍾,其他HTTP請求來臨的時候是無法占用此端口的。單用這個業務計算服務器的利用率會發現,服務器干正經事的時間和端口(資源)被掛着無法被使用的時間的比例是 1:幾百,服務器資源嚴重浪費。(說個題外話,從這個意義出發來考慮服務器性能調優的話,長連接業務的服務就不需要考慮TIMEWAIT狀態。同時,假如你對服務器業務場景非常熟悉,你會發現,在實際業務場景中,一般長連接對應的業務的並發量並不會很高)
綜合這兩個方面,持續的到達一定量的高並發短連接,會使服務器因端口資源不足而拒絕為一部分客戶服務。同時,這些端口都是服務器臨時分配,無法用SO_REUSEADDR選項解決這個問題:(
一對矛盾
TIMEWAIT既友好,又令人頭疼。
但是我們還是要抱着一個友好的態度來看待它,因為它盡它的能力保證了服務器的健壯性。
可行而且必須存在,但是不符合原則的解決方式
1. linux沒有在sysctl或者proc文件系統暴露修改這個TIMEWAIT超時時間的接口,可以修改內核協議棧代碼中關於這個TIMEWAIT的超時時間參數,重編內核,讓它縮短超時時間,加快回收;
2. 利用SO_LINGER選項的強制關閉方式,發RST而不是FIN,來越過TIMEWAIT狀態,直接進入CLOSED狀態。詳見我的博文《TCP之選項SO_LINGER》。
我如何看待這個問題
為什么說上述兩種解決方式我覺得可行,但是不符合原則?
我首先認為,我要依靠TIMEWAIT狀態來保證我的服務器程序健壯,網絡上發生的亂七八糟的問題太多了,我先要服務功能正常。
那是不是就不要性能了呢?並不是。如果服務器上跑的短連接業務量到了我真的必須處理這個TIMEWAIT狀態過多的問題的時候,我的原則是盡量處理,而不是跟TIMEWAIT干上,非先除之而后快:)如果盡量處理了,還是解決不了問題,仍然拒絕服務部分請求,那我會采取分機器的方法,讓多台機器來抗這些高並發的短請求。持續十萬並發的短連接請求,兩台機器,每台5萬個,應該夠用了吧。一般的業務量以及國內大部分網站其實並不需要關注這個問題,一句話,達不到需要關注這個問題的訪問量。
真正地必須使用上述我認為不合理的方式來解決這個問題的場景有沒有呢?答案是有。
像淘寶、百度
、新浪、京東商城這樣的站點,由於有很多靜態小圖片業務,如果過度分服會導致需要上線大量機器,多買機器多花錢,得多配機房,多配備運維工程師來守護這些機器,成本增長非常嚴重。。。這個時候就要盡一切可能去優化。
題外話,服務器上的技術問題沒有絕對,一切都是為業務需求服務的。
如何盡量處理TIMEWAIT過多
如發現系統存在大量TIME_WAIT狀態的連接,通過調整內核參數解決:
編輯文件/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 時間
