2. 网络环境排查:上行带宽测试、丢包率检测、RTT延迟测量、网络抖动分析

推流卡顿,十有八九是网络惹的祸。你想想看,WebRTC 再聪明,也架不住网络本身不行。这一章,我们就来聊聊怎么把网络环境摸清楚。

我个人习惯,接到卡顿反馈后,第一件事不是看代码,而是先做网络排查。为什么?因为如果是网络问题,你调半天编码参数也是白费力气。

2.1 上行带宽测试:你的上传管道够粗吗?

推流用的是上行带宽。很多人测速只看下载,忽略了上传。这是个坑。

上行带宽不足,说白了就是你的数据发不出去。编码器产出的码率如果超过了上行带宽,数据就会在发送缓冲区里排队,越积越多,最终导致延迟飙升、丢包、卡顿。

核心原则:推流码率 ≤ 上行带宽 × 0.8(留 20% 余量应对波动)

怎么测?我推荐几个方法:

  • Speedtest 类工具:选一个离你最近的服务器,测上传。注意要测多次,取平均值。
  • iperf3 工具:更专业,能模拟 UDP 流量。我在项目中遇到过,用 Speedtest 测出来带宽够,但实际推流还是卡。后来用 iperf3 一测,发现 UDP 丢包率很高。
# 服务端(在远端服务器上运行)
iperf3 -s -p 5201

# 客户端(在推流端运行,测试上行 UDP 吞吐量)
iperf3 -c <服务器IP> -p 5201 -u -b 50M -t 30

这个命令会以 50Mbps 的速率发送 30 秒的 UDP 流量。看结果里的 Jitter(抖动)和 Lost/Total Datagrams(丢包率)。

我的经验:如果 iperf3 测出来的实际吞吐量只有宣称带宽的 60%-70%,那说明你的网络环境有问题。可能是运营商限速,也可能是内网有其他设备在抢带宽。

2.2 丢包率检测:数据在半路丢了

丢包是 WebRTC 推流的头号杀手。一个数据包丢了,接收端就得等重传,或者用 FEC(前向纠错)来恢复。不管哪种方式,都会增加延迟,严重时直接卡顿。

丢包率怎么测?

  • ping 命令:最基础的方法。连续 ping 100 个包,看丢包率。
  • WebRTC 内部统计:通过 RTCPeerConnection.getStats() 获取。这是最准确的,因为它反映的是实际推流链路上的丢包情况。
// 获取 WebRTC 统计信息
const stats = await peerConnection.getStats();
stats.forEach(report => {
  if (report.type === 'candidate-pair' && report.state === 'succeeded') {
    console.log('丢包率:', report.packetsLost / report.packetsSent * 100, '%');
    console.log('RTT:', report.currentRoundTripTime * 1000, 'ms');
  }
});

注意:ping 命令测的是 ICMP 协议的丢包,和 WebRTC 用的 UDP 不完全一样。有些网络设备会优先处理 ICMP,导致 ping 测出来丢包率很低,但实际 UDP 丢包率很高。我曾经就被这个坑过。

丢包率的分级参考:

丢包率 影响程度 建议措施
< 1% 良好 WebRTC 内置机制可应对
1% - 5% 轻度 建议启用 FEC,降低码率
5% - 10% 中度 必须降低码率,考虑使用 SVC
> 10% 严重 基本无法正常推流,需更换网络

2.3 RTT 延迟测量:一来一回要多久

RTT(Round-Trip Time)就是数据从发送端到接收端,再返回确认的时间。RTT 越大,WebRTC 的拥塞控制反应就越慢。

举个例子:如果 RTT 是 200ms,你发送一个包,要等 200ms 才知道它到了没有。这期间你不敢发太快,怕把网络撑爆。所以 RTT 高,直接导致发送速率上不去。

测量 RTT 的方法:

  • WebRTC getStats:上面代码里已经展示了,currentRoundTripTime 就是 RTT,单位是秒。
  • traceroute:可以看每一跳的延迟,帮你定位是哪个环节慢。

避坑指南:我曾经遇到一个案例,RTT 只有 30ms,但推流就是卡。后来用 traceroute 一看,发现数据包绕了大半个地球,中间经过了一个延迟很高的节点。所以,RTT 低不代表路径好,还要看路径的稳定性。

RTT 的参考标准:

RTT 范围 体验评价
< 50ms 极佳,本地网络或同城
50ms - 150ms 良好,跨省或跨国较近
150ms - 300ms 一般,跨国或卫星链路
> 300ms 差,基本无法实时互动

2.4 网络抖动分析:忽快忽慢最要命

抖动(Jitter),就是延迟的变化量。网络稳定时,每个包的延迟都差不多。抖动大,说明网络忽快忽慢。

为什么抖动比高延迟更可怕?因为 WebRTC 有抖动缓冲(Jitter Buffer),它会缓存一些数据来平滑波动。但如果抖动太大,缓冲要么溢出(丢数据),要么欠载(没数据可播),结果就是卡顿。

抖动的测量:

  • iperf3:上面命令的输出里就有 Jitter 值。
  • WebRTC 统计:通过 inbound-rtp 或 outbound-rtp 的 jitter 字段获取。
// 获取抖动数据
stats.forEach(report => {
  if (report.type === 'inbound-rtp' && report.kind === 'video') {
    console.log('抖动:', report.jitter * 1000, 'ms');
  }
});

抖动值一般以毫秒为单位。WebRTC 内部会做归一化处理,所以直接看数值就好。

注意:Wi-Fi 网络下的抖动通常比有线网络大很多。如果你在 Wi-Fi 环境下推流,抖动超过 30ms 是常有的事。这时候,适当增大 Jitter Buffer 的容量会有帮助,但会增加延迟。这是个 trade-off。

2.5 网络排查全景图

下面这张图,是我自己总结的网络排查流程。每次遇到卡顿,我就按这个顺序走一遍,基本能定位问题。

网络环境排查流程图 网络环境排查流程 收到卡顿反馈 ① 上行带宽测试(iperf3 / Speedtest) ② 丢包率检测(ping / getStats) ③ RTT 延迟测量(getStats / traceroute) ④ 网络抖动分析(iperf3 / getStats) 定位问题,制定方案 关键指标 带宽利用率 < 80% 丢包率 < 1% RTT < 150ms 抖动 < 20ms

嗯,这张图把四个排查步骤串起来了。你按这个顺序走,基本不会漏掉什么。

2.6 综合判断:别只看单一指标

最后说一句,网络排查不能只看一个指标。我见过有人丢包率只有 0.5%,但抖动高达 50ms,推流照样卡。也见过 RTT 200ms,但带宽和丢包都很好,推流反而流畅。

所以,要综合看。我个人习惯,先看丢包率,再看抖动,最后看 RTT 和带宽。如果丢包率超过 1%,优先解决丢包问题。如果丢包率正常但卡顿,再查抖动和带宽。