TCP 三次握手皱坛,給我長(zhǎng)臉了噢

大家好编曼,我是小富~

前言

之前有個(gè)小伙伴在技術(shù)交流群里咨詢過(guò)一個(gè)問(wèn)題,我當(dāng)時(shí)還給提供了點(diǎn)排查思路剩辟,是個(gè)典型的八股文轉(zhuǎn)實(shí)戰(zhàn)分析的案例掐场,我覺得挺有意思往扔,趁著中午休息簡(jiǎn)單整理出來(lái)和大家分享下,有不嚴(yán)謹(jǐn)?shù)牡胤綒g迎大家指出熊户。

[圖片上傳失敗...(image-f057f3-1678959123451)]

問(wèn)題分析

我們先來(lái)看看他的問(wèn)題萍膛,下邊是他在群里對(duì)這個(gè)問(wèn)題的描述,我大致的總結(jié)了一下嚷堡。

他們有很多的 IOT 設(shè)備與服務(wù)端建立連接卦羡,當(dāng)增加設(shè)備并發(fā)請(qǐng)求變多,TCP連接數(shù)在接近1024個(gè)時(shí)麦到,可用TCP連接數(shù)會(huì)降到200左右并且無(wú)法建立新連接,而且分析應(yīng)用服務(wù)的GC和內(nèi)存情況均未發(fā)現(xiàn)異常欠肾。

[圖片上傳失敗...(image-a003b0-1678959123451)]

從他的描述中我提取了幾個(gè)關(guān)鍵值瓶颠,1024200刺桃、無(wú)法建立新連接粹淋。

看到這幾個(gè)數(shù)值,直覺告訴我大概率是TCP請(qǐng)求溢出了瑟慈,我給的建議是先直接調(diào)大全連接隊(duì)列半連接隊(duì)列的閥值試一下效果桃移。

[圖片上傳失敗...(image-5a7a2-1678959123451)]

那為什么我會(huì)給出這個(gè)建議?

半連接隊(duì)列和全連接隊(duì)列又是個(gè)啥玩意葛碧?

弄明白這些回顧下TCP的三次握手流程借杰,一切就迎刃而解了~

回顧TCP

TCP三次握手,熟悉吧进泼,面試八股里經(jīng)常全文背誦的題目蔗衡。

話不多說(shuō)先上一張圖,看明白TCP連接的整個(gè)過(guò)程乳绕。

[圖片上傳失敗...(image-641ed-1678959123451)]

第一步:客戶端發(fā)起SYN_SEND連接請(qǐng)求绞惦,服務(wù)端收到客戶端發(fā)起的SYN請(qǐng)求后,會(huì)先將連接請(qǐng)求放入半連接隊(duì)列洋措;

第二步:服務(wù)端向客戶端響應(yīng)SYN+ACK济蝉;

第三步:客戶端會(huì)返回ACK確認(rèn),服務(wù)端收到第三次握手的 ACK 后標(biāo)識(shí)連接成功菠发。如果這時(shí)全連接隊(duì)列沒滿王滤,內(nèi)核會(huì)把連接從半連接隊(duì)列移除,創(chuàng)建新的連接并將其添加到全連接隊(duì)列雷酪,等待客戶端調(diào)用accept()方法將連接取出來(lái)使用淑仆;

TCP協(xié)議三次握手的過(guò)程,Linux內(nèi)核維護(hù)了兩個(gè)隊(duì)列哥力,SYN半連接隊(duì)列和accepet全連接隊(duì)列蔗怠。即然叫隊(duì)列墩弯,那就存在隊(duì)列被壓滿的時(shí)候,這種情況我們稱之為隊(duì)列溢出寞射。

當(dāng)半連接隊(duì)列或全連接隊(duì)列滿了時(shí)渔工,服務(wù)器都無(wú)法接收新的連接請(qǐng)求,從而導(dǎo)致客戶端無(wú)法建立連接桥温。

全連接隊(duì)列

隊(duì)列信息

全連接隊(duì)列溢出時(shí)引矩,首先要查看全連接隊(duì)列的狀態(tài),服務(wù)端通常使用 ss 命令即可查看侵浸,ss 命令獲取的數(shù)據(jù)又分為 LISTEN狀態(tài) 和 非LISTEN兩種狀態(tài)下旺韭,通常只看LISTEN狀態(tài)數(shù)據(jù)就可以。

LISTEN狀態(tài)

Recv-Q:當(dāng)前全連接隊(duì)列的大小掏觉,表示上圖中已完成三次握手等待可用的 TCP 連接個(gè)數(shù)区端;

Send-Q:全連接最大隊(duì)列長(zhǎng)度,如上監(jiān)聽8888端口的TCP連接最大全連接長(zhǎng)度為128澳腹;

# -l 顯示正在Listener 的socket
# -n 不解析服務(wù)名稱
# -t 只顯示tcp
[root@VM-4-14-centos ~]#  ss -lnt | grep 8888
State  Recv-Q Send-Q  Local Address:Port   Peer Address:Port
LISTEN     0   100       :::8888                  :::*               

非LISTEN 狀態(tài)下Recv-Q织盼、Send-Q字段含義有所不同

Recv-Q:已收到但未被應(yīng)用進(jìn)程讀取的字節(jié)數(shù);

Send-Q:已發(fā)送但未收到確認(rèn)的字節(jié)數(shù)酱塔;

# -n 不解析服務(wù)名稱
# -t 只顯示tcp
[root@VM-4-14-centos ~]#  ss -nt | grep 8888
State  Recv-Q Send-Q  Local Address:Port   Peer Address:Port
ESTAB     0   100       :::8888                  :::*               

隊(duì)列溢出

一般在請(qǐng)求量過(guò)大沥邻,全連接隊(duì)列設(shè)置過(guò)小會(huì)發(fā)生全連接隊(duì)列溢出,也就是LISTEN狀態(tài)下 Send-Q < Recv-Q 的情況羊娃。接收到的請(qǐng)求數(shù)大于TCP全連接隊(duì)列的最大長(zhǎng)度唐全,后續(xù)的請(qǐng)求將被服務(wù)端丟棄,客戶端無(wú)法創(chuàng)建新連接迁沫。

# -l 顯示正在Listener 的socket
# -n 不解析服務(wù)名稱
# -t 只顯示tcp
[root@VM-4-14-centos ~]#  ss -lnt | grep 8888
State  Recv-Q Send-Q  Local Address:Port   Peer Address:Port
LISTEN     200   100       :::8888                  :::*               

如果發(fā)生了全連接隊(duì)列溢出芦瘾,我們可以通過(guò)netstat -s命令查詢溢出的累計(jì)次數(shù),若這個(gè)times持續(xù)的增長(zhǎng)集畅,那就說(shuō)明正在發(fā)生溢出近弟。

[root@VM-4-14-centos ~]# netstat -s | grep overflowed
  7102 times the listen queue of a socket overflowed #全連接隊(duì)列溢出的次數(shù)

拒絕策略

在全連接隊(duì)列已滿的情況,Linux提供了不同的策略去處理后續(xù)的請(qǐng)求挺智,默認(rèn)是直接丟棄祷愉,也可以通過(guò)tcp_abort_on_overflow配置來(lái)更改策略,其值 0 和 1 表示不同的策略赦颇,默認(rèn)配置 0二鳄。

# 查看策略
[root@VM-4-14-centos ~]# cat /proc/sys/net/ipv4/tcp_abort_on_overflow
0

tcp_abort_on_overflow = 0:全連接隊(duì)列已滿時(shí),服務(wù)端直接丟棄客戶端發(fā)送的 ACK媒怯,此時(shí)服務(wù)端仍然是 SYN_RCVD 狀態(tài)订讼,在該狀態(tài)下服務(wù)端會(huì)重試幾次向客戶端推送 SYN + ACK

[圖片上傳失敗...(image-682f50-1678959123451)]

重試次數(shù)取決于tcp_synack_retries配置扇苞,重試次數(shù)超過(guò)此配置后后欺殿,服務(wù)端不在重傳寄纵,此時(shí)客戶端發(fā)送數(shù)據(jù),服務(wù)端直接向客戶端回復(fù)RST復(fù)位報(bào)文脖苏,告知客戶端本次建立連接已失敗程拭。

RST: 連接 reset 重置消息,用于連接的異常關(guān)閉棍潘。常用場(chǎng)景例如:服務(wù)端接收不存在端口的連接請(qǐng)求恃鞋;客戶端或者服務(wù)端異常,無(wú)法繼續(xù)正常的連接處理亦歉,發(fā)送 RST 終止連接操作恤浪;長(zhǎng)期未收到對(duì)方確認(rèn)報(bào)文,經(jīng)過(guò)一定時(shí)間或者重傳嘗試后肴楷,發(fā)送 RST 終止連接资锰。

[root@VM-4-14-centos ~]# cat /proc/sys/net/ipv4/tcp_synack_retries
0

tcp_abort_on_overflow = 1:全連接隊(duì)列已滿時(shí),服務(wù)端直接丟棄客戶端發(fā)送的 ACK阶祭,直接向客戶端回復(fù)RST復(fù)位報(bào)文,告知客戶端本次連接終止直秆,客戶端會(huì)報(bào)錯(cuò)提示connection reset by peer濒募。

隊(duì)列調(diào)整

解決全連接隊(duì)列溢出我們可以通過(guò)調(diào)整TCP參數(shù)來(lái)控制全連接隊(duì)列的大小,全連接隊(duì)列的大小取決于 backlog 和 somaxconn 兩個(gè)參數(shù)圾结。

這里需要注意一下瑰剃,兩個(gè)參數(shù)要同時(shí)調(diào)整,因?yàn)槿〉膬烧咧凶钚≈?code>min(backlog,somaxconn)筝野,經(jīng)常發(fā)生只挑調(diào)大其中一個(gè)另一個(gè)值很小導(dǎo)致不生效的情況晌姚。

backlog 是在socket 創(chuàng)建的時(shí)候 Listen() 函數(shù)傳入的參數(shù),例如我們也可以在 Nginx 配置中指定 backlog 的大小歇竟。

server {
   listen 8888 default backlog = 200
   server_name fire100.top
   .....
}

somaxconn 是個(gè) OS 級(jí)別的參數(shù)挥唠,默認(rèn)值是 128,可以通過(guò)修改 net.core.somaxconn 配置焕议。

[root@localhost core]# sysctl -a | grep net.core.somaxconn
net.core.somaxconn = 128
[root@localhost core]# sysctl -w net.core.somaxconn=1024
net.core.somaxconn = 1024
[root@localhost core]# sysctl -a | grep net.core.somaxconn
net.core.somaxconn = 1024

如果服務(wù)端處理請(qǐng)求的速度跟不上連接請(qǐng)求的到達(dá)速度宝磨,隊(duì)列可能會(huì)被快速填滿,導(dǎo)致連接超時(shí)或丟失盅安。應(yīng)該及時(shí)增加隊(duì)列大小唤锉,以避免連接請(qǐng)求被拒絕或超時(shí)。

增大該參數(shù)的值雖然可以增加隊(duì)列的容量别瞭,但是也會(huì)占用更多的內(nèi)存資源窿祥。一般來(lái)說(shuō),建議將全連接隊(duì)列的大小設(shè)置為服務(wù)器處理能力的兩倍左右蝙寨。

半連接隊(duì)列

隊(duì)列信息

上邊TCP三次握手過(guò)程中晒衩,我們知道服務(wù)端SYN_RECV狀態(tài)的TCP連接存放在半連接隊(duì)列嗤瞎,所以直接執(zhí)行如下命令查看半連接隊(duì)列長(zhǎng)度。

[root@VM-4-14-centos ~]  netstat -natp | grep SYN_RECV | wc -l
1111

隊(duì)列溢出

半連接隊(duì)列溢出最常見的場(chǎng)景就是浸遗,客戶端沒有及時(shí)向服務(wù)端回ACK猫胁,使得服務(wù)端有大量處于SYN_RECV狀態(tài)的連接,導(dǎo)致半連接隊(duì)列被占滿跛锌,得不到ACK響應(yīng)半連接隊(duì)列中的 TCP 連接無(wú)法移動(dòng)全連接隊(duì)列弃秆,以至于后續(xù)的SYN請(qǐng)求無(wú)法創(chuàng)建。這也是一種常見的DDos攻擊方式髓帽。

[圖片上傳失敗...(image-12d9fc-1678959123451)]

查看TCP半連接隊(duì)列溢出情況菠赚,可以執(zhí)行netstat -s命令,SYNs to LISTEN前的數(shù)值表示溢出的次數(shù)郑藏,如果反復(fù)查詢幾次數(shù)值持續(xù)增加衡查,那就說(shuō)明半連接隊(duì)列正在溢出。

[root@VM-4-14-centos ~]# netstat -s | egrep “l(fā)isten|LISTEN”
1606 times the listen queue of a socket overflowed
1606 SYNs to LISTEN sockets ignored

隊(duì)列調(diào)整

可以修改 Linux 內(nèi)核配置 /proc/sys/net/ipv4/tcp_max_syn_backlog來(lái)調(diào)大半連接隊(duì)列長(zhǎng)度必盖。

[root@VM-4-14-centos ~]# echo 2048 > /proc/sys/net/ipv4/tcp_max_syn_backlog

為什么建議

看完上邊對(duì)兩個(gè)隊(duì)列的粗略介紹拌牲,相信大家也能大致明白,為啥我會(huì)直接建議他去調(diào)大隊(duì)列了歌粥。

因?yàn)閺乃拿枋鲋刑岬搅藘蓚€(gè)關(guān)鍵值塌忽,TCP連接數(shù)增加至1024個(gè)時(shí),可用連接數(shù)會(huì)降至200以內(nèi)失驶,一般centos系統(tǒng)全連接隊(duì)列長(zhǎng)度一般默認(rèn) 128土居,半連接隊(duì)列默認(rèn)長(zhǎng)度 1024。所以隊(duì)列溢出可以作為第一嫌疑對(duì)象嬉探。

全連接隊(duì)列默認(rèn)大小 128

[root@localhost core]# sysctl -a | grep net.core.somaxconn
net.core.somaxconn = 128

半連接隊(duì)列默認(rèn)大小 1024

[root@iZ2ze3ifc44ezdiif8jhf7Z ~]# cat /proc/sys/net/ipv4/tcp_max_syn_backlog
1024

總結(jié)

簡(jiǎn)單分享了一點(diǎn)TCP全連接隊(duì)列擦耀、半連接隊(duì)列的相關(guān)內(nèi)容,講的比較淺顯涩堤,如果有不嚴(yán)謹(jǐn)?shù)牡胤綒g迎留言指正眷蜓,畢竟還是個(gè)老菜鳥。

全連接隊(duì)列胎围、半連接隊(duì)列溢出是比較常見账磺,但又容易被忽視的問(wèn)題,往往上線會(huì)遺忘這兩個(gè)配置痊远,一旦發(fā)生溢出垮抗,從CPU線程狀態(tài)碧聪、內(nèi)存看起來(lái)都比較正常冒版,偏偏連接數(shù)上不去。

[圖片上傳失敗...(image-7b19d2-1678959123451)]

定期對(duì)系統(tǒng)壓測(cè)是可以暴露出更多問(wèn)題的逞姿,不過(guò)話又說(shuō)回來(lái)辞嗡,就像我和小伙伴聊的一樣捆等,即便測(cè)試環(huán)境程序跑的在穩(wěn)定,到了線上環(huán)境也總會(huì)出現(xiàn)各種奇奇怪怪的問(wèn)題续室。

我是小富栋烤,下期見~

技術(shù)交流,歡迎關(guān)注公眾號(hào):程序員小富

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末挺狰,一起剝皮案震驚了整個(gè)濱河市明郭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌丰泊,老刑警劉巖薯定,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瞳购,居然都是意外死亡话侄,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門学赛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)年堆,“玉大人,你說(shuō)我怎么就攤上這事盏浇∴秩停” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵缠捌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我译蒂,道長(zhǎng)曼月,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任柔昼,我火速辦了婚禮哑芹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捕透。我一直安慰自己聪姿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布乙嘀。 她就那樣靜靜地躺著末购,像睡著了一般。 火紅的嫁衣襯著肌膚如雪虎谢。 梳的紋絲不亂的頭發(fā)上盟榴,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音婴噩,去河邊找鬼擎场。 笑死羽德,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的迅办。 我是一名探鬼主播宅静,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼站欺!你這毒婦竟也來(lái)了姨夹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镊绪,失蹤者是張志新(化名)和其女友劉穎匀伏,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝴韭,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡够颠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了榄鉴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片履磨。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庆尘,靈堂內(nèi)的尸體忽然破棺而出剃诅,到底是詐尸還是另有隱情,我是刑警寧澤驶忌,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布矛辕,位于F島的核電站,受9級(jí)特大地震影響付魔,放射性物質(zhì)發(fā)生泄漏聊品。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一几苍、第九天 我趴在偏房一處隱蔽的房頂上張望翻屈。 院中可真熱鬧,春花似錦妻坝、人聲如沸伸眶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)厘贼。三九已至,卻和暖如春圣拄,著一層夾襖步出監(jiān)牢的瞬間涂臣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赁遗,地道東北人署辉。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像岩四,于是被迫代替她去往敵國(guó)和親哭尝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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