TCP 三次握手原理壶运,你真的理解嗎耕突?

轉(zhuǎn)載至?https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247487779&idx=1&sn=0980243dcec05c5df8e2e60937c2c5ed&chksm=e9292c2cde5ea53a7b309e3575c78940a378b358292a3badb828d6c9bb6e8d3997800564b1d5&mpshare=1&scene=1&srcid=07056QyIsBQcfBlh2lZygZ8j#rd


阿里妹導(dǎo)讀:最近凌摄,阿里中間件小哥哥蟄劍碰到一個(gè)問題——client端連接服務(wù)器總是拋異常羡蛾。在反復(fù)定位分析、并查閱各種資料文章搞懂后锨亏,他發(fā)現(xiàn)沒有文章把這兩個(gè)隊(duì)列以及怎么觀察他們的指標(biāo)說清楚痴怨。

因此,蟄劍寫下這篇文章器予,希望借此能把這個(gè)問題說清楚浪藻。歡迎大家一起交流探討。

問題描述

場景:JAVA的client和server劣摇,使用socket通信珠移。server使用NIO。

1.間歇性得出現(xiàn)client向server建立連接三次握手已經(jīng)完成,但server的selector沒有響應(yīng)到這連接钧惧。

2.出問題的時(shí)間點(diǎn)暇韧,會(huì)同時(shí)有很多連接出現(xiàn)這個(gè)問題。

3.selector沒有銷毀重建浓瞪,一直用的都是一個(gè)懈玻。

4.程序剛啟動(dòng)的時(shí)候必會(huì)出現(xiàn)一些,之后會(huì)間歇性出現(xiàn)乾颁。

分析問題

正常TCP建連接三次握手過程:

第一步:client 發(fā)送 syn 到server 發(fā)起握手涂乌;

第二步:server 收到 syn后回復(fù)syn+ack給client;

第三步:client 收到syn+ack后英岭,回復(fù)server一個(gè)ack表示收到了server的syn+ack(此時(shí)client的56911端口的連接已經(jīng)是established)湾盒。

從問題的描述來看,有點(diǎn)像TCP建連接的時(shí)候全連接隊(duì)列(accept隊(duì)列诅妹,后面具體講)滿了罚勾,尤其是癥狀2、4. 為了證明是這個(gè)原因吭狡,馬上通過 netstat -s | egrep "listen" 去看隊(duì)列的溢出統(tǒng)計(jì)數(shù)據(jù): ? ?

反復(fù)看了幾次之后發(fā)現(xiàn)這個(gè)overflowed 一直在增加尖殃,那么可以明確的是server上全連接隊(duì)列一定溢出了。

接著查看溢出后划煮,OS怎么處理:

tcp_abort_on_overflow 為0表示如果三次握手第三步的時(shí)候全連接隊(duì)列滿了那么server扔掉client 發(fā)過來的ack(在server端認(rèn)為連接還沒建立起來)

為了證明客戶端應(yīng)用代碼的異常跟全連接隊(duì)列滿有關(guān)系送丰,我先把tcp_abort_on_overflow修改成 1,1表示第三步的時(shí)候如果全連接隊(duì)列滿了弛秋,server發(fā)送一個(gè)reset包給client器躏,表示廢掉這個(gè)握手過程和這個(gè)連接(本來在server端這個(gè)連接就還沒建立起來)。

接著測試铐懊,這時(shí)在客戶端異常中可以看到很多connection reset by peer的錯(cuò)誤邀桑,到此證明客戶端錯(cuò)誤是這個(gè)原因?qū)е碌模ㄟ壿媷?yán)謹(jǐn)、快速證明問題的關(guān)鍵點(diǎn)所在)科乎。

于是開發(fā)同學(xué)翻看java 源代碼發(fā)現(xiàn)socket 默認(rèn)的backlog(這個(gè)值控制全連接隊(duì)列的大小,后面再詳述)是50贼急,于是改大重新跑茅茂,經(jīng)過12個(gè)小時(shí)以上的壓測,這個(gè)錯(cuò)誤一次都沒出現(xiàn)了太抓,同時(shí)觀察到 overflowed 也不再增加了空闲。

到此問題解決,簡單來說TCP三次握手后有個(gè)accept隊(duì)列走敌,進(jìn)到這個(gè)隊(duì)列才能從Listen變成accept碴倾,默認(rèn)backlog 值是50,很容易就滿了。滿了之后握手第三步的時(shí)候server就忽略了client發(fā)過來的ack包(隔一段時(shí)間server重發(fā)握手第二步的syn+ack包給client)跌榔,如果這個(gè)連接一直排不上隊(duì)就異常了异雁。

但是不能只是滿足問題的解決,而是要去復(fù)盤解決過程僧须,中間涉及到了哪些知識(shí)點(diǎn)是我所缺失或者理解不到位的纲刀;這個(gè)問題除了上面的異常信息表現(xiàn)出來之外,還有沒有更明確地指征來查看和確認(rèn)這個(gè)問題担平。

深入理解TCP握手過程中建連接的流程和隊(duì)列


(圖片來源:http://www.cnxct.com/something-about-phpfpm-s-backlog/)

如上圖所示示绊,這里有兩個(gè)隊(duì)列:syns queue(半連接隊(duì)列);accept queue(全連接隊(duì)列)暂论。

三次握手中面褐,在第一步server收到client的syn后,把這個(gè)連接信息放到半連接隊(duì)列中取胎,同時(shí)回復(fù)syn+ack給client(第二步)盆耽;

第三步的時(shí)候server收到client的ack,如果這時(shí)全連接隊(duì)列沒滿扼菠,那么從半連接隊(duì)列拿出這個(gè)連接的信息放入到全連接隊(duì)列中摄杂,否則按tcp_abort_on_overflow指示的執(zhí)行。

這時(shí)如果全連接隊(duì)列滿了并且tcp_abort_on_overflow是0的話循榆,server過一段時(shí)間再次發(fā)送syn+ack給client(也就是重新走握手的第二步)析恢,如果client超時(shí)等待比較短,client就很容易異常了秧饮。

在我們的os中retry 第二步的默認(rèn)次數(shù)是2(centos默認(rèn)是5次):

如果TCP連接隊(duì)列溢出映挂,有哪些指標(biāo)可以看呢?

上述解決過程有點(diǎn)繞盗尸,聽起來懵柑船,那么下次再出現(xiàn)類似問題有什么更快更明確的手段來確認(rèn)這個(gè)問題呢?(通過具體的泼各、感性的東西來強(qiáng)化我們對(duì)知識(shí)點(diǎn)的理解和吸收鞍时。)

netstat -s

比如上面看到的 667399 times ,表示全連接隊(duì)列溢出的次數(shù)扣蜻,隔幾秒鐘執(zhí)行下逆巍,如果這個(gè)數(shù)字一直在增加的話肯定全連接隊(duì)列偶爾滿了。

ss 命令

上面看到的第二列Send-Q 值是50莽使,表示第三列的listen端口上的全連接隊(duì)列最大為50锐极,第一列Recv-Q為全連接隊(duì)列當(dāng)前使用了多少。

全連接隊(duì)列的大小取決于:min(backlog, somaxconn) . backlog是在socket創(chuàng)建的時(shí)候傳入的芳肌,somaxconn是一個(gè)os級(jí)別的系統(tǒng)參數(shù)灵再。

這個(gè)時(shí)候可以跟我們的代碼建立聯(lián)系了肋层,比如Java創(chuàng)建ServerSocket的時(shí)候會(huì)讓你傳入backlog的值:

(來自JDK幫助文檔:https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html)

半連接隊(duì)列的大小取決于:max(64, ?/proc/sys/net/ipv4/tcp_max_syn_backlog),不同版本的os會(huì)有些差異翎迁。

我們寫代碼的時(shí)候從來沒有想過這個(gè)backlog或者說大多時(shí)候就沒給他值(那么默認(rèn)就是50)栋猖,直接忽視了他,首先這是一個(gè)知識(shí)點(diǎn)的盲點(diǎn)鸳兽;其次也許哪天你在哪篇文章中看到了這個(gè)參數(shù)掂铐,當(dāng)時(shí)有點(diǎn)印象,但是過一陣子就忘了揍异,這是知識(shí)之間沒有建立連接全陨,不是體系化的。但是如果你跟我一樣首先經(jīng)歷了這個(gè)問題的痛苦衷掷,然后在壓力和痛苦的驅(qū)動(dòng)自己去找為什么辱姨,同時(shí)能夠把為什么從代碼層推理理解到OS層,那么這個(gè)知識(shí)點(diǎn)你才算是比較好地掌握了戚嗅,也會(huì)成為你的知識(shí)體系在TCP或者性能方面成長自我生長的一個(gè)有力抓手雨涛。

netstat 命令

netstat跟ss命令一樣也能看到Send-Q、Recv-Q這些狀態(tài)信息懦胞,不過如果這個(gè)連接不是Listen狀態(tài)的話替久,Recv-Q就是指收到的數(shù)據(jù)還在緩存中,還沒被進(jìn)程讀取躏尉,這個(gè)值就是還沒被進(jìn)程讀取的 bytes蚯根;而 Send 則是發(fā)送隊(duì)列中沒有被遠(yuǎn)程主機(jī)確認(rèn)的 bytes 數(shù)。

netstat -tn 看到的 Recv-Q 跟全連接半連接沒有關(guān)系胀糜,這里特意拿出來說一下是因?yàn)槿菀赘?ss -lnt 的 Recv-Q 搞混淆颅拦,順便建立知識(shí)體系,鞏固相關(guān)知識(shí)點(diǎn) 教藻。??

比如如下netstat -t 看到的Recv-Q有大量數(shù)據(jù)堆積距帅,那么一般是CPU處理不過來導(dǎo)致的:


上面是通過一些具體的工具、指標(biāo)來認(rèn)識(shí)全連接隊(duì)列(工程效率的手段)括堤。 ?

實(shí)踐驗(yàn)證一下上面的理解

把java中backlog改成10(越小越容易溢出)碌秸,繼續(xù)跑壓力,這個(gè)時(shí)候client又開始報(bào)異常了痊臭,然后在server上通過 ss 命令觀察到:

按照前面的理解哮肚,這個(gè)時(shí)候我們能看到3306這個(gè)端口上的服務(wù)全連接隊(duì)列最大是10,但是現(xiàn)在有11個(gè)在隊(duì)列中和等待進(jìn)隊(duì)列的广匙,肯定有一個(gè)連接進(jìn)不去隊(duì)列要overflow掉,同時(shí)也確實(shí)能看到overflow的值在不斷地增大恼策。

Tomcat和Nginx中的Accept隊(duì)列參數(shù)

Tomcat默認(rèn)短連接鸦致,backlog(Tomcat里面的術(shù)語是Accept count)Ali-tomcat默認(rèn)是200, Apache Tomcat默認(rèn)100潮剪。

Nginx默認(rèn)是511

因?yàn)镹ginx是多進(jìn)程模式,所以看到了多個(gè)8085分唾,也就是多個(gè)進(jìn)程都監(jiān)聽同一個(gè)端口以盡量避免上下文切換來提升性能 ??

總結(jié)

全連接隊(duì)列抗碰、半連接隊(duì)列溢出這種問題很容易被忽視,但是又很關(guān)鍵绽乔,特別是對(duì)于一些短連接應(yīng)用(比如Nginx弧蝇、PHP,當(dāng)然他們也是支持長連接的)更容易爆發(fā)折砸。 一旦溢出看疗,從cpu、線程狀態(tài)看起來都比較正常睦授,但是壓力上不去两芳,在client看來rt也比較高(rt=網(wǎng)絡(luò)+排隊(duì)+真正服務(wù)時(shí)間),但是從server日志記錄的真正服務(wù)時(shí)間來看rt又很短去枷。

jdk怖辆、netty等一些框架默認(rèn)backlog比較小,可能有些情況下導(dǎo)致性能上不去删顶。

希望通過本文能夠幫大家理解TCP連接過程中的半連接隊(duì)列和全連接隊(duì)列的概念竖螃、原理和作用,更關(guān)鍵的是有哪些指標(biāo)可以明確看到這些問題(工程效率幫助強(qiáng)化對(duì)理論的理解)逗余。

另外每個(gè)具體問題都是最好學(xué)習(xí)的機(jī)會(huì)特咆,光看書理解肯定是不夠深刻的,請(qǐng)珍惜每個(gè)具體問題猎荠,碰到后能夠把來龍去脈弄清楚坚弱,每個(gè)問題都是你對(duì)具體知識(shí)點(diǎn)通關(guān)的好機(jī)會(huì)。

最后提出相關(guān)問題給大家思考

全連接隊(duì)列滿了會(huì)影響半連接隊(duì)列嗎关摇?

netstat -s看到的overflowed和ignored的數(shù)值有什么聯(lián)系嗎荒叶?

如果client走完了TCP握手的第三步,在client看來連接已經(jīng)建立好了输虱,但是server上的對(duì)應(yīng)連接實(shí)際沒有準(zhǔn)備好些楣,這個(gè)時(shí)候如果client發(fā)數(shù)據(jù)給server,server會(huì)怎么處理呢宪睹?(有同學(xué)說會(huì)reset愁茁,你覺得呢?)

提出這些問題亭病,希望以這個(gè)知識(shí)點(diǎn)為抓手鹅很,讓你的知識(shí)體系開始自我生長。

參考文章

http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html

http://www.cnblogs.com/zengkefu/p/5606696.html

http://www.cnxct.com/something-about-phpfpm-s-backlog/

http://jaseywang.me/2014/07/20/tcp-queue-%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98/

http://jin-yang.github.io/blog/network-synack-queue.html#

http://blog.chinaunix.net/uid-20662820-id-4154399.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末罪帖,一起剝皮案震驚了整個(gè)濱河市促煮,隨后出現(xiàn)的幾起案子邮屁,更是在濱河造成了極大的恐慌,老刑警劉巖菠齿,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佑吝,死亡現(xiàn)場離奇詭異,居然都是意外死亡绳匀,警方通過查閱死者的電腦和手機(jī)芋忿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疾棵,“玉大人戈钢,你說我怎么就攤上這事÷穑” “怎么了逆趣?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嗜历。 經(jīng)常有香客問我宣渗,道長,這世上最難降的妖魔是什么梨州? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任痕囱,我火速辦了婚禮,結(jié)果婚禮上暴匠,老公的妹妹穿的比我還像新娘鞍恢。我一直安慰自己,他們只是感情好每窖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布帮掉。 她就那樣靜靜地躺著,像睡著了一般窒典。 火紅的嫁衣襯著肌膚如雪蟆炊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天瀑志,我揣著相機(jī)與錄音涩搓,去河邊找鬼。 笑死劈猪,一個(gè)胖子當(dāng)著我的面吹牛昧甘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播战得,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼充边,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了常侦?” 一聲冷哼從身側(cè)響起痛黎,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤予弧,失蹤者是張志新(化名)和其女友劉穎刮吧,沒想到半個(gè)月后湖饱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杀捻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年井厌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片致讥。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仅仆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出垢袱,到底是詐尸還是另有隱情墓拜,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布请契,位于F島的核電站咳榜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏爽锥。R本人自食惡果不足惜涌韩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氯夷。 院中可真熱鬧臣樱,春花似錦、人聲如沸腮考。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踩蔚。三九已至棚放,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寂纪,已是汗流浹背席吴。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捞蛋,地道東北人孝冒。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像拟杉,于是被迫代替她去往敵國和親庄涡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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