服务器丢包率高怎么解决?网络诊断工具与排查步骤

丢包是网络问题里最难缠的一类,因为它几乎从不单独出现:延迟高、速度慢、连接超时、网页打不开,背后都可能是丢包。而且丢包的现象极具迷惑性——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。

排查顺序建议

按这个顺序走,能最快定位到问题层:

  1. 用 ip -s link 和 ethtool -S 看本机错误计数,排除物理层和 Ring Buffer 问题
  2. 用 sar -n DEV 看带宽是否跑满,排除本机带宽瓶颈
  3. 用 mtr 定位丢包发生在哪一跳,用 TCP 模式复核
  4. 双向测(服务器上反向 mtr),确认是否是回程问题
  5. 分时段测,确认是否与晚高峰相关(判断运营商/跨境拥塞)
  6. 用 iperf3 UDP 模式测真实丢包率和吞吐
  7. 用 tcpdump 抓包确认丢的是哪种包,排除对端处理慢
  8. 检查 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 只是临时缓解。