一、TCP四次揮手過程
(轉(zhuǎn)載):https://blog.csdn.net/zhaobryant/article/details/80557158
TCP在建立連接時需要握手汁蝶,同理,在關(guān)閉連接的時候也需要握手娄蔼。
由于TCP連接是雙向的脸爱,所以在關(guān)閉連接的時候,兩個方向各自都需要關(guān)閉撒遣。先發(fā)FIN包的一方執(zhí)行的是主動關(guān)閉喳逛,后發(fā)送FIN包的一方執(zhí)行的是被動關(guān)閉瞧捌。主動關(guān)閉的一方會進入TIME_WAIT狀態(tài),并且在此狀態(tài)停留2MSL時長润文。
對于MSL姐呐,其指的是報文段的最大生存時間。如果報文段在網(wǎng)絡(luò)中活動了MSL時間典蝌,還沒有被接收曙砂,那么就會被丟棄。關(guān)于MSL的大小骏掀,RFC 793協(xié)議中給出的建議是2分鐘鸠澈,不過Linux中柱告,通常是半分鐘。
具體如下所示:
我們關(guān)注幾個概念:
TIME_WAIT的產(chǎn)生條件:主動關(guān)閉方在發(fā)送四次揮手的最后一個ACK后會變?yōu)門IME_WAIT狀態(tài)笑陈,持續(xù)時間為2MSL(Linux中一個MSL是30秒际度,是不可配置的)。
TIME_WAIT持續(xù)兩個MSL的作用:首先涵妥,可靠安全地關(guān)閉TCP連接乖菱。比如網(wǎng)絡(luò)擁塞,如果主動關(guān)閉方最后一個ACK沒有被被動關(guān)閉方接收到蓬网,這時被動關(guān)閉方會對FIN進行超時重傳块请,在這時尚未關(guān)閉的TIME_WAIT就會把這些尾巴問題處理掉,不至于對新連接及其他服務(wù)產(chǎn)生影響拳缠。其次,防止由于沒有持續(xù)TIME_WAIT時間導(dǎo)致的新的TCP連接建立起來贸弥,延遲的FIN重傳包會干擾新的連接窟坐。
TIME_WAIT占用的資源:少量內(nèi)存(大概4K)和一個文件描述符fd。
TIME_WAIT關(guān)閉的危害:首先绵疲,當(dāng)網(wǎng)絡(luò)情況不好時哲鸳,如果主動方無TIME_WAIT等待,關(guān)閉前個連接后盔憨,主動方與被動方又建立起新的TCP連接徙菠,這時被動方重傳或延時過來的FIN包到達后會直接影響新的TCP連接;其次郁岩,當(dāng)網(wǎng)絡(luò)情況不好時婿奔,同時沒有TIME_WAIT等待時,關(guān)閉連接后無新連接问慎,那么當(dāng)接收到被動方重傳或延遲的FIN包后萍摊,會給被動方回送一個RST包,可能會影響被動方其他的服務(wù)連接如叼。
TCP: time wait bucket table overflow產(chǎn)生原因及影響:原因是當(dāng)TIME_WAIT數(shù)超過了Linux系統(tǒng)的TW數(shù)量的閾值冰木。危害是超過閾值后,系統(tǒng)會把多余的TIME_WAIT Socket刪除掉笼恰,并且顯示警告信息踊沸。如果是NAT網(wǎng)絡(luò)且又存在大量訪問時,會產(chǎn)生各種連接不穩(wěn)定斷開的情況社证。
二逼龟、相關(guān)參數(shù)優(yōu)化調(diào)整
1. tcp_tw_recycle
顧名思義就是回收TIME_WAIT連接∽菲希可以說這個內(nèi)核參數(shù)已經(jīng)變成了處理TIME_WAIT的萬金油审轮,如果你在網(wǎng)絡(luò)上搜索TIME_WAIT的解決方案肥哎,十有八九會推薦設(shè)置它,不過這里隱藏著一個不易察覺的陷阱:當(dāng)多個客戶端通過NAT方式聯(lián)網(wǎng)并與服務(wù)端交互時疾渣,服務(wù)端看到的是同一個IP篡诽,也就是說對服務(wù)端而言這些客戶端實際上等同于一個,由于這些客戶端的時間戳可能存在差異榴捡,所以從服務(wù)端的視角看杈女,便可能出現(xiàn)時間戳錯亂的現(xiàn)象,進而直接導(dǎo)致時間戳小的數(shù)據(jù)包被丟棄吊圾。參考:tcp_tw_recycle和tcp_timestamps導(dǎo)致connect失敗問題达椰。
tcp_tw_recycle = 0
備注:建議不要開啟該選項,現(xiàn)在互聯(lián)網(wǎng)NAT使用很多项乒,可能導(dǎo)致無法進行三次握手啰劲。
開啟后在3.5*RTO(RTO時間是根據(jù)RTT時間計算而來)內(nèi)回收TIME_WAIT,并60s內(nèi)同一源ip主機的socket connect請求中的timestamp必須是遞增的檀何,對于服務(wù)端蝇裤,同一個源ip可能會是NAT后很多機器,這些機器timestamp遞增性無可保證频鉴,服務(wù)器會拒絕非遞增請求連接栓辜,直接導(dǎo)致不能三次握手。
2. tcp_tw_reuse
顧名思義就是復(fù)用TIME_WAIT連接垛孔。當(dāng)創(chuàng)建新連接的時候藕甩,如果可能的話會考慮復(fù)用相應(yīng)的TIME_WAIT連接。通常認(rèn)為tcp_tw_reuse比tcp_tw_recycle安全一些周荐,這是因為一來TIME_WAIT創(chuàng)建時間必須超過一秒才可能會被復(fù)用狭莱;二來只有連接的時間戳是遞增的時候才會被復(fù)用。官方文檔里是這樣說的:如果從協(xié)議視角看它是安全的概作,那么就可以使用贩毕。這簡直就是外交辭令啊仆嗦!按我的看法辉阶,如果網(wǎng)絡(luò)比較穩(wěn)定,比如都是內(nèi)網(wǎng)連接瘩扼,那么就可以嘗試使用谆甜。
不過需要注意的是在哪里使用,既然我們要復(fù)用連接集绰,那么當(dāng)然應(yīng)該在連接的發(fā)起方使用规辱,而不能在被連接方使用。舉例來說:客戶端向服務(wù)端發(fā)起HTTP請求栽燕,服務(wù)端響應(yīng)后主動關(guān)閉連接罕袋,于是TIME_WAIT便留在了服務(wù)端改淑,此類情況使用tcp_tw_reuse是無效的,因為服務(wù)端是被連接方浴讯,所以不存在復(fù)用連接一說朵夏。讓我們延伸一點來看,比如說服務(wù)端是PHP榆纽,它查詢另一個MySQL服務(wù)端仰猖,然后主動斷開連接,于是TIME_WAIT就落在了PHP一側(cè)奈籽,此類情況下使用tcp_tw_reuse是有效的饥侵,因為此時PHP相對于MySQL而言是客戶端,它是連接的發(fā)起方衣屏,所以可以復(fù)用連接躏升。
說明:如果使用tcp_tw_reuse,請激活tcp_timestamps狼忱,否則無效膨疏。
tcp_timestamps = 1
tcp_tw_reuse = 1
3. tcp_max_tw_buckets
顧名思義就是控制TIME_WAIT總數(shù)。官網(wǎng)文檔說這個選項只是為了阻止一些簡單的DoS攻擊藕赞,平常不要人為的降低它。如果縮小了它卖局,那么系統(tǒng)會將多余的TIME_WAIT刪除掉斧蜕,日志里會顯示:TCP: time wait bucket table overflow。
需要提醒大家的是物極必反砚偶,曾經(jīng)看到有人把「tcp_max_tw_buckets」設(shè)置成0批销,也就是說完全拋棄TIME_WAIT,這就有些冒險了染坯,用一句圍棋諺語來說:入界宜緩均芽。
當(dāng)出現(xiàn)TCP: time wait bucket table overflow時,盡量調(diào)大下面參數(shù):
tcp_max_tw_buckets = 256000
三单鹿、總結(jié)
有時候掀宋,如果我們換個角度去看問題,往往能得到四兩撥千斤的效果仲锄。前面提到的例子:客戶端向服務(wù)端發(fā)起HTTP請求劲妙,服務(wù)端響應(yīng)后主動關(guān)閉連接,于是TIME_WAIT便留在了服務(wù)端儒喊。這里的關(guān)鍵在于主動關(guān)閉連接的是服務(wù)端镣奋!在關(guān)閉TCP連接的時候,先出手的一方注定逃不開TIME_WAIT的宿命怀愧,套用一句歌詞:把我的悲傷留給自己侨颈,你的美麗讓你帶走余赢。如果客戶端可控的話,那么在服務(wù)端打開KeepAlive哈垢,盡可能不讓服務(wù)端主動關(guān)閉連接妻柒,而讓客戶端主動關(guān)閉連接,如此一來問題便迎刃而解了温赔。
四蛤奢、補充
RST簡介:
在TCP協(xié)議中,RST表示復(fù)位陶贼,用來關(guān)閉異常連接啤贩。發(fā)送RST包關(guān)閉連接時,不必等到緩沖區(qū)的數(shù)據(jù)包都發(fā)送出去拜秧,直接丟棄緩存區(qū)的數(shù)據(jù)包而發(fā)送RST包痹屹。接收端在接收到RST包后,不必發(fā)送ACK包來確認(rèn)枉氮。
出現(xiàn)RST的幾種情況:
端口未打開:客戶端連接服務(wù)器程序未打開的端口志衍。當(dāng)客戶端向服務(wù)器的某個端口發(fā)送SYN請求后愧杯,但是服務(wù)器上并沒有打開該端口错沽,因此其會向客戶端發(fā)送RST。但是汉柒,并不是所有的操作系統(tǒng)都會發(fā)送RST給客戶端惹悄,win7就會直接忽略該SYN報文春叫。
在一個已關(guān)閉的socket上收到數(shù)據(jù):如果某個socket已經(jīng)關(guān)閉,但是依然接收數(shù)據(jù)泣港,那么也會產(chǎn)生RST暂殖。
接收緩沖區(qū)還存在數(shù)據(jù)時,關(guān)閉連接:在請求方請求數(shù)據(jù)当纱,未處理完緩沖區(qū)中的所有數(shù)據(jù)呛每,就請求關(guān)閉連接時,請求方不會如預(yù)期的發(fā)送FIN包坡氯,進入4路關(guān)閉邏輯晨横,而是可能會直接發(fā)送一個RST包強制完成連接的關(guān)閉。