前言
干運維這么多年,見過各種各樣的故障,但有些問題真的是讓人抓狂。前段時間遇到的一個MTU問題,差點讓我懷疑人生。表面上看是簡單的丟包,實際上折騰了整整兩天才定位到根因。今天就把這個案例完整地記錄下來,順便把MTU相關的知識點系統地梳理一遍,希望能幫到遇到類似問題的兄弟們。
說實話,MTU這個東西,很多人覺得不就是個數字嘛,有什么難的。但真正遇到問題的時候,你會發現水很深。特別是現在云原生環境下,各種overlay網絡、隧道封裝,MTU問題比以前復雜多了。
一、故障背景
1.1 環境介紹
先說下我們的環境背景。公司用的是混合云架構,自建機房跑著Kubernetes集群,同時也用了阿里云和AWS。業務是做在線教育的,有直播、點播、互動白板等模塊。
基礎設施情況:
自建機房:100多臺物理服務器,跑著3個K8s集群
網絡架構:核心交換機是華為CE12800,接入層是H3C S6800
Kubernetes版本:1.29.3
CNI插件:Cilium 1.15
服務網格:Istio 1.21
1.2 問題現象
那天下午3點多,突然接到告警,業務方反饋直播推流出現卡頓,而且是間歇性的。看了下監控,發現一個奇怪的現象:
# 某個服務的網絡監控數據 TCP重傳率: 2.3% (正常應該在0.1%以下) 丟包率: 1.8% 延遲: P99從5ms飆到了200ms
第一反應是網絡抖動,讓網絡組的兄弟查了下核心交換機,沒發現異常。接著排查了服務本身,CPU、內存、磁盤IO都正常。
最詭異的是,這個問題只在某些特定場景下才會出現。小文件傳輸沒問題,一旦傳大文件或者大數據包就開始丟包。ping是通的,telnet端口也是通的,但就是業務數據傳不過去。
1.3 初步排查
按照常規套路,先看網絡基礎指標:
# 查看網卡統計信息 ip -s link show eth0 # 輸出結果 2: eth0:mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether fa3exx:xx brd ffffff:ff RX: bytes packets errors dropped overrun mcast 892734821 6823421 0 0 0 0 TX: bytes packets errors dropped carrier collsns 723891234 5234123 0 1823 0 0
TX dropped有1823個包被丟棄了,這個數字在增長。繼續深入:
# 查看更詳細的網卡統計 ethtool -S eth0 | grep -i drop # 輸出 tx_dropped: 1823 rx_dropped: 0 tx_window_errors: 0
丟包發生在發送端。再看看系統日志:
dmesg | grep -i"too long" # 發現了這個 [89234.123456] eth0: dropped packet, size 1514 > 1500
看到這個日志,心里大概有數了,八成是MTU問題。
二、MTU基礎知識回顧
在深入排查之前,先把MTU相關的基礎知識捋一遍。這些東西可能有些老生常談,但確實很重要。
2.1 什么是MTU
MTU(Maximum Transmission Unit)就是網絡設備能夠傳輸的最大數據包大小。這個概念是在數據鏈路層定義的,不同的網絡技術有不同的MTU值:
| 網絡類型 | MTU值 |
|---|---|
| Ethernet II | 1500字節 |
| PPPoE | 1492字節 |
| GRE隧道 | 1476字節 |
| VXLAN | 1450字節 |
| IPsec (ESP+AH) | 約1400字節 |
| Jumbo Frame | 9000字節 |
以太網的1500字節MTU是最常見的,這個數字從1980年代沿用至今。當時的考量是在傳輸效率和錯誤概率之間取得平衡。
2.2 MTU vs MSS
很多人分不清MTU和MSS的區別,這里說明一下:
+------------------+------------------+------------------+------------------+
| 以太網幀頭 | IP頭部 | TCP頭部 | 數據 |
| 14字節 | 20字節 | 20字節 | 最大1460字節 |
+------------------+------------------+------------------+------------------+
|<-------------- MTU 1500字節 ---------------->|
|<- MSS ->|
MTU:包含IP頭和TCP頭,以太網默認1500字節
MSS(Maximum Segment Size):只計算TCP數據部分,默認1460字節(1500-20-20)
TCP三次握手的時候,雙方會協商MSS值。如果MSS設置不當,會導致分片或者丟包。
2.3 Path MTU Discovery
PMTUD(Path MTU Discovery)是用來自動發現整條鏈路上最小MTU的機制。工作原理:
發送端發送DF(Don't Fragment)標志位設置為1的數據包
如果中間路由器的MTU小于數據包大小,會返回ICMP "Fragmentation Needed"消息
發送端根據ICMP消息調整數據包大小
重復上述過程,直到數據包能夠成功傳輸
問題是,很多防火墻會把ICMP包干掉,導致PMTUD失效。這就是著名的"PMTUD黑洞"問題。
# 測試PMTUD是否正常工作 ping -Mdo-s 1472 192.168.1.1 # -M do: 設置DF標志,不允許分片 # -s 1472: 1472 + 8(ICMP頭) + 20(IP頭) = 1500
如果1472能ping通但1473 ping不通,說明MTU是1500且PMTUD工作正常。
2.4 分片與重組
當數據包大于MTU時,如果DF標志沒有設置,IP層會進行分片:
# 查看分片統計 cat /proc/net/snmp | grep -i frag # 輸出示例 Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates Ip: 1 64 12893456 0 0 0 0 0 12893456 10234567 0 0 0 0 0 0 0 0 0
分片會帶來幾個問題:
增加CPU開銷
任何一個分片丟失,整個包都要重傳
分片攻擊的安全風險
狀態防火墻可能無法正確處理分片包
所以現代網絡一般都不建議分片,而是在應用層控制數據包大小。
三、深入排查過程
回到我們的故障。既然懷疑是MTU問題,就開始針對性排查。
3.1 確認MTU配置
首先檢查各個節點的MTU配置:
# 物理機網卡MTU ip link show eth0 | grep mtu # 輸出: mtu 1500 # K8s節點的CNI網卡 ip link show cilium_host | grep mtu # 輸出: mtu 1500 # Pod內部網卡 kubectlexec-ittest-pod -- ip link show eth0 # 輸出: mtu 1500 # 檢查VXLAN隧道接口 ip link show cilium_vxlan | grep mtu # 輸出: mtu 1500 <-- 問題出在這里!
發現問題了!VXLAN隧道接口的MTU也是1500,但VXLAN封裝會額外增加50字節的開銷:
VXLAN封裝開銷: - 外層以太網頭: 14字節 - 外層IP頭: 20字節 - 外層UDP頭: 8字節 - VXLAN頭: 8字節 總共: 50字節
也就是說,原始數據包如果是1500字節,加上VXLAN封裝后會變成1550字節,超過了物理網卡的MTU限制,導致丟包。
3.2 抓包確認
用tcpdump抓包確認問題:
# 在物理機上抓包 tcpdump -i eth0 -nn'icmp[0]=3 and icmp[1]=4' # 在Pod內發送大包 kubectlexec-ittest-pod -- ping -Mdo-s 1472 10.244.1.100
果然抓到了ICMP Fragmentation Needed的包:
1545.123456 IP 192.168.1.1 > 10.244.0.5: ICMP 10.244.1.100 unreachable - need to frag (mtu 1450), length 556
交換機告訴我們MTU應該是1450,但我們的VXLAN接口設置的是1500,所以大包就被丟了。
3.3 驗證問題
寫個簡單的腳本來驗證不同包大小的通信情況:
#!/bin/bash # mtu_test.sh - 測試不同包大小的連通性 TARGET_IP=$1 START_SIZE=1400 END_SIZE=1500 echo"Testing MTU to$TARGET_IP" echo"=========================" forsizein$(seq$START_SIZE$END_SIZE);do ifping -Mdo-c 1 -s$size-W 1$TARGET_IP> /dev/null 2>&1;then echo"Size$size: OK" else echo"Size$size: FAIL <-- MTU boundary" ? ? ? ??break ? ??fi done
運行結果:
Testing MTU to 10.244.1.100 ========================= Size 1400: OK Size 1401: OK ... Size 1422: OK Size 1423: FAIL <-- MTU boundary
1422 + 8(ICMP頭) + 20(IP頭) = 1450,確認了實際的Path MTU就是1450。
3.4 為什么之前沒問題
這個問題困擾了我很久:配置一直是這樣的,為什么之前沒事,現在才出問題?
后來查了Cilium的更新日志才發現,1.15版本修改了默認的PMTUD行為。之前版本會自動處理MTU mismatch,新版本默認關閉了這個功能,需要手動開啟。
# 查看Cilium版本 cilium version # 查看相關配置 kubectl -n kube-system get configmap cilium-config -o yaml | grep -i mtu # 輸出 enable-pmtu-discovery:"false"# 這個是關閉的 mtu:"0"# 0表示自動檢測,但檢測的是本地MTU
另外,我們的業務最近上線了一個新功能,傳輸的數據包變大了。以前的小包剛好不超過1450,所以沒問題。這就解釋了為什么問題是突然出現的。
四、解決方案
找到根因后,解決方案就比較清晰了。
4.1 方案一:調整Pod網絡MTU
最直接的方法是把Pod網絡的MTU調小,留出VXLAN封裝的空間:
# Cilium ConfigMap修改 apiVersion:v1 kind:ConfigMap metadata: name:cilium-config namespace:kube-system data: mtu:"1450" enable-pmtu-discovery:"true"
重啟Cilium:
kubectl -n kube-system rollout restart daemonset/cilium
驗證配置生效:
# 檢查cilium_host接口MTU kubectl -n kube-systemexec-it cilium-xxxxx -- ip link show cilium_host # 檢查Pod內的MTU kubectlexec-ittest-pod -- ip link show eth0
4.2 方案二:開啟Jumbo Frame
如果你的網絡環境支持,可以考慮開啟巨型幀(Jumbo Frame),把MTU設置為9000:
# 在所有物理節點上設置 ip linkseteth0 mtu 9000 # 永久生效,修改網卡配置 # CentOS/RHEL cat >> /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF MTU=9000 EOF # Ubuntu/Debian cat >> /etc/netplan/01-netcfg.yaml << EOF ethernets: ? eth0: ? ? mtu: 9000 EOF # 應用配置 netplan apply
注意,Jumbo Frame需要整條鏈路上的所有設備都支持,包括:
服務器網卡
交換機所有端口
路由器
負載均衡器
如果中間有任何設備不支持9000 MTU,就會出問題。
# 檢查交換機端口是否支持Jumbo Frame # 華為設備 display interface GigabitEthernet0/0/1 | include MTU # H3C設備 display interface GigabitEthernet1/0/1 | include MTU
4.3 方案三:TCP MSS Clamping
如果沒法改MTU,可以通過iptables調整TCP MSS:
# 在FORWARD鏈上做MSS clamping iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu # 或者指定固定值 iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400 # 持久化規則 iptables-save > /etc/iptables/rules.v4
在Kubernetes環境中,可以通過Cilium的BPF程序實現類似功能:
# Cilium配置 apiVersion:v1 kind:ConfigMap metadata: name:cilium-config namespace:kube-system data: enable-bpf-masquerade:"true" enable-endpoint-routes:"true" auto-direct-node-routes:"true"
4.4 我們采用的方案
綜合考慮后,我們采用了方案一和方案三的組合:
把Cilium的MTU設置為1450
同時開啟PMTUD
添加MSS clamping作為兜底
# 完整的解決腳本
#!/bin/bash
# fix_mtu.sh
# 1. 更新Cilium配置
kubectl -n kube-system patch configmap cilium-config --typemerge -p'
{
"data": {
"mtu": "1450",
"enable-pmtu-discovery": "true"
}
}'
# 2. 重啟Cilium
kubectl -n kube-system rollout restart daemonset/cilium
# 3. 等待重啟完成
kubectl -n kube-system rollout status daemonset/cilium
# 4. 添加MSS clamping(在所有節點執行)
fornodein$(kubectl get nodes -o name | cut -d/ -f2);do
ssh$node"iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu"
done
# 5. 驗證修復
kubectlexec-ittest-pod -- ping -Mdo-s 1422 10.244.1.100
echo"MTU fix completed!"
五、不同場景下的MTU配置
MTU問題在不同的網絡環境下表現不同,這里總結一下各種場景的最佳配置。
5.1 物理機環境
最簡單的場景,直接設置網卡MTU即可:
# 臨時設置 ip linkseteth0 mtu 1500 # 永久設置 - systemd-networkd cat > /etc/systemd/network/10-eth0.network << EOF [Match] Name=eth0 [Network] DHCP=yes [Link] MTUBytes=1500 EOF systemctl restart systemd-networkd # 驗證 ip link show eth0 | grep mtu
5.2 虛擬機環境
虛擬化環境要考慮虛擬交換機的MTU:
# KVM/libvirt環境 # 修改虛擬網絡配置 virsh net-edit default # 添加MTU配置# VMware環境 # 在vSphere中設置分布式交換機的MTU # vSphere Client -> Networking -> DVS -> Edit Settings -> MTU default ...
OpenStack環境需要同時設置多個組件:
# /etc/neutron/plugins/ml2/ml2_conf.ini [ml2] path_mtu = 1500 physical_network_mtus = provider:1500 # /etc/neutron/plugins/ml2/openvswitch_agent.ini [ovs] of_inactivity_probe = 10 # /etc/nova/nova.conf [DEFAULT] network_device_mtu = 1450
5.3 容器環境
Docker單機環境:
# 修改Docker daemon配置
cat > /etc/docker/daemon.json << EOF
{
??"mtu": 1450
}
EOF
systemctl restart docker
# 驗證
docker network inspect bridge | grep -i mtu
Kubernetes環境要根據CNI插件配置:
# Calico
apiVersion:crd.projectcalico.org/v1
kind:FelixConfiguration
metadata:
name:default
spec:
mtu:1450
wireguardMTU:1420
# Flannel
apiVersion:v1
kind:ConfigMap
metadata:
name:kube-flannel-cfg
namespace:kube-system
data:
net-conf.json:|
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan",
"MTU": 1450
}
}
# Cilium
apiVersion:v1
kind:ConfigMap
metadata:
name:cilium-config
namespace:kube-system
data:
mtu:"1450"
5.4 云環境
各大云廠商的MTU限制不同:
| 云廠商 | 默認MTU | 最大MTU | 備注 |
|---|---|---|---|
| AWS | 1500 | 9001 | VPC內部支持Jumbo Frame |
| 阿里云 | 1500 | 1500 | 跨可用區有限制 |
| 騰訊云 | 1500 | 1500 | VPC內部統一 |
| Azure | 1500 | 1500 | ExpressRoute支持更大 |
| GCP | 1460 | 1460 | 因為使用了封裝 |
AWS VPC配置Jumbo Frame:
# 檢查實例是否支持Jumbo Frame aws ec2 describe-instances --instance-ids i-1234567890abcdef0 --query'Reservations[].Instances[].NetworkInterfaces[].Groups' # 在實例內設置MTU sudo ip linkseteth0 mtu 9001 # 持久化 - Amazon Linux 2 echo'MTU=9001'| sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth0
阿里云環境注意事項:
# 阿里云的ENI彈性網卡有MTU限制 # 主網卡固定1500,不可修改 # 如果使用Terway CNI(阿里云官方K8s網絡方案) # 需要考慮ENI的MTU限制 # 檢查當前MTU ip link show eth0 # 阿里云VPC內Pod網絡推薦MTU # - 普通VPC網絡: 1500 # - ENI多IP模式: 1500 # - IPVLAN模式: 1500
5.5 VPN和隧道環境
各種隧道封裝的MTU開銷:
# 常見隧道協議的開銷
IPsec (ESP, tunnel mode): 52-73字節
IPsec (ESP, transport mode): 38-59字節
GRE: 24字節
VXLAN: 50字節
Geneve: 50字節 + 可變長度選項
WireGuard: 60字節
# WireGuard配置
[Interface]
PrivateKey = ...
Address = 10.0.0.1/24
MTU = 1420 # 1500 - 60(WireGuard) - 20(IP頭)
# IPsec strongSwan配置
# /etc/ipsec.conf
conn myvpn
...
fragmentation = yes
# /etc/strongswan.d/charon.conf
charon {
fragment_size = 1400
}
5.6 SD-WAN和Overlay網絡
企業SD-WAN環境的MTU配置:
# 以Cisco SD-WAN為例 # 邊緣設備配置 interface GigabitEthernet0/0 ip mtu 1400 tcp adjust-mss 1360 # 控制平面配置 system overlay-mtu 1450 control-mtu 1500
六、MTU問題排查工具箱
這里整理一套完整的MTU排查工具和方法。
6.1 基礎診斷命令
# 查看所有接口的MTU ip -d link show | grep -E"^[0-9]+:|mtu" # 查看路由的MTU ip route get 10.0.0.1 # 輸出示例 10.0.0.1 via 192.168.1.1 dev eth0 src 192.168.1.100 uid 0 cache mtu 1450 # 查看TCP連接的MSS ss -ti | head -20 # 輸出示例 cubic wscale:7,7 rto:204 rtt:3.5/2 ato:40 mss:1448 pmtu:1500 # 查看系統的分片統計 cat /proc/net/snmp | grep -E"^Ip:"| head -2 # 查看網卡的詳細統計 ethtool -S eth0 | grep -E"drop|error|frag"
6.2 PMTUD測試腳本
#!/bin/bash
# pmtud_test.sh - 完整的PMTUD測試腳本
TARGET=$1
START_MTU=${2:-1500}
if[ -z"$TARGET"];then
echo"Usage:$0 [start_mtu]"
exit1
fi
echo"Testing Path MTU to$TARGET"
echo"Starting from MTU:$START_MTU"
echo"================================"
# 二分查找最大可用MTU
low=576
high=$START_MTU
last_success=0
while[$low-le$high];do
mid=$(( (low + high) / 2 ))
payload=$(( mid - 28 )) # 減去IP頭(20)和ICMP頭(8)
ifping -Mdo-c 1 -s$payload-W 2$TARGET> /dev/null 2>&1;then
last_success=$mid
low=$(( mid + 1 ))
else
high=$(( mid - 1 ))
fi
done
if[$last_success-gt 0 ];then
echo""
echo"Path MTU to$TARGET:$last_successbytes"
echo"Recommended TCP MSS:$(( last_success - 40 )) bytes"
else
echo"Error: Cannot determine Path MTU"
fi
6.3 tracepath檢測
tracepath比ping更適合檢測MTU問題:
# 使用tracepath檢測路徑MTU tracepath 10.0.0.1 # 輸出示例 1?: [LOCALHOST] pmtu 1500 1: gateway 0.234ms 1: gateway 0.198ms 2: 10.0.0.1 0.456ms reached Resume: pmtu 1500 hops 2 back 2
tracepath會自動發現整條路徑的MTU,并顯示在哪一跳發生了MTU變化。
6.4 抓包分析
# 抓取ICMP Fragmentation Needed消息 tcpdump -i eth0 -nn'icmp[0]=3 and icmp[1]=4'-w /tmp/frag_needed.pcap # 抓取所有ICMP錯誤消息 tcpdump -i eth0 -nn'icmp[0]=3'-v # 抓取帶DF標志的大包 tcpdump -i eth0 -nn'ip[6:2] & 0x4000 != 0 and len > 1400' # 分析抓包文件 tshark -r /tmp/frag_needed.pcap -T fields -e ip.src -e ip.dst -e icmp.mtu # 使用Wireshark過濾器 # icmp.type == 3 && icmp.code == 4
6.5 內核參數調優
# 查看當前PMTUD相關參數 sysctl -a | grep -E"pmtu|mtu" # 關鍵參數說明 net.ipv4.ip_no_pmtu_disc = 0 # 0=啟用PMTUD, 1=禁用 net.ipv4.tcp_mtu_probing = 1 # 0=禁用, 1=黑洞檢測時啟用, 2=始終啟用 net.ipv4.tcp_base_mss = 1024 # TCP MTU探測的初始MSS net.ipv4.route.min_pmtu = 552 # 最小PMTU值 # 優化配置 cat >> /etc/sysctl.d/99-mtu.conf << EOF # MTU優化 net.ipv4.ip_no_pmtu_disc = 0 net.ipv4.tcp_mtu_probing = 1 net.ipv4.tcp_base_mss = 1024 # 路由緩存優化 net.ipv4.route.gc_timeout = 100 net.ipv4.route.min_pmtu = 552 EOF sysctl -p /etc/sysctl.d/99-mtu.conf
6.6 一鍵診斷腳本
#!/bin/bash
# mtu_diagnosis.sh - MTU問題一鍵診斷
RED='?33[0;31m'
GREEN='?33[0;32m'
YELLOW='?33[1;33m'
NC='?33[0m'
echo"=========================================="
echo"MTU Diagnosis Tool v1.0"
echo"=========================================="
# 1. 檢查所有接口MTU
echo-e"
${YELLOW}[1/6] Network Interfaces MTU${NC}"
ip -o link show | awk'{print $2, $5}'| column -t
# 2. 檢查路由MTU
echo-e"
${YELLOW}[2/6] Route MTU Cache${NC}"
ip route show cache | grep -i mtu ||echo"No cached MTU entries"
# 3. 檢查內核參數
echo-e"
${YELLOW}[3/6] Kernel MTU Parameters${NC}"
echo"ip_no_pmtu_disc:$(sysctl -n net.ipv4.ip_no_pmtu_disc)"
echo"tcp_mtu_probing:$(sysctl -n net.ipv4.tcp_mtu_probing)"
echo"tcp_base_mss:$(sysctl -n net.ipv4.tcp_base_mss)"
# 4. 檢查丟包統計
echo-e"
${YELLOW}[4/6] Drop Statistics${NC}"
forifacein$(ls /sys/class/net/);do
tx_dropped=$(cat /sys/class/net/$iface/statistics/tx_dropped 2>/dev/null)
if["$tx_dropped"!="0"] && [ -n"$tx_dropped"];then
echo-e"${RED}$iface: tx_dropped=$tx_dropped${NC}"
fi
done
# 5. 檢查最近的ICMP錯誤
echo-e"
${YELLOW}[5/6] Recent ICMP Errors${NC}"
netstat -s | grep -i -E"frag|mtu|icmp"| head -10
# 6. 檢查iptables MSS規則
echo-e"
${YELLOW}[6/6] iptables MSS Rules${NC}"
iptables -t mangle -L -n | grep -i mss ||echo"No MSS clamping rules found"
echo-e"
${GREEN}Diagnosis completed!${NC}"
七、Kubernetes環境MTU最佳實踐
Kubernetes環境下MTU問題更復雜,這里專門講講K8s的MTU配置。
7.1 CNI插件MTU配置對比
不同CNI插件的MTU處理方式不同:
# Calico - 自動檢測或手動配置 kubectl -n kube-system get configmap calico-config -o yaml | grep -A5 cni_network_config # Calico 推薦配置 apiVersion: crd.projectcalico.org/v1 kind: FelixConfiguration metadata: name: default spec: mtu: 1440 # VXLAN模式 vxlanMTU: 1410 # VXLAN接口 wireguardMTU: 1380 # WireGuard加密 # Flannel - 在ConfigMap中配置 kubectl -n kube-system get configmap kube-flannel-cfg -o yaml # Cilium - 支持自動MTU檢測 kubectl -n kube-system get configmap cilium-config -o yaml | grep mtu # Canal (Calico + Flannel) kubectl -n kube-system get configmap canal-config -o yaml
7.2 服務網格的MTU考慮
Istio Envoy Sidecar會增加網絡復雜度:
# Istio MTU配置
apiVersion:install.istio.io/v1alpha1
kind:IstioOperator
spec:
meshConfig:
defaultConfig:
proxyMetadata:
# 調整Envoy的buffer大小
ISTIO_META_NETWORK:network1
values:
global:
proxy:
# 資源配置
resources:
requests:
memory:128Mi
Envoy本身不會改變MTU,但需要確保Sidecar注入不影響MTU設置:
# 檢查注入Sidecar后的MTU kubectlexec-it my-pod -c istio-proxy -- ip link show eth0 # 檢查Envoy的連接狀態 kubectlexec-it my-pod -c istio-proxy -- curl localhost:15000/stats | grep -i mss
7.3 跨集群網絡MTU
多集群場景下MTU更需要注意:
# Submariner 跨集群網絡配置 apiVersion:submariner.io/v1alpha1 kind:Broker metadata: name:submariner-broker spec: globalCIDR:242.0.0.0/8 --- apiVersion:submariner.io/v1alpha1 kind:ClusterGlobalEgressIP metadata: name:cluster-egress spec: # MTU需要考慮跨集群隧道開銷 # IPsec: ~50字節 # WireGuard: ~60字節
Cilium Cluster Mesh配置:
# Cilium跨集群配置 apiVersion:v1 kind:ConfigMap metadata: name:cilium-config namespace:kube-system data: cluster-name:cluster1 cluster-id:"1" # 跨集群MTU設置 mtu:"1400" enable-endpoint-routes:"true" tunnel:"vxlan"
高性能計算場景需要特殊的MTU配置:
# NVIDIA GPU Direct RDMA需要Jumbo Frame
# Mellanox網卡配置
mlxconfig -d /dev/mst/mt4123_pciconf0setLINK_TYPE_P1=2 LINK_TYPE_P2=2
# 設置IB網絡MTU
ip linksetib0 mtu 4092
# RoCE v2配置
echo4096 > /sys/class/infiniband/mlx5_0/ports/1/gid_attrs/ndevs/0/mtu
# K8s RDMA Device Plugin配置
apiVersion: v1
kind: ConfigMap
metadata:
name: rdma-devices
data:
config.json: |
{
"mode":"shared",
"maxPods": 100
}
7.5 NetworkPolicy與MTU
NetworkPolicy通常不影響MTU,但某些實現可能會引入額外的處理開銷:
# 確保NetworkPolicy不影響PMTUD
apiVersion:networking.k8s.io/v1
kind:NetworkPolicy
metadata:
name:allow-icmp
spec:
podSelector:{}
policyTypes:
-Ingress
ingress:
-ports:
# 允許ICMP,確保PMTUD正常工作
-protocol:ICMP
# 檢查是否有丟棄ICMP的規則 iptables -L -n | grep -i icmp # Cilium的ICMP策略 kubectl get cnp -A -o yaml | grep -i icmp
八、高級場景和邊界情況
8.1 IPv6環境的MTU
IPv6的最小MTU是1280字節,比IPv4的576字節大:
# 檢查IPv6 MTU ip -6 link show eth0 | grep mtu # IPv6 Path MTU Discovery ping6 -Mdo-s 1452 2001:1 # IPv6的PMTUD使用ICMPv6 # Packet Too Big消息代替ICMP Fragmentation Needed tcpdump -i eth0'icmp6 and ip6[40] = 2'
IPv6隧道的MTU計算:
IPv6-in-IPv4 隧道: 1500 - 20(IPv4頭) = 1480 IPv6-in-IPv6 隧道: 1500 - 40(IPv6頭) = 1460
8.2 容器運行時差異
不同容器運行時對MTU的處理:
# Docker docker network create --driver bridge --opt com.docker.network.driver.mtu=1450 mynet # containerd # CNI配置文件 cat /etc/cni/net.d/10-containerd-net.conflist { "plugins": [ { "type":"bridge", "bridge":"cni0", "mtu": 1450 } ] } # CRI-O # 修改CNI配置 cat /etc/cni/net.d/100-crio-bridge.conf { "type":"bridge", "mtu": 1450 }
8.3 負載均衡器MTU
各種LB的MTU處理:
# HAProxy - 不直接處理MTU,但可以調整buffer
# /etc/haproxy/haproxy.cfg
global
tune.bufsize 16384
tune.maxrewrite 1024
# Nginx - 可以調整proxy buffer
upstream backend {
server 10.0.0.1:80;
}
server {
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# IPVS/LVS - DR模式需要MTU一致
# 檢查IPVS連接
ipvsadm -Ln
云負載均衡器通常有自己的MTU限制:
# AWS ALB/NLB # MTU自動處理,無需配置 # 阿里云SLB # 經典網絡: 1500 # VPC網絡: 1500 # 跨可用區: 注意MTU差異 # GCP Load Balancer # 默認1460,因為GCP網絡MTU是1460
8.4 eBPF和XDP對MTU的影響
eBPF程序可能影響數據包處理:
// XDP程序需要考慮MTU
SEC("xdp")
intxdp_prog(struct xdp_md *ctx){
void*data_end = (void*)(long)ctx->data_end;
void*data = (void*)(long)ctx->data;
// 檢查包大小
if(data +sizeof(struct ethhdr) +sizeof(struct iphdr) > data_end)
returnXDP_PASS;
structethhdr*eth=data;
structiphdr*iph=data+sizeof(structethhdr);
// 可以在這里檢查和處理MTU相關邏輯
__u16 tot_len = ntohs(iph->tot_len);
if(tot_len >1500-sizeof(struct ethhdr)) {
// 包太大,記錄或處理
}
returnXDP_PASS;
}
Cilium的eBPF MTU處理:
# 查看Cilium的BPF程序 bpftool prog show # 查看MTU相關的map bpftool map show name cilium_metrics
九、生產環境MTU配置規范
根據多年的經驗,總結一套生產環境的MTU配置規范。
9.1 配置清單模板
# mtu-config-template.yaml # 生產環境MTU配置清單 # 1. 物理網絡層 physical_network: datacenter: core_switch_mtu:9000 # 如果支持Jumbo Frame access_switch_mtu:9000 server_nic_mtu:9000 wan: mtu:1500 # 公網固定1500 # 2. 虛擬化層 virtualization: hypervisor: virtual_switch_mtu:1500 vm_nic_mtu:1500 # 3. 容器網絡層 container_network: cni_mtu:1450 # VXLAN環境 pod_mtu:1450 service_mesh_overhead:0 # Istio不增加頭部 # 4. 隧道和VPN tunnels: vxlan_mtu:1450 # 1500 - 50 ipsec_mtu:1400 # 保守值 wireguard_mtu:1420 # 1500 - 80 # 5. 云環境 cloud: aws_vpc_mtu:9001 # 支持Jumbo Frame aliyun_vpc_mtu:1500 gcp_vpc_mtu:1460
9.2 變更流程
#!/bin/bash
# mtu_change_procedure.sh - MTU變更標準流程
# 1. 變更前檢查
echo"=== Pre-change Checks ==="
ip link show | grep mtu
ip route get 10.0.0.1
netstat -s | grep -i frag
# 2. 備份當前配置
echo"=== Backup Current Config ==="
ip link show > /tmp/mtu_backup_$(date +%Y%m%d).txt
cp /etc/network/interfaces /tmp/ 2>/dev/null
cp /etc/sysconfig/network-scripts/ifcfg-* /tmp/ 2>/dev/null
# 3. 灰度變更(先在一臺機器測試)
echo"=== Gradual Change ==="
# 這里執行實際變更
# 4. 驗證變更
echo"=== Post-change Verification ==="
# 測試連通性
ping -Mdo-s 1422 10.0.0.1
# 測試業務
curl -o /dev/null -w"%{time_total}"http://service:8080/health
# 5. 監控觀察
echo"=== Monitoring ==="
# 觀察丟包率和重傳率變化
watch -n 1'cat /proc/net/snmp | grep -E "^Tcp:"'
9.3 監控告警配置
# Prometheus告警規則
groups:
-name:mtu-alerts
rules:
# 高丟包率告警
-alert:HighPacketDrop
expr:rate(node_network_transmit_drop_total[5m])>10
for:5m
labels:
severity:warning
annotations:
summary:"High packet drop on{{ $labels.instance }}"
description:"Interface{{ $labels.device }}has high TX drops"
# TCP重傳率告警
-alert:HighTCPRetransmit
expr:rate(node_netstat_Tcp_RetransSegs[5m])/rate(node_netstat_Tcp_OutSegs[5m])>0.01
for:5m
labels:
severity:warning
annotations:
summary:"High TCP retransmit rate on{{ $labels.instance }}"
# MTU不一致告警(自定義exporter)
-alert:MTUMismatch
expr:mtu_config_current!=mtu_config_expected
for:1m
labels:
severity:critical
annotations:
summary:"MTU mismatch detected on{{ $labels.instance }}"
Grafana面板配置:
{
"panels": [
{
"title":"Network Interface MTU",
"type":"table",
"targets": [
{
"expr":"node_network_mtu_bytes",
"legendFormat":"{{ device }}"
}
]
},
{
"title":"Packet Drop Rate",
"type":"graph",
"targets": [
{
"expr":"rate(node_network_transmit_drop_total[1m])",
"legendFormat":"TX Drop - {{ device }}"
},
{
"expr":"rate(node_network_receive_drop_total[1m])",
"legendFormat":"RX Drop - {{ device }}"
}
]
}
]
}
9.4 自動化檢查腳本
#!/bin/bash
# mtu_health_check.sh - MTU健康檢查自動化腳本
set-e
LOG_FILE="/var/log/mtu_health_check.log"
EXPECTED_MTU=1450
ALERT_THRESHOLD=100
log() {
echo"[$(date '+%Y-%m-%d %H:%M:%S')]$1"| tee -a$LOG_FILE
}
check_interface_mtu() {
log"Checking interface MTU..."
forifacein$(ls /sys/class/net/ | grep -v lo);do
current_mtu=$(cat /sys/class/net/$iface/mtu)
if["$current_mtu"!="$EXPECTED_MTU"];then
log"WARNING:$ifaceMTU is$current_mtu, expected$EXPECTED_MTU"
return1
fi
done
log"All interface MTU values are correct"
return0
}
check_packet_drops() {
log"Checking packet drops..."
forifacein$(ls /sys/class/net/ | grep -v lo);do
tx_dropped=$(cat /sys/class/net/$iface/statistics/tx_dropped)
if["$tx_dropped"-gt"$ALERT_THRESHOLD"];then
log"ALERT:$ifacehas$tx_droppedTX drops"
return1
fi
done
log"Packet drop counts are within threshold"
return0
}
check_pmtud() {
log"Checking PMTUD functionality..."
# 測試目標IP(需要替換為實際的測試目標)
TEST_TARGET="10.0.0.1"
ifping -Mdo-c 1 -s 1422 -W 2$TEST_TARGET> /dev/null 2>&1;then
log"PMTUD is working correctly"
return0
else
log"WARNING: PMTUD may not be working"
return1
fi
}
check_kernel_params() {
log"Checking kernel MTU parameters..."
pmtu_disc=$(sysctl -n net.ipv4.ip_no_pmtu_disc)
mtu_probing=$(sysctl -n net.ipv4.tcp_mtu_probing)
if["$pmtu_disc"!="0"];then
log"WARNING: PMTU discovery is disabled"
fi
if["$mtu_probing"=="0"];then
log"INFO: TCP MTU probing is disabled"
fi
return0
}
# 主函數
main() {
log"========== MTU Health Check Started =========="
errors=0
check_interface_mtu || ((errors++))
check_packet_drops || ((errors++))
check_pmtud || ((errors++))
check_kernel_params || ((errors++))
if[$errors-gt 0 ];then
log"Health check completed with$errorsissues"
exit1
else
log"Health check passed"
exit0
fi
}
main
十、總結和經驗教訓
10.1 這次故障的教訓
回顧這次MTU問題的排查過程,有幾點教訓:
升級前要看Release Notes:Cilium 1.15的變更導致了這個問題,如果升級前仔細看了Release Notes,可能就不會踩坑。
監控要覆蓋網絡層指標:之前我們的監控主要關注應用層,網絡層的丟包、重傳這些指標覆蓋不夠。
變更要有對照組:如果當時有個沒升級的集群做對照,可能更快定位問題。
文檔要及時更新:環境的MTU配置沒有統一的文檔記錄,排查時浪費了不少時間。
10.2 MTU問題排查思路總結
MTU問題排查流程圖: 1. 現象確認 ├── 大包丟失,小包正常? → 很可能是MTU問題 ├── 特定路徑丟包? → 檢查路徑上的MTU └── 隨機丟包? → 可能不是MTU問題 2. 快速診斷 ├── ping -Mdo-s 1472 目標IP ├── tracepath 目標IP └── tcpdump抓ICMP錯誤 3. 定位問題點 ├── 檢查所有接口MTU ├── 檢查隧道/overlay的MTU └── 檢查云環境的MTU限制 4. 驗證修復 ├── 調整MTU配置 ├── 測試不同大小的包 └── 觀察監控指標
10.3 預防措施
為了避免類似問題再次發生,我們做了以下改進:
標準化MTU配置:所有環境使用統一的MTU值(1450),并寫入Ansible Playbook自動化配置。
增加監控告警:在Prometheus中添加了丟包率、重傳率的告警規則。
變更CheckList:升級CNI插件前必須檢查MTU相關配置變化。
定期健康檢查:每天自動運行MTU健康檢查腳本。
文檔化:把所有網絡配置(包括MTU)都記錄在CMDB中。
10.4 參考資料
寫這篇文章的時候參考了一些資料,列在這里供大家參考:
RFC 1191 - Path MTU Discovery
RFC 8899 - Packetization Layer Path MTU Discovery for Datagram Transports
Cilium Documentation - MTU Configuration
Calico Documentation - Configure MTU
Linux Kernel Documentation - ip-sysctl.txt
各云廠商的VPC網絡文檔
10.5 寫在最后
MTU這個東西,說簡單也簡單,就是個數字;說復雜也復雜,涉及到整個網絡棧的方方面面。特別是在現在這種云原生、多層封裝的環境下,MTU問題比以前更容易出現,也更難排查。
希望這篇文章能幫到遇到類似問題的兄弟們。如果有什么問題或者更好的方法,歡迎交流討論。
最后說一句,做運維這行,遇到問題不可怕,可怕的是遇到問題不記錄、不總結。每次故障都是一次學習的機會,把經驗積累下來,下次遇到類似問題就能更快解決。
-
服務器
+關注
關注
14文章
10250瀏覽量
91476 -
網絡
+關注
關注
14文章
8264瀏覽量
94692 -
阿里云
+關注
關注
3文章
1038瀏覽量
45687
原文標題:MTU配置不當引發的血案:一次詭異的網絡丟包排查
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
波特率漂移導致通信異常的故障排查過程
網絡丟包常見故障分析及處理方式
網絡丟包怎么辦,常見故障分析及處理方式
DC-DC電源故障排查過程和總結,珍貴的經驗!資料下載
深入分析Linux網絡丟包問題!
Java應用OOM問題的排查過程
詳解網絡丟包故障排查過程
評論