《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 通信與網(wǎng)絡(luò) > 其他 > Linux教學(xué)——用了TCP協(xié)議,就一定不會丟包嗎?

Linux教學(xué)——用了TCP協(xié)議,就一定不會丟包嗎?

2022-08-19
作者:小白
來源:小白debug
關(guān)鍵詞: TCP

  平時,我們想要知道,自己的機(jī)器到目的機(jī)器之間,網(wǎng)絡(luò)通不通,一般會執(zhí)行ping命令。

  一般對于狀況良好的網(wǎng)絡(luò)來說,你能看到它對應(yīng)的loss丟包率為0%,也就是所謂的能ping通。如果看到丟包率100%,也就是ping不通。

微信截圖_20220819170226.png

  那么問題來了,假設(shè)我能ping通某臺機(jī)器,那這時候如果我改用TCP協(xié)議去發(fā)數(shù)據(jù)到目的機(jī)器,也一定能通嗎?

  或者換個問法,ping和tcp協(xié)議走的網(wǎng)絡(luò)路徑是一樣的嗎?

  這時候第一反應(yīng)就是不一定,因?yàn)閜ing完之后中間鏈路里的某個路由器可能會掛了(斷電了),再用TCP去連就會走別的路徑。

  也沒錯。但假設(shè),中間鏈路沒發(fā)生任何變化呢?

  我先直接說答案。

  不一定,走的網(wǎng)絡(luò)路徑還是有可能是不同的。

  今天就來聊聊為什么。

  我之前寫過一篇《斷網(wǎng)了,還能ping通 127.0.0.1 嗎?》,里面提到過ping數(shù)據(jù)包和tcp數(shù)據(jù)包的區(qū)別。

  微信圖片_20220819170247.png

  ping和TCP發(fā)消息的區(qū)別

  我們知道網(wǎng)絡(luò)是分層的,每一層都有對應(yīng)協(xié)議。

  微信圖片_20220819170310.png

  五層網(wǎng)絡(luò)協(xié)議對應(yīng)的消息體變化分析

  而這網(wǎng)絡(luò)層就像搭積木一樣,上層協(xié)議都是基于下層協(xié)議搭出來的。

  不管是ping(用了ICMP協(xié)議)還是tcp本質(zhì)上都是基于網(wǎng)絡(luò)層IP協(xié)議的數(shù)據(jù)包,而到了物理層,都是二進(jìn)制01串,都走網(wǎng)卡發(fā)出去了。

  如果網(wǎng)絡(luò)環(huán)境沒發(fā)生變化,目的地又一樣,那按道理說他們走的網(wǎng)絡(luò)路徑應(yīng)該是一樣的,什么情況下會不同呢?

  我們就從路由這個話題聊起吧。

  網(wǎng)絡(luò)路徑

  在我們的想象中,當(dāng)我們想在兩臺機(jī)器之間傳輸數(shù)據(jù)。本機(jī)和目的機(jī)器之間會建立一條連接,像一條管道一樣,數(shù)據(jù)從這頭到那頭。這條管道其實(shí)是我們?yōu)榱朔奖憷斫舛橄蟪鰜淼母拍睢?/p>

  實(shí)際上,我們將數(shù)據(jù)包從本地網(wǎng)卡發(fā)出之后,會經(jīng)過各種路由器(或者交換機(jī)),才能到達(dá)目的機(jī)器。

  這些路由器數(shù)量眾多,相互之間可以互連,連起來之后就像是一張大網(wǎng),所以叫"網(wǎng)絡(luò)"可以說是非常的形象。

  微信圖片_20220819170647.png

  路由器構(gòu)成的網(wǎng)絡(luò)

  考慮到交換機(jī)有的功能,路由器基本上都支持,所以我們這邊只討論路由器。

  那么現(xiàn)在問題來了,路由器收到數(shù)據(jù)后,怎么知道應(yīng)該走哪條路徑,傳給哪個路由器?

  路徑由什么決定?

  在上面的那么大一張網(wǎng)絡(luò)中,隨便一個路由器都有可能走任何一個路徑,將數(shù)據(jù)發(fā)到另外一個路由器上,

  但路由和路由之間距離,帶寬啥的可能都不同。

  于是就很需要知道,兩點(diǎn)之間走哪條路才是最優(yōu)路徑。

  于是問題就變成了這樣一個圖狀結(jié)構(gòu)。每條邊都帶有成本或權(quán)重,算這上面任意兩點(diǎn)的最短距離。

  微信圖片_20220819171114.png

  路由器和Dijkstra

  這時候想必大家回憶壓不住要上來了。

  這題我熟,這就是大學(xué)時候刷的Dijkstra算法。菊花廠的OJ筆試題集里也經(jīng)常出現(xiàn),現(xiàn)在終于明白為什么他們家的筆試題里圖類題目比別的大廠貌似要多一些了吧,因?yàn)榫栈◤S就是搞通信的,做路由器的老玩家了。

  路由表的生成

  基于Dijkstra算法,封裝出了一個新的協(xié)議,OSPF協(xié)議(Open Shortest Path First, 開放最短路徑優(yōu)先)。

  有了OSPF,路由器就得到了網(wǎng)絡(luò)圖里自己到其他點(diǎn)之間的最短距離,于是就知道了數(shù)據(jù)包要到某個點(diǎn),該走哪條最優(yōu)路徑。

  將這些信息匯成一張表,也就是我們常說的路由表。

  路由表里記錄了到什么IP需要走什么端口,以及走這條路徑的成本(metric)。

  可以通過 route 命令查看到。

  微信圖片_20220819171148.png

  route表

  路由表決定數(shù)據(jù)包路徑

  數(shù)據(jù)包在發(fā)送的過程中,會在網(wǎng)絡(luò)層加入目標(biāo)地址IP。

  路由器會根據(jù)這個IP跟路由表去做匹配。

  然后路由表,會告訴路由器,什么樣的消息該轉(zhuǎn)發(fā)到什么端口。

  舉個例子。

  微信圖片_20220819171208.png

  通過路由表轉(zhuǎn)發(fā)數(shù)據(jù)

  假設(shè)A要發(fā)消息到D。也就是192.168.0.105/24要發(fā)消息到192.168.1.11/24。

  那么A會把消息經(jīng)發(fā)到路由器。

  路由器已知目的地IP192.168.1.11/24 ,去跟路由表做匹配,發(fā)現(xiàn)192.168.1.0/24, 就在e2端口,那么就會把消息從e2端口發(fā)出,(可能還會經(jīng)過交換機(jī))最后把消息打到目的機(jī)器。

  當(dāng)然,如果路由表里找不到,那就打到默認(rèn)網(wǎng)關(guān)吧,也就是從e1口發(fā)出,發(fā)到IP192.0.2.1。這個路由器的路由表不知道該去哪,說不定其他路由器知道。

  路由表的匹配規(guī)則

  上面的例子里,是只匹配上了路由表里的一項(xiàng),所以只能是它了。

  但是,條條大路通羅馬。實(shí)際上能到目的地的路徑肯定有很多。

  如果路由表里有很多項(xiàng)都被匹配上了,會怎么選?

  如果多個路由項(xiàng)都能到目的地,那就優(yōu)先選匹配長度更長的那個。比如,還是目的地192.168.1.11,發(fā)現(xiàn)路由表里的192.168.1.0/24 和 192.168.0.0/16都能匹配上,但明顯前者匹配長度更長,所以最后會走 192.168.1.0/24對應(yīng)的轉(zhuǎn)發(fā)端口。

  但如果兩個表項(xiàng)的匹配長度都一樣呢?

  那就會看生成這個路由表項(xiàng)的協(xié)議是啥,選優(yōu)先級高的,優(yōu)先級越高也就是所謂的管理距離(AD,AdministrativeDistance)越小。比如說優(yōu)先選手動配的靜態(tài)(static)路由,次優(yōu)選OSPF動態(tài)學(xué)習(xí)過來的表項(xiàng)。

  如果還是相同,就看度量值metrics,其實(shí)也就是路徑成本cost,成本越小,越容易被選中。

  路由器能選的路線有很多,但按道理,最優(yōu)的只有"一條",所以到這里為止,我們都可以認(rèn)為,對于同一個目的地,ping和TCP走的路徑是相同的。

  但是。

  如果連路徑成本都一樣呢?也就是說有多條最優(yōu)路徑呢。

  那就都用。

  這也就是所謂的等價多路徑,ECMP(Equal Cost MultiPath)。

  我們可以通過traceroute看下鏈路是否存在等價多路徑的情況。

  微信圖片_20220819171623.png

  可以看到,中間某幾行,有好幾個IP,也就是說這一跳里同時可以選好幾個目的機(jī)器,說明這段路徑支持ECMP。

  ECMP有什么用

  利用等價多路徑,我們可以增加鏈路帶寬。

  舉個例子。

  微信圖片_20220819171644.png

  沒有ECMP時只能選擇某一條路徑

  從A點(diǎn)到B點(diǎn),如果這兩條路徑成本不同,帶寬都是1千兆。那數(shù)據(jù)包肯定就選成本低的那條路了,如果這條路出故障了,就走下面那條路。但不管怎么樣,同一時間,只用到了一條路徑。另外一條閑置就有些浪費(fèi)了,有沒有辦法可以利用起來呢?

  有,將它們兩條路徑的成本設(shè)置成一樣,那它們就成了等價路由,然后中間的路由器開啟ECMP特性,就可以同時利用這兩條鏈路了。帶寬就從原來的1千兆變成了2千兆。數(shù)據(jù)就可以在兩條路徑中隨意選擇了。

  微信圖片_20220819171704.png

  利用ECMP可以同時使用兩條鏈路

  但這也帶來了另外一個問題。加劇了數(shù)據(jù)包亂序。

  原來我只使用一條網(wǎng)絡(luò)路徑,數(shù)據(jù)依次發(fā)出,如無意外,也是依次到達(dá)。

  現(xiàn)在兩個數(shù)據(jù)包走兩條路徑,先發(fā)的數(shù)據(jù)包可能后到。這就亂序了。

  那么問題又又來了。

  亂序會有什么問題?

  對于我們最最最常使用的TCP協(xié)議來說,它是個可靠性網(wǎng)絡(luò)的協(xié)議,這里提到的可靠,不僅是保證數(shù)據(jù)要能送到目的地,還要保證數(shù)據(jù)順序要跟原來發(fā)送端的一樣。

  實(shí)現(xiàn)也很簡單,TCP為每個數(shù)據(jù)包(segment)做上編號。數(shù)據(jù)到了接收端后,根據(jù)數(shù)據(jù)包編號發(fā)現(xiàn)是亂序數(shù)據(jù)包,就會扔到亂序隊(duì)列中對數(shù)據(jù)包進(jìn)行排序。如果前面的數(shù)據(jù)包還沒到,哪怕后面的數(shù)據(jù)包先到了,也得在亂序隊(duì)列中一直等,到齊后才能被上層拿到。

  舉個例子,發(fā)送端發(fā)出三個數(shù)據(jù)包,編號1,2,3,假設(shè)在傳輸層2和3先到了,1還沒到。那此時應(yīng)用層是沒辦法拿到2和3的數(shù)據(jù)包的,必須得等1來了之后,應(yīng)用層才能一次性拿到這三個包。因?yàn)檫@三個包原來可能表示的是一個完整的消息,少了1, 那么消息就不完整,應(yīng)用層拿到了也毫無意義。

  像這種,由于前面的數(shù)據(jù)丟失導(dǎo)致后面的數(shù)據(jù)沒辦法及時給到應(yīng)用層的現(xiàn)象,就是我們常說的TCP隊(duì)頭阻塞。

  微信圖片_20220819172025.png

  亂序隊(duì)列等待數(shù)據(jù)包的到來

  亂序發(fā)生時2和3需要待在亂序隊(duì)列中,而亂序隊(duì)列其實(shí)用的也是接收緩沖區(qū)的內(nèi)存,而接收緩沖區(qū)是有大小限制的。通過下面的命令可以看到接收緩沖區(qū)的大小。

  # 查看接收緩沖區(qū)

  $ sysctl net.ipv4.tcp_rmem

  net.ipv4.tcp_rmem = 4096(min)    87380(default)  6291456(max)

  # 緩沖區(qū)會在min和max之間動態(tài)調(diào)整

  亂序的情況越多,接收緩沖區(qū)的內(nèi)存就被占用的越多,對應(yīng)的接收窗口就會變小,那正常能收的數(shù)據(jù)就變少了,網(wǎng)絡(luò)吞吐就變差了,也就是性能變差了。

  因此,我們需要盡量保證所有同一個TCP連接下的所有TCP包都走相同路徑,這樣才能最大程度避免丟包。

  ECMP的路徑選擇策略

  當(dāng)初開啟ECMP就是為了提升性能,現(xiàn)在反而加重了亂序,降低了TCP傳輸性能。

  這怎么能忍。

  為了解決這個問題,我們需要有一個合理的路徑選擇策略。為了避免同一個連接里的數(shù)據(jù)包亂序,我們需要保證同一個連接里的數(shù)據(jù)包,都走同樣的路徑。

  這好辦。我們可以通過連接的五元組(發(fā)送方的IP和端口,接收方的IP和端口,以及通信協(xié)議)信息定位到唯一一條連接。

  微信圖片_20220819172102.png

  五元組

  然后對五元組信息生成哈希鍵,讓同一個哈希鍵的數(shù)據(jù)走同一條路徑,問題就完美解決了。

  

微信截圖_20220819172245.png

  TCP和Ping走的網(wǎng)絡(luò)路徑一樣嗎

  現(xiàn)在我們回到文章開頭的問題。

  對于同樣的發(fā)送端和接收端,TCP和Ping走的網(wǎng)絡(luò)路徑一樣嗎?

  不一定一樣,因?yàn)槲逶M里的信息里有一項(xiàng)是通信協(xié)議。ping用的是ICMP協(xié)議,跟TCP協(xié)議不同,并且ping不需要用到端口,所以五元組不同,生成的哈希鍵不同,通過ECMP選擇到的路徑也可能不同。

  微信圖片_20220819172401.png

  TCP和ping的五元組差異

  同樣都用TCP協(xié)議,數(shù)據(jù)包走的網(wǎng)絡(luò)路徑一樣嗎

  還是同樣的發(fā)送端和接收端,同樣是TCP協(xié)議,不同TCP連接走的網(wǎng)絡(luò)路徑是一樣的嗎?

  跟上面的問題一樣,其實(shí)還是五元組的問題,同樣都是TCP協(xié)議,對于同樣的發(fā)送端和接收端,他們的IP和接收端的端口肯定是一樣的,但發(fā)送方的端口是可以隨時變化的,因此通過ECMP走的路徑也可能不同。

  微信圖片_20220819172422.png

  不同TCP連接的五元組差異

  但問題又來了。

  我知道這個有什么用呢?我做業(yè)務(wù)開發(fā),又沒有設(shè)置網(wǎng)絡(luò)路由的權(quán)限。

  利用這個知識點(diǎn)排查問題

  對于業(yè)務(wù)開發(fā),這絕對不是個沒用的知識點(diǎn)。

  如果某天,你發(fā)現(xiàn),你能ping通目的機(jī)器,但用TCP去連,卻偶爾連不上目的機(jī)器。而且兩端機(jī)器都挺空閑,沒什么性能上的瓶頸。實(shí)在走投無路了。

  你就可以想想,會不會是網(wǎng)絡(luò)中用到了ECMP,其中一條鏈路有問題導(dǎo)致的。

  微信圖片_20220819172509.png

  ping能成功但部分TCP連接失敗

  排查方法也很簡單。

  你是知道本機(jī)的IP以及目的機(jī)器的IP和端口號的,也知道自己用的是TCP連接。

  只要你在報(bào)錯的時候打印下錯誤信息,你就知道了發(fā)送端的端口號了。

  這樣五元組是啥你就知道了。

  下一步就是指定發(fā)送端的端口號重新發(fā)起TCP請求,同樣的五元組,走同樣的路徑,按理說如果鏈路有問題,就肯定會復(fù)現(xiàn)。

  如果不想改自己的代碼,你可以用nc命令指定客戶端端口看下能不能正常建立TCP連接。

  nc -p 6666 baidu.com 80

  -p 6666是指定發(fā)出請求的客戶端端口是6666,后面跟著的是連接的域名和80端口。

  微信圖片_20220819172535.png

  通過nc成功建立tcp連接

  假設(shè)用了6666端口的五元組去連接總是失敗,改用6667或其他端口卻能成功,你可以帶著這個信息去找找負(fù)責(zé)網(wǎng)絡(luò)的同事。

  總結(jié)

  路由器可以通過OSPF協(xié)議生成路由表,利用數(shù)據(jù)包里的IP地址去跟路由表做匹配,選擇最優(yōu)路徑后進(jìn)行轉(zhuǎn)發(fā)。

  當(dāng)路由表一個都匹配不上時會走默認(rèn)網(wǎng)關(guān)。當(dāng)匹配上多個的時候,會先看匹配長度,如果一樣就看管理距離,還一樣就看路徑成本。如果連路徑成本都一樣,那等價路徑。如果路由開啟了ECMP,那就可以同時利用這幾條路徑做傳輸。

  ECMP可以提高鏈路帶寬,同時利用五元組做哈希鍵進(jìn)行路徑選擇,保證了同一條連接的數(shù)據(jù)包走同一條路徑,減少了亂序的情況。

  可以通過traceroute命令查看到鏈路上是否有用到ECMP的情況。

  開啟了ECMP的網(wǎng)絡(luò)鏈路中,TCP和ping命令可能走的路徑不同,甚至同樣是TCP,不同連接之間,走的路徑也不同,因此出現(xiàn)了連接時好時壞的問題,實(shí)在是走投無路了,可以考慮下是不是跟ECMP有關(guān)。

  當(dāng)然,遇到問題多懷疑自己,要相信絕大部分時候真的跟ECMP無關(guān)。


  更多信息可以來這里獲取==>>電子技術(shù)應(yīng)用-AET<<

微信圖片_20210517164139.jpg



本站內(nèi)容除特別聲明的原創(chuàng)文章之外,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點(diǎn)。轉(zhuǎn)載的所有的文章、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認(rèn)版權(quán)者。如涉及作品內(nèi)容、版權(quán)和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失。聯(lián)系電話:010-82306118;郵箱:aet@chinaaet.com。