GCC算法总结
传统的拥塞控制算法通常只依赖一种信号(要么是丢包,要么是延迟)。而GCC则采用延迟加丢包两种拥塞信号,同时运行两个独立的控制器:
- 基于延迟的控制 (Delay-based Control):这是一种主动式、预测性的方法。它通过监测数据包在网络中传输的单向延迟变化趋势来判断拥塞。当延迟开始持续增长时,GCC 会认为网络路径上的某个路由器队列正在被填满,这是拥塞即将发生的早期信号。GCC 会在大量丢包发生之前就降低发送速率,从而有效控制延迟。
- 基于丢包的控制 (Loss-based Control):这是一种被动式、反应性的方法。它是网络拥塞控制的传统方法。当网络中出现丢包时,GCC 会认为网络已经发生了明确的拥塞(路由器队列已满,开始丢弃数据包)。此时,它会根据丢包率来计算一个合适的发送速率。
最终的发送码率由这两个控制器共同决定,总是取两者估算出的码率中更小、更保守的那一个。这样就确保了系统的稳定性和安全性。
GCC的首要目标是保证低延迟,其次才是高带宽。
算法原理
基于延迟的控制器
信息获取
- 发送端:为每个发出的 RTP 包打上一个全链路唯一的序列号(Transport-Wide Sequence Number)和发送时间戳 tsend(i)。
- 接收端:记录每个包的到达时间戳 tarrival(i)。
- 反馈:接收端通过 RTCP TCC (Transport-wide Congestion Control) Feedback 消息,定期将包的序列号和对应的到达时间戳打包,发送回发送端。
这样,发送端就拿到了一系列的配对信息:{ seq_num1, tsend1, tarrival1 }, { seq_num2, tsend2, tarrival2}, …
1:计算延迟变化
发送端收到反馈后,可以计算出每个数据包的单向传播延迟: d(i)=tarrival(i)−tsend(i)
但是,绝对的延迟会因为时钟不同步而有误差。GCC 关注的是延迟的变化量,这可以消除时钟偏移的影响。它计算相邻两个数据包(或数据包组)之间的延迟差值: Δd(i)=d(i)−d(i−1)
这个 Δd(i) 反映了网络路径上排队延迟的变化。
- 如果 Δd(i)>0,说明网络中的排队队列可能正在变长。
- 如果 Δd(i)<0,说明队列可能正在缩短。
- 如果 Δd(i)≈0,说明网络状态相对稳定。
2:状态估计
网络延迟的测量值是充满“噪声”的,会受到网络抖动等因素的瞬时影响。为了从这些嘈杂的数据中提取出真实的排队延迟增长趋势,GCC 创造性地使用了卡尔曼滤波器 (Kalman Filter)。
- 作用:卡尔曼滤波器是一种强大的数学工具,可以从一系列不完整和包含噪声的测量中,估计出动态系统的状态。
- 在GCC中的应用:它将测得的延迟变化量 Δd(i) 作为输入,通过内部的状态转移和更新模型,对齐进行平滑和去噪,最终输出一个更准确的网络排队延迟估计值 q(i)。
3:过载检测
有了经过卡尔曼滤波器处理后的排队延迟估计值 q(i),接下来就需要判断网络是否“过载”了。
- 算法设定一个动态的阈值 γ。
- 将 q(i) 与阈值 γ 进行比较,判断网络状态:
    - Over-use (过载): 如果 q(i)>γ 并且持续了一小段时间,说明排队延迟明显且持续增长,网络处于过载状态。
- Under-use (低载): 如果 q(i)<−γ,说明排队延迟在减小,网络负载很低,有提升码率的空间。
- Normal (正常): 如果 ∣q(i)∣≤γ,说明网络状态稳定。
 
4:速率控制
根据过载检测器输出的状态,速率控制器会调整目标码率 Ad(基于延迟估算的码率):
- 
    检测到 Over-use:立即执行乘性减 (Multiplicative Decrease)。Ad=Ad×β(其中 β≈0.85) 这是一种快速降低码率的方式,以迅速缓解网络拥塞。 
- 
    检测到 Under-use或Normal:执行加性增 (Additive Increase) 或 乘性增 (Multiplicative Increase),这被称为“探测阶段”。- 算法会缓慢地增加码率,以探测网络是否还有更多的可用带宽。增加的速度会受到当前码率和网络往返时间(RTT)的影响,确保探测行为是温和的,不会立即引发新的拥塞。
 
基于丢包的控制器
这部分逻辑相对简单,作为网络严重拥塞时的“安全网”。
1:计算丢包率
发送端根据自己发送的包记录和从接收端反馈回来的确认信息,可以很容易地计算出最近一个时间窗口(如 1 秒)内的丢包率 Ploss。
2:计算目标码率
基于丢包率,GCC 会计算出一个目标码率 Al。这个计算通常基于经典的 TCP 友好码率控制(TFRC)公式的变种。
- 
    当丢包率很低时(如 < 2%):认为网络状况良好,此时 Al 不会成为码率的限制因素。它甚至可能会允许码率缓慢增加。 
- 
    当丢包率处于中等水平时(如 2% - 10%):算法会根据丢包率、RTT 和数据包大小计算出一个目标码率。丢包率越高,计算出的 Al 越低。 Al≈f(RTT,Ploss,packet_size) 
- 
    当丢包率很高时(如 > 10%):这是一个明确的强拥塞信号。算法会快速且大幅度地降低码率,通常也是采用乘性减的方式。 
时延控制和延迟控制结合
在任何一个时刻,GCC 都会同时运行上述两个控制器,得到两个目标码率:
- Ad:来自基于延迟的控制器。
- Al:来自基于丢包的控制器。
最终发送端采用的目标码率 Atarget 是两者中的最小值,并且还会受到应用层设置的最高/最低码率限制。
Atarget=min(Ad, Al, Amax_app)
- 场景1(拥塞初期):延迟开始增加,但还未丢包。此时 Ad 会首先下降,Atarget 会跟随 Ad 下降,实现了主动降速,避免了丢包和高延迟。
- 场景2(突发拥塞):网络突然恶化,直接开始大量丢包。此时 Ploss 飙升,导致 Al 急剧下降。Atarget 会跟随 Al 下降,对严重拥塞做出快速反应。