跳到主要内容

网络排查方法论

分层排查模型

网络故障排查遵循自底向上的分层方法,从物理层开始逐层排查:

排查流程

各层排查工具

物理层 & 链路层

# 查看网卡状态
ip link show
ethtool eth0 # 查看网卡详细信息(速率、双工、连接状态)
ethtool -S eth0 # 查看网卡统计(丢包、错误)

# 网卡错误统计
cat /proc/net/dev # 查看所有网卡收发包统计
# 关注 errs(错误)、drop(丢弃)、fifo(溢出)列

# 查看/清除 ARP 缓存
ip neigh show
ip neigh flush dev eth0

# 检查网卡 bonding 状态
cat /proc/net/bonding/bond0

网络层

# === ping ===
ping -c 4 gateway_ip # 测试网关连通性
ping -c 4 8.8.8.8 # 测试外网连通性
ping -I eth0 target # 指定源接口
ping -s 1472 -M do target # 测试 MTU(不分片)

# === traceroute / tracepath ===
traceroute -n target # -n 不解析主机名(更快)
traceroute -T -p 80 target # TCP traceroute(防止 ICMP 被拦截)
tracepath target # 自动探测 MTU

# === mtr(综合 ping + traceroute)===
mtr -rn target # 生成报告模式
mtr --tcp -P 80 target # TCP 模式
# mtr 输出字段:
# Loss% - 丢包率 Snt - 发送包数
# Last - 最近延迟 Avg - 平均延迟
# Best - 最低延迟 Wrst - 最高延迟
# StDev - 标准差(越大越不稳定)

# === 路由排查 ===
ip route show # 查看路由表
ip route get target_ip # 查看到目标的路由
traceroute -n target # 跟踪路由路径
mtr 输出解读
HOST                   Loss%  Snt   Last   Avg  Best  Wrst  StDev
1. 10.0.0.1 0.0% 10 0.5 0.6 0.4 1.2 0.2
2. 172.16.0.1 0.0% 10 1.2 1.5 1.0 3.0 0.5
3. ??? 100.0 10 0.0 0.0 0.0 0.0 0.0 ← ICMP 被禁
4. 10.20.0.1 10.0% 10 5.2 5.5 4.8 8.0 1.0 ← 丢包
5. target 0.0% 10 5.0 5.2 4.5 7.0 0.8
  • 第 3 跳 100% Loss 但后续正常 → 中间路由器不回 ICMP,不是故障
  • 第 4 跳开始有丢包且后续也有 → 从第 4 跳开始有问题
  • 第 4 跳有丢包但第 5 跳(目标)无丢包 → 第 4 跳路由器限制 ICMP

传输层

# === 端口测试 ===
telnet target 80 # 测试 TCP 端口
nc -zv target 80 # netcat 端口扫描
nc -zv target 80-90 # 端口范围扫描
nc -zuv target 53 # UDP 端口测试

# === 连接状态分析 ===
ss -s # 连接状态概要
ss -ant # 所有 TCP 连接
ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn # 按状态统计

ss -tnp # 查看连接的进程信息
ss -ant state time-wait # 查看特定状态的连接
ss -ant dst 10.0.0.100 # 查看到特定目标的连接

# === 端口监听 ===
ss -tlnp # 查看 TCP 监听端口
ss -ulnp # 查看 UDP 监听端口
lsof -i :80 # 查看占用 80 端口的进程
fuser 80/tcp # 查看占用 80 端口的 PID

应用层

# === HTTP 测试 ===
curl -v https://target # 详细输出
curl -o /dev/null -s -w "%{http_code} %{time_total}s\n" URL
curl --connect-timeout 5 --max-time 10 URL # 超时控制

# === DNS 测试 ===
dig target
dig +trace target
dig @8.8.8.8 target

# === SSL/TLS 测试 ===
openssl s_client -connect target:443 -servername target
echo | openssl s_client -connect target:443 2>/dev/null | openssl x509 -noout -dates

tcpdump 抓包

常用抓包命令

# 基础抓包
tcpdump -i eth0 # 抓取 eth0 所有流量
tcpdump -i any # 抓取所有接口流量

# 按主机过滤
tcpdump -i any host 10.0.0.100 # 特定主机
tcpdump -i any src 10.0.0.1 # 源地址
tcpdump -i any dst 10.0.0.2 # 目标地址

# 按端口过滤
tcpdump -i any port 80 # 端口 80
tcpdump -i any portrange 8000-9000 # 端口范围
tcpdump -i any "port 80 or port 443" # 多端口

# 按协议过滤
tcpdump -i any tcp # TCP 流量
tcpdump -i any udp # UDP 流量
tcpdump -i any icmp # ICMP 流量

# 组合过滤
tcpdump -i any "host 10.0.0.1 and port 80 and tcp"

# 只抓 SYN 包(分析连接建立)
tcpdump -i any "tcp[tcpflags] & (tcp-syn) != 0 and tcp[tcpflags] & (tcp-ack) == 0"

# 只抓 RST 包(连接被重置)
tcpdump -i any "tcp[tcpflags] & (tcp-rst) != 0"

# 常用选项
tcpdump -n # 不解析主机名
tcpdump -nn # 不解析主机名和端口名
tcpdump -c 100 # 抓 100 个包后停止
tcpdump -A # 以 ASCII 显示内容
tcpdump -X # 以 HEX+ASCII 显示
tcpdump -w capture.pcap # 保存为 pcap 文件
tcpdump -r capture.pcap # 读取 pcap 文件
tcpdump -s 0 # 抓取完整包(不截断)

抓包分析实战

场景 1:分析 TCP 连接问题

# 抓取 SYN 和 RST 包,分析连接是否被拒绝
tcpdump -i any -nn "host target and (tcp[tcpflags] & (tcp-syn|tcp-rst) != 0)" -c 50

# 输出解读:
# SYN → SYN,ACK → ACK 正常三次握手
# SYN → RST 端口未监听或被防火墙拒绝
# SYN → (无响应) 包被丢弃(防火墙 DROP)
# SYN → SYN,ACK → RST 客户端重置(可能是连接池问题)

场景 2:分析 HTTP 请求

# 抓取 HTTP 请求行
tcpdump -i any -nn -A port 80 | grep -E "^(GET|POST|PUT|DELETE|HTTP/)"

场景 3:分析 DNS 查询

# 抓取 DNS 流量
tcpdump -i any -nn port 53
# 输出:
# 10.0.0.1.52345 > 8.8.8.8.53: A? example.com → DNS 查询
# 8.8.8.8.53 > 10.0.0.1.52345: A 93.184.216.34 → DNS 响应

常见网络故障场景

场景 1:服务无法访问

# 1. 检查服务是否监听
ss -tlnp | grep PORT

# 2. 检查本机防火墙
iptables -L -n | grep PORT
firewall-cmd --list-all

# 3. 测试端口连通性
telnet target PORT
nc -zv target PORT

# 4. 检查安全组(云环境)

# 5. 抓包分析
tcpdump -i any port PORT -nn -c 20

场景 2:网络延迟高

# 1. 确认延迟位置
mtr -rn target

# 2. 检查带宽使用
iftop -i eth0 # 实时带宽监控
nethogs # 按进程查看带宽
nload # 网卡流量图

# 3. 检查 TCP 重传
netstat -s | grep retransmit
ss -ti | grep -E "rto:|retrans:"

# 4. 检查丢包
ping -c 100 target | tail -3 # 查看丢包率

场景 3:间歇性断连

# 1. 持续监测
mtr -rn -c 200 target # 长时间 mtr

# 2. 检查连接跟踪表(NAT 场景)
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
# 如果 count 接近 max,会导致新连接被丢弃

# 扩大 conntrack 表
sysctl -w net.netfilter.nf_conntrack_max=524288

# 3. 检查 TCP keepalive
sysctl net.ipv4.tcp_keepalive_time

# 4. 检查网卡错误
ethtool -S eth0 | grep -i error

场景 4:DNS 解析异常

# 1. 确认本地 DNS 配置
cat /etc/resolv.conf

# 2. 对比不同 DNS 服务器
dig @8.8.8.8 domain
dig @1.1.1.1 domain
dig @local_dns domain

# 3. 追踪解析链路
dig +trace domain

# 4. 清除本地缓存
resolvectl flush-caches # systemd-resolved
systemctl restart nscd # nscd

实用排查脚本

network-check.sh
#!/bin/bash
# 快速网络诊断脚本

TARGET=${1:-"8.8.8.8"}
echo "===== 网络诊断: $TARGET ====="

echo ""
echo "[1] 网卡状态"
ip -br link show

echo ""
echo "[2] IP 地址"
ip -br addr show

echo ""
echo "[3] 默认路由"
ip route show default

echo ""
echo "[4] DNS 配置"
cat /etc/resolv.conf | grep nameserver

echo ""
echo "[5] Ping 网关"
GW=$(ip route show default | awk '{print $3}')
ping -c 2 -W 2 "$GW" 2>&1 | tail -3

echo ""
echo "[6] Ping 目标: $TARGET"
ping -c 4 -W 2 "$TARGET" 2>&1 | tail -3

echo ""
echo "[7] DNS 解析测试"
dig +short google.com

echo ""
echo "[8] TCP 连接状态统计"
ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "[9] 监听端口"
ss -tlnp | head -20

echo ""
echo "===== 诊断完成 ====="

常见面试问题

Q1: 如何排查"网络不通"问题?

答案

按 TCP/IP 分层自底向上排查:

  1. 物理层ip link show 确认网卡 UP,ethtool 查看连接状态
  2. 链路层arping gateway 检查 ARP
  3. 网络层ping gatewayping 8.8.8.8traceroute target
  4. 传输层telnet target port / nc -zv target port
  5. 应用层curl -v target / dig target

同时要 check 防火墙和安全组配置。

Q2: ping 通但 telnet 不通是什么原因?

答案

ping 使用 ICMP 协议,telnet 使用 TCP。可能原因:

  1. 目标端口上没有服务监听
  2. 防火墙/安全组允许 ICMP 但不允许目标 TCP 端口
  3. 服务绑定了 127.0.0.1 而非 0.0.0.0
  4. TCP 连接数达到上限

使用 ss -tlnp | grep PORT 检查服务监听状态。

Q3: 如何分析网络丢包发生在哪一跳?

答案

使用 mtr -rn target 持续监测。关注每一跳的 Loss%:

  • 某一跳 100% 丢包但后续正常 → 该路由器不回 ICMP,不是故障
  • 某一跳开始丢包且后续都有丢包 → 从该跳开始有问题
  • 只有最后一跳丢包 → 目标主机自身的问题(CPU 高、接口限速等)

Q4: conntrack 表满了会有什么现象?怎么解决?

答案

现象:新连接随机失败,dmesg 中出现 nf_conntrack: table full, dropping packet

解决

  1. 扩大 conntrack 表:sysctl -w net.netfilter.nf_conntrack_max=524288
  2. 缩短超时时间:
    sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=1200
    sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
  3. 如果不需要 NAT 和状态跟踪,可以用 raw 表 NOTRACK 跳过连接跟踪

相关链接