TIME_WAIT 問題解決

TIME_WAIT 的問題

應(yīng)用服務(wù)器需要通過發(fā)起 TCP 連接其他服務(wù)器,比如 代理服務(wù)器需要請(qǐng)求上游服務(wù)器,每個(gè)連接會(huì)占用一個(gè)port,在高并發(fā)場景下,可能會(huì)導(dǎo)致端口耗盡。為了TCP正常斷開連接,TCP 發(fā)起揮手的一端為了確保最后一個(gè)ACK 能夠達(dá)到被動(dòng)關(guān)閉方,所以會(huì)等待 2MSL。


MSL (maximum segment lifetime):LINUX 的硬編碼字段,名稱為 TCP_TIMEWAIT_LEN,值為60s,而一個(gè)time_wait 默認(rèn)等待的時(shí)間為 2MSL


TIME_WAIT 的危害

  • 內(nèi)存資源占用,內(nèi)存資源的占用不是很嚴(yán)重,可暫且忽略
  • 端口資源占用,一個(gè)TCP連接需要消耗一個(gè)本地端口,一般可開啟的端口為32768 ~ 61000。

如何優(yōu)化

net.ipv4.ip_local_port_range

制定主動(dòng)建聯(lián)時(shí)的端口范圍

net.ipv4.tcp_max_tw_buckets

此值默認(rèn)是 18000,當(dāng)系統(tǒng)中處于 TIME_WAIT 的連接大于該值后,系統(tǒng)會(huì)將所有的 TIME_WAIT 連接重置,并打印出警告信息。這個(gè)方法過于暴力,解決的問題比帶來的問題多,不建議使用

調(diào)低 TCP_TIMEWAIT_LEN,重新編譯系統(tǒng)

得編譯內(nèi)核,而且TCP發(fā)明至今這些固化到內(nèi)核的參數(shù)都是有一定道理的,不要亂改。

SO_LINGER 設(shè)置

在應(yīng)用程序中設(shè)置套接字選項(xiàng),調(diào)用close 或者 shutdown 關(guān)閉連接時(shí)候的行為。

int setsockopt(int sockfd, int level, int optname, const void *optval,
        socklen_t optlen);
struct linger {
 int  l_onoff;    /* 0=off, nonzero=on */
 int  l_linger;    /* linger time, POSIX specifies units as seconds */
}
  • l_onoff: linger 的開關(guān)
    • l_onoff 為 0:關(guān)閉linger 選項(xiàng),默認(rèn)行為,close 或 shutdown 立即返回,如果在套接字發(fā)送緩沖區(qū)有數(shù)據(jù)殘留,系統(tǒng)會(huì)將試著把這些數(shù)據(jù)都發(fā)送出去
    • l_onoff 為 1:打開linger 選項(xiàng),具體行為看 l_linger
      • l_linger 為0:調(diào)用close后,立即發(fā)送一個(gè)RST標(biāo)志給對(duì)端,該TCP跳過四次揮手,直接關(guān)閉,這種方式被稱為“強(qiáng)行關(guān)閉”,這種情況下,排隊(duì)的數(shù)據(jù)不會(huì)被發(fā)送,被動(dòng)關(guān)閉方也不知道對(duì)端已經(jīng)徹底斷開,只有當(dāng)被動(dòng)關(guān)閉方正阻塞在recv() 調(diào)用上,接受到 RST 時(shí),會(huì)立刻得到一個(gè) “connect reset by peer”的異常。
      • l_linger 為1:調(diào)用close后,調(diào)用close的線程將阻塞,直到數(shù)據(jù)都被發(fā)送出去,或者設(shè)置 l_linger 的計(jì)時(shí)時(shí)間到。

net.ipv4.tcp_tw_reuse : 更安全的設(shè)置

Linux 對(duì) net.ipv4_tw_reuse的解析如下:

Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. Default value is 0.It should not be changed without advice/request of technical experts.

這段話意思是說從協(xié)議角度理解如果是安全的話,可以復(fù)用處于 TIME_WAIT 的套接字為新的連接所用。

協(xié)議角度 的安全是指:

  1. 只適用與連接的發(fā)起方,即客戶端
  2. 對(duì)應(yīng)的TIME_WAIT 狀態(tài)的連接創(chuàng)建時(shí)間超過1s才可以被復(fù)用

使用的這個(gè)選項(xiàng)的前提,需要打開對(duì)TCP時(shí)間戳的支持。
即 net.ipv4.tcp_timestamps = 1 (默認(rèn)即為1),重復(fù)的數(shù)據(jù)包會(huì)因?yàn)闀r(shí)間戳過期被自然丟棄。

SO_REUSEADDR

這個(gè)比較特殊,網(wǎng)上有很多教程都說拿這個(gè)解決 TIME_WAIT,其實(shí)是對(duì)的,但是不是一回事。為什么?
這個(gè)是解決端口復(fù)用問題的,并不是解決 TIME_WAIT ,這個(gè)是告訴內(nèi)核,即使TIME_WAIT 的套接字,也可以作為新的套接字使用,這是為了避免服務(wù)端監(jiān)聽端口時(shí),因?yàn)楸槐O(jiān)聽的端口處于 TIME_WAIT 導(dǎo)致服務(wù)端無法啟動(dòng)。
其本質(zhì)是解決 服務(wù)端 監(jiān)聽端口時(shí)的 TIME_WAIT ,而我們上面一直說的是作為客戶端建聯(lián)時(shí)沒有足夠的隨機(jī)端口導(dǎo)致的無法建聯(lián)。

終極解決方案: 長連接

條件允許的,把連接保持住,避免頻繁的建連和斷開。但是僅限內(nèi)網(wǎng)這么搞,公網(wǎng)的話,一條連接總是不斷,運(yùn)營商可能會(huì)搞些小動(dòng)作,給你限個(gè)速。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容