Google 实时流拥塞控制算法GCC
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Google 实时流拥塞控制算法GCC相关的知识,希望对你有一定的参考价值。
参考技术A 1、简介参考:https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02#section-4.4
gcc是google实时流拥塞控制算法的简称,已经在webrtc中实现,应用于chrome,后面将应用到Hangouts(视频聊天产品)中,主要用于视频流的拥塞控制。
网络瓶颈主要发生在中间的传输设备上,比如路由器,所以如果有中间设备的帮助(ECN),网络瓶颈应该会更早并且更准确的被检测到,gcc属于端到端的拥塞控制算法,端到端的算法将中间路径想象成一个黑盒子,它不借助中间设备的帮助,这就增加了网络拥塞预测的难度。端到端的实时流拥塞算法主要有以下难点:
(1)网络拥塞一般与链路容量,当前链路中的流量以及即将发送的流量有关,由于路由的不确定性以及链路是由多个流共享并且瞬息万变等原因,对于一个流而言这三个因素都是随机变量。
(2)拥塞控制算法要求同一种流(都使用gcc)能够公平分享带宽,同时能够与TCP流公平相处,不会被TCP流抢占带宽,也尽量不要抢占TCP流的带宽。
(3)视频解码器对丢包敏感,但实时性又不能使用重传机制,因为需要尽量减少丢包,另一方面解码器并不能快速的调整码率,因而估计出的带宽尽量平滑,减少毛刺。
2、实现
gcc由基于延迟的控制器和基于丢包的控制器组成,信令基于RTP扩展头和RTCP传输。
(1)反馈和扩展
gcc可以有两种实现,第一种是两种控制器都在发送端实现,接收端周期性的反馈到达的每一个包的序列号和到达时间,发送端记录每一个包的发送时间和到达时间,同时计算出丢包率。第二种是延迟控制器在接收端实现,接收端计算出组间延迟,根据组间延迟计算出发送比特率通过REMB消息反馈给发送端,接收端通过RTCP消息将丢包率反馈给发送端,丢包控制器在发送端实现,发送端通过接收端反馈的信息计算出最终的发送比特率。
(2)发送引擎
定速器用于实现发送固定比特率的视频包,编码器产生的数据先会放到定时队列中,定时器会在每个burst_time发送一组包,burst_time建议为5ms,这一组包的大小是由发送比特率和burst_time计算出来的。
(3)延迟控制器
(3.1)到达时间模型
d(i) = t(i) - t(i-1) - (T(i) - T(i-1))
d(i)表示第i组包的延迟和第i-1组包的延迟之差,t(i)表示第i组包的到达时间,取最后一个包的到达时间,T(i)表示第i组包的发送时间,取最后一个包的发送时间,忽略乱序的包。
d(i) > 0说明组间的延迟增大了,d(i) < 0说明组间的延迟减少了,d(i) = 0说明组间的延迟没变化。
我们将组间延迟建模成 d(i) = w(i),w(i)是一个随机过程W的采样,这个随机过程是链路容量,当前链路的流量以及当前发送的比特率的函数。将W建模成白高斯过程。如果我们过度使用链路则我们期望w(i)增大,如果链路中的队列正在排空,则意味着w(i)将会减小,其它情况w(i)将是0。
d(i) = w(i) = m(i) + v(i)
m(i)是从w(i)中提取出来的使w(i)的均值为0的部分。v(i)是噪声项代表网络抖动以及其它模型捕捉不到的影响延迟的因素,v(i)是均值为0的高斯白噪声,方差var_v = Ev(i)^2。
(3.2)滤波之前
链路中断会使延迟瞬间变化很大,影响模型的准确计算,所以滤波之前会把一些包合并成一组,如果满足下面的条件将会合并,(1)一些包的发送时间在一个burst_time内(2)一个包的组间到达时间小于burst_time并且组间延迟d(i)小于0。
(3.3)到达时间滤波
我们将要估计m(i)然后用这个估计值检测链路过载。gcc使用kalman滤波器来估计m(i)。
m(i+1) = m(i) + u(i)
上面的是m(i)的状态转移方程。u(i)是状态噪声,将它建模成均值为0,方差为q(i)的符合高斯统计的稳态过程,其中q(i) = Eu(i)^2,q(i)建议值为10^-3。
kalman滤波器递归地更新m(i)的估计值m_hat(i)
z(i) = d(i) - m_hat(i-1)
m_hat(i) = m_hat(i-1) + z(i) * k(i)
k(i) = (e(i-1) + q(i)) / var_v_hat(i) + (e(i-1) + q(i))
e(i) = (1 - k(i)) * (e(i-1) + q(i))
其中;
var_v_hat(i) = max(alpha * var_v_hat(i-1) + (1-alpha) * z(i)^2, 1)
alpha = (1-chi)^(30/(1000 * f_max))
f_max = max 1/(T(j) - T(j-1)) for j in i-K+1,...,i 代表最近K组包的最大发送频率。
(3.4)过载探测
用到达时间滤波模块估计出的组间延迟m(i)与阈值del_var_th(i)进行比较,如果m(i) > del_var_th(i)则意味着过载,这一个条件还不能给速率控制系统发送过载信号,检测的过载时间最少维持overuse_time_th毫秒,并且不能出现m(i) < m(i-1)的情况。相反的情况,如果m(i) < -del_var_th(i)则意味着网络使用不足,最后一种情况是正常状态。
del_var_th对算法的整体仿真和性能有很大的影响,另外如果del_var_th取一个固定的值,将会被当前的TCP流占用带宽导致饥饿的产生。这个饥饿可以通过将del_var_th设置成足够大的值而避免。因而有必要动态调整del_var_th去获取更好的性能,例如与基于丢包的流的竞争中。
del_var_th(i) = del_var_th(i-1) + (t(i)-t(i-1)) * K(i) * (|m(i)|-del_var_th(i-1))
另外,如果|m(i)| - del_var_th(i) > 15时不更新del_var_th(i),并且del_var_th(i) 在[6, 600]区间内。
(3.5)速率控制器
当检测到过载,延迟控制器估计的有效带宽将会减少,通过这种方式获得一个递归的自适应的有效带宽估计。
速率控制子系统有3个状态,Increase, Decrease 和Hold状态。当没有检测出拥塞时是Increase状态,检测出拥塞时是Decrease状态,Hold状态表示等待队列清空的过程。
增大当前有效带宽将使用乘法或加法,取决于当前的状态,如果当前估计的带宽离拥塞较远,则使用乘法,如果接近拥塞,则使用加法。如果当前的比特率R_hat(i)接近之前Decrease状态的平均比特率则认为接近拥塞。
R_hat(i)是延迟控制器在T秒钟的窗口中计算出来的接收比特率:
R_hat(i) = 1/T * sum(L(j)) for j from 1 to N(i)
其中N(i)是T秒钟接收的包数,L(j)是第j个包的负载长度。窗口建议设置成0.5秒到1秒之间。
eta = 1.08^min(time_since_last_update_ms / 1000, 1.0)
A_hat(i) = eta * A_hat(i-1)
在加法增长阶段,估计值在response_time最多增长半个包的长度。
response_time_ms = 100 + rtt_ms
alpha = 0.5 * min(time_since_last_update_ms / response_time_ms, 1.0)
A_hat(i) = A_hat(i-1) + max(1000, alpha * expected_packet_size_bits)
expected_packet_size_bits用于在低码率时获得一个缓慢的增长。它可以根据当前的码率估算出来。
bits_per_frame = A_hat(i-1) / 30
packets_per_frame = ceil(bits_per_frame / (1200 * 8))
avg_packet_size_bits = bits_per_frame / packets_per_frame
之前的讨论都是假设链路会出现拥塞,如果发送端产生不了足够的比特流,估计的有效带宽需要保持在一个给定的范围内。
A_hat(i) < 1.5 * R_hat(i)
如果检测到过载,则进入Decrease状态,延迟控制器估计的有效带宽会减少。
A_hat(i) = beta * R_hat(i)
beta一般选择属于[0.8, 0.95],一般建议是0.85。
(4)丢包控制器
定义丢包控制器估计有效带宽为As_hat。
延迟控制器估计的有效带宽只在队列足够大时有效,如果队列较小,就需要使用丢包率检测过载。
As_hat(i) = As_hat(i - 1) (2 < p < 10%)
As_hat(i) = As_hat(i-1)(1-0.5p) (p > 10%)
As_hat(i) = 1.05(As_hat(i-1)) (p < 2%)
真实的发送速率设置成丢包控制器估计值和延迟控制器估计值的较小的。
我们观察到由于过载出现少量的丢包,如果不调整发送的比特率,丢包率会快速增长到达10%门限值然后调整发送比特率。然而,如果丢包率不增加,拥塞很可能不是自己造成的,因而不需要进行调整。
(5)互操作
如果发送端实现了这个算法,但是接收端没有实现RTCP消息和RTP头扩展,建议发送端检测RTCP的接收端报告,然后使用丢包率和rtt做为丢包控制器的输入,关闭延迟控制器。
注:服务中的自适应流控也可以参考GCC,后面这个是BRPC的流控: BRPC自适应流控
转载WebRTC基于GCC的拥塞控制(上) - 算法分析
实时流媒体应用的最大特点是实时性,而延迟是实时性的最大敌人。从媒体收发端来讲,媒体数据的处理速度是造成延迟的重要原因;而从传输角度来讲,网络拥塞则是造成延迟的最主要原因。网络拥塞可能造成数据包丢失,也可能造成数据传输时间变长,延迟增大。
拥塞控制是实时流媒体应用质量保证(QoS)的重要手段之一,它在缓解网络拥堵、减小网络延迟、平滑数据传输等质量保证方面发挥重要作用。WebRTC通控制发送端数据发送码率来达到控制网络拥塞的目的,其采用谷歌提出的拥塞控制算法(Google Congestion Control,简称GCC[1])来控制发送端码率。
本文是关于WebRTC拥塞控制算法GCC的上半部分,主要集中于对算法的理论分析,力图对WebRTC的QoS有一个全面直观的认识。在下半部分,将深入WebRTC源代码内部,仔细分析GCC的实现细节。
1 GCC算法综述
Google关于GCC的RFC文档在文献[1],该RFC目前处于草案状态,还没有成为IETF的正式RFC。此外,Google陆续发布了一系列论文[2][3][4]来论述该算法的实现细节,以及其在Google Hangouts、WebRTC等产品中的应用。本文主要根据这些文档资料,从理论上学习GCC算法。
GCC算法分两部分:发送端基于丢包率的码率控制和接收端基于延迟的码率控制。如图1所示
图1 GCC算法整体结构
基于丢包率的码率控制运行在发送端,依靠RTCP RR报文进行工作。WebRTC在发送端收到来自接收端的RTCP RR报文,根据其Report Block中携带的丢包率信息,动态调整发送端码率As。基于延迟的码率控制运行在接收端,WebRTC根据数据包到达的时间延迟,通过到达时间滤波器,估算出网络延迟m(t),然后经过过载检测器判断当前网络的拥塞状况,最后在码率控制器根据规则计算出远端估计最大码率Ar。得到Ar之后,通过RTCP REMB报文返回发送端。发送端综合As、Ar和预配置的上下限,计算出最终的目标码率A,该码率会作用到Encoder、RTP和PacedSender等模块,控制发送端的码率。
2 发送端基于丢包率的码率控制
GCC算法在发送端基于丢包率控制发送码率,其基本思想是:丢包率反映网络拥塞状况。如果丢包率很小或者为0,说明网络状况良好,在不超过预设最大码率的情况下,可以增大发送端码率;反之如果丢包率变大,说明网络状况变差,此时应减少发送端码率。在其它情况下,发送端码率保持不变。
GCC使用的丢包率根据接收端RTP接收统计信息计算得到,通过RTCP RR报文中返回给发送端。RTCP RR报文统计接收端RTP接收信息,如Packet Loss,Jitter,DLSR等等,如图2所示:
图2 RTCP RR报文结构[5]
图3 GCC基于丢包率的码率计算公式[4]
最终码率会作用于Encoder、RTP和PacedSender模块,用以在编码器内部调整码率和平滑发送端发送速率。
3 接收端基于延迟的码率控制
GCC算法在接收端基于数据包到达延迟估计发送码率Ar,然后通过RTCP REMB报文反馈到发送端,发送端把Ar作为最终目标码率的上限值。其基本思想是: RTP数据包的到达时间延迟m(i)反映网络拥塞状况。当延迟很小时,说明网络拥塞不严重,可以适当增大目标码率;当延迟变大时,说明网络拥塞变严重,需要减小目标码率;当延迟维持在一个低水平时,目标码率维持不变。
基于延时的拥塞控制由三个主要模块组成:到达时间滤波器,过载检查器和速率控制器;除此之外还有过载阈值自适应模块和REMB报文生成模块,如图1所示。下面分别论述其工作过程。
3.1 到达时间滤波器(Arrival-time Filter)
该模块用以计算相邻相邻两个数据包组的网络排队延迟m(i)。数据包组定义为一段时间内连续发送的数据包的集合。一系列数据包短时间里连续发送,这段时间称为突发时间,建议突发时间为5ms。不建议在突发时间内的包间隔时间做度量,而是把它们做为一组来测量。通过相邻两个数据包组的发送时间和到达时间,计算得到组间延迟d (i)。组间延迟示意图及计算公式如图4所示:
T(i)是第i个数据包组中第一个数据包的发送时间,t(i)是第i个数据包组中最后一个数据包的到达时间。帧间延迟通过如下公式计算得到:
d(i) = t(i) – t(i-1) – (T(i) – T(i-1)) (3.1.1)
公式1.3.1是d(i)的观测方程。另一方面,d(i)也可由如下状态方程得到:
d(i) = dL(i)/C(i) + w(i) (3.1.2)
d(i) = dL(i)/C(i) + m(i) + v(i) (3.1.3)
其中dL(i)表示相邻两帧的长度差,C(i)表示网络信道容量,m(i)表示网络排队延迟,v(i)表示零均值噪声。m(i)即是我们要求得的网络排队延迟。通过Kalman Filter可以求得该值。具体计算过程请参考文献[1][4][6]。
3.2 过载检测器(Over-use Detector)
该模块以到达时间滤波器计算得到的网络排队延迟m(i)为输入,结合当前阈值gamma_1,判断当前网络是否过载。判断算法如图5所示[2]。
图5 过载检测器伪代码
需要注意的是,阀值gamma_1对算法的影响很大,并且阈值gamma_1是自适应性的。如果其是静态值,会带来一系列问题,详见文献[4]。所以gamma_1需要动态调整来达到良好的表现。这就是图1中的Adaptive threshould模块。阈值gamma_1动态更新的公式如下:
gamma_1(i) = gamma_1(i-1) + (t(i)-t(i-1)) * K(i) * (|m(i)|-gamma_1(i-1)) (3.2.4)
当|m(i)|>gamma_1(i-1)时增加gamma_1(i),反之减小gamma_1(i),而当|m(i)|– gamma_1(i) >15,建议gamma_1(i)不更新。K(i)为更新系数,当|m(i)|<gamma_1(i-1)时K(i) = K_d,否则K(i) = K_u。同时建议gamma_1(i)控制在[6,600]区间。太小的值会导致探测器过于敏感。建议增加系数要大于减少系数K_u > K_d。文献[1]给出的建议值如下:
gamma_1(0) = 12.5 ms
gamma_2 = 10 ms
K_u = 0.01
K_d = 0.00018
3.3 速率控制器(Remote Rate Controller)
该模块以过载检测器给出的当前网络状态s为输入,首先根据图7所示的有限状态机判断当前码率的变化趋势,然后根据图8所示的公式计算目标码率Ar。
图7 目标码率Ar变化趋势有限状态机
当前网络过载时,目标码率处于Decrease状态;当前网络低载时,目标码率处于Hold状态;当网络正常时,处于Decrease状态时迁移到Hold状态,处于Hold/Increase状态时都迁移到Increase状态。当判断出码率变化趋势后,根据图8所示公式进行计算目标码率。
图8 目标码率Ar计算公式
REMB报文每秒发送一次,当Ar(i) < 0.97 * Ar(i-1)时则立即发送。
3.4 发送端目标码率的确定
发送端最终目标码率的确定结合了基于丢包率计算得到的码率As和基于延迟计算得到的码率Ar。此外,在实际实现中还会配置目标码率的上限值和下限值。综合以上因素,最终目标码率确定如下:
target_bitrate = max( min( min(As, Ar), Amax), Amin) (3.4.1)
目标码率确定之后,分别设置到Encoder模块和PacedSender模块。
4 总结
本文在广泛调研WebRTC GCC算法的相关RFC和论文的基础上,全面深入学习GCC算法的理论分析,以此为契机力图对WebRTC的QoS有一个全面直观的认识。为将来深入WebRTC源代码内部分析GCC的实现细节奠定基础。
以上是关于Google 实时流拥塞控制算法GCC的主要内容,如果未能解决你的问题,请参考以下文章