# 别再ping着发呆了:银行老运维的10分钟网络排障法
> **云间豹变 | Linux调优实战系列**
---
记得某次半夜值班遇到告警,应用电话打过来:「A系统调B系统接口,间歇超时,帮忙看一下网络。」
我揉了揉眼睛,`ping 10.10.1.20`——通。
`telnet 10.10.1.20 8080`——通。
「网络没问题啊,你们应用层自己查。」
挂了电话,五分钟后告警又来了,一晚上反复如此,第二天还被喷没解决问题。
**这是我早年入行踩过最深的坑:ping通,不等于网络没问题。**
后来我整理了一套「10分钟网络定位法」,从那以后再也没被这类网络基础问题「骚扰」过。
---
## 先建一张「网络排查地图」
从技术原理角度来看,银行生产环境的网络问题,藏在至少6个层面。出了事你得知道先查哪层:
| | |
|---|
| `ping / `ping6`` | |
| `ip route / `traceroute`` | |
| `ss / `netstat`` | |
| `dig / `nslookup`` | |
| `ethtool / `ip addr`` | |
| `tcpdump` | |
| `curl -w` | |
**10分钟排障法则的核心**:不要上来就ping。先问清楚症状(慢?不通?间歇?),再从底层往上层逐层查。
---
## 六个命令,覆盖物理层到应用层
**① ss — 连接状态一看就懂**
```
# 查看所有TCP连接,按状态分组统计
# NR>1 跳过表头行,避免把 "State" 也算进去
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
# 查看哪个进程在监听8080端口(排障必用)
sudo ss -tlnp | grep 8080
# 查看已建立的连接,按本地端口聚合,看有没有异常外联
# state established 比简写 est 兼容性更好(老版本 RHEL/CentOS 适用)
ss -tn state established | awk 'NR>1 {print $4}' | sort | uniq -c | sort -rn | head -20
```
**② ip route — 路由表是第一现场**
```
# 查看路由表,默认路由指向谁
ip route show
# 追踪到目标IP的路径(每一跳延迟,IP都是随便取的,无需在意)
traceroute -n 10.10.1.20
# 或者用mtr(实时刷新,推荐)
mtr -r -c 10 10.10.1.20
```
**③ tcpdump — 抓包,看清包到底到没到**
```
# 抓取到达eth0的HTTP流量(排障神器)
sudo tcpdump -i eth0 -nn port 80 and host 10.10.1.20 -c 100
# 抓取ICMP包,看ping的包有没有出去
sudo tcpdump -i eth0 -nn icmp
# 保存到文件,事后用Wireshark分析
sudo tcpdump -i eth0 -w /tmp/capture.pcap port not 22
```
**④ dig — DNS问题别再背锅了**
```
# 查A记录,看解析对不对
dig +short api.example.com
# 追踪DNS解析全过程(看是哪一层DNS的问题)
dig +trace api.example.com
# 反向解析,从IP查域名(安全审计常用)
dig -x 10.10.1.20
```
**⑤ ethtool — 网卡物理层排障**
```
# 看网卡是否UP、协商速率和双工模式(百兆/千兆/万兆)
ethtool eth0 | grep -E "Speed|Duplex|Link detected"
# 看网卡驱动信息和固件版本
ethtool -i eth0
# 看网卡收发包统计(有多少错误、丢包)
ethtool -S eth0 | grep -iE "drop|error|discard"
```
> 💡 **什么时候用 ethtool?** 当你怀疑是"网线松了""网卡掉速""协商到百兆而不是千兆"这类物理层问题的时候。`ping` 看不出来,`ss` 也看不出来,只有 `ethtool` 能确认。
---
**⑥ curl — 应用层时间拆解(从开发角度排查必备)**
```
# 把一次HTTP请求的时间拆成 DNS→TCP握手→SSL→服务端处理 四段
curl -w '\nDNS解析: %{time_namelookup}s
TCP握手: %{time_connect}s
SSL握手: %{time_appconnect}s
服务端首字节: %{time_starttransfer}s
总耗时: %{time_total}s\n' \
-o /dev/null -s http://10.10.1.20:8080/api/health
```
> 💡 `ping` 告诉你网络通不通,`curl -w` 告诉你**慢在哪一段**。DNS 慢找 DNS,TCP 握手慢找路由,服务端慢找应用——不用猜。
---
## 真实案例:10分钟从「ping通」找到「MTU丢包」
这是我处理过最「烧脑」的一次故障。
**故障现象**:应用A调用应用B的接口,小请求正常(GET /health 秒回),但带 payload 的 POST 大请求就超时。A和B在同一网段,`ping` 正常,`telnet` 端口也通。
**定位过程(实际耗时10分钟)**:
```
# 第1分钟:确认基础连通性
ping 10.10.1.20
# 通。不是网络不通的问题。
# 第2分钟:用curl模拟大请求——复现问题
curl -X POST -d "$(dd if=/dev/urandom bs=1000 count=50 2>/dev/null | base64)" \
--connect-timeout 3 --max-time 10 \
http://10.10.1.20:8080/api/submit
# 超时!小请求OK,带body的大请求挂。
# 第3分钟:检查TCP握手时的MSS协商(tcpdump抓包)
sudo tcpdump -i eth0 -nn 'tcp port 8080 and (tcp[tcpflags] & tcp-syn != 0)' -c 3
# 看到 A→B SYN 包中 MSS=1460(A端MTU 1500 正常)
# 看到 B→A SYN-ACK 包中 MSS=8960(B端MTU 9000 巨帧!)
```
**问题就在 MSS=8960**。
B 端虚拟机迁移后网卡被配成了 MTU=9000。TCP 握手时,B 向 A 通告 "我能收 8960 字节的 TCP 段"。A 端客户端看到这个值,尝试构造接近 8960 字节的大段发送——但 A 自己的网卡 MTU 只有 1500,内核只能做 **IP 分片**。
```
# 第4分钟:验证分片行为
ip link show eth0 | grep mtu
# A端: mtu 1500
ip link show eth0 | grep mtu # 在B端执行
# B端: mtu 9000 ← 问题在这
```
被分片的 IP 包经过交换机时,部分交换机对分片包的处理不稳定——重组队列有限、分片可能乱序到达。**一旦有一个分片丢了,B 端的 TCP 层就永远等不到完整段,应用层超时。** 小请求为什么没事?因为小于 1460 字节,根本不需要分片。
```
# 第5分钟:临时修复——把B端MTU改回1500,立即恢复
sudo ip link set eth0 mtu 1500
# 验证:再次curl大请求
curl -X POST -d "$(dd if=/dev/urandom bs=1000 count=50 2>/dev/null | base64)" \
--connect-timeout 3 --max-time 10 \
http://10.10.1.20:8080/api/submit
# 正常返回!
```
**永久生效**(根据是否使用 NetworkManager 选一种,切记提工单去做):
```
# 方式一:传统 network-scripts(RHEL 7 及以前)
sed -i 's/^MTU=.*/MTU=1500/' /etc/sysconfig/network-scripts/ifcfg-eth0
# 方式二:NetworkManager(RHEL 8+ 及大部分现代发行版)
nmcli con mod eth0 802-3-ethernet.mtu 1500
nmcli con up eth0
```
从告警到恢复,**10分钟搞定手工**。
如果用传统方式——先找应用组查代码、再找网络组查路由、再逐层拉会——这个故障保底耗2小时。
---
## 放进crontab的网络巡检脚本
不要等出事才查。这个脚本每天跑一次,主动发现问题:
```
#!/bin/bash
# network_check.sh — 日常网络健康巡检
REPORT="/tmp/network_report_$(date +%Y%m%d).txt"
echo"=== 网络巡检报告 $(date) ===" > "$REPORT"
# 1. 检查默认路由是否存在
DEFAULT_ROUTE=$(ip route | grep default | wc -l)
echo"默认路由数量: ${DEFAULT_ROUTE}" >> "$REPORT"
[ "$DEFAULT_ROUTE" -eq 0 ] && echo"[WARN] 缺少默认路由!" >> "$REPORT"
# 2. 检查DNS配置是否正常(银行环境不通外网,改查本地resolver)
DNS_NS=$(grep -c '^nameserver' /etc/resolv.conf 2>/dev/null)
echo"DNS服务器数量: ${DNS_NS}" >> "$REPORT"
[ "$DNS_NS" -eq 0 ] && echo"[WARN] 未配置DNS服务器!" >> "$REPORT"
# 能访问外网的机器可以加一步验证:dig +time=2 +short 你的内网域名
# 3. 检查网卡状态和协商速率
for iface in $(ls /sys/class/net/ | grep -v lo); do
STATE=$(cat /sys/class/net/$iface/operstate 2>/dev/null || echo"N/A")
SPEED=$(ethtool $iface 2>/dev/null | grep -oP 'Speed: \K.*')
[ -z "$SPEED" ] && SPEED="N/A"
echo"网卡 $iface: 速率=${SPEED} 状态=${STATE}" >> "$REPORT"
[ "$STATE" != "up" ] && echo"[WARN] 网卡 $iface 不是UP状态!" >> "$REPORT"
done
# 4. 检查MTU是否与标准值一致(巨帧未关是常见坑)
for iface in $(ls /sys/class/net/ | grep -v lo); do
MTU=$(cat /sys/class/net/$iface/mtu 2>/dev/null)
[ -n "$MTU" ] && [ "$MTU" -ne 1500 ] && \
echo"[WARN] 网卡 $iface MTU=${MTU} (非标准1500)!" >> "$REPORT"
done
# 5. 检查异常连接数(根据业务实际情况调整阈值)
ESTAB_COUNT=$(ss -tn state established | tail -n +2 | wc -l)
echo"当前ESTABLISHED连接数: ${ESTAB_COUNT}" >> "$REPORT"
[ "$ESTAB_COUNT" -gt 500 ] && echo"[WARN] 连接数超阈值(${ESTAB_COUNT}),请核查" >> "$REPORT"
# 6. 检查有没有丢包的网卡
for iface in $(ls /sys/class/net/ | grep -v lo); do
RX_DROP=$(cat /sys/class/net/$iface/statistics/rx_dropped 2>/dev/null || echo 0)
TX_DROP=$(cat /sys/class/net/$iface/statistics/tx_dropped 2>/dev/null || echo 0)
[ "$RX_DROP" -gt 100 ] && echo"[WARN] $iface RX丢包: $RX_DROP" >> "$REPORT"
[ "$TX_DROP" -gt 100 ] && echo"[WARN] $iface TX丢包: $TX_DROP" >> "$REPORT"
done
cat "$REPORT"
```
和之前排查日志一样[别再tail -f发呆了:银行老运维的10分钟日志排障法](https://mp.weixin.qq.com/s?__biz=MzkwMzI3ODA4Mg==&mid=2247483873&idx=1&sn=8ac51fd8341e0ef1b151a8e2a9939cce&scene=21#wechat_redirect),加进crontab每天早上8点跑一次:
```
0 8 * * * /opt/scripts/network_check.sh >> /var/log/network_daily.log 2>&1
```
---
**尾声**
10分钟定位,不是玄学,是方法。
地图建好了,从底层往上层逐层推——物理网卡→路由→传输层→应用端口,基本不会走弯路。
下次碰到网络故障,不用只会ping了。
---
**你遇到过最「烧脑」的网络故障是什么?**
是MTU不匹配,还是路由表被误改?
评论区聊聊,没准能帮到下一个正在ping着发呆的人。
---
*👉 觉得有用就转发给你的运维bro,在网络排障的时候说不定用得上*
*如果不想错过下一期排障实战,点个关注,每次更新直接推到你微信里。顺手点个「在看」,让我知道这类干货你们爱看。*