MTU 怎麼設定:用 ping 測出合適值,再在 Linux、Windows 和交換器上修改
MTU 怎麼設定分兩步:先用禁止分片的 ping 測出這條路徑能透過的最大包,再把發包一端的網路卡 MTU 改成這個值。普通乙太網伺服器保持 1500 不用動,需要改的是 PPPoE 撥號、GRE/VXLAN/WireGuard 隧道和儲存網巨幀;Linux 用 ip link 臨時修改、寫進網路配置才永久生效,Windows 用 netsh 一條命令改完並儲存。
MTU 怎麼設定,第一步是確定“設成多少”。這個數不靠經驗值,而是測出來的:在 Windows 上用 ping -f -l 載荷 目標、在 Linux 上用 ping -M do -s 載荷 目標 傳送禁止分片的包,從 1472 開始往下減,能收到回覆的最大載荷加上 28 位元組(IPv4 首部 20 + ICMP 首部 8),就是這條路徑的 MTU。第二步是在發包的那一端修改網路卡:Linux 用 ip link set dev eth0 mtu 1450 立即生效、重啟後失效,要永久生效得寫進 NetworkManager、netplan 或 ifcfg 配置;Windows 用 netsh interface ipv4 set subinterface 一條命令修改並儲存。交換器一般不動 IP 層的 MTU,而是放大連接埠允許透過的最大幀長,也就是開巨幀。下面按“定值、測試、修改、驗證”的順序給出每一步的命令。
MTU 設定多少合適:先看是什麼場景
絕大多數情況下的答案是:不用改,保持 1500。伺服器、交換器和寬頻的乙太網介面預設就是 1500,公網上絕大多數鏈路也是 1500,單方面改大沒有意義,改小隻會讓每個包多一點首部開銷。真正需要動 MTU 的,是包外面又套了一層封裝,或者想在內網用巨幀的場景:
| 場景 | 在哪台裝置、哪個介面上改 | 常用值 | 備註 |
|---|---|---|---|
| 普通伺服器的公網口、內網口 | 不改 | 1500 | 預設值 |
| PPPoE 撥號 | 路由器或光貓的撥號(WAN)介面 | 1492 | 內網電腦保持 1500,由路由器做 MSS 鉗制 |
| GRE 隧道 | 隧道介面,如 gre1 | 1476 | 物理口不動 |
| WireGuard | wg0 介面 | 出口網路卡 MTU 減 80,出口為 1500 時是 1420 | wg-quick 預設就按這個規則計算 |
| VXLAN | 虛擬機器、容器的網路卡 | 1450 | 也可以把承載網調到 1550 以上,內層保持 1500 |
| 儲存網、虛擬化遷移網 | 該網段所有主機網路卡,加上沿途交換器連接埠 | 主機 9000,交換器幀長 9216 | 只在封閉的二層網段裡用 |
| 雲伺服器、虛擬機器 | 一般不改 | 平台下發的值 | 不同平台預設值不同,以平台文件為準,不要擅自改回 1500 |
網上常見“把 MTU 從 1500 改成 1497 能提速、降低遊戲延遲”的說法,值得單獨說一句。1497 不對應任何一種常見的封裝:PPPoE 少的是 8 位元組(1492),GRE 少的是 24 位元組(1476)。從 1500 改到 1497,每個滿長度的包只少裝 3 位元組資料,頻寬利用率的變化不到千分之三,延遲的變化也小到無法察覺。如果改完以後某些網頁反而能開啟了,說明這條路徑本來就存在 MTU 問題,正確的做法是用下一節的方法測出實際值,而不是猜一個數字。
用 ping 測出合適的 MTU:Windows 與 Linux 步驟
原理是給 ping 包打上“禁止分片”(DF)標誌。包比路徑上某一段的 MTU 大時,路由器不會把它切小轉發,而是丟棄並回一條“需要分片”的 ICMP 訊息。逐步減小載荷,第一個能正常回復的大小就是上限。
ping 命令裡的大小引數指的是 ICMP 資料部分,不含首部,換算關係如下:
| 協議 | 線路上的 IP 包長度 | MTU 1500 對應的載荷 | MTU 9000 對應的載荷 |
|---|---|---|---|
| IPv4 | 載荷 + 8(ICMP 首部)+ 20(IPv4 首部) | 1472 | 8972 |
| IPv6 | 載荷 + 8(ICMPv6 首部)+ 40(IPv6 首部) | 1452 | 8952 |
Windows:ping -f -l
- 開啟命令提示符或 PowerShell,普通許可權即可。
- 先發 1472 位元組的載荷:
ping -f -l 1472 -n 2 203.0.113.10
- 讀結果:
來自 203.0.113.10 的回覆: 位元組=1472 時間=35ms TTL=52:1500 能完整透過,不需要調整。需要拆分資料包但是設定 DF。:包太大,被本機或沿途裝置拒絕,繼續減小載荷。請求超時。:可能是目標不回 ping,也可能是沿途裝置丟了大包卻沒有發回通知。先用ping -l 64 203.0.113.10確認小包能通,再繼續減小載荷。
- 先以 10 為步長往下減(1462、1452……),找到能通的區間後再以 1 為步長細找。
- 能透過的最大載荷加 28 就是路徑 MTU。例如 1422 能通、1423 不通,MTU 就是 1450。
逐個手工試比較慢,可以交給 PowerShell 迴圈:
$dst = "203.0.113.10"
foreach ($size in 1472..1200) {
$out = ping -n 1 -w 1000 -f -l $size $dst
if ($out -match "TTL=") { "最大載荷 $size 位元組,路徑 MTU = $($size + 28)"; break }
}
指令碼用回覆裡的 TTL= 判斷是否透過,中文和英文系統都適用。Windows 的 -f 只對 IPv4 有效,測 IPv6 的路徑 MTU 建議到 Linux 上用 ping -6 -M do -s 1452 目標。
Linux:ping -M do -s
ping -M do -s 1472 -c 3 203.0.113.10
-M do 表示設定 DF、本機也不分片,-s 指定載荷大小。可能看到三種輸出:
| 輸出 | 含義 |
|---|---|
1480 bytes from 203.0.113.10: icmp_seq=1 ttl=52 time=35.2 ms |
透過;1480 是 ICMP 部分,即 1472 + 8 |
ping: local error: message too long, mtu=1500 |
本機網路卡的 MTU,或者核心已經記下的這條路徑的 MTU 比這個包小,包沒有發出去 |
From 192.0.2.9 icmp_seq=1 Frag needed and DF set (mtu = 1476) |
沿途的 192.0.2.9 放不下這個包,並告訴你它的 MTU 是 1476 |
第三種最省事:路由器已經把答案告訴你了,1476 − 28 = 1448,再用 -s 1448 驗證一次即可。什麼回應都沒有時,用二分法讓指令碼自己找:
#!/bin/bash
# 用法:bash pmtu.sh 目標位址
dst=$1; lo=1200; hi=1472
ping -M do -s $lo -c 2 -W 1 -q "$dst" >/dev/null 2>&1 || { echo "1200 位元組都不通,先檢查連通性"; exit 1; }
while [ $lo -lt $hi ]; do
mid=$(( (lo + hi + 1) / 2 ))
if ping -M do -s $mid -c 2 -W 1 -q "$dst" >/dev/null 2>&1; then lo=$mid; else hi=$((mid - 1)); fi
done
echo "最大載荷 $lo 位元組,路徑 MTU = $((lo + 28))"
測試時注意三點:
- 兩個方向都要測。去程和回程可能走不同的路由,MTU 也可能不同,在兩端各跑一次。
- 目標要選對。測隧道就 ping 隧道對端的內層位址,測儲存網就 ping 同網段的另一台主機,測公網就選業務真正要存取的對端。
- 測出來比 1500 小,不一定要改本機。如果卡住的是公網上別人的一段鏈路,改伺服器網路卡會影響它的全部流量;能在隧道閘道器上做 MSS 鉗制,或者讓沿途放行 ICMP“需要分片”訊息的,優先這樣處理。
Linux 修改 MTU:ip link 臨時生效,寫進配置才永久
先看當前值:
ip link show dev eth0 # 輸出中的 mtu 1500
臨時修改,立即生效,重啟或網路服務重新載入配置後恢復原值:
ip link set dev eth0 mtu 1450
# 沒有 ip 命令的老系統:ifconfig eth0 mtu 1450
永久修改要按系統使用的網路管理方式來寫,改錯地方就會出現“重啟後又變回 1500”:
| 系統 | 配置位置 | 寫法 | 讓它生效 |
|---|---|---|---|
| RHEL、Rocky、AlmaLinux 8/9 等(NetworkManager) | nmcli 連線配置 | nmcli connection modify eth0 802-3-ethernet.mtu 1450 |
nmcli connection up eth0 |
| Ubuntu 18.04 及以後(netplan) | /etc/netplan/ 下的 yaml 檔案,對應網路卡下 | mtu: 1450 |
netplan try,確認無誤後回車 |
| CentOS 7(network-scripts) | /etc/sysconfig/network-scripts/ifcfg-eth0 | MTU=1450 |
systemctl restart network |
| Debian(ifupdown) | /etc/network/interfaces 對應的 iface 段(static 方式) | mtu 1450 |
ifdown eth0 && ifup eth0 |
nmcli 命令裡的 eth0 是連線名,不一定等於網路卡名,先用 nmcli -g NAME,DEVICE connection show 查出來;部分系統上連線名是 System eth0 這類帶空格的名字,命令裡要加引號。netplan 的寫法範例:
network:
version: 2
ethernets:
eth0:
addresses: [203.0.113.10/24]
mtu: 1450
netplan try 會先應用新配置,120 秒內不按回車確認就自動回滾,遠端修改時比 netplan apply 穩妥。
伺服器上有 bond、VLAN 子介面或網橋時,要從下往上改,規則是上層不能比下層大:
- 物理網路卡 eth0、eth1 設為 9000;
- bond0 設為 9000,bond 會把 MTU 同步給成員網路卡;
- VLAN 子介面 bond0.100 設為 9000,它不能超過 bond0;
- 網橋 br100 設為 9000,Linux 網橋預設取所連連接埠裡最小的 MTU,一個連接埠沒改,整個網橋就卡在 1500。
只改了最上層的網橋,或者只改了物理口,巨幀都會在某一層被卡住。
Windows 修改 MTU:netsh 一條命令
Windows 網路卡屬性的圖形介面裡沒有 IP 層 MTU 這一項,“MTU 值在哪裡修改”的答案是命令列。以管理員身份開啟 PowerShell(netsh 在 PowerShell 裡同樣可用):
# 檢視各介面的名稱和當前 MTU
netsh interface ipv4 show subinterfaces
# 修改並永久儲存;改成 store=active 則只在本次開機期間有效
netsh interface ipv4 set subinterface "乙太網" mtu=1450 store=persistent
# IPv6 要單獨設定
netsh interface ipv6 set subinterface "乙太網" mtu=1450 store=persistent
介面名以第一條命令的輸出為準,英文系統一般是 Ethernet。也可以用 PowerShell 自帶的命令:
Get-NetIPInterface | Select-Object InterfaceAlias, AddressFamily, NlMtu
Set-NetIPInterface -InterfaceAlias "乙太網" -AddressFamily IPv4 -NlMtuBytes 1450
要用 9000 巨幀時,只改 netsh 不夠:IP 層的 MTU 不能超過網路卡驅動允許的幀長,要先在網路卡的高階屬性裡開啟“巨型幀”(Jumbo Packet,各驅動的叫法不同),再回頭確認 MTU:
Get-NetAdapterAdvancedProperty -Name "乙太網" -RegistryKeyword "*JumboPacket"
Set-NetAdapterAdvancedProperty -Name "乙太網" -RegistryKeyword "*JumboPacket" -RegistryValue 9014
9014 是包含 14 位元組乙太網頭的幀長,對應 IP 層的 9000;可選的數值由網路卡驅動決定,各廠商不同,可以在裝置管理器裡該網路卡屬性的“高階”選項卡中檢視。修改高階屬性會讓網路卡重新初始化,網路斷開幾秒。
交換器上怎麼設定 MTU 與巨幀
交換器上有兩種“MTU”,配置時不要混在一起:
- 二層連接埠的最大幀長,也就是巨幀:決定多大的乙太網幀能從這個連接埠進出。主機開了 9000,沿途每個連接埠都要放大。
- 三層介面的 IP MTU:VLANIF、路由口傳送 IP 包的上限,影響交換器自己發出的包和需要它分片的包,一般保持 1500。
主流廠商的寫法如下,取值範圍和預設值隨型號、版本不同,以裝置文件為準:
| 廠商 | 二層巨幀 | 三層介面 IP MTU | 檢視 |
|---|---|---|---|
| 華為 S 系列 | 介面檢視 jumboframe enable 9216 |
VLANIF 介面檢視 mtu 1500 |
display interface GigabitEthernet0/0/1,看 Maximum Frame Length |
| H3C Comware V7 | 介面檢視 jumboframe enable 9216 |
VLAN 介面檢視 mtu 1500 |
display interface GigabitEthernet1/0/1 |
| 思科 Catalyst 9000 | 全域性 system mtu 9198 |
三層介面下 ip mtu 1500 |
show system mtu |
| 思科 Nexus | 介面下 mtu 9216,部分型號要透過 network-qos 策略設定 |
三層介面下 mtu 1500 |
show interface ethernet1/1 |
華為交換器上把接儲存伺服器的一組連接埠放開到 9216 位元組:
system-view
port-group group-member GigabitEthernet0/0/1 to GigabitEthernet0/0/24
jumboframe enable 9216
交換器設 9216、主機設 9000 是有意留出餘量:交換器的數值通常按幀長計算,要裝下 9000 位元組的 IP 包,還得加上乙太網頭和 VLAN 標籤。Catalyst 9000 的 system mtu 是全域性設定,作用於所有介面;部分老型號(如 Catalyst 2960、3750 系列)的千兆口用 system mtu jumbo 9000,改完要重啟交換器才生效,要放在維護視窗裡做。上聯運營商的連接埠和公網介面保持 1500,不要跟著放大。
改完怎麼驗證,改錯了怎麼回退
改完按下面三項逐一確認:
- 用新值反向驗證。MTU 改為 1450,就用
ping -M do -s 1422測到對端;開了巨幀,就在同網段每一對需要通訊的主機之間測ping -M do -s 8972。只測一對不夠,漏改了一台主機或一個交換器連接埠,那一對就不通。 - 跑一次大包業務。
scp一個幾百 MB 的檔案,或curl一個大頁面,看能否順利傳完、速率是否正常。 - 看錯誤計數。主機上
ip -s link show dev eth0的 errors、dropped;交換器連接埠的超長幀計數(思科show interfaces裡的 giants,其他廠商的欄位名以裝置為準)。計數在漲,說明有超過連接埠允許值的幀被丟棄。
遠端修改伺服器 MTU 有一個風險:值改錯了,SSH 會話本身可能卡住,敲命令正常,一輸出大段內容就掛起,想改回去也改不了。動手前給自己留一條退路:
# 先掛一個 5 分鐘後自動恢復 1500 的任務,用 nohup 讓它脫離當前 SSH 會話
nohup sh -c 'sleep 300; ip link set dev eth0 mtu 1500' >/dev/null 2>&1 &
echo $! > /tmp/mtu-rollback.pid
ip link set dev eth0 mtu 9000
# 驗證無誤後,取消自動恢復
kill "$(cat /tmp/mtu-rollback.pid)"
不要用普通的 ( ... ) & 後台任務代替 nohup:SSH 連線一旦斷開,shell 會把結束通話訊號轉發給自己的後台任務,回退任務恰好在最需要它的時候被一起結束。
另外,部分網路卡驅動修改 MTU 時會重置鏈路,網路中斷幾秒,做了 bond 的伺服器還可能觸發一次主備切換。生產伺服器的 MTU 調整,和交換器巨幀一樣放在維護視窗裡做。
在管理系統裡怎麼落地
MTU 改錯最棘手的情況,是伺服器自己的網路出了問題、遠端登入不上。Toplink DCIM 的 IPMI 遠端管理透過 BMC 通道開啟 VNC 控制檯,不經過伺服器的業務網路卡,MTU 改壞了也能從控制檯登入進去改回來。巨幀要求沿途的交換器連接埠一起修改,交換器管理的伺服器列表直接列出每台伺服器接在哪台交換器的哪個連接埠、連接埠速率和 VLAN,一個儲存網段涉及哪些連接埠,不用再到現場翻線核對;需要執行 jumboframe enable 或檢查幀長時,可以在瀏覽器裡開啟交換器的 SSH 終端,會話全程錄影並記錄命令日誌,哪個連接埠在什麼時候被誰改過,事後都查得到。
常見問題
修改 MTU 需要重啟伺服器嗎?
不需要。Linux 的 ip link 和 Windows 的 netsh 改完立即生效,nmcli 改完執行一次 nmcli connection up 即可,只是部分網路卡驅動會重置鏈路,網路斷開幾秒。需要重啟的可能是交換器:部分老型號(如思科 Catalyst 2960、3750 系列)修改 system mtu jumbo 後要重啟才生效,以裝置文件為準。
Docker 容器的 MTU 怎麼設定?
預設網橋上的容器,在 /etc/docker/daemon.json 裡把 mtu 鍵設為需要的值(如 1450),重啟 Docker 後對新建的容器生效;自定義網路在建立時指定,例如 docker network create -o com.docker.network.driver.mtu=1450 mynet。宿主機出口在 VXLAN 或隧道里、MTU 小於 1500 時,容器的 MTU 不能超過宿主機出口網路卡的值。
MTU 最小能設成多少?
IPv4 只要求鏈路至少能傳 68 位元組,但實際不要低於 1280:IPv6 規定鏈路 MTU 不得小於 1280 位元組(RFC 8200),Linux 上把網路卡 MTU 設到 1280 以下,這塊網路卡上的 IPv6 會被停用。測出來的路徑 MTU 低於 1280 時,先複查測試目標和方法,再查鏈路上是否疊了多層封裝。