Linux 网络故障排查:思路、工具与实战场景 - 夜莺博客

Linux 网络故障排查:思路、工具与实战场景

网络故障是运维工程师每天都要面对的挑战,一次中断可能造成数万元业务损失,快速定位问题的能力直接体现工程师的价值。本文整理企业环境中沉淀下来的 Linux 网络故障排查经验:先建立 OSI 分层排查思路,再掌握必备工具,最后通过四大高频故障场景的完整排查流程,帮你形成系统化的排障方法论。

故障排查的黄金法则:分层排查

网络故障排查遵循 OSI 七层模型,自下而上逐层分析:物理层 → 数据链路层 → 网络层 → 传输层 → 应用层。这种自下而上的方式能快速收敛问题范围,避免在错误方向上浪费时间——先确认链路通不通,再谈协议和服务。

必备工具箱

# 连通性测试
ping -c 4 目标IP
# 路由追踪(推荐 mtr 持续观察)
mtr --report --report-cycles 10 目标IP
# 端口连通性
nc -zv 目标IP 端口
# 网络统计
ss -tulpn
# 流量分析
tcpdump -i eth0 -w capture.pcap

场景 1:服务器无法连接外网

现象:内网通信正常,ping 不通外网 IP,域名解析失败。排查步骤:① ip addr show 和 ip route show 检查本地网络配置;② ip route | grep default 拿到网关后 ping -c 4 网关IP 验证网关连通性;③ 检查防火墙:CentOS/RHEL 用 firewall-cmd --list-all,Ubuntu 用 ufw status;④ 检查 DNS:cat /etc/resolv.conf、nslookup 验证解析。

场景 2:网络延迟异常

现象:连接超时、响应缓慢、丢包率高。深度分析:ping -c 100 -i 0.1 目标IP 做细粒度丢包测试,mtr --report --report-cycles 100 定位丢包发生在哪一跳,iperf3 -c 目标服务器 测真实带宽。若确认是 TCP 缓冲区问题,可调整内核参数:net.core.rmem_max = 16777216、net.core.wmem_max = 16777216 后 sysctl -p 生效。

场景 3:端口无法访问

服务明明启动了却连不上端口?按顺序排查:① ss -tlpn | grep :端口号 确认监听状态和监听地址——0.0.0.0 监听所有接口,127.0.0.1 仅监听回环(这是最常见的坑);② telnet 127.0.0.1 端口号 本机测试;③ 检查 SELinux 策略和防火墙规则;④ 验证应用配置。

场景 4:DNS 解析缓慢

网站访问极慢但直接访问 IP 正常,基本就是 DNS 问题。time nslookup domain.com 测量解析耗时,对比 nslookup domain.com 8.8.8.8 与 114.114.114.114 的差异,必要时 systemctl restart systemd-resolved 清缓存、调整 resolv.conf 里的 nameserver 顺序。完整的分层排查流程可参考本站 Linux 网络故障排查分步指南,更多高频故障见 Linux 运维常见故障 33 个技巧,抓包实战见 tcpdump 抓包与 BPF 过滤器指南。

动手之前:先问三个问题

经验丰富的运维在敲第一条命令之前,脑子里已经有三个答案:影响范围有多大、什么时候开始变慢的、最像哪一类故障。这三个问题决定了你先登录哪台机器、先抓哪个包,能省掉大量无效操作。

  • 影响范围:一台机器 → 大概率是本机配置或进程;同机架多台 → 大概率是接入交换机或网卡;跨可用区 → 大概率是路由、防火墙或上游运营商。
  • 时间点:和发布、扩容、内核升级时间对齐就是软件回归;毫无规律地偶发就是硬件老化或链路质量。
  • 症状分类:丢包、延迟、解析、权限四类,起手的命令完全不同。

还有一条纪律:修改前先留证据。抓包文件、ss 输出、ip route show 结果都存下来再动手,否则问题“自愈”之后就再也没有根因了。

工具箱补全:从 ping 到 nstat

前面几个场景用到的工具只是起点。真正排生产故障时,下面这套组合拳覆盖了从网卡到协议栈的全部观测点。

# 网卡层:速率、双工、驱动统计
ethtool eth0
ethtool -S eth0 | grep -Ev ': 0$'          # 只看非零计数,噪声更少
ethtool -k eth0 | grep -i offload          # 卸载特性,排查校验和异常

# 协议栈统计:重传、丢包、拥塞事件
nstat -az | grep -Ei 'retrans|drop|timeout'
ss -s                                       # 连接总数与状态分布

# 连接细节:队列、拥塞窗口、重传次数
ss -ti state established dst 10.20.0.30

# 路由与邻居
ip route get 8.8.8.8                       # 内核认为的出接口与源地址
ip neigh show                              # ARP/ND 邻居状态
ip -s link show eth0                       # 接口丢包/错误计数

# 内核丢包点
cat /proc/net/softnet_stat                 # 每 CPU 的 backlog 丢弃
netstat -s | grep -i listen                # accept 队列溢出

# 抓包:只抓必要字段,避免 pcap 撑爆磁盘
tcpdump -i eth0 -nn -c 200 'tcp port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack) != 0'
tcpdump -i eth0 -nn 'host 10.20.0.30 and not port 22' -w /tmp/x.pcap

# 带宽与路径
iperf3 -c 10.0.0.20 -t 30 -P 4
tracepath 8.8.8.8                          # 顺带探测路径 MTU

把 ip -s link(网卡计数)、nstat(协议栈计数)、ss -ti(连接计数)三条放在一起,基本就能判断丢包发生在网卡、内核还是对端。抓包的进阶过滤器写法见本站 tcpdump 抓包与 BPF 过滤器指南,内核级追踪可以看 bpftrace 生产环境一行命令。

场景 5:连接被重置,服务端日志一片空白

客户端报 Connection reset by peer 或 Connection refused,而应用日志没有任何记录,说明请求根本没到应用层。区分两种错误是关键:

  • Connection refused:收到 RST,通常是端口没监听、监听地址不对,或防火墙 REJECT。
  • Connection reset:连接建立后被重置,常见于对方进程崩溃、闲置超时、或中间设备清理会话表。
ss -tlpn | grep :8080            # 确认监听地址:0.0.0.0 vs 127.0.0.1
iptables -L -n -v | grep 8080    # 是否有 REJECT 规则
conntrack -L | grep 8080         # 中间设备/本机连接跟踪是否超时
tcpdump -i any -nn 'port 8080 and (tcp[tcpflags] & tcp-rst != 0)'   # 找 RST 来源
dmesg | tail -30                 # OOM Killer 是否杀掉了进程

如果 tcpdump 显示 RST 的源 IP 并不是服务器本身,那就是中间有防火墙或 NAT 设备在清理会话,需要调整其会话老化时间,而不是改服务器配置。

场景 6:网卡丢包与队列溢出

如果 ping 看着正常但吞吐上不去,或者 ss 里重传很多,多半是网卡或内核队列在丢包。三个观测点对应三种根因。

# 1) 网卡硬件计数:rx_missed_errors 增长 → 环形缓冲区太小
ethtool -S eth0 | grep -E 'missed|no_buffer|dropped|discard'

# 2) 内核 backlog 丢弃:softnet_stat 第二列增长 → 软中断处理不过来
awk '{print $1, $2, $3}' /proc/net/softnet_stat

# 3) 应用来不及 accept:ListenOverflows 增长 → socket backlog 太小
nstat -az | grep -i listen

对症下药:环形缓冲区用 ethtool -G eth0 rx 4096 加大;软中断瓶颈用 ethtool -L eth0 combined 8 增加队列并把中断分散到多个 CPU;应用 accept 慢则调整 net.core.somaxconn 与应用的 backlog 参数。注意 ethtool -G 设置过大会增加内存占用和延迟抖动,按实际包速率调,不要照抄网上的“最大值”。

场景 7:容器或命名空间里网络不通

容器网络故障的排查路径与物理机一致,只是要先确认自己站在哪个命名空间里。

ip netns list                        # 有哪些命名空间
nsenter -t $(docker inspect -f '{{.State.Pid}}' web) -n ip addr   # 进入容器网络命名空间
ip -d link show veth1a2b             # veth 对端是否 up
bridge link show                     # veth 挂到哪个网桥
iptables -t nat -S | grep -i masquerade   # 出网 NAT 规则是否存在
sysctl net.ipv4.ip_forward           # 转发开关是否为 1

最常见的三类问题:veth 一端没 up(对端网桥状态不一致)、docker0/CNI 网桥缺少 MASQUERADE 规则导致出网没回包、以及 MTU 继承错误导致大包被静默丢弃。命名空间与 veth 的完整实验方法见 Linux 网络命名空间与 veth 对实战。

场景 8:偶发超时,抓包却看不出问题

这类“幽灵故障”通常是协议细节在作祟,最常见的两个原因是 IPv6 优先与 PMTU 黑洞。

getent ahosts example.com        # 同时看 A 与 AAAA 记录
curl -4 -w '@-' -o /dev/null -s https://example.com   # 强制 IPv4 对比耗时
ping -M do -s 1472 -c 3 10.20.0.30   # 探测 1500 MTU 是否通
ping -M do -s 1400 -c 3 10.20.0.30   # 缩小包长再试
ip link show eth0 | grep mtu
tracepath 10.20.0.30

如果 -4 之后一切正常,就去修 IPv6 的可用性(RA、路由通告、防火墙放行 ICMPv6),而不是把 DNS 的 AAAA 记录删掉了事。如果小包通、大包不通,就是 PMTU 黑洞——中间的 ICMP 需要 fragmentation needed 被过滤掉了,解决办法是调整 MTU 或在两端做 MSS clamping。完整做法参考 MTU、MSS 与 PMTUD:修复黑洞连接。

DNS 排查的完整路径

DNS 问题的表现是“访问网站慢,但直接用 IP 就快”,排查要按本地缓存 → 上游解析 → 政策顺序三层走。

resolvectl status                              # 当前生效的 DNS 与每接口配置
resolvectl query example.com                   # 顺带显示走了哪台服务器
cat /etc/nsswitch.conf | grep hosts            # hosts/dns 的顺序
dig +stats +trace example.com                  # 从根开始逐级追踪
dig @8.8.8.8 example.com +short +stats         # 对比公共 DNS 的耗时
dig @114.114.114.114 example.com +short +stats # 对比国内 DNS
tcpdump -i eth0 -nn port 53 -c 50              # 抓包看是否有超时重试

两个高频细节:/etc/resolv.conf 里配了多台服务器时,glibc 会按顺序尝试且默认每次只等 5 秒,第一台不可用就会造成 5 秒卡顿——用 options timeout:1 attempts:2 可以缓解;另外 nsswitch.conf 里 hosts: files dns 的顺序决定了本地 hosts 是否优先。systemd-resolved 环境下不要直接改 /etc/resolv.conf,它可能是个符号链接,正确方法见 systemd-resolved 与 resolvectl 排障。

内核网络参数调优清单

调参的前提是先确认瓶颈在哪,否则只会掩盖问题。下面这些参数覆盖了绝大多数高并发服务器场景。

# /etc/sysctl.d/99-network.conf
net.core.somaxconn = 4096            # accept 队列上限
net.core.netdev_max_backlog = 8192   # 内核收包 backlog
net.ipv4.tcp_max_syn_backlog = 8192  # 半连接队列
net.ipv4.tcp_tw_reuse = 1            # 允许复用 TIME_WAIT(仅客户端侧)
net.ipv4.tcp_fin_timeout = 15        # 缩短 FIN_WAIT_2
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_mtu_probing = 1         # PMTU 黑洞时自动降 MSS
net.ipv4.tcp_keepalive_time = 600    # 更早探测死连接
net.ipv4.ip_local_port_range = 10240 65535   # 可用源端口范围

改完执行 sysctl --system,然后用 sysctl -a | grep 或 ss -s、nstat -az 观察效果。务必一次只改一组参数并记录基线,否则出问题时无法回退到已知良好状态。绑定多网卡做聚合的场景,还要看 Linux Bonding 802.3ad 的 LACP 速率与哈希策略,哈希策略选错会导致单条流跑不满带宽。

故障定位决策树

现象 先看什么 常见根因
完全不通 ip addr / ip route get 地址缺失、路由缺失、接口 down
能 ping 通但端口不通 ss -tlpn / iptables -L -n 监听地址错误、防火墙拦截
延迟高但丢包少 mtr / tracepath 路径绕行、队列积压、缓冲膨胀
丢包但链路不忙 ethtool -S / softnet_stat 环形缓冲区小、软中断瓶颈
大包不通小包通 ping -M do / ip link show MTU 不一致、PMTU 黑洞
域名解析慢 resolvectl / dig +stats 上游 DNS 超时、顺序配置错误
连接被重置 tcpdump 找 RST 来源 会话老化、进程崩溃、中间设备

排障检查清单

  1. 确认影响范围与起始时间,对齐变更记录。
  2. 记录本机网络状态:ip -br addr、ip route、ss -tulpn。
  3. 分层验证:物理链路 → 网关 → 外部 IP → 域名。
  4. 用 nstat 与 ethtool -S 区分丢包发生的层次。
  5. 抓包仅在需要时进行,记得设置 -c 与 -w 限制大小。
  6. 一次只改一个变量,改前记录原值。
  7. 恢复业务优先,根因分析放到复盘会。
  8. 把结论写进文档:现象、命令、输出、根因、长效措施。

原文链接:https://cloud.tencent.com/developer/article/2608669