线上网络丢包了?别慌,这 5 步 + tcpdump 让你快速定位

0 阅读12分钟

线上网络丢包了?别慌,这 5 步 + tcpdump 让你快速定位

前阵子,银行某条业务线反馈:偶发的接口超时,一天大概十几笔,说不准什么时候来。

运维常规排查了一圈——CPU 没飙升、内存没溢出、磁盘 IO 很闲、应用日志也没有报错。

一切指标正常,就是偶尔丢请求。

这种"薛定谔的故障"最折磨人:你能感知它,但你抓不到它。

后来我盯上了网络层。用 sar -n DEV 1 5 持续观察了五分钟,发现 rxdrop/s 一直在零和个位数之间跳动——不是狂暴式丢包,而是一种间歇性的、随机的缓慢泄漏。单次看 ifconfig 根本注意不到,只有持续观测才能抓到。

丢包了。而且丢得很安静。

我后来花了不少时间把网卡收包到应用读取这条链路彻底摸了一遍,踩了一堆坑,才总结出今天这套 5 步排查法 + tcpdump 实战。不讲虚的,每一步都是在银行生产环境里真刀真枪用过的。


一、先搞懂:数据包是怎么"丢"的?

要排查丢包,首先得知道数据包从网卡到应用程序,中间经历了什么。

我把它简化成 一条流水线,你把每一站想象成快递分拣中心:

网卡收到包裹 → DMA搬到内存仓库 → 敲钟喊CPU来取 → CPU分拣处理 → 应用来领包裹
   (第1站)        (第2站)           (第3站)         (第4站)        (第5站)

具体来说:

  1. 网卡硬件收到数据包(快递到了)。
  2. 网卡通过 DMA 把数据包拷贝到内存中的 rx ring buffer(卸到仓库暂存区)。
  3. 网卡发起硬中断,通知 CPU 来处理(敲钟)。
  4. CPU 响应硬中断,再触发软中断,让内核协议栈去处理数据(分拣员开始工作)。
  5. 应用程序通过 read() 从 socket 缓冲区取走数据(收件人签字领走)。

丢包最常发生在第 2 站和第 4 站:

丢包站点原因现象
第 2 站:rx ring buffer网卡收包太快,驱动来不及分配缓冲区,硬件缓存满了 → 新包直接丢弃ifconfigoverruns 增长(等同于 /proc/net/dev 里的 fifo 字段)
第 4 站:软中断/协议栈软中断处理不过来,或 socket 接收队列满了 → 内核丢弃数据包netstat -sprunes(队列满)或 packet drops(各种原因)增加

💡 一句话记忆overruns 是网卡太忙(驱动跟不上),prunes 是应用太慢(来不及读)。但 drop 不一定——它还可能是防火墙丢包、策略路由丢包,后面排查步骤会细分。

⚠️ 注意:现代多队列网卡(如 Intel ixgbe、i40e)下,overruns 可能不增长,丢包会体现在 netdev_queue 或其他计数器中。如果你用的是 10G/25G 网卡,别只盯 overruns 一个指标。

明白了原理,排查就有方向了。


二、黄金 60 秒:网卡丢包排查 5 步法

登录服务器后,按顺序敲下面命令,快速定位丢包原因。

第 1 步:确认丢包存在——看网卡统计

ifconfig eth0
# 或
ip -s link show eth0

重点关注 RX droppedRX overruns。如果数字在增长,说明确实有丢包。

🔧 我在银行遇到过一次ifconfig 显示 RX dropped 每秒涨 200+,但 CPU 使用率只有 15%。最后查出来是 rx ring buffer 只有默认的 256,调到 4096 后丢包归零。详情后面第 4 步会讲。

第 2 步:看软中断分布——CPU 是否有瓶颈

watch -n 1 'cat /proc/softirqs | grep NET_RX'

观察 NET_RX 这一行的数字。正常情况应该是持续增长,且均匀分布在各个 CPU 核心

⚠️ 异常信号:

  • 某个核心的数字远低于其他 → 软中断负载不均衡
  • 所有核心的数字增长极慢 → 软中断处理能力不足
  • 某个核心的数字远高于其他 → 有个 CPU 被"单点打爆"了

💡 单队列网卡 vs 多队列网卡:如果你的网卡是单队列(比如老旧的千兆网卡),软中断天然集中在一个 CPU 上处理,这是正常现象,不是异常。只有多队列网卡下,软中断集中在单核才是问题。可以用 ethtool -l eth0 查看网卡队列数。

第 3 步:检查系统参数——先看"天花板"有多高

这一步放在前面,是因为先搞清楚系统参数的上限,后面看队列状态才有参照

# rx ring buffer 大小(当前值 vs 最大值)
ethtool -g eth0

# socket 接收队列默认大小
sysctl net.core.rmem_default
sysctl net.core.rmem_max

# listen 队列 backlog
sysctl net.core.somaxconn

三个常见坑

参数默认值(常见)问题建议值
rx ring buffer256高流量下容易满 → overruns 丢包ethtool -G eth0 rx 4096
net.core.rmem_max87380(约 85KB)单个 socket 缓冲区太小 → prune 丢包sysctl -w net.core.rmem_max=16777216(16MB)
net.core.somaxconn128高并发连接请求堆积sysctl -w net.core.somaxconn=4096

⚠️ 改完记得加到 /etc/sysctl.conf 里持久化,否则重启就白改了。

第 4 步:看 socket 接收队列——应用是否读太慢

确认了系统参数后,再看应用层是否真的撞到了天花板。

# 看连接数
netstat -an | grep :80 | wc -l

# 看 LISTEN 队列是否有积压
ss -lnt | grep :80

# 看是否有因队列满而丢弃的包
netstat -s | grep -E "prune|drop|overflow"

如果 prunes 数值大,说明应用程序读数据太慢,导致 socket 队列溢出。

💡 但如果只有 drops 增长、prunes 没变化,那别急着改应用——先排查是不是防火墙或内核策略丢的包(见第 5 步)。

💡 这时候别急着调系统参数,先查应用本身:是不是有慢查询、线程阻塞、GC 停顿?根源在应用,不在网络。

第 5 步:用 tcpdump 抓包——锁定丢包"犯罪现场"

前 4 步是定位"丢包发生在哪一环",第 5 步是用 tcpdump 确认"丢的是什么包、什么特征"。

这一步太重要了,单独展开讲。


三、tcpdump 实战:抓包分析丢包现场

很多新手觉得 tcpdump 输出看不懂。别怕,你只需要掌握 3 个常用组合,就能覆盖 90% 的丢包分析场景。

万能起手式(背下来)

tcpdump -i eth0 -s 0 -nn -c 100 -w /tmp/dump.pcap
参数作用
-i eth0抓哪个网卡
-s 0抓取完整数据包(不截断)
-nn不解析主机名和端口名(直接显示 IP 和数字端口)
-c 100抓 100 个包就停止
-w /tmp/dump.pcap保存到文件,用 Wireshark 分析更直观

场景 1:大量 TCP 重传 → 网络质量差或中间丢包

# 抓 SYN 包,看是否有重传
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn) != 0' -c 50

怎么判断:同一个五元组(源IP:端口 → 目的IP:端口)的 SYN 包出现两次以上 → 客户端重传了 → 说明之前的 SYN 包在网络中丢了。

🏦 真实案例:银行有次做跨机房迁移,新链路的交换机端口协商成半双工模式。tcpdump 抓到大量 SYN 重传,ping 虽然通但延迟波动大。改了交换机端口配置后恢复。

场景 2:接收窗口为 0 → 应用程序读太慢

# 抓 TCP 零窗口通告(window 字段为 0)
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-fin) == 0 and tcp[14:2] == 0' -c 20

💡 tcp[14:2] 是 TCP header 中 window 字段(偏移 14 字节,2 字节长度),值为 0 表示接收窗口已满。

看到 win 0 字样,说明接收端缓冲区满了,通知发送方"别发了"。

这不是网络问题,是应用问题。 检查应用代码:有没有死锁?有没有慢查询?有没有线程池耗尽?

场景 3:大量重复 ACK → 中间链路丢包触发快速重传

# 抓取 TCP ACK 包,排除 SYN/FIN/RST,只看纯 ACK
tcpdump -i eth0 -nn 'tcp[tcpflags] == tcp-ack' -c 200 | tee /tmp/acks.txt

# 统计重复 ACK(基于 ack 号)
cat /tmp/acks.txt | awk -F'[ ,]' '{for(i=1;i<=NF;i++) if($i~/ack/) {print $i; break}}' | sort | uniq -c | sort -rn | head -20

如果某个 ack 号出现 3 次以上,说明对端没收到那个序号之前的包,触发了 TCP 快速重传。丢包发生在你和对端之间的链路上。

💡 更高效的做法:保存为 pcap 文件,用 Wireshark 的 Statistics → Conversations → TCP 直接看重传率,比命令行数快得多。

🛠️ 动手练习(强烈建议在虚拟机上跑一遍)

# 1. 模拟 10% 丢包率
tc qdisc add dev eth0 root netem loss 10%

# 2. 开一个终端 ping,同时另一个终端抓包
# 终端 A:
ping 8.8.8.8 -c 50

# 终端 B:
tcpdump -i eth0 icmp -c 50

# 3. 观察:ping 会丢包,tcpdump 看到请求和回复数量不一致

# 4. 结束模拟(千万别忘了!)
tc qdisc del dev eth0 root

⚠️ 在生产服务器上别乱用 tc 命令制造丢包! 拿虚拟机或自己的云主机练手。


四、进阶:dropwatch 和 iptables 排查

上面 5 步能解决大部分丢包问题,但有两种场景它们覆盖不到:内核静默丢包防火墙丢包。这两种在银行环境里特别常见。

dropwatch:看到内核"丢包实况"

前面所有方法都是看计数器(事后统计),而 dropwatch实时观测内核在哪一层丢弃了包,类似给丢包过程装了个摄像头。

# 安装(CentOS/RHEL)
yum install -y dropwatch

# 启动,实时显示丢包的内核调用栈
dropwatch -l kas

你会看到类似这样的输出:

8 drops at func: __netif_receive_skb_core+0x4e8/0x720   # 网卡驱动层丢包
3 drops at func: tcp_v4_rcv+0x15/0x400                   # TCP 协议栈丢包
1 drop  at func: ip_rcv+0x2b/0x300                       # IP 层丢包

🏦 银行实战:有一次生产环境丢包,ifconfig 无异常、netstat -s 无异常、tcpdump 也看不出端倪。最后用 dropwatch 发现丢包发生在 __netif_receive_skb_core——原来是 bonding 模式配置错误导致包被丢弃。没有 dropwatch,这个问题不知道要排查多久。

iptables:别忽略"隐形杀手"

银行网络环境有大量安全策略,防火墙静默丢包不记录在任何网络统计中

# 看各链的丢包计数
iptables -L -nv | grep -E "DROP|REJECT"

# 看 mangle/raw 表(有些策略不在 filter 表)
iptables -t mangle -L -nv
iptables -t raw -L -nv

# 看 conntrack 是否满了(连接跟踪表满也会导致丢包)
sysctl net.netfilter.nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count

如果 nf_conntrack_count 接近 nf_conntrack_max,说明连接跟踪表满了,新连接会被静默丢弃。这在高并发短连接场景(比如大量 HTTP 请求)中很常见。

解决办法

# 增大连接跟踪表上限
sysctl -w net.netfilter.nf_conntrack_max=1048576
# 或者直接关闭不需要的连接跟踪(内网服务可以考虑)
iptables -t raw -I PREROUTING -j NOTRACK

五、常见丢包原因 & 解决方案速查表

这张表建议收藏,下次遇到丢包直接对照着查:

现象可能原因怎么解决
ifconfig 看到 RX overruns 持续增长rx ring buffer 太小,或 CPU 来不及处理软中断ethtool -G eth0 rx 4096;开启 RPS 分散软中断
netstat -s 看到 prunessocket 接收队列满,应用读慢优化应用处理逻辑;增大 net.core.rmem_max
netstat -s 看到 dropsprunes 不增长防火墙丢包、策略路由丢包、conntrack 满等iptables -L -nv;检查 conntrack 使用率
tcpdump 抓到零窗口(win 0应用进程阻塞或处理慢检查应用代码:死锁、慢查询、线程池耗尽
大量 TCP 重传,但网卡统计无丢包网络链路质量差(交换机丢包、光衰、半双工)检查相邻交换机端口统计;更换网线/光模块
软中断 NET_RX 只在一个 CPU 上跑(多队列网卡)网卡队列未绑定多个 CPU开启 RPS:echo fff > /sys/class/net/eth0/queues/rx-0/rps_cpus
ping 通但业务请求超时防火墙丢包或路由策略丢包iptables -L -nv 检查规则;tracepath 检查 MTU
所有计数器正常但仍然丢包内核静默丢包dropwatch -l kas 看内核调用栈定位
nf_conntrack_count 接近 nf_conntrack_max连接跟踪表满增大上限或对内网服务关闭连接跟踪

六、排查方法论:这张图记住就够了

总结一下,网卡丢包排查的完整思路就一句话:

从硬件到应用,逐层排除。先看 ifconfig 确认丢包存在,再看 softirqs 判断 CPU 瓶颈,然后 netstat -s 看队列状态,接着 ethtool 检查参数,最后 tcpdump 锁定现场。

很多新手害怕 tcpdump,觉得输出是天书。其实记住这三点就够了:

  • -i eth0 -s 0 -nn万能开头
  • -w 保存后用 Wireshark 看,更直观
  • 重点盯 重传零窗口重复 ACK 这三个异常模式

不出几次实战,你就能成为团队里的"抓包小能手"。


七、转发给你团队的运维兄弟

这篇文章写了我整整一个周末,把这几年的丢包排查经验都塞进去了。

如果你觉得有用,随手转发到你的运维群或技术群——我敢保证,群里至少有一半人被丢包问题坑过。下次再遇到,这篇文章能帮他们省至少一小时的排查时间。


下期预告:《TCP 重传的三种类型及排查方法》

你遇到过最诡异的丢包案例是什么?是交换机端口协商问题?还是内核参数踩坑?评论区聊聊,点赞最高的 3 条评论,我送《Wireshark 网络分析就这么简单》电子书。


关注公众号「云间豹变」,后台回复 丢包 获取本文所有命令的速查表 + tcpdump 练习脚本。

公众号.jpg