0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

TIME_WAIT狀態(tài)的優(yōu)化思路

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-10 10:44 ? 次閱讀
  1. 為什么需要TIME_WAIT狀態(tài)?為什么TIME_WAIT的時長是2*MSL?

原因1:防止連接關(guān)閉時四次揮手中的最后一次ACK丟失:

TCP需要保證每一包數(shù)據(jù)都可靠的到達(dá)對端,包括正常連接狀態(tài)下的業(yè)務(wù)數(shù)據(jù)報文,以及用于連接管理的握手、揮手報文,這其中在四次揮手中的最后一次ACK報文比較特殊,TIME_WAIT狀態(tài)就是為了應(yīng)對最后一條ACK丟失的情況。

TCP保證可靠傳輸?shù)那疤崾鞘瞻l(fā)兩端分別維護(hù)關(guān)于這條連接的狀態(tài)信息(TCB控制塊),當(dāng)發(fā)生丟包時進(jìn)行ARQ重傳。如果連接釋放了,就無法進(jìn)行重傳,也就無法保證發(fā)生丟包時的可靠傳輸。

對于最后一條ACK,如果沒有TIME_WAIT狀態(tài),主動關(guān)閉一方(客戶端)就會在收到對端(服務(wù)器)的FIN并回復(fù)ACK后 直接從FIN_WAIT_2 進(jìn)入 CLOSED狀態(tài),并釋放連接,銷毀TCB實例。此時如果最后一條ACK丟失,那么服務(wù)器重傳的FIN將無人處理,最后導(dǎo)致服務(wù)器長時間的處于 LAST_ACK狀態(tài)而無法正常關(guān)閉(服務(wù)器只能等到達(dá)到FIN的最大重傳次數(shù)后關(guān)閉)。

至于將TIME_WAIT的時長設(shè)置為 2MSL,是因為報文在鏈路中的最大生存時間為MSL(Maximum Segment Lifetime),超過這個時長后報文就會被丟棄。TIME_WAIT的時長則是:最后一次ACK傳輸?shù)椒?wù)器的時間 + 服務(wù)器重傳FIN 的時間,即為 2MSL。

原因2:防止新連接收到舊鏈接的TCP報文:

TCP使用四元組區(qū)分一個連接(源端口、目的端口、源IP、目的IP),如果新、舊連接的IP與端口號完全一致,則內(nèi)核協(xié)議棧無法區(qū)分這兩條連接。

2*MSL 的時間足以保證兩個方向上的數(shù)據(jù)都被丟棄,使得原來連接的數(shù)據(jù)包在網(wǎng)絡(luò)中都自然消失,再出現(xiàn)的數(shù)據(jù)包一定是新連接上產(chǎn)生的。

MSL(Maximum Segment Lifetime) 報文最大生存時間在不同操作系統(tǒng)中的具體值:

Windows : 2 min
Linux(Ubuntu) : 60 s
Unix : 30 s

2. TIME_WAIT對連接并發(fā)數(shù)的影響(TIME_WAIT過多的危害):

在Linux系統(tǒng)中,MSL = 60 s, 2 * MSL = 120 s,所以一條待關(guān)閉的TCP連接會在 TIME_WAIT 狀態(tài)等待 120秒(2分鐘)。

當(dāng)連接處于TIME_WAIT狀態(tài)時仍會占用系統(tǒng)資源(fd、端口、內(nèi)存),當(dāng)系統(tǒng)的并發(fā)連接數(shù)很大時,過多的TIME_WAIT狀態(tài)的連接會對系統(tǒng)的并發(fā)量造成影響。

(1)對服務(wù)器的影響:

由于服務(wù)器一般只需要監(jiān)聽一個固定的端口,所以服務(wù)器所能支持的最大并發(fā)出數(shù)的上限取決于系統(tǒng)套接字描述符fd的大小,以及服務(wù)器的內(nèi)存大小。

fd:

Linux中一個進(jìn)程 所能打開的fd的最大數(shù)量默認(rèn)為 1024 個,可通過 "ulimit -n (+指定數(shù)量)" 進(jìn)行修改。

Linux系統(tǒng)所能支持的fd最大值在 /proc/sys/fs/fd-max 文件中可以查看,系統(tǒng)當(dāng)前的fd使用情況可以通過 /proc/sys/fs/fd-nr 查看。(本機(jī)上的fd-max的值為:1221842,即100W級。實際上fd的最大值同樣也取決于系統(tǒng)內(nèi)存的大小)

內(nèi)存:

假設(shè)每一個TCP連接需要開辟 “4k的接收緩沖區(qū) + 4k的發(fā)送緩沖區(qū) = 8k”,1W的并發(fā)連接需要80M內(nèi)存,10W并發(fā)需要800M,100W并發(fā)需要8G內(nèi)存。

綜上,服務(wù)器的并發(fā)數(shù)主要受限于系統(tǒng)內(nèi)存的大小,當(dāng) TIME_WAIT 狀態(tài)的連接過多時,會導(dǎo)致消耗的內(nèi)存增加,這一點可以通過擴(kuò)展服務(wù)器的內(nèi)存來解決。

(2)對客戶端的影響:

客戶端的并發(fā)數(shù)主要受限于端口數(shù)量。

一種典型的場景是:高并發(fā)短連接(“短連接”表示“業(yè)務(wù)處理+傳輸數(shù)據(jù)”的時間遠(yuǎn)遠(yuǎn)小于TIME_WAIT超時的時間)。

在這種場景下,客戶端可能會消耗大量的端口(例如取一個Web網(wǎng)頁,1秒鐘的HTTP短連接處理完業(yè)務(wù)數(shù)據(jù),卻需要 2分鐘的TIME_WAIT等待時間,在這段時間內(nèi)客戶端上的這個端口是無法被其他連接使用的,如果新建連接則需要使用另外的端口號),Linux系統(tǒng)的最大端口為65535,除去系統(tǒng)使用的端口號,假設(shè)網(wǎng)絡(luò)進(jìn)程可使用的端口有 6W個,由于TIME_WAIT狀態(tài)下在 2*MSL(120秒)內(nèi)無法再被使用,這就限制了客戶端的連接速率為 60000 / 120秒 = 500 次/秒, 這是一個非常低的并發(fā)率。

同時,大量的TIME_WAIT連接同樣會消耗客戶端的內(nèi)存,所以客戶端的最大并發(fā)數(shù)取決于 端口號與內(nèi)存 二者中的最小值。

3. 優(yōu)化TIME_WAIT的方法:

方法1:修改內(nèi)核參數(shù) tcp_tw_reuse:

net.ipv4.tcp_tw_reuse = 1;
net.ipv4.tcp_timestamp = 1;

注意:tcp_tw_reuse 內(nèi)核參數(shù)只在調(diào)用 connect() 函數(shù)時起作用,所以只能用于客戶端(主動連接的一端)。

tcp_tw_reuse 的作用是:在調(diào)用connect()函數(shù)時,內(nèi)核會隨機(jī)找一個處于TIME_WAIT狀態(tài) 超過1秒 的連接給新連接復(fù)用。(超時時間由 tcp_timestamp設(shè)置,默認(rèn)為 1秒)

這種方式可以縮短 TIME_WAIT 的等待時間。

方法2:修改內(nèi)核參數(shù) tcp_max_tw_buckets:

net.ipv4.tcp_max_tw_buckets 參數(shù)的默認(rèn)值為18000,當(dāng)系統(tǒng)中處于 TIME_WAIT 狀態(tài)的連接數(shù)量超過閾值,系統(tǒng)會將后面的TIME_WAIT連接重置。

由于這種方法會直接重置連接,因此需要謹(jǐn)慎使用。

方法3:設(shè)置套接字選項 SO_LINGER:

SO_LINGER選項用于設(shè)置 調(diào)用close() 關(guān)閉TCP連接時的行為,注意 SO_LINGER選項會使用RST復(fù)位報文段取代 FIN-ACK四次揮手的過程,設(shè)置了SO_LINGER選項的一方在調(diào)用close() 時會直接發(fā)送一個RST,接收端收到后復(fù)位連接,不會回復(fù)任何響應(yīng)。

這樣做的弊端是導(dǎo)致TCP緩沖區(qū)中的數(shù)據(jù)被丟棄。

正常情況下,調(diào)用close后的缺省行為是:如果有待發(fā)送的數(shù)據(jù)殘留在發(fā)送緩沖區(qū)中,內(nèi)核協(xié)議棧將繼續(xù)將這些數(shù)據(jù)發(fā)送給接收端后才關(guān)閉連接,走正常的四次揮手流程;

設(shè)置SO_LINGER后,立即關(guān)閉連接,通過RST分組,發(fā)送緩沖區(qū)如果有未發(fā)送的數(shù)據(jù),將會被丟棄,主動關(guān)閉的一方跳過TIME_WAIT狀態(tài),直接進(jìn)入CLOSED(也跳過了FIN_WAIT_1 和 FIN_WAIT_2)。

SO_LINGER的另一種更溫和的實現(xiàn)方式是設(shè)置一個超時時間(so_linger.l_linger),而不是直接關(guān)閉。

應(yīng)用程序調(diào)用close后進(jìn)入睡眠,內(nèi)核協(xié)議棧負(fù)責(zé)發(fā)送緩沖中殘留的待發(fā)送數(shù)據(jù),如果在 l_linger 超時時間內(nèi)發(fā)送完畢,則走正常的四次揮手流程;如果超時未發(fā)送完,則發(fā)送RST強(qiáng)制關(guān)閉連接,并丟棄發(fā)送緩沖區(qū)中其余的數(shù)據(jù)(接收端收到RST后也會丟棄接收緩沖區(qū)中的數(shù)據(jù)),并且發(fā)送端close()函數(shù)返回 EWOULDBLOCK。

綜上,如果只是單純?yōu)榱艘?guī)避 TIME_WAIT 狀態(tài),使用 SO_LINGER并不是一個好主意,因為它會在調(diào)用close關(guān)閉連接時 使用RST強(qiáng)制關(guān)閉連接,這可能會導(dǎo)致 發(fā)送緩沖區(qū)、接收緩沖區(qū) 中還未處理完的數(shù)據(jù)被丟棄。

struct linger so_linger;
so_linger.l_onoff = 1; //0表示關(guān)閉,忽略l_linger的值;非0表示打開
so_linger.l_linger = 0; //設(shè)置等待時間,等于0則表示立即關(guān)閉

setsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));

方法4:設(shè)置套接字選項 SO_REUSEADDR:

SO_REUSEADDR 選項用于通知內(nèi)核:

如果端口忙,并且端口對應(yīng)的TCP連接狀態(tài)為TIME_WAIT,則可以重用端口;

如果端口忙,并且端口對應(yīng)的TCP連接處于其他狀態(tài)(非TIME_WAIT),則返回 “Address already in use” 的錯誤信息。

設(shè)置SO_REUSEADDR的風(fēng)險是可能會導(dǎo)致新連接上收到舊連接的數(shù)據(jù)(復(fù)用了舊連接的端口,導(dǎo)致新舊連接的四元組完全一致,內(nèi)核協(xié)議棧無法區(qū)分這兩個連接)。

SO_REUSEADDR 選項并沒像 tcp_tw_reuse 那樣同時提供一個 tcp_timestamp 參數(shù)可以設(shè)置 TIME_WAIT的等待時長。

綜上,對TIME_WAIT狀態(tài)的優(yōu)化思路是盡量縮小等待時長,而不是暴力的直接關(guān)閉(可能會引起新連接收到舊連接數(shù)據(jù)的風(fēng)險),也不要直接發(fā)送RST復(fù)位連接(可能會引起發(fā)送、接收緩沖區(qū)中的數(shù)據(jù)丟失),所以使用修改內(nèi)核參數(shù) tcp_tw_reuse 參數(shù)是最保險的方式,通過根據(jù)實際網(wǎng)絡(luò)情況和應(yīng)用場景適當(dāng)?shù)恼{(diào)節(jié) tcp_timestamp 的值,可以達(dá)到縮小 TIME_WAIT 等待時長,進(jìn)而減少系統(tǒng)中同一時刻處于 TIME_WAIT 狀態(tài)的連接數(shù)量的目的。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    6819

    瀏覽量

    88746
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    6689

    瀏覽量

    123141
  • TIME
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    14312
收藏 人收藏

    評論

    相關(guān)推薦

    CC3200 socket狀態(tài)如何查詢?

    已,正在等待本地套接字的關(guān)閉確認(rèn) FIN_WAIT_2 套接字已關(guān)閉,正在等待遠(yuǎn)程套接字關(guān)閉TIME_WAIT 這個套接字已經(jīng)關(guān)閉,正在等待遠(yuǎn)程套接字的關(guān)閉傳送
    發(fā)表于 05-06 11:00

    WEB CLOSE_WAIT socket不釋放如何解決呢

    :web連接過后發(fā)現(xiàn)有大量的TIME_WAIT狀態(tài)的socket,怎么限制WEB的并發(fā)數(shù)量,把rtConfig.h中的這個宏改小到多少合適呢?如果太小了會不會導(dǎo)致web登錄不了的情況?#define WEBNET_CONN_MAX 8
    發(fā)表于 09-27 10:06

    GPRS優(yōu)化思路總結(jié)報告

    GPRS優(yōu)化思路總結(jié)報告:一、概述 2二、無線優(yōu)化思路 2三、(E)GPRS網(wǎng)絡(luò)資源容量分析優(yōu)化 53.1、
    發(fā)表于 07-27 21:29 ?26次下載

    狀態(tài)機(jī)思路在單片機(jī)程序設(shè)計中的應(yīng)用

    狀態(tài)機(jī)思路在單片機(jī)程序設(shè)計中的應(yīng)用 狀態(tài)機(jī)的概念狀態(tài)機(jī)是軟件編程中的一個重要概念。比這個概念更重要的是對它的靈活應(yīng)用。在一個思路清晰而且高
    發(fā)表于 02-09 11:25 ?1w次閱讀
    <b class='flag-5'>狀態(tài)</b>機(jī)<b class='flag-5'>思路</b>在單片機(jī)程序設(shè)計中的應(yīng)用

    實時時鐘的選擇與優(yōu)化-Real-Time-Clock Sel

    Abstract: This application note describes real-time clock (RTC) and crystal selection criteria
    發(fā)表于 04-21 10:35 ?3481次閱讀
    實時時鐘的選擇與<b class='flag-5'>優(yōu)化</b>-Real-<b class='flag-5'>Time</b>-Clock Sel

    GPRS優(yōu)化思路總結(jié)報告_李青春

    (E)GPRS 優(yōu)化思路通信網(wǎng)絡(luò)優(yōu)化,GSM上網(wǎng),PDCH,EDGEGPRS.
    發(fā)表于 01-14 15:21 ?4次下載

    分析在java中sleep和wait的不同

    的監(jiān)控狀態(tài)依然保持者,當(dāng)指定的時間到了又會自動恢復(fù)運(yùn)行狀態(tài)。 在調(diào)用sleep()方法的過程中,線程不會釋放對象鎖。 而當(dāng)調(diào)用wait()方法的時候,線程會放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象調(diào)用notify(
    發(fā)表于 09-27 14:41 ?0次下載

    服務(wù)器產(chǎn)生大量的TIME_WAIT究竟是因為什么

    寫在開頭,大概 4 年前,聽到運(yùn)維同學(xué)提到 TIME_WAIT 狀態(tài)的 TCP 連接過多的問題,但是當(dāng)時沒有去細(xì)琢磨;最近又聽人說起,是一個新手進(jìn)行壓測過程中,遇到的問題,因此,花點時間,細(xì)深究一下
    的頭像 發(fā)表于 10-13 16:47 ?1.4w次閱讀
    服務(wù)器產(chǎn)生大量的<b class='flag-5'>TIME_WAIT</b>究竟是因為什么

    學(xué)習(xí)Linux命令的正確姿勢

    短時間后,所有的 TIME_WAIT 全都消失,被回收,端口包括服務(wù),均正常。即,在高并發(fā)的場景下,TIME_WAIT 連接存在,屬于正?,F(xiàn)象。
    的頭像 發(fā)表于 08-31 10:27 ?476次閱讀

    關(guān)于手動伺服優(yōu)化調(diào)整思路分享

    常規(guī)的伺服優(yōu)化調(diào)整一般需要用到SERVO GUIDE 軟件,而對于一些不是很懂該軟件操作的客戶或者在現(xiàn)場無法進(jìn)行在線聯(lián)網(wǎng)調(diào)整的情況下,手動調(diào)整就顯得比較關(guān)鍵實用,在此提供手動伺服優(yōu)化調(diào)整思路
    發(fā)表于 01-29 12:18 ?2502次閱讀

    圖解Java多線程中的wait()和notify()方法

    wait()和notify()是Object類的方法,用于線程的等待與喚醒,必須搭配synchronized 鎖來使用。
    的頭像 發(fā)表于 03-22 09:29 ?2578次閱讀

    KUKA機(jī)器人WAIT FOR運(yùn)用條件

    WAIT FOR … : 等至條件已滿足 WAITFOR 停止程序,直到已滿足特定的條件。然后程序繼續(xù)運(yùn)行。WAIT FOR 將觸發(fā)預(yù)進(jìn)停止。 編譯器識別不到由于錯誤的表達(dá)而使表達(dá)式無法采用數(shù)值
    的頭像 發(fā)表于 06-13 11:31 ?3047次閱讀

    TCP和UDP分別是什么 TCP和UDP協(xié)議各有什么特點

    在 TCP 四次揮手的最后一步,客戶端進(jìn)入 TIME_WAIT 狀態(tài),需要等待一段時間再進(jìn)入 CLOSED 狀態(tài)。等待時間通常是兩個最大報文段生命周期,即 2MSL,這是為了確保服務(wù)器端能夠收到客戶端發(fā)送的最后一個 ACK 報文
    的頭像 發(fā)表于 08-09 12:34 ?4264次閱讀

    TIME_WAIT是什么

    ,遇到了這道題目: 生產(chǎn)環(huán)境 Nginx 后端服務(wù)大量 TIME-WAIT 的解決步驟 這里小編給大家做一下系統(tǒng)化、體系化的梳理,使得大家可以充分展示一下大家雄厚的 “技術(shù)肌肉”,讓面試官愛到 “不能自已、口水直流”。 基礎(chǔ)知識 TIME_WAIT是什么? 在構(gòu)建TCP客
    的頭像 發(fā)表于 11-10 14:48 ?606次閱讀
    <b class='flag-5'>TIME_WAIT</b>是什么

    為什么要有TIME_WAIT狀態(tài)

    首先我們說下狀態(tài) TIME_WAIT 出現(xiàn)的原因 TCP的新建連接,斷開連接的流程和各個狀態(tài),如下圖所示 由上圖可知:TIME_WAIT 是主動斷開連接的一方會出現(xiàn)的,客戶端,服務(wù)器都
    的頭像 發(fā)表于 11-13 11:26 ?1908次閱讀
    為什么要有<b class='flag-5'>TIME_WAIT</b><b class='flag-5'>狀態(tài)</b>