网络问题排查的系统方法论
网络问题是最让人头疼的故障类型之一——现象模糊、原因复杂、影响面广。本文建立一套自底向上的排查体系,从物理层到应用层逐层排查,确保不错过任何可能。
排查路线图
应用层 ── curl / telnet / nc / strace
↑
传输层 ── ss / netstat / tcpdump
↑
网络层 ── ping / traceroute / ip route
↑
链路层 ── ip link / ethtool / arp
↑
物理层 ── 网线 / 灯 / dmesg
第一层:物理与链路检查
# 网卡状态
ip link show
# 关注: state UP/DOWN, 是否有 NO-CARRIER
# 网卡详细信息和错误统计
ip -s link show eth0
# RX errors/dropped/overruns > 0 表示有问题
# 网卡协商速率
ethtool eth0 | grep -E "Speed|Duplex|Link"
# 期望: Speed: 1000Mb/s, Duplex: Full
# 网卡驱动信息
ethtool -i eth0
# 内核网卡相关日志
dmesg | grep -i eth0 | tail -20
# 关键词: link up/down, reset, timeout
常见物理层问题:
- 网线松动 / 水晶头氧化 → RX errors 增多
- 速率协商不匹配 → 半双工导致碰撞
- 网卡驱动 bug →
dmesg中出现 reset
第二层:IP 和路由检查
# IP 地址
ip addr show
# 路由表
ip route show
# 确认默认路由存在: default via x.x.x.x dev eth0
# ARP 表(局域网通信基础)
ip neigh show
# STALE 状态 = 正常,FAILED = 不可达
# 到目标主机的路径
traceroute -n 8.8.8.8
mtr -r -c 10 8.8.8.8 # 更直观(组合 ping + traceroute)
# MTR 输出示例(关注 Loss% 和 Avg)
# HOST Loss% Snt Avg Best Wrst
# 1. 10.0.0.1 0.0% 10 1.2 0.8 3.5
# 2. 100.64.0.1 0.0% 10 5.3 4.1 8.2
# 3. ??? 100.0% 10 0.0 0.0 0.0 ← 中间节点不响应 ICMP,正常
# 4. 8.8.8.8 0.0% 10 35.2 33.1 38.7
第三层:TCP/UDP 连接检查
# 监听端口
ss -tlnp # TCP 监听
ss -ulnp # UDP 监听
# 所有连接(按状态统计)
ss -s
# 关注: TIME-WAIT 过多 (>几千) 需要调内核参数
# 查看特定端口的连接
ss -tnp 'sport = :80 or dport = :80'
# 进程的网络连接
ss -tnp | grep <pid>
# 连接数量 Top N(来源 IP)
ss -tn | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
TCP 状态机关键状态
LISTEN → 服务端等待连接
SYN-SENT → 客户端发送 SYN 后(可能被防火墙拦截)
SYN-RECV → 服务端收到 SYN(可能遭遇 SYN Flood)
ESTABLISHED → 正常连接
FIN-WAIT-1 → 主动关闭,等待对方 ACK
CLOSE-WAIT → 对方已关闭,本端未关闭(程序 bug!)
TIME-WAIT → 主动关闭方等待 2MSL
第四层:DNS 检查
# DNS 解析测试
nslookup example.com
dig example.com +short
host example.com
# 查看 DNS 解析过程
dig +trace example.com
# 指定 DNS 服务器测试
dig @8.8.8.8 example.com
# 反向解析
dig -x 8.8.8.8
# 本地 DNS 缓存(systemd-resolved)
resolvectl status
resolvectl query example.com
常见 DNS 问题:
/etc/resolv.conf被错误覆盖- systemd-resolved 与 NetworkManager 冲突
- DNS 服务器不可达 / 限流
tcpdump 抓包分析
# 基础抓包
tcpdump -i eth0 -nn port 80
# 抓取特定主机的 HTTP 流量
tcpdump -i eth0 -nn -A 'host 10.0.1.100 and port 80'
# 抓取 TCP SYN 包(排查建连问题)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0'
# 抓取并保存到文件(用 Wireshark 分析)
tcpdump -i eth0 -w capture.pcap port 3306
# 抓取特定时长的包
timeout 30 tcpdump -i eth0 -w capture.pcap
# 限制抓包大小(每个包只抓前100字节)
tcpdump -i eth0 -s 100 -w capture.pcap
快速定位 TCP 握手问题
# 观察是否有 SYN 发出但无 SYN-ACK 返回(防火墙拦截)
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'
# 观察是否有大量 RST(连接被拒绝)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
# RST 常见原因:
# 1. 端口未监听 → 服务未启动
# 2. 防火墙 DROP → iptables -L -n -v
# 3. 应用层拒绝 → 程序主动 reset
# 4. 连接超时 → connect timeout 后系统发 RST
防火墙排查
# iptables 规则查看
iptables -L -n -v --line-numbers
iptables -t nat -L -n -v
# 检查是否有 DROP 规则
iptables -L -n -v | grep DROP
# firewalld 状态(CentOS 7+)
firewall-cmd --state
firewall-cmd --list-all
# 临时关闭防火墙排查(仅测试!)
systemctl stop firewalld
# 或
iptables -P INPUT ACCEPT && iptables -F
# ufw 状态(Ubuntu)
ufw status verbose
strace 追踪系统调用
# 追踪 nginx 的网络相关系统调用
strace -f -e trace=network -p $(pgrep nginx | head -1)
# 追踪 connect(看连接到了哪里)
strace -e trace=connect curl http://example.com 2>&1 | grep connect
# 追踪 sendto/recvfrom(看数据发送和接收)
strace -e trace=sendto,recvfrom -p <pid>
# 常见发现:
# - connect(...) = -1 ECONNREFUSED → 目标端口未监听
# - connect(...) = -1 ETIMEDOUT → 防火墙拦截或路由不通
# - connect(...) = -1 ENETUNREACH → 网络不可达
实战案例:Web 服务超时排查
现象:用户反馈网站访问偶尔超时,持续 5-10 秒后恢复。
排查步骤:
# 1. 确认问题范围
# 是所有用户还是个别用户?所有页面还是特定接口?
# 2. 检查服务器连接数
ss -s # TIME-WAIT 8000+ → 需要调优
# 3. 抓包看 TCP 握手情况
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0' | head -50
# 发现大量 SYN 重传 → SYN Cookie 被触发
# 4. 检查 SYN 队列
netstat -s | grep -i listen
# 出现 SYNs to LISTEN sockets dropped → SYN 队列溢出
# 5. 调优
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
echo "net.core.somaxconn = 65535" >> /etc/sysctl.conf
# 6. Nginx 端
# listen 80 backlog=65535;
nginx -s reload
排查心法:不要凭直觉猜测,用数据说话。每一个结论都要有命令输出的支撑,每一个假设都要用抓包或日志来验证。