“网络不通”是工程师最常遇到也最怕遇到的故障描述。它可能是 DNS 解析失败,可能是防火墙规则阻断,可能是 MTU 黑洞,可能是 BGP 路由震荡,可能是交换机端口的双工不匹配。如果没有系统化的排查方法,你只能一个一个猜,运气好 5 分钟解决,运气差排查 5 小时。
本文建立一套系统化的网络故障排查方法论。核心原则是分层隔离——按照网络模型逐层排查,每一层用对应的工具验证,快速缩小故障范围。
一、故障分类:先判断类型再选方法
1.1 三类网络故障
所有网络故障可以归入三类,每类的排查思路完全不同:
| 类型 | 典型表现 | 排查策略 | 难度 |
|---|---|---|---|
| 连通性故障 | 完全不通,Connection refused,No route to host | 分层排查法,从 L1 到 L7 逐层验证 | 中等 |
| 性能故障 | 延迟高,吞吐低,偶发超时 | 延迟分解 + 基线对比 + 指标分析 | 较高 |
| 间歇性故障 | 时好时坏,随机丢包,偶发断连 | 持续监控 + 日志关联 + 统计分析 | 最高 |
间歇性故障最难排查,因为它可能在你开始排查时就”自愈”了。对付间歇性故障的关键是持续采集——在故障复现之前就部署好监控和抓包。
1.2 排查的黄金法则
在深入任何故障之前,记住这几条:
- 先确认问题的范围:是所有用户还是部分用户?是所有服务还是单个服务?范围越窄,排查越快。
- 先确认最近的变更:90% 的故障都能关联到最近的变更——部署、配置修改、网络设备变更、DNS 记录变更。
- 先用最简单的工具:
ping能解决的问题不要上tcpdump。 - 不要同时改多个东西:一次只改一个变量,验证后再改下一个。
二、OSI 分层排查法
2.1 分层排查的逻辑
分层排查的核心思想:从低层到高层逐层验证。低层故障会影响所有高层,高层故障不会影响低层。
┌─────────────────┐
│ L7 应用层 │ HTTP 返回 502?gRPC 超时?
├─────────────────┤
│ L4 传输层 │ TCP 连接能建立吗?端口开放吗?
├─────────────────┤
│ L3 网络层 │ IP 可达吗?路由正确吗?
├─────────────────┤
│ L2 数据链路层 │ ARP 能解析吗?VLAN 正确吗?
├─────────────────┤
│ L1 物理层 │ 网线插好了吗?网卡 UP 吗?
└─────────────────┘
实际排查时,不一定严格从 L1 开始。如果你确定物理层没问题(比如云服务器),可以直接从 L3 开始。但当你卡住时,往下退一层检查是好习惯。
2.2 L1 物理层检查
物理层故障在数据中心比在云环境更常见。典型检查:
# 网卡状态
ip link show eth0
# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
# 状态应该是 UP 和 LOWER_UP
# LOWER_UP 表示物理链路正常(有载波信号)
# 如果是 NO-CARRIER
ip link show eth0
# 2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> ...
# → 网线没插好或对端设备端口 down
# 网卡错误统计
ip -s link show eth0
# 关注 errors、dropped、overruns、carrier 计数
# 如果持续增长,说明物理层或驱动有问题
# ethtool 检查链路参数
ethtool eth0
# Speed: 1000Mb/s
# Duplex: Full ← 必须是 Full,Half 会导致大量冲突
# Link detected: yes ← 必须是 yes常见 L1 问题:
| 现象 | 可能原因 | 检查方法 |
|---|---|---|
| NO-CARRIER | 网线松了、对端 down | 物理检查、ethtool eth0 |
| Speed: 100Mb/s | 自协商失败降速 | ethtool -s eth0 speed 1000 duplex full |
| Duplex: Half | 双工不匹配 | 两端强制设置相同参数 |
| RX errors 持续增长 | 网线质量差、EMI 干扰 | 更换网线、检查走线 |
2.3 L2 数据链路层检查
L2 故障通常表现为同一子网内无法通信:
# ARP 表检查
ip neigh show
# 10.0.1.1 dev eth0 lladdr aa:bb:cc:dd:ee:ff REACHABLE
# 10.0.1.2 dev eth0 FAILED ← ARP 解析失败
# 手动发 ARP 请求
arping -c 3 -I eth0 10.0.1.2
# VLAN 检查(如果使用 VLAN)
cat /proc/net/vlan/config
# 或
ip -d link show eth0.100
# 检查 bridge/交换表(如果是网桥)
bridge fdb show常见 L2 问题:
| 现象 | 可能原因 | 排查 |
|---|---|---|
| ARP FAILED | 目标不在同一 L2 域、目标 down | arping、检查 VLAN 配置 |
| 单向通信 | ARP 表错误、MAC 地址冲突 | ip neigh flush dev eth0、检查 MAC |
| 广播风暴 | STP 未启用或环路 | 检查交换机 STP 状态 |
2.4 L3 网络层检查
L3 是最常见的故障层,涉及 IP 地址、路由和防火墙:
# 1. IP 地址检查
ip addr show eth0
# 确认 IP 地址、子网掩码正确
# 2. 路由表检查
ip route show
# default via 10.0.1.1 dev eth0
# 10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.50
# 检查到目标的路由
ip route get 10.0.2.100
# 10.0.2.100 via 10.0.1.1 dev eth0 src 10.0.1.50
# 3. ping 测试(ICMP)
ping -c 5 10.0.2.100
# 如果 ping 不通,检查是不是 ICMP 被过滤
# 用 TCP 连接测试替代
nc -zv -w 3 10.0.2.100 443
# 或
hping3 -S -p 443 -c 3 10.0.2.100
# 4. 防火墙规则检查
iptables -L -n -v --line-numbers
# 或
nft list ruleset
# 5. 检查 IP 转发(如果是网关/路由器角色)
sysctl net.ipv4.ip_forward
# 应该是 1L3 排查决策树:
ping 目标 IP
├── 成功 → L3 正常,检查 L4
└── 失败
├── ping 网关
│ ├── 成功 → 问题在网关之后
│ │ ├── traceroute 看在哪一跳丢失
│ │ └── 检查中间设备防火墙
│ └── 失败 → 问题在本地
│ ├── 检查 IP 地址和子网掩码
│ ├── 检查网关 ARP 能否解析
│ └── 检查本地防火墙
└── 注意:ping 不通不代表不可达
└── 用 TCP 连接测试确认
2.5 L4 传输层检查
L3 可达但服务不通,通常是 L4 问题(端口、连接状态):
# 1. 端口开放检查(本地)
ss -tlnp | grep :443
# LISTEN 0 4096 *:443 *:* users:(("nginx",pid=1234,fd=6))
# 如果端口没监听
# → 服务没启动,或者绑定了错误的地址
# 2. 远程端口连通性
nc -zv -w 5 10.0.2.100 443
# Connection to 10.0.2.100 443 port [tcp/https] succeeded!
# 超时 → 防火墙丢弃(DROP)
# Connection refused → 端口未监听(服务端 RST)
# 3. TCP 连接状态分析
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn
# 1523 ESTAB
# 342 TIME-WAIT
# 28 CLOSE-WAIT ← 如果持续增长,说明应用没有正确关闭连接
# 5 SYN-SENT ← 如果大量堆积,说明对端不可达或防火墙 DROP
# 2 SYN-RECV ← 正常;如果大量堆积,可能是 SYN Flood
# 4. 检查连接数限制
sysctl net.core.somaxconn # listen backlog 上限
sysctl net.ipv4.tcp_max_syn_backlog # SYN 队列上限
cat /proc/sys/net/netfilter/nf_conntrack_count # 当前连接跟踪数
cat /proc/sys/net/netfilter/nf_conntrack_max # 连接跟踪表上限
# 5. 检查是否有 conntrack 表满
dmesg | grep "nf_conntrack: table full"L4 常见故障及解决:
| 现象 | 错误信息 | 根因 | 解决 |
|---|---|---|---|
| 连接超时 | connect: Connection timed out |
防火墙 DROP 或路由黑洞 | 检查防火墙规则和路由 |
| 连接被拒 | connect: Connection refused |
端口未监听 | 检查服务状态 |
| 连接重置 | read: Connection reset by peer |
服务端异常关闭或中间设备 RST | 抓包分析 RST 来源 |
| CLOSE_WAIT 堆积 | 连接数持续增长 | 应用未调用 close() | 修复应用的连接关闭逻辑 |
| conntrack 表满 | nf_conntrack: table full |
连接数超过内核限制 | 增大 nf_conntrack_max |
2.6 L7 应用层检查
前面各层都正常,但服务返回错误或行为异常:
# 1. HTTP 状态码检查
curl -sI https://api.example.com/health
# HTTP/2 502 ← 502 Bad Gateway 通常是代理后端不可达
# 2. HTTP 响应体检查
curl -s https://api.example.com/health | jq .
# 3. SSL/TLS 证书检查
echo | openssl s_client -connect api.example.com:443 \
-servername api.example.com 2>/dev/null | openssl x509 -noout -dates
# notBefore=Jan 1 00:00:00 2025 GMT
# notAfter=Apr 1 00:00:00 2025 GMT ← 证书过期!
# 4. DNS 解析检查
dig api.example.com +short
# 如果返回错误的 IP,问题在 DNS
# 5. 日志检查
journalctl -u nginx --since "10 minutes ago" --no-pager
tail -100 /var/log/nginx/error.log三、排查工具链速查
3.1 按场景选工具
┌─────────────────────────────────────────────────────────────┐
│ 网络故障排查工具选择 │
├────────────────┬────────────────────────────────────────────┤
│ 想知道什么 │ 用什么工具 │
├────────────────┼────────────────────────────────────────────┤
│ 网卡状态 │ ip link, ethtool │
│ IP 和路由 │ ip addr, ip route │
│ ARP 解析 │ ip neigh, arping │
│ 基础连通性 │ ping, hping3 │
│ 路径分析 │ traceroute, mtr │
│ 端口开放 │ ss, nc (netcat), nmap │
│ TCP 连接状态 │ ss -tan, netstat -an │
│ 防火墙规则 │ iptables -L, nft list │
│ DNS 解析 │ dig, nslookup, resolvectl │
│ TLS/证书 │ openssl s_client, curl -v │
│ HTTP 请求 │ curl, wget, httpie │
│ 抓包分析 │ tcpdump, tshark, wireshark │
│ 延迟分解 │ curl -w, mtr, hping3 │
│ 带宽测试 │ iperf3, netperf │
│ 连接跟踪 │ conntrack, /proc/net/nf_conntrack │
│ 内核诊断 │ bpftrace, ss -ti, /proc/net/* │
└────────────────┴────────────────────────────────────────────┘
3.2 一条命令排查脚本
快速收集系统网络状态的脚本:
#!/bin/bash
# net-diag.sh — 网络状态快速诊断
TARGET="${1:-8.8.8.8}"
echo "========== 网络接口 =========="
ip -br link show
echo ""
echo "========== IP 地址 =========="
ip -br addr show
echo ""
echo "========== 路由表 =========="
ip route show
echo ""
echo "========== DNS 配置 =========="
cat /etc/resolv.conf | grep -v '^#'
echo ""
echo "========== DNS 解析测试 =========="
dig +short "$TARGET" 2>/dev/null || echo "dig 不可用"
echo ""
echo "========== 网关连通性 =========="
GW=$(ip route | grep default | awk '{print $3}')
ping -c 3 -W 2 "$GW" 2>/dev/null | tail -2
echo ""
echo "========== 目标连通性 =========="
ping -c 3 -W 2 "$TARGET" 2>/dev/null | tail -2
echo ""
echo "========== TCP 连接统计 =========="
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn
echo ""
echo "========== 监听端口 =========="
ss -tlnp 2>/dev/null | head -20
echo ""
echo "========== 防火墙规则 =========="
iptables -L -n 2>/dev/null | head -20 || echo "无 iptables 权限"
echo ""
echo "========== 最近网络错误 =========="
dmesg | grep -i -E "nf_conntrack|dropped|error|reset|refused" | tail -10
echo ""
echo "========== 网卡错误统计 =========="
ip -s link show | grep -A 2 "RX\|TX" | grep -v "^--$"四、常见故障模式与排查路径
4.1 Connection Refused
错误: connect: Connection refused (ECONNREFUSED)
含义:目标主机收到了 SYN,但目标端口没有进程监听,内核回复 RST。
排查路径:
# 1. 确认服务是否在运行
systemctl status myservice
# 或
ps aux | grep myservice
# 2. 确认监听地址和端口
ss -tlnp | grep :8080
# 常见问题:服务绑定了 127.0.0.1 但你从外部访问
# LISTEN 0 128 127.0.0.1:8080 *:* ← 只监听了 loopback
# 3. 确认是不是绑定了错误的端口
ss -tlnp | grep myservice
# 发现监听在 8081 而不是 8080
# 4. 检查是否端口冲突
ss -tlnp | grep :8080
# 另一个进程占了端口4.2 Connection Timed Out
错误: connect: Connection timed out (ETIMEDOUT)
含义:SYN 包发出去了但没收到 SYN-ACK,TCP 重传多次后超时。
排查路径:
# 1. 确认 IP 可达(L3)
ping -c 3 -W 2 10.0.2.100
# 如果 ping 也超时 → L3 不可达
# 2. 如果 ping 通但连接超时 → 可能是端口级防火墙
hping3 -S -p 8080 -c 3 10.0.2.100
# 没有响应 → 防火墙在 DROP
# 3. 检查本地防火墙出站规则
iptables -L OUTPUT -n -v
# 4. 检查目标机器防火墙入站规则(如果有权限)
ssh 10.0.2.100 "iptables -L INPUT -n -v"
# 5. 检查安全组(云环境)
# AWS: aws ec2 describe-security-groups
# 阿里云: aliyun ecs DescribeSecurityGroupAttribute
# 6. 抓包确认 SYN 是否到达目标
# 在目标机器上:
tcpdump -i eth0 'tcp port 8080 and tcp[tcpflags] & tcp-syn != 0' -c 104.3 间歇性丢包
间歇性丢包是最难排查的故障类型,因为无法按需复现。
排查策略:持续监控 + 关联分析
# 1. 持续 ping 监控(记录时间戳)
ping -D -i 0.5 10.0.2.100 | tee ping-log-$(date +%Y%m%d).txt
# -D 打印 UNIX 时间戳
# 2. mtr 持续路径监控
mtr -rw -c 1000 -i 0.1 10.0.2.100 | tee mtr-log.txt
# 3. 抓包准备(滚动捕获,等待故障复现)
tcpdump -i eth0 -w /tmp/capture-%H%M.pcap \
-G 300 -C 100 -W 20 \
host 10.0.2.100 and tcp port 443
# 4. 关联系统指标
# 在 ping 丢包的时间点,检查:
sar -n DEV 1 # 网卡流量
sar -n EDEV 1 # 网卡错误
sar -n TCP,ETCP 1 # TCP 统计
vmstat 1 # CPU/内存/IO
# 5. 检查 NIC ring buffer 丢包
ethtool -S eth0 | grep -i drop
# rx_dropped: 12345 ← ring buffer 满导致丢包
# 6. 检查内核丢包
cat /proc/net/snmp | grep -A 1 "Tcp:"
# 关注 InErrs、RetransSegs
# 7. 检查 netfilter/conntrack 丢包
dmesg | grep "nf_conntrack: table full"
conntrack -C # 当前连接数
conntrack -L | wc -l间歇性丢包的常见根因:
| 根因 | 检测方法 | 解决方案 |
|---|---|---|
| NIC ring buffer 溢出 | ethtool -S eth0 \| grep drop |
增大 ring
buffer:ethtool -G eth0 rx 4096 |
| conntrack 表满 | dmesg \| grep nf_conntrack |
增大 nf_conntrack_max |
| CPU softirq 来不及处理 | cat /proc/net/softnet_stat |
调整 RPS,增加 netdev_budget |
| TCP backlog 满 | netstat -s \| grep overflow |
增大 somaxconn 和应用 backlog |
| 带宽饱和 | sar -n DEV 1 |
扩容或限流 |
| MTU 黑洞 | ping -M do -s 1472 target |
修复 PMTUD 或降低 MTU |
4.4 MTU 黑洞
MTU 黑洞是一种隐蔽的故障:小包正常,大包丢失。原因是路径上某个设备的 MTU 小于发送端,且 ICMP “Fragmentation Needed” 消息被防火墙丢弃。
检测方法:
# 1. 用不同大小的包测试
# 1472 = 1500 (MTU) - 20 (IP header) - 8 (ICMP header)
ping -M do -s 1472 -c 3 target.example.com # 标准 MTU
ping -M do -s 1400 -c 3 target.example.com # 常见 VPN/隧道 MTU
ping -M do -s 1300 -c 3 target.example.com # 更小
ping -M do -s 1200 -c 3 target.example.com # 更小
# 2. 二分法找到精确的 Path MTU
# 如果 1472 失败、1300 成功,在中间尝试 1400、1350...
# 3. tracepath 自动发现 Path MTU
tracepath target.example.com
# ...
# Resume: pmtu 1420 ← Path MTU 是 1420
# 4. 修复:降低本地 MTU 或 MSS
# 方法 A:直接降低接口 MTU
ip link set dev eth0 mtu 1400
# 方法 B:用 iptables 钳制 MSS(推荐,不影响本地通信)
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 13604.5 DNS 故障
DNS 故障的表现多种多样,排查时要区分 DNS 本身的问题和 DNS 配置的问题:
# 1. 确认 DNS 解析是否正常
dig example.com
# 如果 ;; connection timed out → DNS 服务器不可达
# 如果 SERVFAIL → DNS 服务器有问题
# 如果 NXDOMAIN → 域名不存在(或 DNS 劫持)
# 2. 测试不同 DNS 服务器
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com
dig @$(grep nameserver /etc/resolv.conf | head -1 | awk '{print $2}') example.com
# 3. 完整解析链路追踪
dig +trace example.com
# 4. 检查是否被劫持
# 从多个 DNS 服务器查询,结果应该一致
for dns in 8.8.8.8 1.1.1.1 223.5.5.5 114.114.114.114; do
echo -n "$dns: "; dig @$dns +short example.com
done
# 5. 检查本地 DNS 配置
cat /etc/resolv.conf
resolvectl status
systemd-resolve --status五、排查决策树
5.1 “完全不通”的排查决策树
#!/bin/bash
# diagnose-connectivity.sh — 连通性排查自动化
TARGET_IP="${1:?Usage: $0 <target-ip> [target-port]}"
TARGET_PORT="${2:-443}"
echo "=== 连通性诊断: $TARGET_IP:$TARGET_PORT ==="
# L1: 本地网卡
echo -n "[L1] 网卡状态: "
if ip link show eth0 | grep -q "state UP"; then
echo "UP ✓"
else
echo "DOWN ✗ → 检查网卡和网线"
exit 1
fi
# L2: ARP/网关
GW=$(ip route | grep default | awk '{print $3}')
echo -n "[L2] 网关 ARP ($GW): "
if arping -c 1 -w 2 -I eth0 "$GW" &>/dev/null; then
echo "OK ✓"
else
echo "FAILED ✗ → 检查 VLAN 和交换机"
exit 1
fi
# L3: IP 可达
echo -n "[L3] 网关 ping: "
if ping -c 2 -W 2 "$GW" &>/dev/null; then
echo "OK ✓"
else
echo "FAILED ✗ → 检查 IP 配置和路由"
exit 1
fi
echo -n "[L3] 目标 ping: "
if ping -c 2 -W 2 "$TARGET_IP" &>/dev/null; then
echo "OK ✓"
else
echo "FAILED (ICMP 可能被过滤,继续检查 L4)"
fi
# L3: 路由
echo -n "[L3] 路由: "
ROUTE=$(ip route get "$TARGET_IP" 2>/dev/null)
if [ $? -eq 0 ]; then
echo "$(echo $ROUTE | head -1) ✓"
else
echo "无路由 ✗ → 检查路由表"
exit 1
fi
# L4: TCP 连接
echo -n "[L4] TCP $TARGET_PORT: "
if nc -zv -w 5 "$TARGET_IP" "$TARGET_PORT" &>/dev/null; then
echo "OPEN ✓"
else
echo "CLOSED/FILTERED ✗"
echo " → Connection refused = 端口未监听"
echo " → Timed out = 防火墙 DROP"
fi
# DNS: 如果目标是域名
if [[ "$TARGET_IP" =~ [a-zA-Z] ]]; then
echo -n "[DNS] 解析: "
RESOLVED=$(dig +short "$TARGET_IP" | head -1)
if [ -n "$RESOLVED" ]; then
echo "$RESOLVED ✓"
else
echo "FAILED ✗ → 检查 DNS 配置"
fi
fi
# L7: HTTP(如果是 Web 服务)
if [ "$TARGET_PORT" = "443" ] || [ "$TARGET_PORT" = "80" ]; then
SCHEME="http"
[ "$TARGET_PORT" = "443" ] && SCHEME="https"
echo -n "[L7] HTTP 状态: "
STATUS=$(curl -sk -o /dev/null -w "%{http_code}" \
--connect-timeout 5 "${SCHEME}://${TARGET_IP}/")
if [ "$STATUS" != "000" ]; then
echo "HTTP $STATUS"
else
echo "无响应 ✗"
fi
fi5.2 “慢”的排查决策树
用户说"慢"
│
├── 所有请求都慢?
│ ├── 是 → 基础设施问题
│ │ ├── curl -w 做延迟分解
│ │ ├── DNS 阶段慢?→ 检查 DNS 服务器
│ │ ├── TCP 阶段慢?→ mtr 检查路径
│ │ ├── TLS 阶段慢?→ openssl 检查版本/证书
│ │ └── Server 阶段慢?→ 检查服务端负载
│ └── 否 → 部分请求慢
│ ├── 特定用户?→ 检查该用户的网络路径
│ ├── 特定接口?→ 检查接口性能(慢 SQL?)
│ └── 随机分布?→ 检查负载均衡器和后端健康
│
├── P50 正常但 P99 高?
│ ├── → 长尾延迟问题
│ ├── GC 暂停?→ 检查 GC 日志
│ ├── 锁竞争?→ 检查锁等待指标
│ ├── 慢查询?→ 检查数据库慢日志
│ └── 外部依赖超时?→ 检查外部服务 SLA
│
└── 最近才开始慢?
├── 关联最近部署 → 回滚验证
├── 关联最近配置变更 → 回退配置
└── 无明显关联 → 检查流量增长和资源利用率
六、防火墙与安全组排查
6.1 iptables 规则排查
防火墙是网络故障的高频元凶。排查时要同时检查入站和出站:
# 查看所有链的规则(包含计数)
iptables -L -n -v --line-numbers
# 查看 NAT 表
iptables -t nat -L -n -v
# 关键指标:看 pkts 和 bytes 列
# 如果某条 DROP 规则的 pkts 持续增长,它就是嫌疑人
# 实时监控被 DROP 的包
iptables -I INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4
# 然后:
tail -f /var/log/kern.log | grep "IPT-DROP"
# 临时插入 ACCEPT 规则验证
iptables -I INPUT 1 -s 10.0.1.0/24 -p tcp --dport 8080 -j ACCEPT
# 验证后记得删除或持久化6.2 conntrack 问题排查
conntrack(连接跟踪)表满是高并发服务的常见故障:
# 当前连接跟踪数和上限
echo "当前: $(cat /proc/sys/net/netfilter/nf_conntrack_count)"
echo "上限: $(cat /proc/sys/net/netfilter/nf_conntrack_max)"
# 如果接近上限
# 1. 临时增大上限
sysctl -w net.netfilter.nf_conntrack_max=1048576
# 2. 减少超时时间(释放旧连接)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=1200
# 3. 查看连接分布
conntrack -L 2>/dev/null | awk '{print $3}' | sort | uniq -c | sort -rn
# 100000 tcp
# 5000 udp
# 2000 icmp
# 4. 查看 TCP 状态分布
conntrack -L -p tcp 2>/dev/null \
| awk '{for(i=1;i<=NF;i++) if($i ~ /^[A-Z_]+$/ && length($i)>3) print $i}' \
| sort | uniq -c | sort -rn七、容器与 Kubernetes 网络排查
7.1 Docker 网络排查
容器网络增加了一层虚拟化,排查时要区分宿主机和容器内的视角:
# 1. 进入容器网络命名空间
docker exec -it <container> sh
# 在容器内检查
ip addr show
ip route show
cat /etc/resolv.conf
# 2. 从宿主机检查容器网络
# 找到容器的 PID
PID=$(docker inspect --format '{{.State.Pid}}' <container>)
# 用 nsenter 进入容器网络命名空间
nsenter -t $PID -n ip addr show
nsenter -t $PID -n ss -tlnp
nsenter -t $PID -n iptables -L -n
# 3. 检查 docker 网络
docker network ls
docker network inspect bridge
# 4. 容器间通信问题
docker exec container-a ping container-b
# 如果用 docker-compose,用服务名
docker exec container-a ping service-b7.2 Kubernetes 网络排查
K8s 的网络排查更复杂,因为涉及 Pod 网络、Service 网络和 Ingress 多层:
# 1. Pod 网络检查
kubectl exec -it <pod> -- sh
# 在 Pod 内
ip addr show
ip route show
cat /etc/resolv.conf
nslookup kubernetes.default
# 2. Service DNS 解析
kubectl exec -it <pod> -- nslookup my-service.my-namespace.svc.cluster.local
# 3. Service Endpoint 检查
kubectl get endpoints my-service
# 如果 ENDPOINTS 为空 → selector 没有匹配到 Pod
# 4. 从 Pod 到 Service 的连通性
kubectl exec -it <pod> -- curl -s http://my-service:8080/health
# 5. 检查 NetworkPolicy
kubectl get networkpolicy -A
kubectl describe networkpolicy <policy-name>
# 6. 用 debug 容器抓包
kubectl debug -it <pod> --image=nicolaka/netshoot -- tcpdump -i eth0 -c 20
# 7. 检查 CNI 状态
kubectl get pods -n kube-system | grep -E "calico|cilium|flannel"
kubectl logs -n kube-system <cni-pod> --tail=50K8s 网络排查决策树:
Pod 无法访问 Service
├── DNS 解析正常?
│ ├── 否 → 检查 CoreDNS Pod 状态
│ └── 是 → 继续
├── Service 有 Endpoints?
│ ├── 否 → selector 不匹配 Pod labels
│ └── 是 → 继续
├── 直接访问 Pod IP 正常?
│ ├── 否 → CNI 或 NetworkPolicy 问题
│ └── 是 → kube-proxy / iptables 规则问题
└── 检查 NetworkPolicy 是否阻断了流量
八、真实故障案例复盘
8.1 案例一:新服务部署后”网络不通”
现象:新部署的服务在 K8s 集群中无法被其他服务访问,curl 超时。
排查过程:
# 1. Service 存在且有 Endpoints
kubectl get svc my-new-service
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# my-new-service ClusterIP 10.96.123.45 <none> 8080/TCP
kubectl get endpoints my-new-service
# NAME ENDPOINTS AGE
# my-new-service 10.244.1.15:8080 5m
# 2. Pod 在运行
kubectl get pod -l app=my-new-service
# NAME READY STATUS RESTARTS
# my-new-service-7f8b9c6d4-x2k9f 1/1 Running 0
# 3. 直接 curl Pod IP → 超时
kubectl exec -it debug-pod -- curl -m 5 http://10.244.1.15:8080/health
# curl: (28) Connection timed out
# 4. 进入 Pod 检查 → 端口在监听
kubectl exec -it my-new-service-7f8b9c6d4-x2k9f -- ss -tlnp
# LISTEN 0 128 127.0.0.1:8080 *:*
# ← 绑定了 127.0.0.1!只接受 localhost 连接
# 5. 根因:应用配置绑定了 127.0.0.1 而不是 0.0.0.0修复:修改应用配置,监听
0.0.0.0:8080。
教训:本地开发环境绑定 127.0.0.1 是好习惯,但部署到容器时必须改成 0.0.0.0。
8.2 案例二:生产环境周期性超时
现象:每天下午 2 点左右,服务的 P99 延迟飙升,持续约 15 分钟。
排查过程:
# 1. 关联时间线
# 下午 2 点有什么定时任务?
crontab -l
# 14:00 /opt/scripts/daily-report.sh ← 嫌疑人
# 2. 检查定时任务做了什么
cat /opt/scripts/daily-report.sh
# 大量数据库查询生成日报告
# 3. 确认数据库是瓶颈
# 在 2 点时刻检查:
mysql -e "SHOW PROCESSLIST" | wc -l
# 在正常时段:50
# 在 2 点:450 ← 连接数暴增
# 4. 检查慢查询
mysql -e "SHOW GLOBAL STATUS LIKE 'Slow_queries'"
# 2 点时段慢查询数量是平时的 10 倍
# 5. 根因:日报脚本的全表扫描查询锁住了表修复:
- 日报脚本使用只读从库
- 大查询拆分成批次,每批之间 sleep
- 添加适当的索引
8.3 案例三:跨可用区间歇性丢包
现象:跨可用区的服务调用偶发超时,约 0.5% 的请求受影响。
# 1. 持续 ping 监控
ping -i 0.1 -D cross-az-service.internal | while read line; do
echo "$(date '+%H:%M:%S.%N') $line"
done > ping-crossaz.log &
# 运行 1 小时后分析
grep "time=" ping-crossaz.log | awk -F'time=' '{print $2}' | \
awk -F' ' '{print $1}' | sort -n | \
awk 'BEGIN{n=0} {a[n++]=$1} END{
printf "P50: %.1f ms\n", a[int(n*0.5)];
printf "P99: %.1f ms\n", a[int(n*0.99)];
printf "Max: %.1f ms\n", a[n-1];
}'
# P50: 0.8 ms
# P99: 3.2 ms
# Max: 245.0 ms ← 偶发高延迟
# 2. 检查网卡丢包
ethtool -S eth0 | grep -E "drop|error"
# rx_queue_0_drops: 15234 ← 网卡队列丢包
# 3. 检查 softirq 处理延迟
cat /proc/net/softnet_stat | awk '{print $2}' | head -8
# 每列是一个 CPU 的 softnet_stat
# 第 2 列 > 0 表示因为 netdev_budget 用完而被 drop
# 4. 根因:CPU 0 处理了所有网络中断,其他 CPU 空闲
# 5. 修复:启用 RPS 分散到多个 CPU
echo "ff" > /sys/class/net/eth0/queues/rx-0/rps_cpus九、排查记录模板
每次故障排查都应该记录,既是知识沉淀也是复盘材料:
## 故障记录:[简短标题]
**时间**:YYYY-MM-DD HH:MM — HH:MM
**影响**:[受影响的服务/用户/范围]
**严重程度**:P0/P1/P2/P3
### 现象
[用户视角的故障表现]
### 时间线
- HH:MM 收到告警
- HH:MM 开始排查
- HH:MM 定位根因
- HH:MM 实施修复
- HH:MM 确认恢复
### 排查过程
[使用的工具和命令,每步的发现]
### 根因
[技术根因分析]
### 修复措施
[短期修复 + 长期预防]
### 经验教训
[这次故障暴露了什么系统性问题?]十、总结:系统化排查的核心原则
先分类后排查。区分连通性故障、性能故障和间歇性故障,选择对应的排查策略。盲目猜测只会浪费时间。
分层隔离。从 L1 到 L7 逐层验证,确认每一层的状态。低层故障必然影响高层,如果 L3 不通,不要去检查 L7。
用数据说话。不要凭感觉判断”网络慢”,用 curl -w 量化延迟,用 mtr 量化丢包,用 ss 量化连接状态。数据是排查的基础。
先确认变更。90% 的故障可以关联到最近的变更。问清楚”什么时候开始的”和”最近改了什么”,往往比跑任何诊断工具都快。
记录和复盘。每次故障排查都是一次学习机会。记录排查过程、根因和修复措施,建立团队的故障知识库。
参考文献
- Sloan, J. D. (2001). Network Troubleshooting Tools, O’Reilly Media
- Linux Advanced Routing & Traffic Control HOWTO (lartc.org)
- Brendan Gregg (2020). Systems Performance, 2nd Edition, Addison-Wesley
- Kubernetes Networking Documentation (kubernetes.io/docs/concepts/services-networking)
- Linux kernel networking documentation (kernel.org/doc/html/latest/networking)
下一篇:ss/netstat/ip 工具链:Socket 状态分析与连接审计
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【网络工程】tcpdump 实战精通:BPF 过滤与捕获策略
系统讲解 tcpdump 的工程实战:BPF 过滤语法完整指南、滚动捕获策略、时间戳精度控制、容器/Pod 环境抓包、高级用法与性能优化,让抓包成为系统化的诊断方法。
【网络工程】ss/netstat/ip 工具链:Socket 状态分析与连接审计
系统讲解 Linux 网络诊断工具链:ss 的过滤语法与性能优势、ip 命令族全景、conntrack 连接追踪、/proc/net/ 文件解读,建立从 Socket 状态到连接审计的工程能力。
【网络工程】BPF 网络诊断:bpftrace 与 bcc 工具实战
系统讲解 eBPF 在网络诊断中的工程应用:bcc 工具集(tcplife/tcpretrans/tcpdrop)的使用场景、bpftrace 自定义网络探针编写、XDP 丢包分析、内核协议栈延迟追踪,建立基于 eBPF 的系统化网络诊断方法。
网络工程索引
汇总本站网络工程系列文章,覆盖分层模型、以太网、IP、TCP、DNS、TLS、HTTP/2/3、CDN、BGP 与故障诊断。