騰訊云和阿里云tcp三次握手的區(qū)別
前言
近日同事遇到一個詭異的問題,幫忙進行了排查,好家伙不查不知道,一查讓我知道了,騰訊云和阿里云TCP三次握手居然還有差異,沒有想到云廠商這種Iass級別的服務,還有不同的標準~
問題現(xiàn)象
?客戶是半托管客戶,我們部署服務請求阿里云的nginx,nginx作為LB,反向代理了N個java服務,Java服務入庫.請求鏈路如下: 客戶物理機Java->阿里云 nginx->阿里云Java?從客戶物理機請求阿里云的nginx的時候,出現(xiàn)了包太大,讀取超時,包小,則無問題。從 物理機到-騰訊云的nginx->Java服務 包大和包小都沒有問題。
半托管Java錯誤日志如下:

nginx日志出現(xiàn)408
?阿里云nginx也有其他客戶在用,沒有出現(xiàn)408錯誤,就這個客戶出現(xiàn)?根據(jù)日志,復原請求內容,在物理機上直接curl 阿里云的機器也是同樣的問題,同樣的請求,curl騰訊云的服務器沒有問題,同樣請求不在客戶的物理機,在本地請求阿里云的機器沒有問題。?據(jù)運維說,這臺物理機壞過,客戶那去維修后,重新部署就出現(xiàn)這個問題,維修前沒有這個問題?物理機直接把請求送給阿里云的Java服務,也是同樣的問題 物理機--》阿里云Java服務?詢問客戶,維修后就裝了個centos系統(tǒng),配置了網(wǎng)絡,其他什么都沒有動?詢問運維,只部署服務,配置和以前一樣
nginx 408
通常產生408錯誤有兩個地方的配置會導致:client_body_timeout和client_header_timeout。
這兩個超時時間默認都是60s。
client_body_timeout:定義讀取客戶端請求正文的超時。超時是指相鄰兩次讀操作之間的最大時間間隔,而不是整個請求正文完成傳輸?shù)淖畲髸r間。如果客戶端在這段時間內沒有傳輸任何數(shù)據(jù),nginx將返回408 (Request Time-out)錯誤到客戶端。
client_header_timeout:定義讀取客戶端請求頭部的超時。如果客戶端在這段時間內沒有傳送完整的頭部到nginx, nginx將返回錯誤408 (Request Time-out)到客戶端。
網(wǎng)上都說是要配置這2個參數(shù),但是我們同樣的請求內容,在騰訊云的nginx上是沒有問題的,騰訊云nginx和阿里云的nginx版本和配置是完全能一致的。所以不會是nginx參數(shù)配置的問題,而且直接送阿里云的Java服務,也是讀取超時,所以基本上可以排除是nginx的問題
我們可以看到408都是讀取超時,那么請求到底送沒送到nginx,這個才是關鍵點。
遇事不決,我們抓個包看看
抓包
?本次抓包 物理機--》阿里云nginx
物理機抓包
ali-nginx抓包
使用wireshark分析抓包文件

從圖中可以看出三次握手是成功了的,在發(fā)送http報文的時候,出現(xiàn)了以下錯誤。
?
TCP dup ack XXX#X是nginx給物理機返回的,就是重復應答#前的表示報文到哪個序號丟失,#后面的是表示第幾次丟失
?
TCP Out_of_Order的原因分析:一般來說是網(wǎng)絡擁塞,導致順序包抵達時間不同,延時太長,或者包丟失,需要重新組合數(shù)據(jù)單元,因為他們可能是由不同的路徑到達你的電腦上面。
?
TCP Retransmission原因分析:很明顯是上面的超時引發(fā)的數(shù)據(jù)重傳
?
nginx上的抓包內容如下

nginx上抓包就更簡單了,上面物理機發(fā)送的http報文,在nginx上居然沒有捕獲到,難道是偶然的?然后又重新試了幾次,在nginx上都沒有捕獲到。到這里,就能確定了,物理機到阿里云的網(wǎng)絡鏈路有問題,出現(xiàn)丟包了。
檢查網(wǎng)絡鏈路
?長ping阿里云的nginx
沒有發(fā)現(xiàn)丟包,網(wǎng)絡很穩(wěn)定
聯(lián)想到只有包特別大才會出問題,所以在ping上加了參數(shù)
發(fā)現(xiàn)到了4000的時候,ping就丟包了,推測是數(shù)據(jù)太大,客戶那邊做了白名單限制,聯(lián)系客戶的網(wǎng)工,進行加白后,測試ping是正常了。
這樣就以為搞定了?那就錯了。客戶加白后,ping是沒有問題了,但是http請求一樣,上面的問題還是一樣,加不加白,對這個問題沒有什么影響。
網(wǎng)卡丟包
重新理下思路,只有這個客戶出現(xiàn)問題,那這個客戶本身網(wǎng)絡問題,嫌疑比較大。詢問客戶網(wǎng)工,網(wǎng)絡架構是怎么搭建的,結果一問三不知。
只有大包才會出現(xiàn)問題,那么很可能和分包有關系,馬上查看客戶網(wǎng)卡信息,發(fā)現(xiàn)MTU的值是1500,沒有改過,而且是生產環(huán)境,總不能直接改MTU的值吧,但是另外一個線索引起了注意。

監(jiān)控下網(wǎng)卡信息
是的,沒有看錯,dropped數(shù)據(jù)一直在增加。
RX==receive,接收,從開啟到現(xiàn)在接收封包的情況,是下行流量。
TX==Transmit,發(fā)送,從開啟到現(xiàn)在發(fā)送封包的情況,是上行流量。
講道理,我們的問題也應該是TX,但是他RX一直在丟包。
查看網(wǎng)卡的ring buffer
已經設置最大了,所以不是ring buffer的問題。
我們通過linux源碼[1]可以知道,Linux支持的協(xié)議都在這里定義了,如果協(xié)議不被linux支持,會直接drop,導致上面網(wǎng)卡的drop數(shù)一直在增加。
通過上面可以linux源代碼可以看到,我們的tcp/ip肯定是受支持的,所以drop這個和我們這個問題沒什么關系。
但是我還是很好奇,是什么協(xié)議導致了Linux內核不支持,我們可以通過以下方式判斷。
打印出包的ether type,然后過濾掉操作系統(tǒng)支持的包,剩下的就是丟掉的包
我們在linux代碼搜一下LLDP協(xié)議,發(fā)現(xiàn)并沒有。在ethertypes[2]發(fā)現(xiàn)他的定義是數(shù)據(jù)鏈路層協(xié)議。所以結果很明顯了。
網(wǎng)卡丟包問題和我們前文提到的問題無關。
修改MTU
到這里,我們的懷疑點就只有MTU了,通過ping設置不允許分包來手工探測MTU值 物理機上
1500-8(icmp頭部)-20(ip頭)=1472 ping不通,自己電腦上在來試試,是ok 的,那么結論很明顯了,就是客戶機器上中間鏈路上有小于1500的mtu設備。
繼續(xù)減少字節(jié)數(shù),臨界點在1465是可以通的,超過1465就不行 那么最佳的mtu的值,等于=1465+8+20=1493
接下來就是改設備的MTU值進行測試了
ps:這么修改mtu值,只要重啟機器,就會失效,要研究修改mtu的值
增加如下內容
重啟服務
改完進行curl測試,發(fā)現(xiàn)請求阿里云的nginx是沒有問題了。
到這里問題就已經解決了,但是有個疑問為什么沒有改mtu值前,騰訊的可以,阿里的不行?
騰訊和阿里 tcp三次握手的區(qū)別
帶著疑問,在騰訊的云主機和物理機上抓了個包,來和阿里云的進行對比。以下抓包文件,是以MTU為1500的為例

發(fā)往騰訊云的SYN包當中,MSS值為1460=(1500-20(tcp頭部字節(jié))-20(ip頭部字節(jié)))1460其實是一個默認的規(guī)范 而騰訊回的SYN,ACK包當中,MSS值為1424,比常規(guī)的1460,少16個字節(jié),當然這16個字節(jié)是減了個啥,我也不知道。
回到上面,我們說中間鏈路有設備MTU的值不是1500,最大的為1493. 1493-20-20=1453,1453才應該是物理機的MSS值,而常規(guī)的1460比1453大,會導致丟包,而按照1424發(fā)包,則是沒有問題的。
所有的一切都能解釋的通了。
騰訊云的機器MTU值不是默認的1500嗎?
不,他就是默認的1500,那1424的邏輯肯定不是我們騰訊機器加的,為了確認這個猜想,我們在騰訊云上進行了抓包,由于機器是NAT機器,騰訊云并沒有綁定公網(wǎng)ip,我們抓的包為nginx代理阿里的java服務的三次握手

可以看到,nginx去和java建立連接的時候使用的是1460,也就是說,1424這個邏輯在進入機器網(wǎng)卡前發(fā)生的。而阿里的java服務,回的是1460,說明在出去的時候,騰訊也把mss改為1424了。
到這里,基本上解決了我們的所有疑問。
后續(xù)
我們在和客戶的網(wǎng)工,溝通后發(fā)現(xiàn)1493是他們那邊設置的,而他沒有改過,以前就是用的這個。而我們的運維說也沒改過。那就奇怪了~
溝通后,客戶的網(wǎng)工設置mtu值為1560,說是最大的值,我其實想讓他改1500的,但是不聽我的。
References
[1]
?linux源碼:?https://elixir.bootlin.com/linux/v3.10/source/include/uapi/linux/if_ether.h[2]
?ethertypes:?https://github.com/openbsd/src/blob/master/sys/net/ethertypes.h#L305
本文使用?文章同步助手?同步