(轉(zhuǎn)載)TCP 三次握手原理占调,你真的理解嗎暂题?

原創(chuàng): 蟄劍 [阿里技術(shù)]

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

因此,蟄劍寫下這篇文章赶站,希望借此能把這個問題說清楚幔虏。歡迎大家一起交流探討。

問題描述

場景:JAVA的client和server贝椿,使用socket通信想括。server使用NIO。

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

2.出問題的時間點,會同時有很多連接出現(xiàn)這個問題渣窜。

3.selector沒有銷毀重建铺根,一直用的都是一個。

4.程序剛啟動的時候必會出現(xiàn)一些乔宿,之后會間歇性出現(xiàn)位迂。

分析問題

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

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

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

  • 第三步:client 收到syn+ack后掂林,回復(fù)server一個ack表示收到了server的syn+ack(此時client的56911端口的連接已經(jīng)是established)。

從問題的描述來看坝橡,有點像TCP建連接的時候全連接隊列(accept隊列泻帮,后面具體講)滿了,尤其是癥狀2计寇、4. 為了證明是這個原因刑顺,馬上通過 netstat -s | egrep "listen" 去看隊列的溢出統(tǒng)計數(shù)據(jù):


反復(fù)看了幾次之后發(fā)現(xiàn)這個overflowed 一直在增加氯窍,那么可以明確的是server上全連接隊列一定溢出了。
接著查看溢出后蹲堂,OS怎么處理:

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

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

接著測試朽基,這時在客戶端異常中可以看到很多connection reset by peer的錯誤布隔,到此證明客戶端錯誤是這個原因?qū)е碌模ㄟ壿媷乐敗⒖焖僮C明問題的關(guān)鍵點所在)稼虎。

于是開發(fā)同學(xué)翻看java 源代碼發(fā)現(xiàn)socket 默認的backlog(這個值控制全連接隊列的大小衅檀,后面再詳述)是50,于是改大重新跑霎俩,經(jīng)過12個小時以上的壓測哀军,這個錯誤一次都沒出現(xiàn)了,同時觀察到 overflowed 也不再增加了打却。

到此問題解決杉适,簡單來說TCP三次握手后有個accept隊列,進到這個隊列才能從Listen變成accept柳击,默認backlog 值是50猿推,很容易就滿了。滿了之后握手第三步的時候server就忽略了client發(fā)過來的ack包(隔一段時間server重發(fā)握手第二步的syn+ack包給client)捌肴,如果這個連接一直排不上隊就異常了蹬叭。

但是不能只是滿足問題的解決,而是要去復(fù)盤解決過程状知,中間涉及到了哪些知識點是我所缺失或者理解不到位的秽五;這個問題除了上面的異常信息表現(xiàn)出來之外寒波,還有沒有更明確地指征來查看和確認這個問題边苹。

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

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

如上圖所示,這里有兩個隊列:syns queue(半連接隊列)饺饭;accept queue(全連接隊列)铺坞。

三次握手中起宽,在第一步server收到client的syn后,把這個連接信息放到半連接隊列中济榨,同時回復(fù)syn+ack給client(第二步)坯沪;

第三步的時候server收到client的ack,如果這時全連接隊列沒滿擒滑,那么從半連接隊列拿出這個連接的信息放入到全連接隊列中腐晾,否則按tcp_abort_on_overflow指示的執(zhí)行叉弦。

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

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

如果TCP連接隊列溢出巨柒,有哪些指標可以看呢樱拴?

上述解決過程有點繞,聽起來懵洋满,那么下次再出現(xiàn)類似問題有什么更快更明確的手段來確認這個問題呢晶乔?(通過具體的、感性的東西來強化我們對知識點的理解和吸收牺勾。)

netstat -s

比如上面看到的 667399 times 正罢,表示全連接隊列溢出的次數(shù),隔幾秒鐘執(zhí)行下驻民,如果這個數(shù)字一直在增加的話肯定全連接隊列偶爾滿了翻具。

ss 命令

上面看到的第二列Send-Q 值是50,表示第三列的listen端口上的全連接隊列最大為50川无,第一列Recv-Q為全連接隊列當前使用了多少呛占。

全連接隊列的大小取決于:min(backlog, somaxconn) . backlog是在socket創(chuàng)建的時候傳入的虑乖,somaxconn是一個os級別的系統(tǒng)參數(shù)懦趋。

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

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

半連接隊列的大小取決于:max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)疹味,不同版本的os會有些差異仅叫。

我們寫代碼的時候從來沒有想過這個backlog或者說大多時候就沒給他值(那么默認就是50),直接忽視了他糙捺,首先這是一個知識點的盲點诫咱;其次也許哪天你在哪篇文章中看到了這個參數(shù),當時有點印象洪灯,但是過一陣子就忘了坎缭,這是知識之間沒有建立連接,不是體系化的签钩。但是如果你跟我一樣首先經(jīng)歷了這個問題的痛苦掏呼,然后在壓力和痛苦的驅(qū)動自己去找為什么,同時能夠把為什么從代碼層推理理解到OS層铅檩,那么這個知識點你才算是比較好地掌握了憎夷,也會成為你的知識體系在TCP或者性能方面成長自我生長的一個有力抓手。

netstat 命令

netstat跟ss命令一樣也能看到Send-Q昧旨、Recv-Q這些狀態(tài)信息拾给,不過如果這個連接不是Listen狀態(tài)的話祥得,Recv-Q就是指收到的數(shù)據(jù)還在緩存中,還沒被進程讀取蒋得,這個值就是還沒被進程讀取的 bytes级及;而 Send 則是發(fā)送隊列中沒有被遠程主機確認的 bytes 數(shù)。

netstat -tn 看到的 Recv-Q 跟全連接半連接沒有關(guān)系额衙,這里特意拿出來說一下是因為容易跟 ss -lnt 的 Recv-Q 搞混淆创千,順便建立知識體系,鞏固相關(guān)知識點 入偷。

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

上面是通過一些具體的工具、指標來認識全連接隊列(工程效率的手段)疏之。

實踐驗證一下上面的理解

把java中backlog改成10(越小越容易溢出)殿雪,繼續(xù)跑壓力,這個時候client又開始報異常了锋爪,然后在server上通過 ss 命令觀察到:

按照前面的理解丙曙,這個時候我們能看到3306這個端口上的服務(wù)全連接隊列最大是10,但是現(xiàn)在有11個在隊列中和等待進隊列的其骄,肯定有一個連接進不去隊列要overflow掉亏镰,同時也確實能看到overflow的值在不斷地增大。

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

Tomcat默認短連接拯爽,backlog(Tomcat里面的術(shù)語是Accept count)Ali-tomcat默認是200, Apache Tomcat默認100索抓。

Nginx默認是511

因為Nginx是多進程模式,所以看到了多個8085毯炮,也就是多個進程都監(jiān)聽同一個端口以盡量避免上下文切換來提升性能

總結(jié)

全連接隊列逼肯、半連接隊列溢出這種問題很容易被忽視,但是又很關(guān)鍵桃煎,特別是對于一些短連接應(yīng)用(比如Nginx篮幢、PHP,當然他們也是支持長連接的)更容易爆發(fā)为迈。 一旦溢出三椿,從cpu、線程狀態(tài)看起來都比較正常葫辐,但是壓力上不去搜锰,在client看來rt也比較高(rt=網(wǎng)絡(luò)+排隊+真正服務(wù)時間),但是從server日志記錄的真正服務(wù)時間來看rt又很短另患。

jdk纽乱、netty等一些框架默認backlog比較小,可能有些情況下導(dǎo)致性能上不去昆箕。

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

另外每個具體問題都是最好學(xué)習的機會薯嗤,光看書理解肯定是不夠深刻的顽爹,請珍惜每個具體問題,碰到后能夠把來龍去脈弄清楚骆姐,每個問題都是你對具體知識點通關(guān)的好機會镜粤。

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

  1. 全連接隊列滿了會影響半連接隊列嗎?

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

  3. 如果client走完了TCP握手的第三步肉渴,在client看來連接已經(jīng)建立好了,但是server上的對應(yīng)連接實際沒有準備好带射,這個時候如果client發(fā)數(shù)據(jù)給server同规,server會怎么處理呢?(有同學(xué)說會reset窟社,你覺得呢券勺?)

提出這些問題,希望以這個知識點為抓手灿里,讓你的知識體系開始自我生長关炼。

參考文章

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

每天一篇技術(shù)文章,

看不過癮匣吊?

發(fā)現(xiàn)更多AI干貨儒拂。


關(guān)注「阿里技術(shù)」把握前沿技術(shù)脈搏
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缀去,隨后出現(xiàn)的幾起案子侣灶,更是在濱河造成了極大的恐慌甸祭,老刑警劉巖缕碎,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異池户,居然都是意外死亡咏雌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門校焦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赊抖,“玉大人,你說我怎么就攤上這事寨典》昭” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵耸成,是天一觀的道長报亩。 經(jīng)常有香客問我浴鸿,道長,這世上最難降的妖魔是什么弦追? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任岳链,我火速辦了婚禮,結(jié)果婚禮上劲件,老公的妹妹穿的比我還像新娘掸哑。我一直安慰自己,他們只是感情好零远,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布苗分。 她就那樣靜靜地躺著,像睡著了一般牵辣。 火紅的嫁衣襯著肌膚如雪俭嘁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天服猪,我揣著相機與錄音供填,去河邊找鬼。 笑死罢猪,一個胖子當著我的面吹牛近她,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膳帕,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼粘捎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了危彩?” 一聲冷哼從身側(cè)響起攒磨,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汤徽,沒想到半個月后娩缰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡谒府,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年拼坎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片完疫。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡泰鸡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出壳鹤,到底是詐尸還是另有隱情盛龄,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站余舶,受9級特大地震影響蹦锋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜欧芽,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一莉掂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧千扔,春花似錦憎妙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至龙誊,卻和暖如春抚垃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背趟大。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工鹤树, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逊朽。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓罕伯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叽讳。 傳聞我的和親對象是個殘疾皇子追他,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

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