线上网络丢包了?别慌,这 5 步 + tcpdump 让你快速定位
前阵子,银行某条业务线反馈:偶发的接口超时,一天大概十几笔,说不准什么时候来。
运维常规排查了一圈——CPU 没飙升、内存没溢出、磁盘 IO 很闲、应用日志也没有报错。
一切指标正常,就是偶尔丢请求。
这种"薛定谔的故障"最折磨人:你能感知它,但你抓不到它。
后来我盯上了网络层。用
sar -n DEV 1 5持续观察了五分钟,发现rxdrop/s一直在零和个位数之间跳动——不是狂暴式丢包,而是一种间歇性的、随机的缓慢泄漏。单次看ifconfig根本注意不到,只有持续观测才能抓到。丢包了。而且丢得很安静。
我后来花了不少时间把网卡收包到应用读取这条链路彻底摸了一遍,踩了一堆坑,才总结出今天这套 5 步排查法 + tcpdump 实战。不讲虚的,每一步都是在银行生产环境里真刀真枪用过的。
一、先搞懂:数据包是怎么"丢"的?
要排查丢包,首先得知道数据包从网卡到应用程序,中间经历了什么。
我把它简化成 一条流水线,你把每一站想象成快递分拣中心:
网卡收到包裹 → DMA搬到内存仓库 → 敲钟喊CPU来取 → CPU分拣处理 → 应用来领包裹
(第1站) (第2站) (第3站) (第4站) (第5站)
具体来说:
- 网卡硬件收到数据包(快递到了)。
- 网卡通过 DMA 把数据包拷贝到内存中的 rx ring buffer(卸到仓库暂存区)。
- 网卡发起硬中断,通知 CPU 来处理(敲钟)。
- CPU 响应硬中断,再触发软中断,让内核协议栈去处理数据(分拣员开始工作)。
- 应用程序通过
read()从 socket 缓冲区取走数据(收件人签字领走)。
丢包最常发生在第 2 站和第 4 站:
| 丢包站点 | 原因 | 现象 |
|---|---|---|
| 第 2 站:rx ring buffer | 网卡收包太快,驱动来不及分配缓冲区,硬件缓存满了 → 新包直接丢弃 | ifconfig 里 overruns 增长(等同于 /proc/net/dev 里的 fifo 字段) |
| 第 4 站:软中断/协议栈 | 软中断处理不过来,或 socket 接收队列满了 → 内核丢弃数据包 | netstat -s 里 prunes(队列满)或 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 dropped 和 RX 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 buffer | 256 | 高流量下容易满 → overruns 丢包 | ethtool -G eth0 rx 4096 |
net.core.rmem_max | 87380(约 85KB) | 单个 socket 缓冲区太小 → prune 丢包 | sysctl -w net.core.rmem_max=16777216(16MB) |
net.core.somaxconn | 128 | 高并发连接请求堆积 | 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 看到 prunes | socket 接收队列满,应用读慢 | 优化应用处理逻辑;增大 net.core.rmem_max |
netstat -s 看到 drops 但 prunes 不增长 | 防火墙丢包、策略路由丢包、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 练习脚本。