之前一直沒怎麼關注過TCP,直到公司這次的事件,這纔開始慢慢去研究,去學習TCP的相關知識,中間也嘗試了很多方法,走了很多彎路,因此記下這篇文章,方便以後回顧
首先說下網絡架構
Nginx和jetty都在同一個服務器,Nginx代理HTTP流量至多個jetty應用,基本情況就是這樣
首先我們來看下,爲什麼會有TIMEWAIT的狀態
客戶端主動關閉連接時,會發送最後一個ack後,然後會進入TIME_WAIT狀態,再停留2個MSL時間,進入CLOSED狀態。
也就是說一般timewait只會出現在client中(因爲主動關閉),server端是不會關閉連接的(以爲一直在監聽)
基於此,我查看了服務器的情況
發現nginx對外的tcp連接數狀態是正常的,問題就在對於jetty的連接數異常的多,並且不釋放
首先度娘解決方法,基本得到的結果基本就是一個修改內核參數(不推薦此做法)
net.ipv4.tcp_tw_reuse = 1
#表示開啓重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認爲0,表示關閉
net.ipv4.tcp_tw_recycle = 1
#表示開啓TCP連接中TIME-WAIT sockets的快速回收,默認爲0,表示關閉
這樣是可以快速的的回收socket,但是後來查詢資料發現這樣做有隱患
1.對於net.ipv4.tcp_tw_recycle ,Linux內核文檔中實戰和麼描述的
tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4)[譯者注:來自linux man tcp的描述]
Enable fast recycling of TIME-WAIT sockets. Enabling this option is not recommended since this causes
problems when working with NAT (Network Address Translation).
啓用TIME-WAIT狀態sockets的快速回收,這個選項不推薦啓用。在NAT(Network Address Translation)網絡下,會導致大量的TCP連接建立錯誤。
2.有些文檔中也說了對於手機端wifi訪問的話,也會有問題,因爲wifi端訪問時間戳會亂跳,導致訪問拒絕
基於以上2個隱患,所以沒有使用此方法。
後來我再觀察的時候,我發現nginx和jetty之間的連接大多都是短連接(因爲默認nginx也是使用短連接),所以有可能是nginx作爲client會快速釋放,所以導致nginx的socket一直都是出於timewait狀態,所以去nginx官網查看資料,配置nginx在負載均衡的時候使用長連接
具體配置爲:
upstream localhost{
……
keepalive 30;
}
location / {
……
proxy_http_version 1.1;
proxy_set_header Connection "";
}
在server 的location模塊裏面 添加以上信息。
注意:需要設置nginx 代理請求的 http 協議版本號爲 1.1, 以及清除掉 Connection 請求header
官方文檔描述:
For HTTP, the proxy_http_version directive should be set to “ 1.1 ” and the “Connection ” header field should be cleared
因爲http協議1.1默認就使用長連接,所以不需要Connection的頭部信息,這樣打開nginx和jetty之間的長連接之後,timewait的狀態大量減少。
總結:我們在遇到問題的時候,百度遇到的解決方案一定要仔細分析,千萬不能隨隨便便就使用,因爲別人的環境跟你的有可能不一樣,即便當時能夠解決問題,後面引發的問題,可能更加難以發現和解決。
還有我們遇到問題要多想,千萬不能自以爲是什麼什麼原因,要有事實依據,才能找到更好的解決方案
最後歡迎大家一起交流和學習。