2、网络基础与延迟模型:RTT、RTP/RTCP协议基础、排队延迟与自延迟模型、TCP与UDP的拥塞控制差异

各位同学,欢迎来到第二章。上一章我们聊了WebRTC的整体架构,今天要扎进网络底层了。说实话,拥塞控制算法再花哨,如果不懂网络延迟的构成,那基本就是盲人摸象。我个人习惯,在分析任何拥塞控制问题之前,先把网络模型画清楚。

这一章,我们重点解决几个核心问题:RTT到底怎么算?RTP和RTCP在拥塞控制里扮演什么角色?排队延迟和自延迟模型是什么鬼?以及,为什么TCP那套拥塞控制不能直接搬到WebRTC里用?

本章知识体系:网络基础与延迟模型 拥塞控制基础 RTT 延迟模型 传输延迟 + 处理延迟 + 排队延迟 RTP / RTCP 协议 媒体传输 + 反馈报告(RR/SR) 排队延迟与自延迟 自延迟模型:发送速率 > 瓶颈带宽 TCP vs UDP 拥塞控制差异 TCP:丢包驱动 / 窗口控制 / 公平性 UDP:延迟驱动 / 速率控制 / 实时性 核心目标:理解延迟构成,为拥塞控制算法打下基础

2.1 RTT:往返时间的真相

RTT,全称Round-Trip Time,往返时间。说白了,就是数据包从A到B,再回到A的总耗时。在WebRTC里,RTT是拥塞控制最核心的输入参数之一。你想想看,如果不知道网络延迟有多大,你怎么判断该不该多发数据?

RTT的构成其实不复杂,但很多人容易忽略细节。它主要由三部分组成:

  • 传输延迟:物理链路上的传播时间。光速在光纤里大约2/3c,这个基本固定。
  • 处理延迟:路由器、交换机处理数据包的时间。通常很小,几微秒到几十微秒。
  • 排队延迟:数据包在路由器缓冲区里等待的时间。这个最要命,也是拥塞控制要重点对付的。

关键点:在WebRTC的拥塞控制中,我们真正关心的是排队延迟的变化量,而不是RTT的绝对值。因为传输延迟和处理延迟基本不变,RTT的波动几乎完全来自排队延迟。

我记得有一次排查线上问题,用户反馈视频卡顿,但RTT看起来只有30ms。后来仔细一查,发现RTT在30ms到120ms之间剧烈抖动。嗯,这就是典型的排队延迟在作怪。如果只看平均RTT,你根本发现不了问题。

2.2 RTP/RTCP协议基础

RTP(Real-time Transport Protocol)和RTCP(RTP Control Protocol)是WebRTC的左右手。RTP负责运媒体数据,RTCP负责反馈网络状态。两者缺一不可。

2.2.1 RTP:媒体数据的搬运工

RTP包的结构其实挺简洁的。每个RTP包都有一个序列号(sequence number)和时间戳(timestamp)。这两个字段在拥塞控制里至关重要。

  • 序列号:用于检测丢包和乱序。接收端通过序列号可以知道哪些包丢了,哪些包到了。
  • 时间戳:用于计算延迟和抖动。发送端打上时间戳,接收端收到后对比本地时间,就能算出单向延迟。

个人经验:我建议你在实现拥塞控制时,一定要仔细处理RTP序列号的回绕问题。序列号是16位的,最大65535。我曾经见过一个团队因为没处理好回绕,导致丢包率计算直接崩了,视频画面花成一团。

2.2.2 RTCP:网络状态的晴雨表

RTCP是RTP的控制协议。它定期发送报告,告诉发送端网络状况。常用的报告有两种:

  • SR(Sender Report):发送端报告,包含发送端的NTP时间戳和RTP时间戳。
  • RR(Receiver Report):接收端报告,包含丢包率、抖动、最后收到的序列号等信息。

WebRTC的拥塞控制算法,比如GCC(Google Congestion Control),就是基于RTCP RR中的信息来调整发送速率的。说白了,接收端告诉发送端:「兄弟,网络有点堵,你慢点发。」

注意:RTCP的发送频率不能太高,否则会占用带宽。WebRTC默认RTCP间隔是5秒,但在拥塞控制中,这个间隔太长了。实际实现中,GCC会动态调整RTCP的发送频率,在需要时缩短到几百毫秒。

2.3 排队延迟与自延迟模型

排队延迟,是拥塞控制的核心战场。为什么这么说?因为网络拥塞的本质,就是数据包在路由器缓冲区里排队排太久了。

自延迟模型(Self-induced Delay Model)是理解排队延迟的关键。它的核心思想很简单:

如果你发送数据的速度超过了瓶颈链路的带宽,数据包就会在路由器缓冲区里堆积,导致延迟增加。

反过来,如果你发送速度低于瓶颈带宽,缓冲区就会清空,延迟下降。所以,通过观察延迟的变化,你就能推断出网络是否拥塞。

核心公式:

排队延迟 = 当前RTT - 最小RTT(base delay)

其中,最小RTT是在网络空闲时测得的RTT,代表传输延迟+处理延迟。当前RTT减去最小RTT,就是排队延迟。

我刚开始做WebRTC时,对自延迟模型的理解不够深。有一次,我直接拿RTT的绝对值来做拥塞判断,结果算法在WiFi环境下完全失效。后来才明白,WiFi的传输延迟本身就不稳定,必须用排队延迟(RTT减去base delay)才能准确反映拥塞状态。

2.4 TCP与UDP的拥塞控制差异

这个问题,面试的时候经常被问到。很多人会说「TCP可靠,UDP不可靠」,但拥塞控制层面的差异远不止这些。

维度 TCP UDP(WebRTC)
拥塞信号 丢包为主(早期),延迟为辅(BBR等) 延迟为主(GCC),丢包为辅
控制方式 窗口控制(cwnd) 速率控制(bps)
公平性 TCP友好(AIMD) 需要与TCP共存(TFMCC)
实时性 低(重传导致延迟大) 高(允许丢包,不重传)
反馈机制 ACK确认 RTCP报告

为什么TCP的拥塞控制不能直接用在WebRTC里?原因很简单:TCP是面向可靠性的,而WebRTC是面向实时性的。

TCP看到丢包,第一反应是「赶紧重传」,然后降低发送窗口。但WebRTC看到丢包,第一反应是「丢就丢了,继续发新的」。因为视频帧过期了,重传也没意义。

另外,TCP的AIMD(加性增乘性减)策略在实时通信中太激进。TCP丢包后窗口减半,但视频编码器没法瞬间把码率减半。你想想看,如果视频码率从2Mbps突然降到1Mbps,画面质量会断崖式下降,用户直接骂娘。

避坑指南:我曾经在一个项目中尝试把TCP的CUBIC算法移植到WebRTC里,结果惨不忍睹。视频在弱网环境下频繁卡顿,因为CUBIC对丢包太敏感了。后来老老实实用GCC,基于延迟的拥塞控制才是实时通信的正解。

总结一下这一章的核心:RTT是基础,但我们要关注的是排队延迟;RTP/RTCP是工具,提供了拥塞控制所需的反馈信息;自延迟模型是理论,解释了延迟与拥塞的关系;TCP与UDP的差异是实践,告诉我们为什么不能照搬。

嗯,这一章的内容就到这里。下一章我们会深入GCC算法的具体实现,看看Google是怎么把延迟模型变成真正的拥塞控制代码的。


公众号:蓝海资料掘金营,微信deep3321