【校招面試】你必須要知道的TIME_WAIT和CLOSE_WAIT細節(jié)

TCP狀態(tài)機里為何需要TIME_WAIT

如果我們來做個類比的話擦俐,TIME_WAIT的出現(xiàn)脸哀,對應的是你的程序里的異常處理凰狞,它的出現(xiàn)吨拗,就是為了解決網(wǎng)絡的丟包和網(wǎng)絡不穩(wěn)定所帶來的其他問題:

第一,防止前一個連接【五元組歉胶,我們以180.172.35.150:45678, tcp, 180.97.33.108:80 為例】上延遲的數(shù)據(jù)包或者丟失重傳的數(shù)據(jù)包汛兜,被后面復用的連接【前一個連接關(guān)閉后,此時你再次訪問百度通今,新的連接可能還是由180.172.35.150:45678, tcp, 180.97.33.108:80 這個五元組來表示粥谬,也就是源端口湊巧還是45678】錯誤的接收(異常:數(shù)據(jù)丟了,或者傳輸太慢了)辫塌,參見下圖:


復雜的愛恨交加

SEQ=3的數(shù)據(jù)包丟失漏策,重傳第一次,沒有得到ACK確認

如果沒有TIME_WAIT臼氨,或者TIME_WAIT時間非常端掺喻,那么關(guān)閉的連接【180.172.35.150:45678, tcp, 180.97.33.108:80 的狀態(tài)變?yōu)榱薈LOSED,源端口可被再次利用】,馬上被重用【對180.97.33.108:80新建的連接感耙,復用了之前的隨機端口45678】褂乍,并連續(xù)發(fā)送SEQ=1,2 的數(shù)據(jù)包

此時,前面的連接上的SEQ=3的數(shù)據(jù)包再次重傳即硼,同時逃片,seq的序號剛好也是3(這個很重要,不然只酥,SEQ的序號對不上褥实,就會RST掉),此時裂允,前面一個連接上的數(shù)據(jù)被后面的一個連接錯誤的接收

第二损离,確保連接方能在時間范圍內(nèi),關(guān)閉自己的連接绝编。其實僻澎,也是因為丟包造成的,參見下圖:

還是復雜的愛恨交加

主動關(guān)閉方關(guān)閉了連接瓮增,發(fā)送了FIN怎棱;

被動關(guān)閉方回復ACK同時也執(zhí)行關(guān)閉動作,發(fā)送FIN包绷跑;此時拳恋,被動關(guān)閉的一方進入LAST_ACK狀態(tài)

主動關(guān)閉的一方回去了ACK,主動關(guān)閉一方進入TIME_WAIT狀態(tài)砸捏;

但是最后的ACK丟失谬运,被動關(guān)閉的一方還繼續(xù)停留在LAST_ACK狀態(tài)

此時,如果沒有TIME_WAIT的存在垦藏,或者說梆暖,停留在TIME_WAIT上的時間很短,則主動關(guān)閉的一方很快就進入了CLOSED狀態(tài)掂骏,也即是說轰驳,如果此時新建一個連接,源隨機端口如果被復用弟灼,在connect發(fā)送SYN包后级解,由于被動方仍認為這條連接【五元組】還在等待ACK,但是卻收到了SYN田绑,則被動方會回復RST

造成主動創(chuàng)建連接的一方勤哗,由于收到了RST,則連接無法成功

所以掩驱,你看到了芒划,TIME_WAIT的存在是很重要的冬竟,如果強制忽略TIME_WAIT,還是有很高的機率民逼,造成數(shù)據(jù)粗亂泵殴,或者短暫性的連接失敗。


你遇到過TIME_WAIT的問題嗎缴挖?

我相信很多都遇到過這個問題袋狞。一旦有用戶在喊:網(wǎng)絡變慢了焚辅。第一件事情就是映屋,通過netstat -a | grep -i TIME_WAIT | wc -l? 完成統(tǒng)計⊥撸或者ss -tan 'sport = :80' | awk '{print $(NF)" "$(NF-1)}' | sed 's/:[^ ]*//g' | sort | uniq -c進行(ss升級版的netstat)棚点。

然后,做的第一件事情就是:打開Google輸入關(guān)鍵詞:too many time wait湾蔓。一定能找到解決方案瘫析,而排在最前面或者被很多人到處轉(zhuǎn)載的解決方案一定是:

打開 sysctl.conf 文件,修改以下幾個參數(shù):

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_timestamps = 1

你也會被告知默责,開啟tw_recylce和tw_reuse一定需要timestamps的支持贬循,而且這些配置一般不建議開啟,但是對解決TIME_WAIT很多的問題桃序,有很好的用處杖虾。

接下來,你就直接修改了這幾個參數(shù)媒熊,reload一下奇适,發(fā)現(xiàn),咦芦鳍,沒幾分鐘嚷往,TIME_WAIT的數(shù)量真的降低了,也沒發(fā)現(xiàn)哪個用戶說有問題柠衅,然后就沒有然后了皮仁。

做到這一步,相信50%或者更高比例的開發(fā)就已經(jīng)止步了菲宴。問題好像解決了贷祈,但是,要徹底理解并解決這個問題裙顽,可能就沒這么簡單付燥,或者說,還有很長的路要走愈犹!

什么是TIME-WAIT和CLOSE-WAIT?

所謂键科,要解決問題闻丑,就要先理解問題。隨便改兩行代碼勋颖,發(fā)現(xiàn)bug“沒有了”嗦嗡,也不是bug真的沒有了,只是隱藏在更深的地方饭玲,你沒有發(fā)現(xiàn)侥祭,或者以你的知識水平,你無法發(fā)現(xiàn)而已茄厘。

大家知道矮冬,由于socket是全雙工的工作模式,一個socket的關(guān)閉次哈,是需要四次握手來完成的胎署。

主動關(guān)閉連接的一方,調(diào)用close()窑滞;協(xié)議層發(fā)送FIN包

被動關(guān)閉的一方收到FIN包后琼牧,協(xié)議層回復ACK;然后被動關(guān)閉的一方哀卫,進入CLOSE_WAIT狀態(tài)巨坊,主動關(guān)閉的一方等待對方關(guān)閉,則進入FIN_WAIT_2狀態(tài)此改;此時趾撵,主動關(guān)閉的一方 等待 被動關(guān)閉一方的應用程序,調(diào)用close操作

被動關(guān)閉的一方在完成所有數(shù)據(jù)發(fā)送后带斑,調(diào)用close()操作鼓寺;此時,協(xié)議層發(fā)送FIN包給主動關(guān)閉的一方勋磕,等待對方的ACK妈候,被動關(guān)閉的一方進入LAST_ACK狀態(tài)

主動關(guān)閉的一方收到FIN包挂滓,協(xié)議層回復ACK苦银;此時,主動關(guān)閉連接的一方赶站,進入TIME_WAIT狀態(tài)幔虏;而被動關(guān)閉的一方,進入CLOSED狀態(tài)

等待2MSL時間贝椿,主動關(guān)閉的一方想括,結(jié)束TIME_WAIT,進入CLOSED狀態(tài)

通過上面的一次socket關(guān)閉操作烙博,你可以得出以下幾點:

主動關(guān)閉連接的一方 - 也就是主動調(diào)用socket的close操作的一方瑟蜈,最終會進入TIME_WAIT狀態(tài)

被動關(guān)閉連接的一方烟逊,有一個中間狀態(tài),即CLOSE_WAIT铺根,因為協(xié)議層在等待上層的應用程序宪躯,主動調(diào)用close操作后才主動關(guān)閉這條連接

TIME_WAIT會默認等待2MSL時間后,才最終進入CLOSED狀態(tài)位迂;

在一個連接沒有進入CLOSED狀態(tài)之前访雪,這個連接是不能被重用的!

所以掂林,這里憑你的直覺臣缀,TIME_WAIT并不可怕(not really,后面講)党饮,CLOSE_WAIT才可怕肝陪,因為CLOSE_WAIT很多,表示說要么是你的應用程序?qū)懙挠袉栴}刑顺,沒有合適的關(guān)閉socket;要么是說饲常,你的服務器CPU處理不過來(CPU太忙)或者你的應用程序一直睡眠到其它地方(鎖蹲堂,或者文件I/O等等),你的應用程序獲得不到合適的調(diào)度時間贝淤,造成你的程序沒法真正的執(zhí)行close操作柒竞。

這里又出現(xiàn)兩個問題:

問題一:上文提到的連接重用,那連接到底是個什么概念播聪?

問題二:見本文第一部分朽基,既然我們明白確實需要TIME_WAIT里,但是這個狀態(tài)為什么默認等待2MSL時間才會進入CLOSED

先解釋清楚這兩個問題离陶,我們再來看稼虎,開頭提到的幾個網(wǎng)絡配置究竟有什么用,以及TIME_WAIT的后遺癥問題招刨。

好吧霎俩,問題真多。

嗯沉眶,有這些問題打却,恰恰說明你對這塊的學習沒問題。好了谎倔,我們不浪費彼此約會時間了柳击,Go on!

第一個問題片习,?具體先看看校招收割9個大offer的作者講解何為socket

第二個問題捌肴,為什么說彤守,TIME_WAIT狀態(tài)會是持續(xù)2MSL(2倍的max segment lifetime)呢?

簡而言之:

第一哭靖,為了保證 A 發(fā)送的最后一個 ACK 報文段能夠到達 B具垫。

第二,防止 “已失效的連接請求報文段”出現(xiàn)在本連接中试幽。A 在發(fā)送完最后一個 ACK 報文段后筝蚕,再經(jīng)過時間 2MSL,就可以使本連接持續(xù)的時間內(nèi)所產(chǎn)生的所有報文段铺坞,都從網(wǎng)絡中消失起宽。這樣就可以使下一個新的連接中不會出現(xiàn)這種舊的連接請求報文段。

哥這個犀利解釋還不夠济榨,行坯沪,咱不放棄不拋棄。

這個時間可以通過修改內(nèi)核參數(shù)調(diào)整嗎擒滑?第一腐晾,這個2MSL,是RFC 793里定義的丐一,參見RFC的截圖標紅的部分:

TCP有限狀態(tài)機

這個定義藻糖,更多的是一種保障(IP數(shù)據(jù)包里的TTL,即數(shù)據(jù)最多存活的跳數(shù)库车,真正反應的才是數(shù)據(jù)在網(wǎng)絡上的存活時間)巨柒,確保最后丟失了ACK,被動關(guān)閉的一方再次重發(fā)FIN并等待回復的ACK柠衍,一來一去兩個來回洋满。內(nèi)核里,寫死了這個MSL的時間為:30秒(有讀者提醒珍坊,RFC里建議的MSL其實是2分鐘牺勾,但是很多實現(xiàn)都是30秒),所以TIME_WAIT的即為1分鐘:

TIME_WAIT

所以垫蛆,再次回想一下前面的問題禽最,如果一條連接,即使在四次握手關(guān)閉了袱饭,由于TIME_WAIT的存在川无,這個連接,在1分鐘之內(nèi)虑乖,也無法再次被復用懦趋,那么,如果你用一臺機器做壓測的客戶端疹味,你一分鐘能發(fā)送多少并發(fā)連接請求仅叫?如果這臺是一個負載均衡服務器帜篇,一臺負載均衡服務器,一分鐘可以有多少個連接同時訪問后端的服務器呢诫咱?

還不夠看笙隙?我的小心臟(內(nèi)核)不都敞開給你了嘛,老流氓坎缭。竟痰。。

讓你一次看個夠掏呼,給你我所有

TIME_WAIT很多坏快,可怕嗎?

如果你通過ss -tan state time-wait | wc -l發(fā)現(xiàn)憎夷,系統(tǒng)中有很多TIME_WAIT莽鸿,很多人都會緊張。多少算多呢拾给?幾百幾千祥得?如果是這個量級,其實真的沒必要緊張鸣戴。第一啃沪,這個量級,因為TIME_WAIT所占用的內(nèi)存很少很少;因為記錄和尋找可用的local port所消耗的CPU也基本可以忽略讹躯。

會占用內(nèi)存嗎宅楞?當然任何你可以看到的數(shù)據(jù)荆姆,內(nèi)核里都需要有相關(guān)的數(shù)據(jù)結(jié)構(gòu)來保存這個數(shù)據(jù)啊。保持大量的連接時,當多為每一連接多保留1分鐘疏之,就會多消耗一些服務器的內(nèi)存。舉個栗子暇咆,如果服務器每秒處理了1W個新的TCP連接锋爪,那么服務器一分鐘將會有1W/s*60s = 60W個TIME_WAIT狀態(tài)的TCP連接,那這將會占用多大的內(nèi)存么爸业?

????首先其骄,從應用的角度來看,一個TIME_WAIT狀態(tài)的socket不會消耗任何內(nèi)存:socket已經(jīng)關(guān)了扯旷。在內(nèi)核中拯爽,TIME-WAIT狀態(tài)的socket,對于三種不同的作用钧忽,有三個不同的結(jié)構(gòu)毯炮。

(1)“TCP established hash table”的連接存儲哈希表(包括其他非established狀態(tài)的連接)逼肯,當有新的數(shù)據(jù)包發(fā)來時,是用來定位查找存活狀態(tài)的連接的桃煎。該哈希表的bucket包含了TIME_WAIT狀態(tài)的socket以及正忱捍保活躍的socket。該哈希表的大小为迈,取決于操作系統(tǒng)內(nèi)存大小三椿。在系統(tǒng)引導時,會打印出來曲尸,dmesg日志中可以看到赋续。

主要用于有新的數(shù)據(jù)到來的時候,從這個hash table里快速找到這條連接另患。不同的內(nèi)核對這個hash table的大小設(shè)置不同纽乱,你可以通過dmesg命令去找到你的內(nèi)核設(shè)置的大小:

認真看

這個數(shù)值昆箕,有可能被kernel啟動參數(shù)thash_entries(設(shè)置TCP連接哈希表的最大數(shù)目)的改動而將其覆蓋鸦列。在該hash的bucket中,每個TIME-WAIT狀態(tài)的socket鹏倘,對應一個tcp_timewait_sock結(jié)構(gòu)體薯嗤,其他狀態(tài)的socket則對應tcp_sock結(jié)構(gòu)體。

struct tcp_timewait_sock?{

struct inet_timewait_sock tw_sk;

u32 tw_rcv_nxt;

u32 tw_snd_nxt;

u32 tw_rcv_wnd;

u32 tw_ts_offset;

u32 tw_ts_recent;

long tw_ts_recent_stamp;

};

struct inet_timewait_sock?{

struct sock_common __tw_common;

int?tw_timeout;

volatile unsigned char tw_substate;

unsigned char tw_rcv_wscale;

__be16 tw_sport;

unsigned?int?tw_ipv6only?:?1,

tw_transparent?:?1,

tw_pad?:?6,

tw_tos?:?8,

tw_ipv6_offset?:?16;

unsigned long tw_ttd;

struct inet_bind_bucket?*tw_tb;

struct hlist_node tw_death_node;

};

(2)?有一組叫做“death row”的鏈表纤泵,是用來終止TIME_WAIT狀態(tài)的連接(socket)的骆姐,鏈表上的連接根據(jù)TIME_WAIT的剩余時間按照由小到大排序,鏈表中的元素則直接復用hash表中的對應元素(所以沒有更多的消耗內(nèi)存)捏题,即結(jié)構(gòu)體inet_timewait_sock中的hlist_node tw_death_node成員玻褪,如上代碼的倒數(shù)第二行。

(3)還有一個hash table用來保存所有的bound ports公荧,即存放調(diào)用后bind函數(shù)的port即其相關(guān)參數(shù)带射。這個hash表的主要作用就是當需要動態(tài)綁定端口時,提供一個可用的port或者隨機端口循狰。這個hash所用的內(nèi)存也可從系統(tǒng)的啟動日志中查到::

再認真看

這個hash表的每個元素都是inet_bind_socket結(jié)構(gòu)體窟社。每個調(diào)用過bind的端口都會有一個元素。對于web服務器來說绪钥,它綁定的是80端口灿里,其TIME-WAIT連接都是共享同一個entry的。對于連接遠程服務器的客戶端來說昧识,他們的端口都是調(diào)用connect時隨機分配的钠四,并不在hash表中占用元素(沒有調(diào)用過bind)。所以,TIME_WAIT狀態(tài)有關(guān)的結(jié)構(gòu)只有結(jié)構(gòu)體tcp_timewait_sock結(jié)構(gòu)體inet_bind_socket缀去。每一個TIME_WAIT狀態(tài)的連接都要消耗一個tcp_timewait_sock結(jié)構(gòu)侣灶,而只有服務端的TIME_WAIT狀態(tài)采用消耗一個inet_bind_socket結(jié)構(gòu)。

???tcp_timewait_sock結(jié)構(gòu)體的大小只有168 bytes缕碎,inet_bind_socket結(jié)構(gòu)體為48bytes褥影。所以,當服務器上有4W個連進來的連接進入TIME-WAIT狀態(tài)時咏雌,才用了10MB不到的內(nèi)存凡怎。而如果作為客戶端有4W個連接到遠程的連接進入TIME-WAIT狀態(tài)時,才用了2.5MB的內(nèi)存赊抖。

由于內(nèi)核需要保存這些數(shù)據(jù)统倒,必然,會占用一定的內(nèi)存氛雪。別擔心房匆,少年,沒那么多报亩。

會消耗CPU嗎浴鸿?當然!每次找到一個隨機端口弦追,還是需要遍歷一遍bound ports的吧岳链,這必然需要一些CPU時間。

TIME_WAIT很多劲件,既占內(nèi)存又消耗CPU掸哑,這也是為什么很多人,看到TIME_WAIT很多零远,就蠢蠢欲動的想去干掉他們举户。其實,如果你再進一步去研究遍烦,1萬條TIME_WAIT的連接,也就多消耗1M左右的內(nèi)存躺枕,對現(xiàn)代的很多服務器服猪,已經(jīng)不算什么了。至于CPU拐云,能減少它當然更好罢猪,但是不至于因為1萬多個hash item就擔憂。


閑扯了這么多叉瘩,那么如何避免或者減小TIME_WAIT的影響呢膳帕?

1.禁用socket延遲關(guān)閉

????通常情況當close被調(diào)用時,SOCKET需要延遲關(guān)閉(lingering),在內(nèi)核buffers中的殘留數(shù)據(jù)將會發(fā)送到遠程地址危彩,同時攒磨,socket會切換到TIME-WAIT狀態(tài)。如果禁用此選項汤徽,則調(diào)用close之后娩缰,底層也會關(guān)閉,不會將Buffers中殘留數(shù)據(jù)未發(fā)送的數(shù)據(jù)繼續(xù)發(fā)送谒府。關(guān)于socket lingering?延遲關(guān)閉拼坎,會有以下兩種行為(具體和設(shè)置參數(shù)有關(guān)):

(1)close函數(shù)后,并不會在發(fā)送FIN分節(jié)完疫,取而代之的是發(fā)送RST分節(jié)泰鸡,而在buffers任何殘留數(shù)據(jù)都會被丟棄。在這種做法中壳鹤,不會再有TIME-WAIT狀態(tài)的SOCKET出現(xiàn)盛龄。

(2)如果當調(diào)用close函數(shù)后,socket發(fā)送buffer中仍然有殘留數(shù)據(jù)器虾,此進程將會休眠讯嫂,直到所有數(shù)據(jù)都發(fā)送完成并確認,或者所配置的linger計時器過期了兆沙。這個機制確保殘留數(shù)據(jù)在配置的超時時間內(nèi)都發(fā)送出去欧芽。 如果數(shù)據(jù)正常發(fā)送出去,F(xiàn)IN包也正常發(fā)送葛圃,那么將會轉(zhuǎn)換為TIME-WAIT狀態(tài)千扔。其他異常情況下,則會發(fā)送RST库正。

2.禁用net.ipv4.tcp_tw_reuse

3.禁用net.ipv4.tcp_tw_recycle

好吧曲楚,該說的不該說的,我都說了褥符。如果龙誊,你真的想去調(diào)優(yōu),還是需要搞清楚別人的調(diào)優(yōu)建議喷楣,以及調(diào)優(yōu)參數(shù)背后的意義趟大!

TIME_WAIT調(diào)優(yōu),你必須理解的幾個調(diào)優(yōu)參數(shù)

在具體的圖例之前铣焊,我們還是先解析一下相關(guān)的幾個參數(shù)存在的意義逊朽。

net.ipv4.tcp_timestamps

RFC 1323 在 TCP?Reliability一節(jié)里,引入了timestamp的TCP option曲伊,兩個4字節(jié)的時間戳字段叽讳,其中第一個4字節(jié)字段用來保存發(fā)送該數(shù)據(jù)包的時間,第二個4字節(jié)字段用來保存最近一次接收對方發(fā)送到數(shù)據(jù)的時間。有了這兩個時間字段岛蚤,也就有了后續(xù)優(yōu)化的余地邑狸。

tcp_tw_reuse 和 tcp_tw_recycle就依賴這些時間字段。

net.ipv4.tcp_tw_reuse

字面意思灭美,reuse TIME_WAIT狀態(tài)的連接推溃。

時刻記住一條socket連接,就是那個五元組届腐,出現(xiàn)TIME_WAIT狀態(tài)的連接铁坎,一定出現(xiàn)在主動關(guān)閉連接的一方。所以犁苏,當主動關(guān)閉連接的一方硬萍,再次向?qū)Ψ桨l(fā)起連接請求的時候(例如,客戶端關(guān)閉連接围详,客戶端再次連接服務端朴乖,此時可以復用了;負載均衡服務器助赞,主動關(guān)閉后端的連接买羞,當有新的HTTP請求,負載均衡服務器再次連接后端服務器雹食,此時也可以復用)畜普,可以復用TIME_WAIT狀態(tài)的連接。

通過字面解釋群叶,以及例子說明吃挑,你看到了,tcp_tw_reuse應用的場景:某一方街立,需要不斷的通過“短連接”連接其他服務器舶衬,總是自己先關(guān)閉連接(TIME_WAIT在自己這方),關(guān)閉后又不斷的重新連接對方赎离。

那么逛犹,當連接被復用了之后,延遲或者重發(fā)的數(shù)據(jù)包到達梁剔,新的連接怎么判斷圾浅,到達的數(shù)據(jù)是屬于復用后的連接,還是復用前的連接呢憾朴?那就需要依賴前面提到的兩個時間字段了。復用連接后喷鸽,這條連接的時間被更新為當前的時間众雷,當延遲的數(shù)據(jù)達到,延遲數(shù)據(jù)的時間是小于新連接的時間,所以砾省,內(nèi)核可以通過時間判斷出鸡岗,延遲的數(shù)據(jù)可以安全的丟棄掉了。

這個配置编兄,依賴于連接雙方轩性,同時對timestamps的支持。同時狠鸳,這個配置揣苏,僅僅影響outbound連接,即做為客戶端的角色件舵,連接服務端[connect(dest_ip, dest_port)]時復用TIME_WAIT的socket卸察。

net.ipv4.tcp_tw_recycle

字面意思,銷毀掉 TIME_WAIT铅祸。

當開啟了這個配置后坑质,內(nèi)核會快速的回收處于TIME_WAIT狀態(tài)的socket連接。多快临梗?不再是2MSL涡扼,而是一個RTO(retransmission timeout,數(shù)據(jù)包重傳的timeout時間)的時間盟庞,這個時間根據(jù)RTT動態(tài)計算出來吃沪,但是遠小于2MSL。

有了這個配置茫经,還是需要保障 丟失重傳或者延遲的數(shù)據(jù)包巷波,不會被新的連接(注意,這里不再是復用了卸伞,而是之前處于TIME_WAIT狀態(tài)的連接已經(jīng)被destroy掉了抹镊,新的連接,剛好是和某一個被destroy掉的連接使用了相同的五元組而已)所錯誤的接收荤傲。在啟用該配置垮耳,當一個socket連接進入TIME_WAIT狀態(tài)后,內(nèi)核里會記錄包括該socket連接對應的五元組中的對方IP等在內(nèi)的一些統(tǒng)計數(shù)據(jù)遂黍,當然也包括從該對方IP所接收到的最近的一次數(shù)據(jù)包時間终佛。當有新的數(shù)據(jù)包到達,只要時間晚于內(nèi)核記錄的這個時間雾家,數(shù)據(jù)包都會被統(tǒng)統(tǒng)的丟掉铃彰。

這個配置,依賴于連接雙方對timestamps的支持芯咧。同時牙捉,這個配置竹揍,主要影響到了inbound的連接(對outbound的連接也有影響,但是不是復用)邪铲,即做為服務端角色芬位,客戶端連進來,服務端主動關(guān)閉了連接带到,TIME_WAIT狀態(tài)的socket處于服務端昧碉,服務端快速的回收該狀態(tài)的連接。

由此揽惹,如果客戶端處于NAT的網(wǎng)絡(多個客戶端被饿,同一個IP出口的網(wǎng)絡環(huán)境),如果配置了tw_recycle永丝,就可能在一個RTO的時間內(nèi)锹漱,只能有一個客戶端和自己連接成功(不同的客戶端發(fā)包的時間不一致,造成服務端直接把數(shù)據(jù)包丟棄掉)慕嚷。

我盡量嘗試用文字解釋清楚哥牍,但是,來點案例和圖示喝检,應該有助于我們徹底理解嗅辣。

我們來看這樣一個網(wǎng)絡情況:

不知道叫啥名字比較霸氣,就叫《劍指BAT》吧

客戶端IP地址為:180.172.35.150挠说,我們可以認為是瀏覽器

負載均衡有兩個IP澡谭,外網(wǎng)IP地址為 115.29.253.156,內(nèi)網(wǎng)地址為10.162.74.10损俭;外網(wǎng)地址監(jiān)聽80端口

負載均衡背后有兩臺Web服務器蛙奖,一臺IP地址為 10.162.74.43,監(jiān)聽80端口杆兵;另一臺為10.162.74.44雁仲,監(jiān)聽 80 端口

Web服務器會連接數(shù)據(jù)服務器,IP地址為 10.162.74.45琐脏,監(jiān)聽 3306 端口

這種簡單的架構(gòu)下攒砖,我們來看看,在不同的情況下日裙,我們今天談論的tw_reuse/tw_recycle對網(wǎng)絡連接的影響吹艇。

先做個假定:

客戶端通過HTTP/1.1連接負載均衡,也就是說昂拂,HTTP協(xié)議投Connection為keep-alive受神,所以我們假定,客戶端 對 負載均衡服務器 的socket連接格侯,客戶端會斷開連接路克,所以樟结,TIME_WAIT出現(xiàn)在客戶端

Web服務器和MySQL服務器的連接,我們假定精算,Web服務器上的程序在連接結(jié)束的時候,調(diào)用close操作關(guān)閉socket資源連接碎连,所以灰羽,TIME_WAIT出現(xiàn)在 Web 服務器端。

那么鱼辙,在這種假定下:

Web服務器上廉嚼,肯定可以配置開啟的配置:tcp_tw_reuse;如果Web服務器有很多連向DB服務器的連接倒戏,可以保證socket連接的復用怠噪。

那么,負載均衡服務器和Web服務器杜跷,誰先關(guān)閉連接傍念,則決定了我們怎么配置tcp_tw_reuse/tcp_tw_recycle了

方案一:負載均衡服務器 首先關(guān)閉連接?

在這種情況下,因為負載均衡服務器對Web服務器的連接葛闷,TIME_WAIT大都出現(xiàn)在負載均衡服務器上憋槐,所以,在負載均衡服務器上的配置:

net.ipv4.tcp_tw_reuse = 1 //盡量復用連接

net.ipv4.tcp_tw_recycle = 0 //不能保證客戶端不在NAT的網(wǎng)絡啊

在Web服務器上的配置為:

net.ipv4.tcp_tw_reuse = 1 //這個配置主要影響的是Web服務器到DB服務器的連接復用

net.ipv4.tcp_tw_recycle: 設(shè)置成1和0都沒有任何意義淑趾。想一想阳仔,在負載均衡和它的連接中,它是服務端扣泊,但是TIME_WAIT出現(xiàn)在負載均衡服務器上近范;它和DB的連接,它是客戶端延蟹,recycle對它并沒有什么影響评矩,關(guān)鍵是reuse

方案二:Web服務器首先關(guān)閉來自負載均衡服務器的連接

在這種情況下,Web服務器變成TIME_WAIT的重災區(qū)等孵。負載均衡對Web服務器的連接稚照,由Web服務器首先關(guān)閉連接,TIME_WAIT出現(xiàn)在Web服務器上俯萌;Web服務器對DB服務器的連接果录,由Web服務器關(guān)閉連接,TIME_WAIT也出現(xiàn)在它身上咐熙,此時弱恒,負載均衡服務器上的配置:

net.ipv4.tcp_tw_reuse:0 或者 1 都行,都沒有實際意義

net.ipv4.tcp_tw_recycle=0 //一定是關(guān)閉recycle

在Web服務器上的配置:

net.ipv4.tcp_tw_reuse = 1 //這個配置主要影響的是Web服務器到DB服務器的連接復用

net.ipv4.tcp_tw_recycle=1 //由于在負載均衡和Web服務器之間并沒有NAT的網(wǎng)絡棋恼,可以考慮開啟recycle返弹,加速由于負載均衡和Web服務器之間的連接造成的大量TIME_WAIT


總結(jié)結(jié)論

1. tw_reuse锈玉,tw_recycle?必須在客戶端和服務端timestamps?開啟時才管用(默認打開)

2. tw_reuse只對客戶端起作用,開啟后客戶端在1s內(nèi)回收

3. tw_recycle?對客戶端和服務器同時起作用义起,開啟后在3.5*RTO?內(nèi)回收拉背,RTO 200ms~ 120s?具體時間視網(wǎng)絡狀況。

l?對于客戶端

1)?作為客戶端因為有端口65535(端口范圍0~65535默终,但0不能使用)問題椅棺,TIME_OUT過多直接影響處理能力,打開tw_reuse?即可解決齐蔽,不建議同時打開tw_recycle两疚,幫助不大。

2)?tw_reuse?幫助客戶端1s完成連接回收含滴,基本可實現(xiàn)單機6w/s請求诱渤,需要再高就增加IP數(shù)量吧。

3)?如果內(nèi)網(wǎng)壓測場景谈况,且客戶端不需要接收連接勺美,同時tw_recycle?會有一點點好處。

4)?業(yè)務上也可以設(shè)計由服務端主動關(guān)閉連接

l?對于服務端

1)?打開tw_reuse無效

2)?線上環(huán)境?tw_recycle?最好不要打開

????服務器處于NAT?負載后鸦做,或者客戶端處于NAT后(這是一定的事情励烦,基本公司家庭網(wǎng)絡都走NAT);公網(wǎng)服務打開就可能造成部分連接失敗泼诱,內(nèi)網(wǎng)的話到時可以視情況打開坛掠;像我所在公司對外服務都放在負載后面,負載會把timestamp?選項都給關(guān)閉治筒,所以就算打開也不起作用屉栓。

3)?服務器TIME_WAIT?高怎么辦

???不像客戶端有端口限制,處理大量TIME_WAIT Linux已經(jīng)優(yōu)化很好了耸袜,每個處于TIME_WAIT?狀態(tài)下連接內(nèi)存消耗很少友多,而且也能通過tcp_max_tw_buckets =?262144?配置最大上限。


回答幾個大家提到的幾個問題

1. 請問我們所說連接池可以復用連接堤框,是不是意味著域滥,需要等到上個連接time wait結(jié)束后才能再次使用?

所謂連接池復用,復用的一定是活躍的連接蜈抓,所謂活躍启绰,第一表明連接池里的連接都是ESTABLISHED的,第二沟使,連接池做為上層應用委可,會有定時的心跳去保持連接的活躍性。既然連接都是活躍的腊嗡,那就不存在有TIME_WAIT的概念了着倾,在文章上面內(nèi)容也有提到拾酝,TIME_WAIT是在主動關(guān)閉連接的一方,在關(guān)閉連接后才進入的狀態(tài)卡者。既然已經(jīng)關(guān)閉了蒿囤,那么這條連接肯定已經(jīng)不在連接池里面了,即被連接池釋放了崇决。

2.?想請問下蟋软,作為負載均衡的機器隨機端口使用完的情況下大量time_wait,不調(diào)整你文字里說的那三個參數(shù)嗽桩,有其他的更好的方案嗎?

第一凄敢,隨機端口使用完碌冶,你可以通過調(diào)整/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,至少修改成?net.ipv4.ip_local_port_range=1024 65535涝缝,保證你的負載均衡服務器至少可以使用6萬個隨機端口扑庞,也即可以有6萬的反向代理到后端的連接,可以支持每秒1000的并發(fā)(想一想拒逮,因為TIME_WAIT狀態(tài)會持續(xù)1分鐘后消失罐氨,所以一分鐘最多有6萬,每秒1000)滩援;如果這么多端口都使用完了栅隐,也證明你應該加服務器了,或者玩徊,你的負載均衡服務器需要配置多個IP地址租悄,或者,你的后端服務器需要監(jiān)聽更多的端口和配置更多的IP(想一下socket的五元組)

第二恩袱,大量的TIME_WAIT泣棋,多大量?如果是幾千個畔塔,其實不用擔心潭辈,因為這個內(nèi)存和CPU的消耗有一些,但是是可以忽略的澈吨。

第三把敢,如果真的量很大,上萬上萬的那種棚辽,可以考慮技竟,讓后端的服務器主動關(guān)閉連接,如果后端服務器沒有外網(wǎng)的連接只有負載均衡服務器的連接(主要是沒有NAT網(wǎng)絡的連接)屈藐,可以在后端服務器上配置tw_recycle榔组,然后同時熙尉,在負載均衡服務器上,配置tw_reuse搓扯。

3. 如果想深入的學習一下網(wǎng)絡方面的知識检痰,有什么推薦的?

學習網(wǎng)絡比學一門編程語言“難”很多锨推。所謂難铅歼,其實,是因為需要花很多的時間投入换可∽狄基本書可以推薦:《TCP/IP 協(xié)議詳解》,必讀沾鳄;《TCP/IP高效編程:改善網(wǎng)絡程序的44個技巧》慨飘,必讀;《Unix環(huán)境高級編程》译荞,必讀瓤的;《Unix網(wǎng)絡編程:卷一》;《linux網(wǎng)絡編程》吞歼,必須不能讀圈膏;《Linux高性能服務器編程》,選讀篙骡;

4.搞到這么多技能稽坤,國內(nèi)還有哪些企業(yè)敢收我呢?

第一医增,BAT慎皱,給你SP offer(除非你最近沒扶老太太過馬路);

第二叶骨,網(wǎng)易茫多,美團,京東忽刽,滴滴天揖,360,今日頭條跪帝,華為(除非你拒絕他們)今膊;


感謝你能堅持看完。不過伞剑,我還沒嘮叨結(jié)束斑唬,明晚繼續(xù)走起。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恕刘,隨后出現(xiàn)的幾起案子缤谎,更是在濱河造成了極大的恐慌,老刑警劉巖褐着,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坷澡,死亡現(xiàn)場離奇詭異,居然都是意外死亡含蓉,警方通過查閱死者的電腦和手機频敛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馅扣,“玉大人斟赚,你說我怎么就攤上這事〔钣停” “怎么了汁展?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長厌殉。 經(jīng)常有香客問我,道長侈咕,這世上最難降的妖魔是什么公罕? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮耀销,結(jié)果婚禮上楼眷,老公的妹妹穿的比我還像新娘。我一直安慰自己熊尉,他們只是感情好罐柳,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著狰住,像睡著了一般张吉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上催植,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天肮蛹,我揣著相機與錄音,去河邊找鬼创南。 笑死伦忠,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的稿辙。 我是一名探鬼主播昆码,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赋咽?” 一聲冷哼從身側(cè)響起旧噪,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎冬耿,沒想到半個月后舌菜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡亦镶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年日月,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缤骨。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡爱咬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绊起,到底是詐尸還是另有隱情精拟,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布虱歪,位于F島的核電站蜂绎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏笋鄙。R本人自食惡果不足惜师枣,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萧落。 院中可真熱鬧践美,春花似錦、人聲如沸找岖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽许布。三九已至兴革,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蜜唾,已是汗流浹背帖旨。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留灵妨,地道東北人解阅。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像泌霍,于是被迫代替她去往敵國和親货抄。 傳聞我的和親對象是個殘疾皇子述召,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容