最近線上出現(xiàn)請求調(diào)用502的問題,A服務(wù)調(diào)用B服務(wù)偶然拋502錯誤,出現(xiàn)的頻率也比較低。排查問題發(fā)現(xiàn)是請求的TIME_WAIT狀態(tài)過多造成的。
什么是TIME_WAIT?

TIME_WAIT: TCP關(guān)閉連接中請求的發(fā)起方收到了接收方的FIN報文,并發(fā)送出了ACK報文,這時進入TIME_WAIT狀態(tài),2MSL后變成CLOSED狀態(tài)了。
TIME_WAIT的作用是什么
(1)在進行關(guān)閉連接四路握手協(xié)議時,最后的ACK是由主動關(guān)閉端發(fā)出的,如果這個最終的ACK丟失,服務(wù)器將重發(fā)最終的FIN,因此客戶端必須維護狀態(tài)信息允 許它重發(fā)最終的ACK。如果不維持這個狀態(tài)信息,那么客戶端將響應(yīng)RST分節(jié),服務(wù)器將此分節(jié)解釋成一個錯誤(在java中會拋出connection reset的SocketException)。因而,要實現(xiàn)TCP全雙工連接的正常終止,必須處理終止序列四個分節(jié)中任何一個分節(jié)的丟失情況,主動關(guān)閉 的客戶端必須維持狀態(tài)信息進入TIME_WAIT狀態(tài)。
(2)允許老的重復(fù)分節(jié)在網(wǎng)絡(luò)中消逝
TCP分節(jié)可能由于路由器異常而“迷途”,在迷途期間,TCP發(fā)送端可能因確認超時而重發(fā)這個分節(jié),迷途的分節(jié)在路由器修復(fù)后也會被送到最終目的地,這個 原來的迷途分節(jié)就稱為lost duplicate。在關(guān)閉一個TCP連接后,馬上又重新建立起一個相同的IP地址和端口之間的TCP連接,后一個連接被稱為前一個連接的化身 (incarnation),那么有可能出現(xiàn)這種情況,前一個連接的迷途重復(fù)分組在前一個連接終止后出現(xiàn),從而被誤解成從屬于新的化身。為了避免這個情 況,TCP不允許處于TIME_WAIT狀態(tài)的連接啟動一個新的化身,因為TIME_WAIT狀態(tài)持續(xù)2MSL,就可以保證當成功建立一個TCP連接的時 候,來自連接先前化身的重復(fù)分組已經(jīng)在網(wǎng)絡(luò)中消逝。
如何解決TIME_WAIT過多問題
在只有一臺客戶端和一臺web服務(wù)器的情況下。構(gòu)建一條TCP連接需要四個值
<源IP地址 ,源端口,目標IP地址,目的端口> ,其中三個都是固定的,只有源端口號是可以改變的。
客戶端每次請求服務(wù)端的時候,都會獲取一個新的源端口,以實現(xiàn)連接的唯一性。但由于原端口的數(shù)量是有限的(如果僅有6000個),而且在2MSL(等于120)秒內(nèi)無法重復(fù)使用.因此最大連接并發(fā)數(shù)為6000/120=500次/秒。
因此解決問題的方法可以分為三種:
1:使端口可重復(fù)使用
2:減少TIME_WAIT的等待時間
3:使用負載均衡策略,增加可用端口
如發(fā)現(xiàn)系統(tǒng)存在大量TIME_WAIT狀態(tài)的連接,通過調(diào)整內(nèi)核參數(shù)解決:
編輯文件/etc/sysctl.conf,加入以下內(nèi)容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 1024 65000
然后執(zhí)行 /sbin/sysctl -p 讓參數(shù)生效。
net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現(xiàn)SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關(guān)閉;
net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0,表示關(guān)閉;
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關(guān)閉。
net.ipv4.tcp_fin_timeout 修改系默認的 TIMEOUT 時間
net.ipv4.ip_local_port_range = 1024 65000 表示用于向外連接的端口范圍