2. 网络延迟分析:网络传输延迟、抖动与丢包、带宽对延迟的影响
做 WebRTC 优化,第一关就是搞懂网络。说白了,你代码写得再漂亮,网络一卡顿,用户照样骂娘。我这些年踩过的坑,十有八九都跟网络分析不到位有关。
网络延迟不是单一概念。它是一堆因素叠加的结果。我们一个个拆开看。
2.1 网络传输延迟:数据在路上的时间
数据从 A 到 B,物理上就不可能瞬间到达。这个时间,叫传输延迟。
它主要由三部分组成:
- 传播延迟:信号在介质里跑的时间。光速再快,绕地球半圈也得 60-70ms。我做过一个跨洋项目,北京到纽约,光这物理延迟就 120ms 打底,再怎么优化也压不下去。
- 传输延迟:数据包从网卡发出去的时间。跟数据包大小和带宽有关。1.5KB 的包在 100Mbps 链路上,传输延迟也就 0.12ms,基本可以忽略。
- 处理延迟:路由器、交换机查路由表、做转发的时间。正常情况几微秒到几十微秒。但遇到拥塞,这个值会暴涨。
- 排队延迟:数据包在路由器队列里等前面包发完的时间。这是最不可控的,也是抖动的主要来源。
关键结论:传播延迟是物理定律,改不了。我们能优化的,主要是排队延迟和处理延迟。
我个人习惯,做延迟分析时先测 RTT(往返时间)。用 ping 或者 WebRTC 内置的 RTCPeerConnection.getStats() 都能拿到。RTT 超过 300ms,语音通话就开始难受了;超过 500ms,视频基本没法聊。
2.2 抖动:比延迟更头疼的问题
抖动是什么?就是延迟的变化量。你想想看,上一包 50ms 到,下一包 200ms 到,再下一包 80ms 到。这种忽快忽慢,比稳定高延迟更让人崩溃。
为什么会这样?
- 网络拥塞导致排队时间忽长忽短
- 路由路径动态变化
- 无线网络的信号波动
我在项目中遇到过最典型的场景:用户在咖啡厅用 Wi-Fi 开会。信号时好时坏,抖动值飙到 100ms 以上。视频画面一卡一卡的,声音像机器人。后来我们加了抖动缓冲(Jitter Buffer),才把这个问题压住。
我的经验:WebRTC 内部有自适应抖动缓冲。但默认参数不一定适合你的场景。做实时互动,建议把抖动缓冲设为动态模式,让它根据网络状况自动调整深度。
衡量抖动,一般用 Interarrival Jitter。计算公式不复杂,就是相邻包到达时间的差异的平滑值。WebRTC 的 RTCInboundRtpStreamStats 里直接有 jitter 字段,单位是秒。正常值应该在 20ms 以内,超过 50ms 就要警惕了。
2.3 丢包:数据丢了怎么办
丢包是网络传输中最直接的伤害。包丢了,数据就不完整。视频会出现马赛克,音频会出现爆音或卡顿。
丢包的原因主要有:
- 队列溢出:路由器缓存满了,新来的包直接扔掉。这是最常见的原因。
- 链路错误:无线信号干扰、网线接触不良,导致数据在传输过程中损坏。
- 拥塞控制主动丢包:有些算法会故意丢包,来通知发送端降低码率。
注意:WebRTC 默认使用 UDP 传输。UDP 不保证可靠交付,丢包了不会自动重传。你需要自己处理丢包恢复,或者依赖 WebRTC 内置的 NACK(否定确认)和 FEC(前向纠错)。
我曾经踩过一个坑:在弱网环境下,丢包率到了 5%,视频基本没法看。我们开了 FEC,丢包率降到 1% 以下,但带宽消耗增加了 20%。这就是典型的用带宽换质量。后来我们做了自适应策略:丢包率低时关 FEC,丢包率高时动态调整 FEC 冗余度。
丢包率的分级参考:
| 丢包率 | 影响程度 | 建议措施 |
|---|---|---|
| 0% - 1% | 几乎无影响 | 保持默认配置 |
| 1% - 3% | 轻微卡顿 | 开启 NACK |
| 3% - 5% | 明显卡顿、马赛克 | 开启 FEC + NACK |
| 5% - 10% | 通话几乎不可用 | 降低分辨率/帧率,增加 FEC 冗余 |
| > 10% | 无法正常通信 | 建议用户切换网络 |
2.4 带宽对延迟的影响
带宽和延迟的关系,很多人搞混。带宽不是延迟的直接决定因素,但带宽不足会间接导致延迟飙升。
想象一下:水管细,水流量大,水就会堵在管口。网络也一样。带宽不够,数据包在发送端和路由器排队,排队延迟就上去了。
这里有个关键概念——带宽延迟积(BDP)。公式很简单:
BDP = 带宽 × RTT
BDP 表示在任意时刻,网络中能容纳的数据量。如果发送窗口小于 BDP,带宽就利用不充分;如果发送窗口大于 BDP,就会造成拥塞。
我习惯用 WebRTC 的 getStats() 接口实时监控带宽估计值。代码大概这样:
const stats = await peerConnection.getStats();
stats.forEach(report => {
if (report.type === 'candidate-pair' && report.state === 'succeeded') {
console.log('可用带宽:', report.availableOutgoingBitrate);
console.log('RTT:', report.currentRoundTripTime);
}
});
带宽不足时,WebRTC 的拥塞控制算法(GCC 或 NADA)会自动降低编码码率。但这个过程有滞后。我建议你在应用层也做一层带宽感知:当带宽低于视频码率的 1.5 倍时,主动降分辨率或帧率,避免排队延迟爆炸。
核心原则:带宽是资源,延迟是代价。用带宽换延迟,或者用延迟换带宽,你要根据场景做取舍。实时通话优先保延迟,点播场景可以适当牺牲延迟保画质。
2.5 知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以把它当作网络延迟分析的检查清单。
这张图把四个核心维度拆开了。你分析网络问题时,就按这个框架来:先看传输延迟的物理上限,再看抖动和丢包的程度,最后评估带宽是否够用。每个维度都有对应的优化手段。