自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

TCP三次握手原理,你到底知道多少?

網(wǎng)絡(luò) 通信技術(shù) 開發(fā)工具
最近碰到一個(gè)問題,Client 端連接服務(wù)器總是拋異常。在反復(fù)定位分析、并查閱各種資料搞懂后,我發(fā)現(xiàn)并沒有文章能把這兩個(gè)隊(duì)列以及怎么觀察他們的指標(biāo)說清楚。

最近碰到一個(gè)問題,Client 端連接服務(wù)器總是拋異常。在反復(fù)定位分析、并查閱各種資料搞懂后,我發(fā)現(xiàn)并沒有文章能把這兩個(gè)隊(duì)列以及怎么觀察他們的指標(biāo)說清楚。

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

問題描述

場(chǎng)景:Java 的 Client 和 Server,使用 Socket 通信。Server 使用 NIO。

問題:

  • 間歇性出現(xiàn) Client 向 Server 建立連接三次握手已經(jīng)完成,但 Server 的 Selector 沒有響應(yīng)到該連接。
  • 出問題的時(shí)間點(diǎn),會(huì)同時(shí)有很多連接出現(xiàn)這個(gè)問題。
  • Selector 沒有銷毀重建,一直用的都是一個(gè)。
  • 程序剛啟動(dòng)的時(shí)候必會(huì)出現(xiàn)一些,之后會(huì)間歇性出現(xiàn)。

分析問題

正常 TCP 建連接三次握手過程,分為如下三個(gè)步驟:

  • 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è)連接就還沒建立起來)。

接著測(cè)試,這時(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í)以上的壓測(cè),這個(gè)錯(cuò)誤一次都沒出現(xiàn)了,同時(shí)觀察到 overflowed 也不再增加了。

到此問題解決,簡(jiǎn)單來說 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ì)列

如上圖所示,這里有兩個(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 的值:

半連接隊(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 或者性能方面成長(zhǎng)自我生長(zhǎng)的一個(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)?Nginx 是多進(jìn)程模式,所以看到了多個(gè) 8085,也就是多個(gè)進(jìn)程都監(jiān)聽同一個(gè)端口以盡量避免上下文切換來提升性能。

總結(jié)

全連接隊(duì)列、半連接隊(duì)列溢出這種問題很容易被忽視,但是又很關(guān)鍵,特別是對(duì)于一些短連接應(yīng)用(比如 Nginx、PHP,當(dāng)然它們也是支持長(zhǎ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í)體系開始自我生長(zhǎng)。

參考文章:

  • 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

責(zé)任編輯:武曉燕 來源: 阿里技術(shù)
相關(guān)推薦

2022-07-07 09:00:17

TCP 連接HTTP 協(xié)議

2018-07-05 14:25:01

TCP握手原理

2019-02-01 09:38:16

2023-09-07 16:46:54

TCP數(shù)據(jù)傳遞

2023-10-24 15:22:09

TCPUDP

2022-10-10 07:34:36

TCP三次握手區(qū)塊鏈

2020-12-08 06:34:16

TCP握手SYN 報(bào)文

2024-01-12 08:23:11

TCPACK服務(wù)器

2015-10-13 09:42:52

TCP網(wǎng)絡(luò)協(xié)議

2019-06-12 11:26:37

TCP三次握手四次揮手

2023-10-17 15:44:19

TCP四次揮手

2019-12-12 10:36:43

TCPSYNIP

2020-08-27 07:41:28

TCP協(xié)議數(shù)據(jù)

2023-03-06 15:43:56

2023-09-02 21:57:52

網(wǎng)絡(luò)TCP協(xié)議

2021-03-08 18:08:08

TCP Connect 協(xié)議

2024-10-09 20:54:16

2022-07-25 07:07:35

TCP客戶端服務(wù)器

2022-07-05 22:18:08

TCP網(wǎng)絡(luò)

2021-01-29 06:11:08

TCP通信三次握手
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)