網(wǎng)絡(luò)連接存在大量time_wait和close_wait的原因以及解決方法
如果對tcp中的握手揮手不了解的同學(xué),請先看這篇博客:《關(guān)于三次握手與四次揮手你要知道這些》。

四次揮手過程:
第一次揮手:主機(jī)A(可以是客戶端,也可以是服務(wù)器端),設(shè)置Sequence Number和Acknowledgment Number,向主機(jī)B發(fā)送一個FIN報文段;此時,主機(jī)A進(jìn)入FIN_WAIT_1狀態(tài);這表示主機(jī)A沒有數(shù)據(jù)要發(fā)送給主機(jī)B了。
第二次揮手:主機(jī)B收到了主機(jī)A發(fā)送的FIN報文段,向主機(jī)A回一個ACK報文段,Acknowledgment Number為Sequence Number加1,主機(jī)A進(jìn)入FIN_WAIT_2狀態(tài);主機(jī)B告訴主機(jī)A,我也沒有數(shù)據(jù)要發(fā)送了,可以進(jìn)行關(guān)閉連接了。
第三次揮手:主機(jī)B向主機(jī)A發(fā)送FIN報文段,請求關(guān)閉連接,同時主機(jī)B進(jìn)入CLOSE_WAIT狀態(tài)。
第四次揮手:主機(jī)A收到主機(jī)B發(fā)送的FIN報文段,向主機(jī)B發(fā)送ACK報文段,然后主機(jī)A進(jìn)入TIME_WAIT狀態(tài);主機(jī)B收到主機(jī)A的ACK報文段以后,就關(guān)閉連接;此時,主機(jī)A等待2MSL后依然沒有收到回復(fù),則證明主機(jī)B已正常關(guān)閉,那好,主機(jī)A也可以關(guān)閉連接了。
大量time_wait
問題原因
《關(guān)于三次握手與四次揮手你要知道這些》中有關(guān)于“四次揮手釋放連接時,等待2MSL的意義”的解釋。正因為有2ML的存在,所以可能會發(fā)生大量time_wait存在的現(xiàn)象,從而影響服務(wù)器性能,甚至導(dǎo)致套接字?jǐn)?shù)量達(dá)到服務(wù)器上限。
實際上,TIME_WAIT對于系統(tǒng)資源的消耗影響比較小,而真正需要考慮因為TIME_WAIT多而觸碰到限制的是如下幾個方面:
源端口數(shù)量 (net.ipv4.ip_local_port_range)
TIME_WAIT bucket 數(shù)量 (net.ipv4.tcp_max_tw_buckets)
文件描述符數(shù)量 (max open files)
解決方法
只需要優(yōu)化服務(wù)器系統(tǒng)的網(wǎng)絡(luò)配置,連接配置,使用socket重用或及時釋放資源即可。(由于系統(tǒng)不斷迭代,所以這里不給出具體參數(shù)修改)
大量close_wait
問題原因
主機(jī)B一直沒有進(jìn)行第三次揮手,會導(dǎo)致主機(jī)B存在大量close_wait狀態(tài)的連接。大量這種情況發(fā)生會影響服務(wù)器性能,同樣可能導(dǎo)致套接字?jǐn)?shù)量達(dá)到服務(wù)器上限。
網(wǎng)絡(luò)連接未及時釋放,通常是服務(wù)端發(fā)生異常后未關(guān)閉連接或者close_wait的配置時間過長。如果是mysql數(shù)據(jù)庫也可能存在事務(wù)開啟后沒有正確rollback或commit的可能。
總之,都是大概率是服務(wù)端代碼或配置的問題。
解決方法
以下方法并不存在順序,定位問題時也并不是一定同時需要。
top查看cpu利用率和load情況(大量close_wait屬于io密集型,會導(dǎo)致load相比cpu利用率高出很多)
netstat觀察close_wait的數(shù)量變化。
wireshark輔助查看網(wǎng)絡(luò)包的發(fā)送情況。
perf或者火焰圖定位熱點函數(shù)。
java可以將服務(wù)器線程堆棧dump,查看大量線程在哪里blocked。
