平時(shí),我們想要知道,自己的機(jī)器到目的機(jī)器之間,網(wǎng)絡(luò)通不通,一般會(huì)執(zhí)行ping命令。
一般對(duì)于狀況良好的網(wǎng)絡(luò)來(lái)說(shuō),你能看到它對(duì)應(yīng)的loss丟包率為0%,也就是所謂的能ping通。如果看到丟包率100%,也就是ping不通。
ping正常 ping不通
那么問(wèn)題來(lái)了,假設(shè)我能ping通某臺(tái)機(jī)器,那這時(shí)候如果我改用TCP協(xié)議去發(fā)數(shù)據(jù)到目的機(jī)器,也一定能通嗎?
或者換個(gè)問(wèn)法,ping和tcp協(xié)議走的網(wǎng)絡(luò)路徑是一樣的嗎?
這時(shí)候第一反應(yīng)就是不一定,因?yàn)閜ing完之后中間鏈路里的某個(gè)路由器可能會(huì)掛了(斷電了),再用TCP去連就會(huì)走別的路徑。
也沒(méi)錯(cuò)。但假設(shè),中間鏈路沒(méi)發(fā)生任何變化呢?
我先直接說(shuō)答案。
不一定,走的網(wǎng)絡(luò)路徑還是有可能是不同的。
今天就來(lái)聊聊為什么。
我之前寫過(guò)一篇《斷網(wǎng)了,還能ping通 127.0.0.1 嗎?》,里面提到過(guò)ping數(shù)據(jù)包和tcp數(shù)據(jù)包的區(qū)別。
ping和TCP發(fā)消息的區(qū)別
我們知道網(wǎng)絡(luò)是分層的,每一層都有對(duì)應(yīng)協(xié)議。
五層網(wǎng)絡(luò)協(xié)議對(duì)應(yīng)的消息體變化分析
而這網(wǎng)絡(luò)層就像搭積木一樣,上層協(xié)議都是基于下層協(xié)議搭出來(lái)的。
不管是ping(用了ICMP協(xié)議)還是tcp本質(zhì)上都是基于網(wǎng)絡(luò)層IP協(xié)議的數(shù)據(jù)包,而到了物理層,都是二進(jìn)制01串,都走網(wǎng)卡發(fā)出去了。
如果網(wǎng)絡(luò)環(huán)境沒(méi)發(fā)生變化,目的地又一樣,那按道理說(shuō)他們走的網(wǎng)絡(luò)路徑應(yīng)該是一樣的,什么情況下會(huì)不同呢?
我們就從路由這個(gè)話題聊起吧。
網(wǎng)絡(luò)路徑
在我們的想象中,當(dāng)我們想在兩臺(tái)機(jī)器之間傳輸數(shù)據(jù)。本機(jī)和目的機(jī)器之間會(huì)建立一條連接,像一條管道一樣,數(shù)據(jù)從這頭到那頭。這條管道其實(shí)是我們?yōu)榱朔奖憷斫舛橄蟪鰜?lái)的概念。
實(shí)際上,我們將數(shù)據(jù)包從本地網(wǎng)卡發(fā)出之后,會(huì)經(jīng)過(guò)各種路由器(或者交換機(jī)),才能到達(dá)目的機(jī)器。
這些路由器數(shù)量眾多,相互之間可以互連,連起來(lái)之后就像是一張大網(wǎng),所以叫"網(wǎng)絡(luò)"可以說(shuō)是非常的形象。
路由器構(gòu)成的網(wǎng)絡(luò)
考慮到交換機(jī)有的功能,路由器基本上都支持,所以我們這邊只討論路由器。
那么現(xiàn)在問(wèn)題來(lái)了,路由器收到數(shù)據(jù)后,怎么知道應(yīng)該走哪條路徑,傳給哪個(gè)路由器?
路徑由什么決定?
在上面的那么大一張網(wǎng)絡(luò)中,隨便一個(gè)路由器都有可能走任何一個(gè)路徑,將數(shù)據(jù)發(fā)到另外一個(gè)路由器上,
但路由和路由之間距離,帶寬啥的可能都不同。
于是就很需要知道,兩點(diǎn)之間走哪條路才是最優(yōu)路徑。
于是問(wèn)題就變成了這樣一個(gè)圖狀結(jié)構(gòu)。每條邊都帶有成本或權(quán)重,算這上面任意兩點(diǎn)的最短距離。
路由器和Dijkstra
這時(shí)候想必大家回憶壓不住要上來(lái)了。
這題我熟,這就是大學(xué)時(shí)候刷的Dijkstra算法。菊花廠的OJ筆試題集里也經(jīng)常出現(xiàn),現(xiàn)在終于明白為什么他們家的筆試題里圖類題目比別的大廠貌似要多一些了吧,因?yàn)榫栈◤S就是搞通信的,做路由器的老玩家了。
路由表的生成
基于Dijkstra算法,封裝出了一個(gè)新的協(xié)議,OSPF協(xié)議(Open Shortest Path First, 開放最短路徑優(yōu)先)。
有了OSPF,路由器就得到了網(wǎng)絡(luò)圖里自己到其他點(diǎn)之間的最短距離,于是就知道了數(shù)據(jù)包要到某個(gè)點(diǎn),該走哪條最優(yōu)路徑。
將這些信息匯成一張表,也就是我們常說(shuō)的路由表。
路由表里記錄了到什么IP需要走什么端口,以及走這條路徑的成本(metric)。
可以通過(guò) route 命令查看到。
route表
路由表決定數(shù)據(jù)包路徑
數(shù)據(jù)包在發(fā)送的過(guò)程中,會(huì)在網(wǎng)絡(luò)層加入目標(biāo)地址IP。
路由器會(huì)根據(jù)這個(gè)IP跟路由表去做匹配。
然后路由表,會(huì)告訴路由器,什么樣的消息該轉(zhuǎn)發(fā)到什么端口。
舉個(gè)例子。
通過(guò)路由表轉(zhuǎn)發(fā)數(shù)據(jù)
假設(shè)A要發(fā)消息到D。也就是192.168.0.105/24要發(fā)消息到192.168.1.11/24。
那么A會(huì)把消息經(jīng)發(fā)到路由器。
路由器已知目的地IP192.168.1.11/24 ,去跟路由表做匹配,發(fā)現(xiàn)192.168.1.0/24, 就在e2端口,那么就會(huì)把消息從e2端口發(fā)出,(可能還會(huì)經(jīng)過(guò)交換機(jī))最后把消息打到目的機(jī)器。
當(dāng)然,如果路由表里找不到,那就打到默認(rèn)網(wǎng)關(guān)吧,也就是從e1口發(fā)出,發(fā)到IP192.0.2.1。這個(gè)路由器的路由表不知道該去哪,說(shuō)不定其他路由器知道。
路由表的匹配規(guī)則
上面的例子里,是只匹配上了路由表里的一項(xiàng),所以只能是它了。
但是,條條大路通羅馬。實(shí)際上能到目的地的路徑肯定有很多。
如果路由表里有很多項(xiàng)都被匹配上了,會(huì)怎么選?
如果多個(gè)路由項(xiàng)都能到目的地,那就優(yōu)先選匹配長(zhǎng)度更長(zhǎng)的那個(gè)。比如,還是目的地192.168.1.11,發(fā)現(xiàn)路由表里的192.168.1.0/24 和 192.168.0.0/16都能匹配上,但明顯前者匹配長(zhǎng)度更長(zhǎng),所以最后會(huì)走 192.168.1.0/24對(duì)應(yīng)的轉(zhuǎn)發(fā)端口。
但如果兩個(gè)表項(xiàng)的匹配長(zhǎng)度都一樣呢?
那就會(huì)看生成這個(gè)路由表項(xiàng)的協(xié)議是啥,選優(yōu)先級(jí)高的,優(yōu)先級(jí)越高也就是所謂的管理距離(AD,AdministrativeDistance)越小。比如說(shuō)優(yōu)先選手動(dòng)配的靜態(tài)(static)路由,次優(yōu)選OSPF動(dòng)態(tài)學(xué)習(xí)過(guò)來(lái)的表項(xiàng)。
如果還是相同,就看度量值metrics,其實(shí)也就是路徑成本cost,成本越小,越容易被選中。
路由器能選的路線有很多,但按道理,最優(yōu)的只有"一條",所以到這里為止,我們都可以認(rèn)為,對(duì)于同一個(gè)目的地,ping和TCP走的路徑是相同的。
但是。
如果連路徑成本都一樣呢?也就是說(shuō)有多條最優(yōu)路徑呢。
那就都用。
這也就是所謂的等價(jià)多路徑,ECMP(Equal Cost MultiPath)。
我們可以通過(guò)traceroute看下鏈路是否存在等價(jià)多路徑的情況。
可以看到,中間某幾行,有好幾個(gè)IP,也就是說(shuō)這一跳里同時(shí)可以選好幾個(gè)目的機(jī)器,說(shuō)明這段路徑支持ECMP。
ECMP有什么用
利用等價(jià)多路徑,我們可以增加鏈路帶寬。
舉個(gè)例子。
沒(méi)有ECMP時(shí)只能選擇某一條路徑
從A點(diǎn)到B點(diǎn),如果這兩條路徑成本不同,帶寬都是1千兆。那數(shù)據(jù)包肯定就選成本低的那條路了,如果這條路出故障了,就走下面那條路。但不管怎么樣,同一時(shí)間,只用到了一條路徑。另外一條閑置就有些浪費(fèi)了,有沒(méi)有辦法可以利用起來(lái)呢?
有,將它們兩條路徑的成本設(shè)置成一樣,那它們就成了等價(jià)路由,然后中間的路由器開啟ECMP特性,就可以同時(shí)利用這兩條鏈路了。帶寬就從原來(lái)的1千兆變成了2千兆。數(shù)據(jù)就可以在兩條路徑中隨意選擇了。
利用ECMP可以同時(shí)使用兩條鏈路
但這也帶來(lái)了另外一個(gè)問(wèn)題。加劇了數(shù)據(jù)包亂序。
原來(lái)我只使用一條網(wǎng)絡(luò)路徑,數(shù)據(jù)依次發(fā)出,如無(wú)意外,也是依次到達(dá)。
現(xiàn)在兩個(gè)數(shù)據(jù)包走兩條路徑,先發(fā)的數(shù)據(jù)包可能后到。這就亂序了。
那么問(wèn)題又又來(lái)了。
亂序會(huì)有什么問(wèn)題?
對(duì)于我們最最最常使用的TCP協(xié)議來(lái)說(shuō),它是個(gè)可靠性網(wǎng)絡(luò)的協(xié)議,這里提到的可靠,不僅是保證數(shù)據(jù)要能送到目的地,還要保證數(shù)據(jù)順序要跟原來(lái)發(fā)送端的一樣。
實(shí)現(xiàn)也很簡(jiǎn)單,TCP為每個(gè)數(shù)據(jù)包(segment)做上編號(hào)。數(shù)據(jù)到了接收端后,根據(jù)數(shù)據(jù)包編號(hào)發(fā)現(xiàn)是亂序數(shù)據(jù)包,就會(huì)扔到亂序隊(duì)列中對(duì)數(shù)據(jù)包進(jìn)行排序。如果前面的數(shù)據(jù)包還沒(méi)到,哪怕后面的數(shù)據(jù)包先到了,也得在亂序隊(duì)列中一直等,到齊后才能被上層拿到。
舉個(gè)例子,發(fā)送端發(fā)出三個(gè)數(shù)據(jù)包,編號(hào)1,2,3,假設(shè)在傳輸層2和3先到了,1還沒(méi)到。那此時(shí)應(yīng)用層是沒(méi)辦法拿到2和3的數(shù)據(jù)包的,必須得等1來(lái)了之后,應(yīng)用層才能一次性拿到這三個(gè)包。因?yàn)檫@三個(gè)包原來(lái)可能表示的是一個(gè)完整的消息,少了1, 那么消息就不完整,應(yīng)用層拿到了也毫無(wú)意義。
像這種,由于前面的數(shù)據(jù)丟失導(dǎo)致后面的數(shù)據(jù)沒(méi)辦法及時(shí)給到應(yīng)用層的現(xiàn)象,就是我們常說(shuō)的TCP隊(duì)頭阻塞。
亂序隊(duì)列等待數(shù)據(jù)包的到來(lái)
亂序發(fā)生時(shí)2和3需要待在亂序隊(duì)列中,而亂序隊(duì)列其實(shí)用的也是接收緩沖區(qū)的內(nèi)存,而接收緩沖區(qū)是有大小限制的。通過(guò)下面的命令可以看到接收緩沖區(qū)的大小。
#查看接收緩沖區(qū) $sysctlnet.ipv4.tcp_rmem net.ipv4.tcp_rmem=4096(min)87380(default)6291456(max) #緩沖區(qū)會(huì)在min和max之間動(dòng)態(tài)調(diào)整
亂序的情況越多,接收緩沖區(qū)的內(nèi)存就被占用的越多,對(duì)應(yīng)的接收窗口就會(huì)變小,那正常能收的數(shù)據(jù)就變少了,網(wǎng)絡(luò)吞吐就變差了,也就是性能變差了。
因此,我們需要盡量保證所有同一個(gè)TCP連接下的所有TCP包都走相同路徑,這樣才能最大程度避免丟包。
ECMP的路徑選擇策略
當(dāng)初開啟ECMP就是為了提升性能,現(xiàn)在反而加重了亂序,降低了TCP傳輸性能。
這怎么能忍。
為了解決這個(gè)問(wèn)題,我們需要有一個(gè)合理的路徑選擇策略。為了避免同一個(gè)連接里的數(shù)據(jù)包亂序,我們需要保證同一個(gè)連接里的數(shù)據(jù)包,都走同樣的路徑。
這好辦。我們可以通過(guò)連接的五元組(發(fā)送方的IP和端口,接收方的IP和端口,以及通信協(xié)議)信息定位到唯一一條連接。
五元組
然后對(duì)五元組信息生成哈希鍵,讓同一個(gè)哈希鍵的數(shù)據(jù)走同一條路徑,問(wèn)題就完美解決了。
五元組映射成hash鍵 根據(jù)五元組選擇ECMP路徑
TCP和Ping走的網(wǎng)絡(luò)路徑一樣嗎
現(xiàn)在我們回到文章開頭的問(wèn)題。
對(duì)于同樣的發(fā)送端和接收端,TCP和Ping走的網(wǎng)絡(luò)路徑一樣嗎?
不一定一樣,因?yàn)?strong>五元組里的信息里有一項(xiàng)是通信協(xié)議。ping用的是ICMP協(xié)議,跟TCP協(xié)議不同,并且ping不需要用到端口,所以五元組不同,生成的哈希鍵不同,通過(guò)ECMP選擇到的路徑也可能不同。
TCP和ping的五元組差異
同樣都用TCP協(xié)議,數(shù)據(jù)包走的網(wǎng)絡(luò)路徑一樣嗎
還是同樣的發(fā)送端和接收端,同樣是TCP協(xié)議,不同TCP連接走的網(wǎng)絡(luò)路徑是一樣的嗎?
跟上面的問(wèn)題一樣,其實(shí)還是五元組的問(wèn)題,同樣都是TCP協(xié)議,對(duì)于同樣的發(fā)送端和接收端,他們的IP和接收端的端口肯定是一樣的,但發(fā)送方的端口是可以隨時(shí)變化的,因此通過(guò)ECMP走的路徑也可能不同。
不同TCP連接的五元組差異
但問(wèn)題又來(lái)了。
我知道這個(gè)有什么用呢?我做業(yè)務(wù)開發(fā),又沒(méi)有設(shè)置網(wǎng)絡(luò)路由的權(quán)限。
利用這個(gè)知識(shí)點(diǎn)排查問(wèn)題
對(duì)于業(yè)務(wù)開發(fā),這絕對(duì)不是個(gè)沒(méi)用的知識(shí)點(diǎn)。
如果某天,你發(fā)現(xiàn),你能ping通目的機(jī)器,但用TCP去連,卻偶爾連不上目的機(jī)器。而且兩端機(jī)器都挺空閑,沒(méi)什么性能上的瓶頸。實(shí)在走投無(wú)路了。
你就可以想想,會(huì)不會(huì)是網(wǎng)絡(luò)中用到了ECMP,其中一條鏈路有問(wèn)題導(dǎo)致的。
ping能成功但部分TCP連接失敗
排查方法也很簡(jiǎn)單。
你是知道本機(jī)的IP以及目的機(jī)器的IP和端口號(hào)的,也知道自己用的是TCP連接。
只要你在報(bào)錯(cuò)的時(shí)候打印下錯(cuò)誤信息,你就知道了發(fā)送端的端口號(hào)了。
這樣五元組是啥你就知道了。
下一步就是指定發(fā)送端的端口號(hào)重新發(fā)起TCP請(qǐng)求,同樣的五元組,走同樣的路徑,按理說(shuō)如果鏈路有問(wèn)題,就肯定會(huì)復(fù)現(xiàn)。
如果不想改自己的代碼,你可以用nc命令指定客戶端端口看下能不能正常建立TCP連接。
nc-p6666baidu.com80
-p 6666是指定發(fā)出請(qǐng)求的客戶端端口是6666,后面跟著的是連接的域名和80端口。
通過(guò)nc成功建立tcp連接
假設(shè)用了6666端口的五元組去連接總是失敗,改用6667或其他端口卻能成功,你可以帶著這個(gè)信息去找找負(fù)責(zé)網(wǎng)絡(luò)的同事。
總結(jié)
路由器可以通過(guò)OSPF協(xié)議生成路由表,利用數(shù)據(jù)包里的IP地址去跟路由表做匹配,選擇最優(yōu)路徑后進(jìn)行轉(zhuǎn)發(fā)。
當(dāng)路由表一個(gè)都匹配不上時(shí)會(huì)走默認(rèn)網(wǎng)關(guān)。當(dāng)匹配上多個(gè)的時(shí)候,會(huì)先看匹配長(zhǎng)度,如果一樣就看管理距離,還一樣就看路徑成本。如果連路徑成本都一樣,那等價(jià)路徑。如果路由開啟了ECMP,那就可以同時(shí)利用這幾條路徑做傳輸。
ECMP可以提高鏈路帶寬,同時(shí)利用五元組做哈希鍵進(jìn)行路徑選擇,保證了同一條連接的數(shù)據(jù)包走同一條路徑,減少了亂序的情況。
可以通過(guò)traceroute命令查看到鏈路上是否有用到ECMP的情況。
開啟了ECMP的網(wǎng)絡(luò)鏈路中,TCP和ping命令可能走的路徑不同,甚至同樣是TCP,不同連接之間,走的路徑也不同,因此出現(xiàn)了連接時(shí)好時(shí)壞的問(wèn)題,實(shí)在是走投無(wú)路了,可以考慮下是不是跟ECMP有關(guān)。
當(dāng)然,遇到問(wèn)題多懷疑自己,要相信絕大部分時(shí)候真的跟ECMP無(wú)關(guān)。
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
6812瀏覽量
88743 -
Ping
+關(guān)注
關(guān)注
0文章
69瀏覽量
15931 -
TCP協(xié)議
+關(guān)注
關(guān)注
1文章
91瀏覽量
12054
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論