【Linux網路編程筆記】TCP短串連產生大量TIME_WAIT導致無法對外建立新TCP串連的原因及解決方案—實踐篇

來源:互聯網
上載者:User

        上篇筆記主要介紹了與TIME_WAIT相關的基礎知識,本文則從實踐出發,說明如何解決文章標題提出的問題。

1. 查看系統網路設定和當前TCP狀態
        在定位並處理應用程式出現的網路問題時,瞭解系統預設網路配置是非常必要的。以x86_64平台Linux kernelversion 2.6.9的機器為例,ipv4網路通訊協定的預設配置可以在/proc/sys/net/ipv4/下查看,其中與TCP協議棧相關的配置項均以tcp_xxx命名,關於這些配置項的含義,請參考這裡的文檔,此外,還可以查看linux源碼樹中提供的官方文檔(src/linux/Documentation/ip-sysctl.txt)。下面列出我機器上幾個需重點關注的配置項及其預設值:

cat /proc/sys/net/ipv4/ip_local_port_range      32768   61000cat /proc/sys/net/ipv4/tcp_max_syn_backlog      1024cat /proc/sys/net/ipv4/tcp_syn_retries          5cat /proc/sys/net/ipv4/tcp_max_tw_buckets       180000cat /proc/sys/net/ipv4/tcp_tw_recycle           0cat /proc/sys/net/ipv4/tcp_tw_reuse             0

        其中,前3項分別說明了local port的分配範圍(預設的可用連接埠數不到3w)、incomplete connection queue的最大長度以及3次握手時SYN的最大重試次數,這3項配置的含義,有個概念即可。後3項配置的含義則需要理解,因為它們在定位、解決問題過程中要用到,下面進行重點說明。

        1) tcp_max_tw_buckets

        
這篇文檔
是這樣描述的:Maximal number of time wait sockets held by system simultaneously. If this number is exceeded TIME_WAIT socket is immediately destroyed and warning is printed. This limit exists only to prevent simple DoS attacks, you must not lower the limit artificially, but rather increase it (probably, after increasing installed memory), if network conditions require more than default value (180000).

        可見,該配置項用來防範簡單的DoS攻擊
,在某些情況下,可以適當調大,但絕對不應調小,否則,後果自負。。。

        
2) tcp_tw_recycle

        Enable fast recycling of sockets in TIME-WAIT status. The defaultvalue is 0 (disabled). It should not be changed without advice/request of technical experts.

        該配置項可用於快速回收處於TIME_WAIT狀態的socket以便重新分配。預設是關閉的,必要時可以開啟該配置。但是開啟該配置項後,有一些需要注意的地方,本文後面會提到。

        
3) tcp_tw_reuse

        
Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. The default value is 0. It should not

be changed without advice/request of technical experts.

        開啟該選項後,kernel會複用處於TIME_WAIT狀態的socket,當然複用的前提是“從協議角度來看,複用是安全的”。關於“
在什麼情況下,協議認為複用是安全的
”這個問題,這篇文章
從linux kernel源碼中挖出了答案,感興趣的同學可以查看。

 2. 網路問題定位思路
        參考前篇筆記開始處描述的線上實際問題,收到某台機器無法對外建立新串連的警示時,排查定位問題過程如下:
       用netstat –at | grep “TIME_WAIT”統計發現,當時出問題的那台機器上共有10w+處於TIME_WAIT狀態的TCP串連,進一步分析發現,由警示模組引起的TIME_WAIT串連有2w+。將netstat輸出的統計結果重定位到檔案中繼續分析,一般會看到原生port被大量佔用。
        由本文前面介紹的系統配置項可知,tcp_max_tw_buckets預設值為18w,而ip_local_port_range範圍不到3w,大量的TIME_WAIT狀態使得local port在TIME_WAIT持續期間不能被再次分配,即沒有可用的local port,這將是導致建立串連失敗的最大原因
        在這裡提醒大家:上面的結論只是我們的初步判斷,具體原因還需要根據代碼的異常傳回值(如socket api的傳回值及errno等)和模組日誌做進一步確認。無法建立新串連的原因還可能是被其它模組列入黑名單了,本人就有過這方面的教訓:程式中用libcurl api請求下遊模組失敗,初步定位發現機器TIME_WAIT狀態很多,於是沒仔細分析curl輸出日誌就認為是TIME_WAIT引起的問題,導致浪費了很多時間,折騰了半天發現不對勁後才想起,下遊模組有防攻擊機制,而發起請求的機器ip被不在下遊模組的訪問白名單內,高峰期上遊模組通過curl請求下遊的次數太過頻繁被列入黑名單,建立串連時被下遊模組的TCP層直接以RST包中斷連線,導致curl api返回”Recv failure: Connection reset by peer”的錯誤。慘痛的教訓呀 =_=
       另外,關於何時發送RST包,《Unix Network Programming Volume 1》第4.3節做了說明,作為筆記,摘出如下:
       An RST is a type of TCP segment that is sent by TCP when somethingis wrong.Three conditions that generatean RST are:            
        1) when a SYN arrives for a port that has no listening server;
        2) when TCP wants to abort an existing connection;
        3) when TCP receives a segment for a connection that does not exist. (TCPv1 [pp.246–250] contains additional information.)

3. 解決方案
        可以用兩種思路來解決機器TIME_WAIT過多導致無法對外建立新TCP串連的問題。
        3.1 修改系統配置
        具體來說,需要修改本文前面介紹的tcp_max_tw_buckets、tcp_tw_recycle、tcp_tw_reuse這三個配置項。
        1)將tcp_max_tw_buckets調大,從本文第一部分可知,其預設值為18w(不同核心可能有所不同,需以機器實際配置為準),根據文檔,我們可以適當調大,至於上限是多少,文檔沒有給出說明,我也不清楚。個人認為這種方法只能對TIME_WAIT過多的問題起到緩解作用,隨著訪問壓力的持續,該出現的問題遲早還是會出現,治標不治本。
        2)開啟tcp_tw_recycle選項:在shell終端輸入命令”echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle”可以開啟該配置。
        需要明確的是:其實TIME_WAIT狀態的socket是否被快速回收是由tcp_tw_recycle和tcp_timestamps兩個配置項共同決定的,只不過由於tcp_timestamps預設就是開啟的,故大多數文章只提到設定tcp_tw_recycle為1。更詳細的說明(分析kernel源碼)可參見這篇文章。
        還需要特別注意的是:當client與server之間有如NAT這類網路轉換裝置時,開啟tcp_tw_recycle選項可能會導致server端drop(直接發送RST)來自client的SYN包。具體的案例及原因分析,可以參考這裡、這裡或這裡以及這裡的分析,本文不再贅述。
        3)開啟tcp_tw_reuse選項:echo1 > /proc/sys/net/ipv4/tcp_tw_reuse。該選項也是與tcp_timestamps共同起作用的,另外socket reuse也是有條件的,具體說明請參見這篇文章。查了很多資料,與在用到NAT或FireWall的網路環境下開啟tcp_tw_recycle後可能帶來副作用相比,貌似沒有發現tcp_tw_reuse引起的網路問題。
        3.2 修改應用程式
       具體來說,可以細分為兩種方式:
        1)將TCP短串連改造為長串連。通常情況下,如果發起串連的目標也是自己可控制的伺服器時,它們自己的TCP通訊最好採用長串連,避免大量TCP短串連每次建立/釋放產生的各種開銷;如果建立串連的目標是不受自己控制的機器時,能否使用長串連就需要考慮對方機器是否支援長串連方式了。
        2)通過getsockopt/setsockoptapi設定socket的SO_LINGER選項,關於SO_LINGER選項的設定方法,《UNP Volume1》一書7.5節給出了詳細說明,想深入理解的同學可以去查閱該教材,也可以參考這篇文章,講的還算清楚。

4. 需要補充說明的問題
        我們說TIME_WAIT過多可能引起無法對外建立新串連,其實有一個例外但比較常見的情況:S模組作為WebServer部署在伺服器上,綁定本地某個連接埠;用戶端與S間為短串連,每次互動完成後由S主動中斷連線。這樣,當用戶端並發訪問次數很高時,S模組所在的機器可能會有大量處於TIME_WAIT狀態的TCP串連。但由於伺服器模組綁定了連接埠,故在這種情況下,並不會引起“由於TIME_WAIT過多導致無法建立新串連”的問題。也就是說,本文討論的情況,通常只會在每次由作業系統分配隨機連接埠的程式啟動並執行機器上出現(每次分配隨機連接埠,導致後面無連接埠可用)。

【參考資料】
1. ipsysctl-tutorial之tcpvariables
2. proc_sys_net_ipv4 
3. linux+v3.2.8/Documentation/networking/ip-sysctl.txt
4. 系列文章—tcp短串連TIME_WAIT問題解決方案大全1-5
5. 開啟tcp_tw_recycle引起的一個問題
6. dropping of connections with tcp_tw_recycle = 1
7. tcp_tw_recycle和nat造成syn_ack問題

================= EOF ==================


 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.