4.5 Linux 网络故障排查方法论与实战
预计阅读时间:16 分钟
📖 目录
学习目标
学完本章后,你将能够:
- 掌握网络故障排查的"自底向上"分层方法论
- 使用
ip、ping、ss、dig等命令诊断常见网络问题 - 分析端口监听、防火墙规则和路由配置
- 使用
tcpdump抓包并分析网络流量 - 排查 DNS 解析、连通性、带宽和延迟问题
核心知识
- OSI 七层模型——从物理层到应用层的网络分层参考模型,排查时应自底向上逐层验证
- TCP/IP 四层模型——实际工业标准:链路层、网络层、传输层、应用层
- 网卡状态(Link)——物理层连接状态,
ip link show查看是否state UP - MTU(最大传输单元)——链路层单帧最大数据量,以太网默认为 1500 字节,超过需分片
- 路由表——决定数据包从本机出发的下一跳路径,
ip route show查看 - ARP(地址解析协议)——将 IP 地址解析为 MAC 地址的协议
- TCP 三次握手——SYN → SYN+ACK → ACK,连接建立的必经过程
- DNS 解析——域名到 IP 地址的转换,
dig和nslookup是标准诊断工具 - tcpdump——命令行网络抓包工具,可保存为 pcap 供 Wireshark 分析
知识关联
- 前置知识:2.11:SSH 深入 SSH 深入(IP 地址、子网掩码、网关与远程连接概念)
- 后续影响:本章排查技能是 4.6:Linux 性能调优 Linux 性能调优和运维日常故障处理的基础
- 配套工具:5.5:防火墙实战 nftables 防火墙(排查防火墙问题时需理解 nftables 规则)
原理讲解
为什么自底向上排查
网络问题可能出现在任何一层,但下层的问题会导致上层所有现象。例如:网线松动(物理层)会导致 IP 获取失败(网络层),进而导致浏览器显示"无法连接"(应用层)。如果从上往下查,看到"无法连接"就去查 Web 服务器配置,可能花费大量时间却找不到原因。自底向上(物理→链路→网络→传输→应用)确保每次排查都以下层确认正常为前提,系统性地缩小问题范围。
四层排查路径
标准排查流程可归纳为四步: ① 物理+链路层——网卡状态 UP?RX/TX 错误包? ② 网络层——IP 地址配置正确?网关可达?能 ping 通远端 IP? ③ 传输层——目标端口在监听?防火墙是否放行?TCP 握手能否完成? ④ 应用层——服务本身运行正常?配置正确?日志中有无报错?
OSI 分层排查法与工具对应表
将 OSI 七层归并为四个排查层次,每层有专属的诊断工具。下层确认正常之前不要跳到上层排查:
| 层次 | 排查内容 | 核心工具 | 关键指标 |
|---|---|---|---|
| 物理 + 链路层 | 网线/网卡/交换机端口/MTU/ARP | ip link、ethtool、ip -s link、arp | state UP、Speed、errors、dropped、mtu |
| 网络层 | IP 配置/网关/路由/MTU 分片 | ip addr、ip route、ping、traceroute、mtr | 丢包率、RTT、TTL、Frag needed |
| 传输层 | 端口监听/防火墙/连接状态/重传 | ss、nc、tcpdump、nmap | LISTEN、SYN-SENT、重传率、RTT |
| 应用层 | 服务进程/配置/证书/DNS 解析 | curl -v、dig、openssl s_client、journalctl | HTTP 状态码、Query time、TLS 握手时间 |
例如"网站打不开":先确认 ip link 链路 UP → 再 ping 网关 确认网络层 → nc -zv 端口 确认传输层 → 最后才查 Web 服务配置。每一层通过后再进入下一层,问题范围逐层收敛。
MTU 导致的黑盒问题
MTU 不匹配是排查中最容易被忽略的原因。例如 VPN 或 GRE 隧道会在原始数据包上加包头,导致实际有效载荷超过路径 MTU。症状表现为:小包正常(ping -c 3)、大包超时(ping -c 3 -M do -s 1472)。这是典型的"传输层以下的问题,应用层才显现"的例子。
为什么网络排查推荐自底向上
网络分层模型(OSI/TCP-IP)决定了下层为上层提供服务——物理层承载链路层,链路层承载网络层,以此类推。任何一层的故障都会向上"泄漏"为上层的异常现象。自底向上排查的本质是排除法:先确认最底层基础设施正常,再逐层向上验证,每通过一层就排除该层的故障可能。如果跳过底层直接查应用层,相当于在未确认地基是否牢固的情况下检查屋顶——很可能白费力气。例如:浏览器报"连接超时"可能是 DNS 问题(应用层)、端口被防火墙拦截(传输层)、网关不通(网络层)或网线松动(物理层),只有从底层逐层验证才能高效定位。
为什么 ping 不通 ≠ 网络不通
许多运维人员看到 ping 不通就判定网络故障,但实际上 ping 使用的是 ICMP 协议,而 ICMP 可能被中间设备(防火墙、云安全组、运营商)丢弃。正确理解:ping 通证明 ICMP 可达(网络层基本正常),ping 不通只说明 ICMP 不可达,不能证明 TCP/UDP 也不通。排查时应该同时测试:① ping 测试 ICMP 连通性;② nc -zv host port 测试 TCP 端口可达性;③ dig 测试 DNS 解析。三者结合才能完整判断网络状态。
tcpdump 的工作原理与局限
tcpdump 通过内核的 AF_PACKET 套接字捕获网卡上的原始数据包。它工作在网卡驱动层之上、协议栈之下,因此能看到进出网卡的所有 L2/L3/L4 数据包。关键机制:① 混杂模式——默认只抓发往本机的包,加 -i any 可抓所有网卡;② BPF 过滤器—— tcpdump 的过滤表达式被编译为 BPF 字节码,在内核态过滤,只把匹配的包传到用户态,开销极小;③ 零拷贝——现代内核用 mmap 环形缓冲区减少数据拷贝。局限性:无法抓到本机发出后被 iptables DROP 的包(因为包在到达网卡驱动层之前即被丢弃),也无法看到交换机/路由器转发但未到达本机的包。
示例代码
1. 网卡与链路状态检查
# 查看所有网卡状态
ip link show
# 输出:
# 1: lo: mtu 65536 ...
# 2: eth0: mtu 1500 ...
# 重要标记: UP = 网卡启用, LOWER_UP = 电缆已连接
# 网卡详细信息(速率、双工模式)
ethtool eth0
# 输出:
# Speed: 1000Mb/s
# Duplex: Full
# Link detected: yes
# 查看网卡统计(错误包、丢包)
ip -s link show eth0
# 输出:
# RX: bytes packets errors dropped overrun mcast
# 12345678 12345 0 0 0 0
# TX: errors 列如果有非零值,说明物理层存在问题
# 检查 MTU
ip link show eth0 | grep mtu
# 如果 MTU 异常(如 PPPoE 需要 1492),调整:
sudo ip link set eth0 mtu 1492
2. IP 配置与网络层排查
# 查看 IP 地址配置
ip addr show eth0
# 输出:
# 2: eth0: ... state UP ...
# inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0
# 注意: 169.254.x.x 表示 DHCP 失败
# 查看路由表
ip route show
# 输出:
# default via 192.168.1.1 dev eth0 proto dhcp
# 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100
# 基本连通性测试
ping -c 4 192.168.1.1 # 网关可达?
ping -c 4 8.8.8.8 # 外网可达?
# MTU 路径探测
ping -c 3 -M do -s 1472 8.8.8.8
# 如果提示 "Frag needed" 说明路径上的 MTU 小于 1500
# 不断减小 -s 参数直到成功,最小 MTU = 28 + 成功时的 -s 值
# 路由追踪
traceroute -n 8.8.8.8
# 输出每一跳的延迟,找出丢包或高延迟的节点
3. DNS 诊断
# 查看系统 DNS 配置
cat /etc/resolv.conf
# 输出:
# nameserver 127.0.0.53
# options edns0 trust-ad
# DNS 查询测试
dig google.com
# 关注输出:
# ;; Query time: 23 msec ← DNS 响应时间
# ;; SERVER: 127.0.0.53#53 ← 使用的 DNS 服务器
# google.com. 108 IN A 142.250.80.14 ← 解析结果
# 指定 DNS 服务器测试
dig @223.5.5.5 google.com # 使用阿里 DNS
dig @8.8.8.8 google.com # 使用 Google DNS
# 反向 DNS 查询
dig -x 8.8.8.8
# 仅显示查询时间
dig google.com | grep "Query time"
# 检查 hosts 文件(是否被本地覆盖)
cat /etc/hosts
# 缓存 DNS 问题排查(systemd-resolved)
sudo resolvectl statistics
sudo resolvectl flush-caches
4. 端口与服务诊断
# 查看所有监听端口
ss -tlnp
# 输出:
# State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1024))
# LISTEN 0 128 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=2048))
# 解读:
# 0.0.0.0:22 = 任意 IP 皆可连接(外网可见)
# 127.0.0.1:3306 = 仅本地可连接(安全隔离)
# TCP 端口探测
nc -zv -w 3 192.168.1.100 22
# 输出: Connection to 192.168.1.100 port 22 [tcp/ssh] succeeded!
# HTTP 服务调试
curl -v http://localhost:8080
# 关注:
# * TCP_NODELAY set ← TCP 连接阶段
# < HTTP/1.1 200 OK ← 应用层响应
# 查看当前连接状态
ss -tan | head -20
# 状态说明: ESTAB(已连接)、TIME-WAIT(等待关闭)、SYN-SENT(发起连接)
5. 防火墙规则检查
# UFW 状态
sudo ufw status verbose
# 输出:
# Status: active
# Logging: on (low)
# Default: deny (incoming), allow (outgoing)
# To Action From
# -- ------ ----
# 22/tcp (SSH) ALLOW Anywhere
# 80/tcp (WWW) ALLOW Anywhere
# nftables 规则
sudo nft list ruleset
# iptables 规则(当前过滤表)
sudo iptables -L -n -v
# 临时放行端口用于测试
sudo ufw allow 8080/tcp
# 查看是否被 fail2ban 封禁
sudo fail2ban-client status sshd
# 连接跟踪表(conntrack)
sudo conntrack -L | head -20
6. 抓包分析
# 基本 HTTP 抓包
sudo tcpdump -i eth0 port 80 -c 10
# 指定主机流量
sudo tcpdump -i eth0 host 192.168.1.100
# 保存到文件(供 Wireshark 分析)
sudo tcpdump -i eth0 -w capture.pcap
# 查看 TCP 握手细节
sudo tcpdump -i eth0 host 192.168.1.100 and port 443 -v
# 输出示例:
# 09:30:01.123456 IP 192.168.1.100.54321 > 93.184.216.34.443: Flags [S] ← SYN
# 09:30:01.234567 IP 93.184.216.34.443 > 192.168.1.100.54321: Flags [S.] ← SYN+ACK
# 09:30:01.234690 IP 192.168.1.100.54321 > 93.184.216.34.443: Flags [.] ← ACK
# 过滤 SYN 连接建立包(排查 SYN flood / 半连接堆积)
sudo tcpdump -i eth0 'tcp[13] & 2 != 0'
# 用 ngrep 分析应用层(HTTP)
sudo ngrep -d eth0 port 80
7. 综合排查脚本
#!/bin/bash
# net-check.sh —— 一键网络诊断
set -euo pipefail
echo "=== 1. 网卡状态 ==="
ip link show | grep -E "state (UP|DOWN)"
echo "=== 2. IP 配置 ==="
ip addr show | grep inet
echo "=== 3. 路由 ==="
ip route show | grep default
echo "=== 4. 网关可达性 ==="
GATEWAY=$(ip route | grep default | awk '{print $3}')
ping -c 2 -W 2 "$GATEWAY" >/dev/null && echo "OK" || echo "FAIL"
echo "=== 5. 外网连通性 ==="
ping -c 2 -W 2 8.8.8.8 >/dev/null && echo "OK" || echo "FAIL"
echo "=== 6. DNS 解析 ==="
dig +short google.com | head -3
echo "=== 7. 关键端口 ==="
for port in 22 80 443; do
ss -tlnp | grep -q ":$port " && echo ":$port LISTENING" || echo ":$port CLOSED"
done
8. tcpdump 常用过滤表达式
# 表达式结构: 类型(host/net/port)+ 方向(src/dst)+ 协议(tcp/udp/icmp)+ 逻辑组合
# 按主机过滤
sudo tcpdump -i eth0 host 192.168.1.100 # 源或目的任一
sudo tcpdump -i eth0 src host 192.168.1.100 # 仅源地址
sudo tcpdump -i eth0 dst host 192.168.1.100 # 仅目的地址
sudo tcpdump -i eth0 net 192.168.1.0/24 # 整个网段
# 按端口过滤
sudo tcpdump -i eth0 port 443 # 任意方向
sudo tcpdump -i eth0 src port 443
sudo tcpdump -i eth0 dst port 3306 # 发往 MySQL 的流量
sudo tcpdump -i eth0 portrange 8000-8100
# 按协议过滤
sudo tcpdump -i eth0 tcp
sudo tcpdump -i eth0 icmp
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0' # 仅 SYN 包
# 逻辑组合(and / or / not,多条件建议加引号)
sudo tcpdump -i eth0 'host 192.168.1.100 and (port 80 or port 443)'
sudo tcpdump -i eth0 'tcp and not port 22' # 排除 SSH 自身流量
sudo tcpdump -i eth0 'icmp[icmptype] = icmp-echo' # 仅 ICMP 请求
# 报文内容查看
sudo tcpdump -i eth0 -A 'tcp port 80' # -A 以 ASCII 显示载荷(HTTP 可见)
sudo tcpdump -i eth0 -X 'tcp port 22' # -X HEX + ASCII 双格式
# 组合实战: 抓 HTTP 三次握手 + 请求头(-n 不解析域名/端口)
sudo tcpdump -i eth0 -nn 'tcp port 80 and tcp[tcpflags] & (tcp-syn|tcp-ack) != 0' -c 20
# 抓包数量与文件大小控制
sudo tcpdump -i eth0 -w cap.pcap -C 100 # 每个文件 100MB 轮转
sudo tcpdump -i eth0 -c 10000 # 最多抓 1 万包自动停止
9. TCP 性能分析:重传、RTT 与窗口
# 1. 全局重传统计(重传率高 = 丢包/拥塞)
nstat -s | grep -i retrans # netstat 已废弃,nstat 是替代工具
# 输出: TcpExtTCPRetransSegs 12
# TcpExtTCPSynRetrans 3
# 2. 抓包只取重传/异常标志
sudo tcpdump -i eth0 'tcp[13] & 4 != 0' -c 50 # RST 重置包
sudo tcpdump -i eth0 'tcp[13] & 8 != 0' -c 50 # PSH 数据推送包
sudo tcpdump -i eth0 -w tcp.pcap port 443 # 保存后用 Wireshark 分析
# 3. 抓包后离线统计(tshark)
tshark -r tcp.pcap -Y tcp.analysis.retransmission | wc -l # 重传包数量
tshark -r tcp.pcap -q -z io,stat,1 # 每秒流量
# 4. 实时查看每个 TCP 连接的 RTT(ss -ti 是性能排查利器)
ss -ti state established | head -30
# 输出示例:
# tcp ESTAB 0 0 192.168.1.10:54321 93.184.216.34:443
# cubic rto:212 rtt:28.4/15.9 ato:40 mss:1460
# rtt:28.4/15.9 = 平均 RTT 28.4ms / 抖动 15.9ms;rto 超时重传阈值
# 5. 丢包率粗测(100 个包,>1% 关注,>5% 显著影响吞吐)
ping -c 100 -i 0.2 8.8.8.8 | tail -2
# 输出: 100 packets transmitted, 98 received, 2% packet loss
# 6. 观察接收窗口(win 字段,决定吞吐上限)
sudo tcpdump -i eth0 -nn 'tcp port 443' -c 5
# 输出: ... win 64240 ... ← 窗口越大单连接吞吐越高
# 吞吐上限 ≈ 窗口大小 / RTT,例如 64KB / 50ms ≈ 10Mbps
10. 真实案例:四个典型网络故障排查
# 案例一:间歇性丢包(应用偶发超时)
# 现象: 监控显示丢包率 2%-5%,集中在晚间 20:00-23:00
mtr -n -c 100 8.8.8.8 # 逐跳观察丢包位置
# 若第 3 跳(运营商设备)丢包 100% 而后续跳正常,多为 ICMP 限速而非真实故障
iperf3 -c 服务器IP -t 60 # 用 TCP 实测验证真实路径质量,关注 retr 列
# 案例二:下载速度慢但 ping 正常(MTU 黑洞)
ping -M do -s 1472 服务器IP # 超时则说明路径 MTU < 1500
ping -M do -s 1400 服务器IP # 缩小包长找到临界值
sudo ip link set eth0 mtu 1400 # 临时验证,确认有效后写入配置
iperf3 -c 服务器IP -R # 反向测速,区分上下行瓶颈
# 案例三:DNS 解析慢(页面首开卡顿数秒)
time dig google.com # 解析总耗时
dig @8.8.8.8 google.com | grep "Query time" # 对比不同 DNS
resolvectl statistics # 缓存命中率 cache hits/misses
# 常见根因: resolv.conf 中失效 nameserver 超时重试、上游 DNS 拥塞
# 修复: 清理无效 nameserver、本地启用 dnsmasq/systemd-resolved 缓存
# 案例四:SSH 连接建立慢(输密码前卡 10 秒)
ssh -vvv user@host 2>&1 | grep -E "connecting|banner"
# 根因1: sshd UseDNS yes 反向解析 → 设 UseDNS no
# 根因2: 客户端 GSSAPIAuthentication 尝试 Kerberos → 加 -o GSSAPIAuthentication=no
# 根因3: 服务器到 DNS 网络故障,认证后每条命令都卡
time ssh user@host true # 改前改后各测一次对比
常见错误
| 错误表现 | 根因 | 正确做法 |
|---|---|---|
| 应用提示"连接被拒绝"但服务已启动 | 服务监听在 127.0.0.1 而非 0.0.0.0 | ss -tlnp | grep :port 查看 Local Address;若为 127.0.0.1:port,配置 bind 到 0.0.0.0 |
| ping 通但浏览器无法打开网页 | DNS 解析失败或 HTTP 服务未正确配置 | dig 域名 检查 DNS;curl -v http://域名 调试 HTTP |
| 小包 ping 通,大包 ping 不通 | 路径 MTU 小于 1500,超大包需要分片但被禁止 | 执行 ping -M do -s 1472 target 逐步减小包大小找到 MTU 值 |
| SSH 连接极慢,登录后正常 | SSHD 开启了 DNS 反向查询(UseDNS yes) | /etc/ssh/sshd_config 中设置 UseDNS no |
| 应用间歇性连接超时 | 连接跟踪表(conntrack)满了,新连接被丢弃 | sudo conntrack -S 查看;增大 nf_conntrack_max |
| ping 正常但传输速度极慢 | 路径 MTU 小于 1500 且中间设备丢弃分片(MTU 黑洞),或 TCP 窗口过小 | ping -M do -s 1472 探测路径 MTU;用 ss -ti 观察 rtt 与窗口 |
| tcpdump 抓不到任何包 | 过滤器条件与流量不匹配,或网卡被交换机镜像/offload 影响 | 先不加过滤条件裸抓验证流量存在;确认监听的网卡名称(ip link) |
最佳实践
| 实践 | 原理 | 示例 |
|---|---|---|
| 按"物理→链路→网络→传输→应用"逐层排查 | 下层问题是上层现象的根因,避免从上往下做无用功 | 先 ip link 再看 ip addr 再 ping |
| 一次只改一个变量,改后测试 | 同时改多个参数无法确定哪个是真正原因 | 改完防火墙规则后立即测试连通性 |
用 curl -v 代替浏览器调试 | 看到完整的请求/响应头和状态码 | curl -v --connect-timeout 5 http://example.com |
| 抓包保留为 pcap 文件 | 团队协作时可发给同事分析,也可与基线对比 | tcpdump -w problem.pcap → Wireshark 分析 |
| 建立网络基线 | 知道"正常时"的延迟/带宽/丢包率,异常时才能判断 | 定期 ping -c 100 gateway 记录 min/avg/max |
练习题
- (概念)为什么网络排查推荐自底向上而非自顶向下?请用一个具体例子说明。
- (概念)
ss -tlnp中-t、-l、-n、-p四个选项分别表示什么? - (实操)在一台服务器上模拟端口不通:启动 Nginx(
sudo apt install nginx),停止 nginx,然后使用nc -zv、ss -tlnp、curl -v三个工具分别探测端口 80,记录输出差异。 - (实操)执行
tcpdump -i eth0 port 80 -c 10抓取 10 个 HTTP 包,然后用curl http://example.com触发流量。观察抓到的 TCP 三次握手(SYN/SYN-ACK/ACK)。 - (🔍 挑战)搭建一个双机环境,在一台机器上配置 iptables/nftables 规则丢弃特定源 IP 的 TCP SYN 包。从另一台机器连接时,用
ss -tan观察连接状态停留在 SYN-SENT,用 tcpdump 确认远端未回复 SYN-ACK。写一份排查报告记录整个过程。
点击查看答案
- 自底向上确保下层正常后才排查上层。例如:浏览器"无法连接"(应用层),若先查 Web 服务器配置可能白费时间;若先查
ip link发现网卡 DOWN,直接定位到物理层问题。 -t只显示 TCP 套接字;-l只显示 LISTEN 状态的端口;-n以数字形式显示地址和端口(不解析服务名);-p显示进程信息(PID/程序名)。- nginx 停止时:
nc -zv localhost 80返回Connection refused;ss -tlnp无:80条目;curl -v http://localhost返回Connection refused。nginx 启动后三者均正常。 tcpdump捕获到Flags [S](客户端 SYN)、Flags [S.](服务器 SYN+ACK)、Flags [.](客户端 ACK),即为三次握手。- iptables 规则:
iptables -A INPUT -s $SOURCE_IP -p tcp --syn -j DROP。客户端ss -tan显示SYN-SENT,tcpdump 看到 SYN 发出但无 SYN-ACK 回复。排查报告需记录规则配置、抓包结果和连接状态。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释网络分层模型和各层常见问题 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成网络诊断工具使用、问题定位 | 在终端实际执行 |
| 原理掌握 | 能说出 TCP/IP 协议栈和 DNS 解析流程 | 画出流程图 |
| 故障排查 | 能独立排查网络连接超时、DNS 解析失败、防火墙阻挡 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么需要按照 OSI 模型分层排查网络问题 | 对比不同方案 |
本章总结
网络故障排查是运维人员最常面对的任务之一。核心方法论是"自底向上逐层验证"——从网卡链路状态开始,依次检查 IP 配置、路由、DNS、端口监听、防火墙规则,最后才是应用层配置。关键工具包括 ip(查看网络接口和路由)、ping(连通性和 MTU 测试)、ss(端口监听和连接状态)、dig(DNS 解析)、tcpdump(抓包分析)。熟练掌握这组工具和方法论,就能覆盖绝大多数日常网络故障的排查。
速查表
| 命令 | 用途 |
|---|---|
ip link show | 查看网卡状态和 MTU |
ip addr show | 查看 IP 配置 |
ip route show | 查看路由表 |
ping -c 4 target | 连通性测试 |
ping -M do -s 1472 target | MTU 路径探测 |
ss -tlnp | 查看 TCP 监听端口 |
nc -zv host port | TCP 端口探测 |
dig domain | DNS 解析查询 |
traceroute -n target | 路由追踪 |
tcpdump -i eth0 -w file.pcap | 抓包保存 |
学习路径建议
- 学完本章后建议阅读 5.5:防火墙实战 nftables 防火墙(更精细的网络管控)
- 进阶可学习 Wireshark 图形化分析和 tc (traffic control) 流量控制
- 云网络场景可看 6.10:云网络基础 云网络基础(VPC、子网、NAT 网关等)
延伸阅读
- tcpdump 手册
- Brendan Gregg 的 Linux 性能工具图谱
- Wireshark 文档和抓包示例
- 推荐书籍:《TCP/IP 详解 卷 1》