天天看點

【轉】記一次TIME_WAIT網絡故障

前段時間,組裡遇到個問題:線上某個業務出現了短連接配接太多,造成tw_bucket溢出。

這個問題比較常見,網上常見的方法有開啟reuse和快速回收(對于NAT結構的網絡,慎重開啟快速回收和reuse這2個參數,具體原因可以自行百度)。

出于複習下基礎知識的目的,網上找了篇部落格,

直接貼他的博文吧:

--  原文從下面開始

最近發現一個PHP腳本時常出現連不上伺服器的現象,調試了一下,發現是TIME_WAIT狀态過多造成的,本文簡要介紹一下解決問題的過程。

遇到這類問題,我習慣于先用strace指令跟蹤了一下看看:

從字面結果看似乎是網絡資源相關問題。這裡順便介紹一點小技巧:在調試的時候一般是從後往前看strace指令的結果,這樣更容易找到有價值的資訊。

檢視一下目前的網絡連接配接情況,結果發現TIME_WAIT數非常大:

補充一下,同netstat相比,ss要快很多:【備注:使用ss -s 指令也可列出概覽,但是不如awk這種顯示優雅 】

重複了幾次測試,結果每次出問題的時候,TIME_WAIT都等于28233,這真是一個魔法數字!實際原因很簡單,它取決于一個核心參數net.ipv4.ip_local_port_range:

因為端口範圍是一個閉區間,是以實際可用的端口數量是:

問題分析到這裡基本就清晰了,解決方向也明确了,内容所限,這裡就不說如何優化程式代碼了,隻是從系統方面來闡述如何解決問題,無非就是以下兩個方面:

首先是增加本地可用端口數量。這點可以用以下指令來實作:

其次是減少TIME_WAIT連接配接狀态。網絡上已經有不少相關的介紹,大多是建議:

注:通過sysctl指令修改核心參數,重新開機後會還原,要想持久化可以參考前面的方法。

這兩個選項在降低TIME_WAIT數量方面可以說是立竿見影,不過如果你覺得問題已經完美搞定那就錯了,實際上這樣可能會引入一個更複雜的網絡故障。

大概意思是說TCP有一種行為,可以緩存每個主機最新的時間戳,後續請求中如果時間戳小于緩存的時間戳,即視為無效,相應的資料包會被丢棄。

Linux是否啟用這種行為取決于tcp_timestamps和tcp_tw_recycle,因為tcp_timestamps預設就是開啟的,是以當tcp_tw_recycle被開啟後,實際上這種行為就被激活了,當用戶端或服務端以NAT方式建構的時候就可能出現問題,下面以用戶端NAT為例來說明:

當多個用戶端通過NAT方式聯網并與服務端互動時,服務端看到的是同一個IP,也就是說對服務端而言這些用戶端實際上等同于一個,可惜由于這些用戶端的時間戳可能存在差異,于是乎從服務端的視角看,便可能出現時間戳錯亂的現象,進而直接導緻時間戳小的資料包被丢棄。如果發生了此類問題,具體的表現通常是是用戶端明明發送的SYN,但服務端就是不響應ACK,我們可以通過下面指令來确認資料包不斷被丢棄的現象:

安全起見,通常要禁止tcp_tw_recycle。說到這裡,大家可能會想到另一種解決方案:把tcp_timestamps設定為0,tcp_tw_recycle設定為1,這樣不就可以魚與熊掌兼得了麼?可惜一旦關閉了tcp_timestamps,那麼即便打開了tcp_tw_recycle,也沒有效果。

好在我們還有另一個核心參數tcp_max_tw_buckets(一般預設是180000)可用:

通過設定它,系統會将多餘的TIME_WAIT删除掉,此時系統日志裡可能會顯示:「TCP: time wait bucket table overflow」,不過除非不得已,否則不要輕易使用。

總體來說,這次網絡故障本身并沒什麼高深之處,本不想羅羅嗦嗦寫這麼多,不過拔出蘿蔔帶出泥,在過程中牽扯的方方面面還是值得大家品味的,于是便有了這篇文字。

本文轉自 lirulei90 51CTO部落格,原文連結:http://blog.51cto.com/lee90/2065987,如需轉載請自行聯系原作者