丢包是网络问题里最难缠的一类,因为它几乎从不单独出现:延迟高、速度慢、连接超时、网页打不开,背后都可能是丢包。而且丢包的现象极具迷惑性——ping 显示丢包 5%,业务却完全正常;或者 ping 一点不丢,用户却抱怨卡得要命。前者通常是 ICMP 限速造成的假象,后者可能是丢包发生在某一个方向的某一段上,你的测试没覆盖到。
这篇文章按"从本机到对端"的顺序把丢包原因分层,给出每一层对应的诊断命令,重点讲清楚三种容易混淆的情况:拥塞丢包与错误丢包的区别、MTU 不匹配导致的分片问题、以及网卡 Ring Buffer 满导致的底层丢包。最后给出对应的解决手段,并明确说明每种手段能解决什么、不能解决什么。
一、先理解丢包的两种基本类型
这个区分决定了后面的排查方向,务必先搞清楚。
| 类型 | 成因 | 特征 | 可解决性 |
|---|---|---|---|
| 拥塞丢包 | 链路或设备队列满了,尾部丢弃 | 与负载强相关,晚高峰严重,延迟和抖动同时升高 | 能,扩容、削峰、换线路 |
| 错误丢包 | 物理层或链路层错误(光模块、网线、CRC 校验失败、驱动异常) | 与负载无关,随机发生,网卡错误计数持续增长 | 能,但通常是换硬件或换驱动 |
判断方法很直接:看丢包是否与流量大小和时间段相关。 白天不丢晚上丢、跑满带宽才丢,是拥塞;全天随机丢、流量很小时也丢,就要查错误计数。
看网卡的错误和丢包计数,这是第一手证据:
ip -s link show eth0
ifconfig eth0 # 看 RX/TX 的 errors、dropped、overruns
ethtool -S eth0 | grep -iE 'drop|discard|error|miss|overrun|fifo'
关注几个关键计数:
| 计数(名称因驱动而异) | 含义 | 说明什么 |
|---|---|---|
rx_errors / crc_errors |
接收错误、CRC 校验失败 | 物理层问题:光模块、网线、交换机端口 |
rx_dropped / rx_missed |
网卡或驱动来不及收 | Ring Buffer 不足或 CPU 处理不过来 |
rx_fifo_errors / rx_over_errors |
FIFO 溢出 | Ring Buffer 太小 |
rx_no_buffer_count |
无可用缓冲区 | Ring Buffer 不足 |
tx_dropped |
发送队列满 | 出方向拥塞,可能是带宽上限 |
如果 rx_errors 或 crc_errors 在持续增长,先别查网络配置,去查物理链路。 换光模块、换网线、换交换机端口,云平台则提交工单要求迁移宿主机或换网卡。
二、按层排查:从本机到对端
第一层:本机
先排除是服务器自己的问题。这一步经常被人跳过,结果查了半天运营商,最后发现是本机带宽跑满了。
看带宽是否跑满:
sar -n DEV 1 5 # 网卡吞吐
sudo iftop -i eth0 -P # 按连接看实时流量
sudo nethogs eth0 # 按进程看流量
vnstat -l -i eth0 # 实时速率与累计
看 CPU 软中断是否打满。 小包高 PPS 场景下,软中断处理会吃满单个 CPU 核心,导致网卡收包不及时:
top # 看 si 列(软中断)是否很高
cat /proc/softirqs # 看 NET_RX 的增长速度
cat /proc/interrupts | grep -i eth0 # 看中断是否集中在某一个核心
mpstat -P ALL 1 5
如果 si 长期很高且中断集中在一个核心,需要开启或调整多队列(RSS):
ethtool -l eth0 # 查看支持的队列数
sudo ethtool -L eth0 combined 4 # 设置(需网卡支持,远程操作谨慎)
风险提示:在线调整网卡队列数可能导致短暂断网,务必在业务低峰期操作,并保留其他可用的登录通道。
看连接跟踪表是否满。 做了 NAT 或大量并发连接的机器上,nf_conntrack 表满会直接丢包,症状是"连接时好时坏":
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
dmesg | grep -i conntrack # 出现 nf_conntrack: table full 就是它
看 Ring Buffer 是否不足:
ethtool -g eth0 # 查看当前和最大值
sudo ethtool -G eth0 rx 4096 tx 4096 # 调大(需网卡支持)
第二层:接入与云网络
云主机的网络问题还可能来自虚拟化层和云网络:
- 安全组规则错误导致部分包被丢(表现为能 ping 通但大流量传输中断,或者特定端口不通)
- 云网络的限速:部分实例规格有内网带宽或 PPS 上限,超出后丢包
- 实例所在的宿主机或可用区网络异常
排查方法:在控制台查看云监控的网卡指标(出/入带宽、包速率),确认是否触及实例规格的上限;同时检查安全组规则是否完整(出方向和入方向都要看)。
第三层:运营商网络
这是最常见的丢包发生位置。用 mtr 定位:
mtr -rwc 500 -n 目标IP
mtr -rwc 500 -n --tcp -P 443 目标IP # TCP 模式,排除 ICMP 限速干扰
读法要点(这是最容易看错的地方):
- 中间某跳丢包、后续跳不丢 → 假象,该跳设备对 ICMP 限速,业务不受影响
- 从某跳开始后续全部持续丢包 → 真实故障点在该跳之前的那段链路
- 只有最后一跳丢包 → 问题在目标服务器或它的接入段
样本量要足够。 100 个包以下得出的丢包率统计意义很低,重要场景用 500 到 1000 个包。
# 也可以用 ping 长时间统计
ping -c 1000 -i 0.05 -q 目标IP
风险提示:ping -f(flood)会以最快速度发包,容易被当作攻击流量,且会影响链路上的其他业务。只在自己完全控制的内网环境或获得明确授权的测试中使用,不要对公网目标执行。
第四层:跨境链路
跨境丢包的特点是时段性强。晚高峰(20:00 到 23:00)国际出口拥塞,丢包率可以从 0% 升到 5% 以上。
判断方法:分时段各测一轮,对比劣化幅度。另外要双向测——去程和回程可能完全不同,用户感受到的是两者之和。
# 在服务器上反向测到你的公网 IP
mtr -rwc 500 -n --tcp -P 443 你的公网IP
第五层:对端
丢包也可能发生在对方的接入链路或服务器本身。特征是只有访问这一个目标时丢包,访问其他目标正常。
验证方法:从多个不同网络访问同一个目标,如果所有位置都丢,问题在对端;如果只有你这边丢,问题在你到它之间的路径上。
三、诊断工具详解
mtr:定位丢包在哪一跳
前面讲过读法,这里补充一个实用技巧:分别用 ICMP、UDP、TCP 三种模式测同一目标,对比结果。 因为网络设备对不同协议的处理策略不同,三种模式结果一致时结论最可靠。
mtr -rwc 300 -n 目标IP # ICMP,默认
mtr -rwc 300 -n -u 目标IP # UDP
mtr -rwc 300 -n --tcp -P 443 目标IP # TCP,最接近真实业务
iperf3:测真实吞吐与 UDP 丢包率
iperf3 的价值在于它能给出端到端的实际吞吐和丢包率,这是 ping 和 mtr 做不到的。特别是 UDP 模式,会直接报告丢包百分比。
# 服务端
iperf3 -s -p 5201
# 客户端:TCP 测吞吐,4 并发
iperf3 -c 服务端IP -p 5201 -t 30 -P 4 -i 1
# 客户端:UDP 测丢包,-b 指定发送速率
iperf3 -c 服务端IP -p 5201 -u -b 100M -t 30
UDP 模式的输出里 lost/total datagrams 直接就是丢包率。用法是:先用低于你带宽上限的速率测(比如带宽的 50%),如果此时就丢包,说明链路有问题;如果低速不丢、接近满速才丢,说明是带宽瓶颈导致的排队丢包。
sudo apt install -y iperf3 # Debian、Ubuntu
sudo dnf install -y iperf3 # Rocky、RHEL、CentOS
注意:iperf3 会在测试期间占满链路,不要在业务高峰对生产链路跑满速测试。
tcpdump:抓包看重传
抓包是确认"到底有没有丢、丢的是什么包"的终极手段。
sudo apt install -y tcpdump # Debian、Ubuntu
sudo dnf install -y tcpdump # Rocky、RHEL、CentOS
# 抓取与某个目标的通信并保存
sudo tcpdump -i eth0 -nn -s 0 -w /tmp/capture.pcap host 1.2.3.4 and port 443
# 快速看有没有 SYN 重传(重传的 SYN 说明第一次握手没收到回应)
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0 and host 1.2.3.4' -c 50
抓下来的 pcap 文件用 Wireshark 打开,用这个过滤表达式直接列出所有重传:
tcp.analysis.retransmission
还可以看这几个更有针对性的:
| 过滤表达式 | 用途 |
|---|---|
tcp.analysis.retransmission |
所有重传包 |
tcp.analysis.fast_retransmission |
快速重传(收到三个重复 ACK 触发) |
tcp.analysis.duplicate_ack |
重复 ACK,通常是丢包的信号 |
tcp.analysis.zero_window |
接收端窗口为 0,说明对端处理不过来(不是网络丢包) |
区分"真丢包"和"对端处理慢"很重要:如果抓包里大量出现 zero window 而没有重传,说明不是网络丢包,而是接收端应用层处理不过来,这时加带宽没用。
用命令行直接统计重传数量:
sudo tcpdump -i eth0 -nn -r /tmp/capture.pcap 2>/dev/null | wc -l
ss 与 netstat:看连接级别的重传
ss -ti # 显示每条连接的 RTT、拥塞窗口、重传数
ss -ti '( dport = :443 )' # 只看某个端口
ss -i 输出里的关键字段:
| 字段 | 含义 |
|---|---|
rtt |
往返时间及抖动 |
cwnd |
拥塞窗口,丢包后会缩小 |
retrans |
该连接的重传计数 |
ssthresh |
慢启动阈值 |
看到某条连接 retrans 持续上升,就确认了该连接存在丢包。
系统级统计:
netstat -s | grep -iE 'retransmit|listen|drop|overflow'
nstat -az | grep -iE 'retrans|drop'
重点看:
TcpExt:ListenOverflows # 监听队列溢出次数
TcpExt:ListenDrops # 因队列满而丢弃的连接
Tcp:RetransSegs # 重传的段数
四、三种容易混淆的专项问题
MTU 与分片问题
MTU(最大传输单元)不匹配导致的丢包,症状非常独特,也极易被误判:
典型症状:
- 能 ping 通(小包),但打开网页卡住或打不开
- SSH 能连上,但传输文件中断
- HTTPS 握手成功,但传输大响应时卡住
- 部分网站正常、部分网站打不开
成因:链路中间某段的 MTU 小于 1500(比如 PPPoE 是 1492、各种隧道会再减 20 到 50 字节),而数据包设置了 DF(不分片)标志。此时中间设备应该返回 ICMP "需要分片"消息让发送端降 MTU,但很多网络为了安全丢弃了这类 ICMP,导致大包被无声丢弃。
诊断:用不分片的方式逐步测试包大小:
ping -M do -s 1472 目标IP # 1472 + 28 = 1500,通说明 MTU 1500 可用
ping -M do -s 1452 目标IP # 1480,PPPoE 环境常用
ping -M do -s 1400 目标IP # 1428
ping -M do -s 1380 目标IP # 1408
从大到小试,能通的最大值加 28 就是可用 MTU。
解决:
# 临时修改本机 MTU
sudo ip link set dev eth0 mtu 1400
# 网关上做 MSS 钳制(推荐,对 TCP 更友好)
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
# 或手动指定 MSS 值
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1360
MSS 钳制的原理是在 SYN 包里改写 MSS 值,让对端一开始就发小包,从根上避免分片。MSS = MTU - 40(IP 头 20 + TCP 头 20)。
风险提示:修改 MTU 会影响所有经过该网卡的连接,建议先在单台机器上验证。改错会导致大包不通,回滚方式是 sudo ip link set dev eth0 mtu 1500。
网卡 Ring Buffer 不足
Ring Buffer 是网卡驱动与内核之间交换数据的环形缓冲区。高流量突发时,如果 CPU 来不及取走数据,缓冲区满后新到的包就被丢弃,而且这种丢包不会体现在带宽利用率上——你可能看到带宽只用了 60%,但实际已经在丢包了。
诊断:
ethtool -S eth0 | grep -iE 'rx_missed|rx_no_buffer|rx_fifo|rx_over|drop'
ip -s link show eth0 # RX 行的 dropped 计数
解决:
ethtool -g eth0 # 看当前值和最大值
sudo ethtool -G eth0 rx 4096 tx 4096 # 调大到网卡支持的最大值
同时,如果软中断集中在单个 CPU 核心,还要配合开启多队列(见第一层)。
连接队列溢出
这也是一种"丢包",丢的是新连接而不是数据包。症状是:业务时好时坏,连接偶尔超时,但已建立的连接很流畅。
netstat -s | grep -i listen
# 看到 "times the listen queue of a socket overflowed" 且数字在增长就是它
ss -lnt # 看 Recv-Q 是否积压
cat /proc/sys/net/core/somaxconn # 系统级上限
cat /proc/sys/net/ipv4/tcp_max_syn_backlog # SYN 队列上限
解决方向:调大 somaxconn 和应用自身的 backlog 参数;Nginx 里调 listen ... backlog=N;以及启用 tcp_syncookies 抵御 SYN 洪水。
sudo sysctl -w net.core.somaxconn=65535
echo 'net.core.somaxconn = 65535' | sudo tee /etc/sysctl.d/99-net.conf
五、解决手段与适用范围
| 手段 | 解决什么 | 不能解决什么 | 成本 |
|---|---|---|---|
| 扩容带宽 | 带宽跑满导致的排队丢包 | 错误丢包、跨境出口拥塞 | 低(花钱) |
| 换线路 | 运营商/跨境链路拥塞丢包 | 本机问题、对端问题 | 中到高 |
| 上 CDN | 用户到源站的跨境丢包 | 源站自身问题 | 中 |
| 调 MTU/MSS | 分片导致的"部分网站打不开" | 其他所有类型的丢包 | 低 |
| 调 Ring Buffer | 高 PPS 突发时的底层丢包 | 拥塞丢包 | 低 |
| 调连接队列 | 连接超时、队列溢出 | 数据传输中的丢包 | 低 |
| 启用 BBR | 有丢包链路上的吞吐量 | 丢包本身、延迟 | 低 |
| 换硬件/迁移实例 | 物理层错误丢包 | 软件配置问题 | 低到中 |
| 限流削峰 | 突发流量打满带宽 | 持续性带宽不足 | 低 |
关于 BBR 要说清楚
BBR 是 Google 提出的拥塞控制算法,它的核心改进是不再把丢包当作拥塞的唯一信号,而是基于带宽和 RTT 的乘积建模,因此在有一定丢包的链路上能维持更高的吞吐。
sysctl net.ipv4.tcp_congestion_control
cat /proc/sys/net/ipv4/tcp_available_congestion_control
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
echo 'net.ipv4.tcp_congestion_control = bbr' | sudo tee /etc/sysctl.d/99-bbr.conf
sudo sysctl -p /etc/sysctl.d/99-bbr.conf
必须明确的局限:
- BBR 不减少丢包,只是让 TCP 在有丢包时不那么保守地降速
- BBR 不降低延迟,传播延迟由物理距离决定
- 在丢包率很高(比如超过 5%)的链路上,BBR 也无能为力
- 在已经有队列缓冲的链路上,BBR 可能加剧 bufferbloat(缓冲膨胀),让延迟升高
风险提示:修改拥塞控制算法影响所有 TCP 连接,生产环境应先在低峰期灰度,观察吞吐、延迟和错误率后再全量。回滚方式是改回 cubic。
BBR 的合理定位是:在确认线路无法立即更换时的临时缓解手段,不能替代换线路、加带宽或上 CDN。
排查顺序建议
按这个顺序走,能最快定位到问题层:
- 用
ip -s link和ethtool -S看本机错误计数,排除物理层和 Ring Buffer 问题 - 用
sar -n DEV看带宽是否跑满,排除本机带宽瓶颈 - 用
mtr定位丢包发生在哪一跳,用 TCP 模式复核 - 双向测(服务器上反向 mtr),确认是否是回程问题
- 分时段测,确认是否与晚高峰相关(判断运营商/跨境拥塞)
- 用
iperf3UDP 模式测真实丢包率和吞吐 - 用
tcpdump抓包确认丢的是哪种包,排除对端处理慢 - 检查 MTU(用小包大包对比测试)和连接队列(看 ListenOverflows)
常见问题
ping 显示丢包但网站正常,需要管吗?
先按第二节的方法判断丢包位置。如果只有中间跳丢、最后一跳不丢,那是 ICMP 限速的假象,不用处理。用 mtr --tcp -P 443 复核一次,TCP 模式下最后一跳正常就说明业务没受影响。
反过来,ping 不丢但很慢是怎么回事?
几种可能:丢包发生在回程而你测的是去程;TCP 拥塞窗口因为偶发丢包一直保持在低位;或者根本不是丢包问题而是延迟高、服务端慢、页面体积大。用 iperf3 测真实吞吐,用 curl -w 分解时间。
丢包率多少需要紧急处理?
经验阈值:超过 1% 就会明显影响 TCP 吞吐(因为拥塞控制会降窗),超过 3% 大多数交互类业务会明显卡顿,超过 5% 基本不可用。注意只看最后一跳的丢包率。
调大 Ring Buffer 有没有副作用?
调大会增加内存占用(每个队列几百 KB 到几 MB),并可能略微增加延迟(包在缓冲区里排队)。在内存充足、对延迟不极敏感的场景下,调大是安全的优化。改完用 ethtool -S 确认 drop 计数是否停止增长。
云服务器丢包该找谁?
先用 mtr 确定丢包位置。如果丢在云厂商网络内部或最后一跳,提交工单并附上 mtr 截图和发生时间;如果丢在中间运营商链路,云厂商通常无法直接解决,只能换线路或用 CDN 绕开。
MTU 改小会不会影响性能?
会有一点点:每个包携带的有效数据变少,头部开销占比上升,同样的有效吞吐需要更多包。但这个代价远小于分片失败导致的连接中断。只在确认存在 MTU 问题时才改,不要无脑调小。
总结
- 先区分拥塞丢包与错误丢包:拥塞丢包与负载和时段强相关(晚高峰严重、延迟抖动同时升高),错误丢包与负载无关且网卡
rx_errors/crc_errors持续增长的属于物理层问题,只能换硬件或迁移实例。 - 排查按层推进:本机(带宽跑满、软中断打满、conntrack 表满、Ring Buffer 不足)→ 云网络(安全组、实例 PPS 上限)→ 运营商链路(mtr 定位)→ 跨境(双向测、分时段测)→ 对端。
- mtr 丢包列的读法是核心技能:中间跳丢包后续不丢是假象,从某跳开始后续全部继承丢包才是真实故障点,最后一跳的丢包率才反映真实业务质量;样本量要 500 包起,用
--tcp模式复核。 - 三类专项问题各有特征:MTU 不匹配表现为"能 ping 通但大页面打不开",用
ping -M do -s逐步测并用TCPMSS --clamp-mss-to-pmtu解决;Ring Buffer 不足表现为带宽没跑满但仍丢包,用ethtool -S和ethtool -G处理;连接队列溢出表现为新连接超时但已建连接流畅,看ListenOverflows并调somaxconn。 - 诊断工具各有分工:iperf3 的 UDP 模式直接给出端到端丢包率,tcpdump 加 Wireshark 的
tcp.analysis.retransmission能确认重传、并用 zero window 排除"对端处理慢",ss -ti看单连接重传计数。 - BBR 只能改善有丢包链路上的吞吐量,不减少丢包也不降低延迟,高丢包场景下无效且可能加剧缓冲膨胀;真正的解决手段仍然是换线路、加带宽、上 CDN,BBR 只是临时缓解。
企业QQ咨询




