乙個朋友問到,自己用go寫了乙個簡單的http服務端程式,為什麼壓測的時候服務端會出現一段時間的time_wait超高的情況,導致壓測的效果不好呢?
記得老王有兩篇文章專門說這個,當時粗粗看了一遍,正好碰上這個問題,又翻出來細細摟了。
第乙個要弄懂的,是time_wait是怎麼產生的。
要弄懂time_wait要從tcp的四次握手的分手協議說起。
上面這個展示了tcp從連線建立到連線釋放的過程中,客戶端和服務端的狀態變化圖。如果只看連線釋放階段,四次握手
當然在這個例子和上面的中,使用客戶端和服務端來描述是不準確的,tcp主動斷開連線的一方可能是客戶端,也可能是服務端。所以使用主動斷開的一方,和被動斷開的一方替換上面的圖可能更為貼切。
不管怎麼說,time_wait的狀態就是主動斷開的一方,傳送完最後一次ack之後進入的狀態。並且持續時間還挺長的。
能不能傳送完ack之後不進入time_wait就直接進入close狀態呢?不行的,這個是為了tcp協議的可靠性,由於網路原因,ack可能會傳送失敗,那麼這個時候,被動一方會主動重新傳送一次fin,這個時候如果主動方在time_wait狀態,則還會再傳送一次ack,從而保證可靠性。那麼從這個解釋來說,2msl的時長設定是可以理解的,msl是報文最大生存時間,如果重新傳送,乙個fin+乙個ack,再加上不定期的延遲時間,大致是在2msl的範圍。
所以從理論上說,網上除錯引數降低time_wait的持續時間的方法是一種以可靠性換取效能的一種方式。嗯,質量守恆定理還是鐵律。
回到上面的問題,go寫了乙個http服務,壓測發現time_wait過多。
首先判斷是不是壓測程式放在服務的同一臺機器...當然不會犯這麼低階的錯誤...
那麼這個感覺就有點奇怪了,http服務並沒有依賴外部mysql或者redis等服務,就是乙個簡單的hello world,而time_wait的是主動斷開方才會出現的,所以主動斷開方是服務端?
答案是是的。在http1.1協議中,有個 connection 頭,connection有兩個值,close和keep-alive,這個頭就相當於客戶端告訴服務端,服務端你執行完成請求之後,是關閉連線還是保持連線,保持連線就意味著在保持連線期間,只能由客戶端主動斷開連線。還有乙個keep-alive的頭,設定的值就代表了服務端保持連線保持多久。
http預設的connection值為close,那麼就意味著關閉請求的一方幾乎都會是由服務端這邊發起的。那麼這個服務端產生time_wait過多的情況就很正常了。
雖然http預設connection值為close,但是現在的瀏覽器傳送請求的時候一般都會設定connection為keep-alive了。所以,也有人說,現在沒有必要通過調整引數來使time_wait降低了。
按照http協議的頭,我們在壓測程式發出的http協議頭裡面加上connection:keep-alive當然能解決這個問題。
還有的方法就是系統引數調優:
sysctl net.ipv4.tcp_tw_reuse=1
sysctl net.ipv4.tcp_tw_recycle=1
sysctl net.ipv4.tcp_timestamps=1
這個引數作用是當新的連線進來的時候,可以復用處於time_wait的socket。預設值是0。
預設time_wait的超時時間是2倍的msl,但是msl一般會設定的非常長。如果tcp_timestamps是關閉的,開啟tcp_tw_recycle是沒用的。但是一般情況下tcp_timestamps是預設開啟的,所以直接開啟就有用了。
我也來說說TIME WAIT狀態
乙個兄弟問到,自個用go寫了乙個簡略的http效勞端程式,為什麼壓測的時分效勞端會呈現一段時刻的time wait超高的狀況,致使壓測的效果不好呢?記住老王有兩篇文章專門說這個,當時粗粗看了一遍,恰好碰上這個疑問,又翻出來細細摟了。第乙個要弄懂的,是time wait是怎樣發生的。要弄懂time w...
TIME WAIT狀態釋疑
一 現象 登陸伺服器的時候輸入netstat natup 發現存在大量time wait狀態的連線 tcp 0 0 127.0.0.1 3306 127.0.0.1 41378 time wait tcp 0 0 127.0.0.1 3306 127.0.0.1 41379 time wait tc...
也說說培訓
現在的公司招聘,特別是面向大學畢業生的招聘,很多大學生都會問乙個問題,就是你公司培訓機制怎麼樣。我記得我剛進公司的時候,公司那時候人員雖然數量沒有現在多,不過水平什麼的要比現在好很多。當時剛進公司有3個培訓,第乙個就是日語培訓,這個培訓一直到現在公司還是在做,而且日語老師水平也還不錯,效果也還行。第...