别再ping着发呆了:银行老运维的10分钟网络排障法
云间豹变 | Linux调优实战系列
记得某次半夜值班遇到告警,应用电话打过来:「A系统调B系统接口,间歇超时,帮忙看一下网络。」
我揉了揉眼睛,ping 10.10.1.20——通。
telnet 10.10.1.20 8080——通。
「网络没问题啊,你们应用层自己查。」
挂了电话,五分钟后告警又来了,一晚上反复如此,第二天还被喷没解决问题。
这是我早年入行踩过最深的坑:ping通,不等于网络没问题。
后来我整理了一套「10分钟网络定位法」,从那以后再也没被这类网络基础问题「骚扰」过。
先建一张「网络排查地图」
从技术原理角度来看,银行生产环境的网络问题,藏在至少6个层面。出了事你得知道先查哪层:
|
|
|
|
|---|---|---|
|
|
ping / |
|
|
|
ip route / |
|
|
|
ss / |
|
|
|
dig / |
|
|
|
ethtool / |
|
|
|
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分钟日志排障法,加进crontab每天早上8点跑一次:
0 8 * * * /opt/scripts/network_check.sh >> /var/log/network_daily.log 2>&1
尾声
10分钟定位,不是玄学,是方法。
地图建好了,从底层往上层逐层推——物理网卡→路由→传输层→应用端口,基本不会走弯路。
下次碰到网络故障,不用只会ping了。
你遇到过最「烧脑」的网络故障是什么?
是MTU不匹配,还是路由表被误改?
评论区聊聊,没准能帮到下一个正在ping着发呆的人。
👉 觉得有用就转发给你的运维bro,在网络排障的时候说不定用得上
如果不想错过下一期排障实战,点个关注,每次更新直接推到你微信里。顺手点个「在看」,让我知道这类干货你们爱看。