MTU與IP分片(可選內容了解)
這里來講一個比較有趣的內容,相信大家都有設置過家用路由器的經歷,不知道有沒有發現一個事情,在設置撥號的時候,里面有一個MTU,值通常是1492或者1480,如果接入方式改為DHCP的情況下,MTU就變成了1500,為什么呢?
(1)了解MTU的作用
Maximum Transmission Unit(MTU):最大傳輸單元。還是以上面的例子,為什么路由器撥號的時候要把MTU設置成1492呢?在這之前已經知道了以太網頭部,一個標準的以太網數據幀最大為1518,其中源MAC 6字節,目的MAC 6個字節,Type 2個字節,FCS 4個字節(前導碼不算在內,在物理層就已經去掉了),6+6+2+4=18個字節,1518-18=1500,這1500正好是是留給上層協議傳輸的大小,也就是我們說的數據幀的大小是1500個字節,包括IP頭部以及上層協議與數據整體在內,也就是說在二層以太網中,實際能傳輸的數據是1500個字節。
舉一個最常見的例子,我們平時在家里用手機或者筆記本連接家用路由器看電視劇、刷抖音,數據包都是這樣的路徑,每個節點都有對應的MTU值,正常都為1500.
假設某一天,外網的對接方式變了,變成了撥號的形式,正常設置后,發現打開網頁很慢或者打不開,咨詢路由器客服后,把MTU值改成1492或者更小點,驚奇的事情發生了,都能正常訪問了,這就回到之前的問題了,為什么現在的路由器MTU都會設置成1492呢?
那是因為寬帶撥號使用的協議是PPPoE,由于還沒涉及這一塊的知識點,我們在這知道它占用8個字節就行,并且是封裝在以太網中的。比如訪問者發送了一個1495字節的數據包給視頻服務器,但是由于家用路由器采用的是這就在原來1500的字節上多出來了8個字節,超過了標準的MTU值1500字節,所以這個時候家用路由器會將這個數據包進行分片,分為2個,一個為數據包為1500個字節,另外一個數據包為3個字節,到了服務器這邊在進行重組。(實際會更加復雜點,待會我們來做個小實驗)
(2)IP分片帶來的問題
IP分片其實在網絡中是一種比較糟糕的情況,帶來了幾個問題
(3)為什么MTU是1500呢,明明IP字段的總長度是65535?
之前學過IP頭部的內容,IP頭部里面有一個總長度,最大值是65535,表示IP協議是能夠承載這么大數據包的,但是由于以太網的數據部分最大為1500,所以你在很多書籍或者稱呼里面會看到IP的數據包最大是1500個字節,多了就會被分片,那為什么以太網要把數據部分定在1500,不能跟IP頭部一樣用65535嗎?那效率不是高很多。
最早的以太網是工作在共享網絡下的,任何一個終端節點發送數據之前,都需要偵聽線路上是否有數據在傳,如果有,需要等待,如果發現線路可用,才可以發送。假設A與B終端同時傳輸1個bit給對方的話,會產生沖突,其中一個就需要等待一端發送完成后在過一個時間間隙才能發送,這個時間間隙是57.6μs。
在10Mbps的以太網中,在57.6μs時間內,能夠傳輸576個bit,以太網中要求數據幀最小長度為576個bit,原因是這個長度正好能夠讓最極端的沖突環境都能夠被檢測到(CSMA/CD),而576個bit換算成字節是72,去掉8個字節的前導符,正好是64個字節,這也是以太網幀數據部分要求的最小長46的原因(46+18),不夠46的會自動填充。
這個是了解64字節的由來,是因為早期工作方式的原因(CSMA/CD),那1500字節又是什么原因呢?
假設以太網沒有這個限制,IP協議最大可以承載65535字節,加上以太網頭部和尾部,是65535+14+4=65553字節,如果早期在10Mbps的以太網上傳輸,會占用共享鏈路50ms,這樣嚴重影響了其他主機的通信,如果有延遲敏感的應用,那肯定是無法接收的,另外如果線路的質量差,大包引起的丟包幾率也會大很多。(50ms的計算方法:(65553*8)/(10*1024*1024)≈0.05(s)(小知識點科普:Mbps為每秒傳輸百萬位比特,而65535是字節單位,1字節=8比特,所以需要*8,10Mbps換算成bps就是10*1024*1024))
竟然大的不行,換成小的呢?,比如MTU等于100,就拿上面學過的ICMP的Ping來說,如果以太網長度為100,ICMP實際數據=100-ICMP頭部(8個字節)-IP頭部(20個字節)-以太網頭部(18個字節)=100-8-20-18=54,你會發現有效率實在太低了,有效率=54/100=54%
最終得到一個通過層層計算,發現如果以太網長度為1518的時候,有效傳輸效率=1472/1518=96.9%,這個值既能保證有一個較大的幀長度,又保證了有效傳效率。更大的或者更小的就會出現上述的問題,這個也是一個折中的長度:1518字節,對應上層IP 就是1500字節(1518-18),這個就是最大傳輸單元MTU的由來。
出現這個問題是因為早期以太網通過Hub這些設備工作,處于共享方式,效率很低,而現在的網絡早已不是10M的網絡了,交換機已經支持1G,10G、100G,而且帶寬獨享,可以同時收發的特性,那有效傳輸效率跟質量提升了非常多,但是如今的網絡你會發現常見的還是用的mtu 1500的標準,只有數據中心或者某些特殊環境使用了一個叫做巨型幀 Jumbo Frame,可以支持大于9000字節的大小,如果全網都使用這種,那傳輸大的文件這些不是更快、延遲很小嗎?
但是現實環境沒這么簡單,因為MTU在每個設備的每一個接口(網卡)上面都是存在的
如果訪問者支持MTU 9000,發送了一個9000大小的數據包交給無線路由器,無線路由正好也支持這么大,交給互聯網設備,互聯網中設備非常多,并不是所有設備都能夠去支持巨型幀的特性,很多地方還使用的非常老的設備在運行,如果要支持勢必是大面積更換,成本會非常大,那如果一個數據包9000大小經過一個MTU是標準1500的設備,那勢必就會造成分片了,還有許多比如超長幀會造成延時、CRC錯誤變多等問題,導致至今無法大面積普及使用的主要原因。
(4)IP分片后為什么會造成延遲跟效率低呢?
拖兩臺電腦,分別設置好地址,然后抓包來看看分片的情況。
說下命令,Ping 192.168.255.2這個都能夠知道啥意思,-l表示ICMP的數據部分(不含其它任何頭部信息)為1473,-c 1只發送一次。
通過抓包,可以看到有幾個信息(wireshark升級了下,界面看起來更美觀了~)
有IP分片包出現,說明剛剛的數據包整體超過1500個字節了。
這里要注意,1473表明的是ICMP數據部分的大小,不計算頭部在內,那么加上頭部后呢? 1473+8(ICMP頭部)+20(IP頭部)=1501,這樣正好超過了1500個字節,所以導致分片了。MTU是二層概念,二層以上的頭部加數據不能超過1500,否則會進行分片。
這里對于剛接觸抓包的朋友來說,可能有點看不懂,我們來看幾個參數
那還有1個字節的包在抓包里面沒有顯示,這可能是抓包中把尾包省略了,但是可以從另外一個地方看出來。
在看一個完整的包可以上面的疑惑了
可能數據包小,感受不到分片帶來的問題,上圖數據大小改成了5000,會發現4個分片(最后一個是隱藏了),那就會多出4個IP頭部,這些是無故多出來的數據,并且這4個頭部不管是中間設備還是接收方都需要去解封裝來看是什么內容,并且接收方根據IP頭部的分片給的信息去組裝,假設某一個分片中途延遲,那么這個數據包就不會完整,必須等待這片來組裝后才能讀取到實際的內容,這種會影響效率(多余的頭部處理),增加延遲(某一個分片沒到,對應的數據沒法重組,導致數據請求遲遲得不到響應。)更嚴重的其實是會加重設備的負擔(可能實際中不只一個數據包分片,接收方需要把收到的進行緩存,等待所有對應的分片來才能讀取到實際的數據,隨著分片越多,緩存越大,對于設備的壓力負擔也越重),如果某一片分配丟失了,會造成這個數據包不完整,被丟棄。
(5)怎么設置合適的MTU呢
由于現在很多協議還沒學習,不同的應用對應的頭部不一樣,自然包含的內容也不一樣,這個會隨著后面學習的深入,慢慢的了解,設置合適的MTU可以用Windows自帶的命令可以探測,比如某個應用有問題,通過抓包發現發送的數據超過了MTU的大小,就可以適當的調整。
ping命令里面帶有一個參數-f 它可以把IP包的DF位置1,讓其不分片,那么超過MTU需要分片的設備發現DF位置一,則直接丟棄,返回一個ICMP的差錯報文結果,通過這樣來測試出一個合適的MTU值。
留一個小疑問
這里為什么1464就可以,1465不可以呢(該環境存在撥號)
“承上啟下”
網絡層的基礎知識到這里就學習完畢了,接下來就進入傳輸層與應用層,對于這兩層,博主會挑對初學者比較重要的部分的講,全部講起來就非常費時間,涉及的內容實在太多,也不是初學者層面能夠理解的,下一篇就進入傳輸層的兩大協議,TCP與UDP。
么是MTU
Maximum Transmission Unit,縮寫MTU,中文名是:最大傳輸單元。
這是哪一層網絡的概念?
從下面這個表格中可以看到,在7層網絡協議中,MTU是數據鏈路層的概念。MTU限制的是數據鏈路層的payload,也就是上層協議的大小,例如IP,ICMP等。
MTU有什么用?
舉一個最簡單的場景,你在家用自己的筆記本上網,用的是路由器,路由器連接電信網絡,然后訪問了www.baidu.com,從你的筆記本出發的一個以太網數據幀總共經過了以下路徑:
筆記本 -> 路由器 -> 電信機房 -> 服務器
其中,每個節點都有一個MTU值,如下:
筆記本(1500) -> 路由器(1500) -> 電信機房 -> 服務器(1500)
假設現在我把筆記本的MTU最大值設置成了1700,然后發送了一個超大的ip數據包(2000),這時候在以外網傳輸的時候會被拆成2個包,一個1700,一個300,然后加上頭信息進行傳輸。
假設現在我把筆記本的MTU最大值設置成了1700,然后發送了一個超大的ip數據包(2000),這時候在以外網傳輸的時候會被拆成2個包,一個1700,一個300,然后加上頭信息進行傳輸。
筆記本(1700) -> 路由器(1500) -> 電信機房 -> 服務器(1500)
路由器接收到了一個1700的幀,發現大于自己設置的最大值:1500,如果IP包DF標志位為1,也就是不允許分包,那么路由器直接就把這個包丟棄了,根本就不會到達電信機房,也就到不了服務器了,所以,到這里我們就會發現,MTU其實就是在每一個節點的管控值,只要是大于這個值的數據幀,要么選擇分片,要么直接丟棄。
為什么是1500?
其實一個標準的以太網數據幀大小是:1518,頭信息有14字節,尾部校驗和FCS占了4字節,所以真正留給上層協議傳輸數據的大小就是:1518 - 14 - 4=1500,那么,1518這個值又是從哪里來的呢?
假設取一個更大的值
假設MTU值和IP數據包大小一致,一個IP數據包的大小是:65535,那么加上以太網幀頭和為,一個以太網幀的大小就是:65535 + 14 + 4=65553,看起來似乎很完美,發送方也不需要拆包,接收方也不需要重組。
那么假設我們現在的帶寬是:100Mbps,因為以太網幀是傳輸中的最小可識別單元,再往下就是0101所對應的光信號了,所以我們的一條帶寬同時只能發送一個以太網幀。如果同時發送多個,那么對端就無法重組成一個以太網幀了,在100Mbps的帶寬中(假設中間沒有損耗),我們計算一下發送這一幀需要的時間:
( 65553 * 8 ) / ( 100 * 1024 * 1024 ) ≈ 0.005(s)
在100M網絡下傳輸一幀就需要5ms,也就是說這5ms其他進程發送不了任何數據。如果是早先的電話撥號,網速只有2M的情況下:
( 65553 * 8 ) / ( 2 * 1024 * 1024 ) ≈ 0.100(s)
100ms,這簡直是噩夢。其實這就像紅綠燈,時間要設置合理,交替通行,不然同一個方向如果一直是綠燈,那么另一個方向就要堵成翔了。
既然大了不行,那設置小一點可以么?
假設MTU值設置為100,那么單個幀傳輸的時間,在2Mbps帶寬下需要:
( 100 * 8 ) / ( 2 * 1024 * 1024 ) * 1000 ≈ 5(ms)
時間上已經能接受了,問題在于,不管MTU設置為多少,以太網頭幀尾大小是固定的,都是14 + 4,所以在MTU為100的時候,一個以太網幀的傳輸效率為:
( 100 - 14 - 4 ) / 100=82%
寫成公式就是:( T - 14 - 4 ) / T,當T趨于無窮大的時候,效率接近100%,也就是MTU的值越大,傳輸效率最高,但是基于上一點傳輸時間的問題,來個折中的選擇吧,既然頭加尾是18,那就湊個整來個1500,總大小就是1518,傳輸效率:
1500 / 1518=98.8%
100Mbps傳輸時間:
( 1518 * 8 ) / ( 100 * 1024 * 1024 ) * 1000=0.11(ms)
2Mbps傳輸時間:
( 1518 * 8 ) / ( 2 * 1024 * 1024 ) * 1000=5.79(ms)
總體上時間都還能接受
最小值被限制在64
為什么是64呢?
這個其實和以太網幀在半雙工下的碰撞有關,感興趣的同學可以自行去搜索。
在我玩游戲的時候,為什么把MTU改成1480就不卡了?
路由器默認值大多都是1500,理論上是沒有問題的,那為什么我玩游戲的時候改成1480才能流暢呢?原因在于當時我使用的是ADSL上網的方式,ADSL使用的PPPoE協議。
PPPoE
PPPoE協議介于以太網和IP之間,協議分為兩部分,PPP( Point to Point Protocol )和oE( over Ethernet ),也就是以太網上的PPP協議,而PPPoE協議頭信息為:
| VER(4bit) | TYPE(4bit) | CODE(8bit) | SESSION-ID(16bit) | LENGTH(16bit) |
這里總共是48位,也就是6個字節,那么另外2個字節是什么呢?答案是PPP協議的ID號,占用兩個字節,所以在PPPoE環境下,最佳MTU值應該是:1500 - 4 - 2=1492。
我的上網方式
當時我的上網路徑如下:
PC -> 路由器 -> 電信
我在路由器進行撥號,然后PC連接路由器進行上網。
最根本原因
問題就出在路由器撥號,如果是PC撥號,那么PC會進行PPPoE的封裝,會按照MTU:1492來進行以太網幀的封裝,即使通過路由器,路由器這時候也只是轉發而已,不會進行拆包。
而當用路由器撥號時,PC并不知道路由器的通信方式,會以網卡的設置,默認1500的MTU來進行以太網幀的封裝,到達路由器時,由于路由器需要進行PPPoE協議的封裝,加上8字節的頭信息,這樣一來,就必須進行拆包,路由器把這一幀的內容拆成兩幀發送,一幀是1492,一幀是8,然后分別加上PPPoE的頭進行發送。
平時玩游戲不卡,是因為數據量路由器還處理得過來,而當進行群怪AOE的時候,由于短時間數據量過大,路由器處理不過來,就會發生丟包卡頓的情況,也就掉線了。
帖子里面提到的1480,猜測可能是盡量設小一點,避免二次撥號帶來的又一次PPPoE的封裝,因為時間久遠,沒辦法回到當時的場景再去抓包了。
結論
1500這個值是考慮到傳輸效率以及傳輸時間而折中選擇的一個值,并且由于目前網絡鏈路中的節點太多,其中某個節點的MTU值如果和別的節點不一樣,就很容易帶來拆包重組的問題,甚至會導致無法發送。
前有個疑問,接口能通過的最大報文長度究竟是幀長還是MTU控制的?
后來發現這其實是把二層轉發和三層轉發弄混淆了。
1、MTU是三層的,二層轉發其實不感知。這也是為什么MTU必須在三層口配置的原因。
2、二層轉發會看數據幀的幀長。當接收的超大幀長度超過接口默認可處理的數據幀長時,設備將不進行處理直接丟棄。此外,接口在入方向才會檢查報文的長度是否超過最大幀長度,在出方向不會檢測報文長度的。
所以,它們不應該被拿來比較,交換機二層轉發入方向會看幀長,具有三層轉發的設備在轉發時會看MTU,超過MTU則分片。
3、那怎么設置MTU呢?方法如下:
# 設置接口10GE1/0/1的MTU值為1200字節。
<HUAWEI> system view
[~HUAWEI] interface 10ge 1/0/1
[~HUAWEI-10GE1/0/1] undo portswitch
[*HUAWEI-10GE1/0/1] mtu 1200
MTU值為整數形式,單位是字節,取值范圍是46~9600。
4、那怎么最大設置幀長呢?
# 配置接口10GE1/0/1允許通過的最大幀長為5000字節。
<HUAWEI> system-view
[~HUAWEI] interface 10ge 1/0/1
[~HUAWEI-10GE1/0/1] jumboframe enable 5000
# 配置接口10GE1/0/1允許通過的最大幀長為5000字節,jumbo幀的幀長最小值為2000字節。
<HUAWEI> system-view
[~HUAWEI] interface 10ge 1/0/1
[~HUAWEI-10GE1/0/1] jumboframe enable 5000 2000
缺省情況下,設備允許最大長度為9216字節的幀通過以太網接口,非jumbo幀長的最大值為1518字節,即小于等于1518字節時為非jumbo幀。
來源 mzpp 華為企業論壇