网络拥塞是基于IP协议的数据宝交换网络中常见的一种网络传输问题。网络拥塞是导致网络吞吐降低,网络丢包等的主要原因之一。
WebRTC中传输的采用的是UDP协议,WebRTC的传输层采用的拥塞算法是GCC算法。
Google congestion control
目前新版本的WebRTC的基于丢包的和基于延迟的带宽评估都是放在发送端的。
旧版本的WebRTC的基于延迟的带宽评估可能放在接收端,然后反馈给发送端。
基于丢包的拥塞控制比较简单。其基本思想是根据丢包的多少来判断网络的拥塞程度,丢包越多则认为网络越拥塞,那么我们就要降低发送速率来缓解网络拥塞。如果没有丢包,则说明网络状况良好,这时候就可以提高发送码率,向上探测是否有更多的带宽可用。实现该算法主要有两点,一是获得接收端的丢包率,一是确定降低码率和提升码率的阈值。
发送端基于丢包率的控制方法在每一个 t k t_k tk时刻, A s ( t k ) A_s(t_k) As(tk)是 t k t_k tk时刻的带宽估计值。
WebRTC通过RTCP协议的Receive Report反馈包来获取接收端的丢包率。Receive Report包中有一个fraction lost字段,包含了接收端的丢包率。
A s ( t k ) = { A s ( t k − 1 ) ∗ ( 1 − 0.5 ∗ f l ) f l > 0.1 1.05 ∗ ( A s ∗ ( t k − 1 ) ) f l < 0.02 A s ( t k − 1 ) o t h e r w i s e A_s(t_k)=\left\{ \begin{array}{rcl} A_s(t_{k-1}) * (1 - 0.5 * fl) & & {fl > 0.1}\\ 1.05 * (A_s * (t_{k-1}) )& & {fl < 0.02}\\ A_s(t_{k-1}) & & {otherwise} \end{array} \right. As(tk)=⎩⎨⎧As(tk−1)∗(1−0.5∗fl)1.05∗(As∗(tk−1))As(tk−1)fl>0.1fl<0.02otherwise
基于延迟的拥塞控制是通过没组包的到达时间的延迟差的增长趋势来判断网络是否过载,如果过载进行码率下调,如果处于平衡范围维持当前码率,如果网络承载不饱满进行码率上调。
WebRTC在评估延迟差的视乎不是对每个包进行估算,而是采用了包组间进行延迟评估,这符合视频传输(视频帧是需要切分成多个UDP包)的特点,也减少了频繁计算带来的误差。那什么是包组呢?就是距包组中第一个包的发送时刻 t 0 t_0 t0小于 b u r s t _ t i m e burst\_time burst_time发送的所有的包成为一组,第一个超过 b u r s t _ t i m e burst\_time burst_time的包作为下一个包组的第一个包。
b u r s t _ t i m e burst\_time burst_time可以与平滑发送的时间间隔联系,比它小就可以。
一般认为:
b u r s t _ t i m e = 5 m s burst\_time = 5ms burst_time=5ms
设相邻的两个数据分组到达接收方的时间间隔为 t ( i ) − t ( i − 1 ) t(i) - t(i-1) t(i)−t(i−1), 而两者被发送的时间间隔则为 T ( i ) − T ( i − 1 ) T(i) - T(i-1) T(i)−T(i−1),那么就有延迟变量 d ( i ) = t ( i ) − t ( i − 1 ) − ( T ( i ) − T ( i − 1 ) ) d(i)=t(i)-t(i-1) - (T(i)-T(i-1)) d(i)=t(i)−t(i−1)−(T(i)−T(i−1))。如果 d ( i ) > 0 d(i) > 0 d(i)>0,就说明数据在网络传输时存在延迟的现象。
到达时间滤波器计算出每组数据包的延迟梯度之后,就要据此判断当前的网络拥塞状态,通过和某个阈值的比较,高过某个阈值就认为时网络拥塞,低于某个阈值就认为网路状态良好,因此如何确定阈值就至关重要。这就是过载检测器的主要工作,它主要有两部分,一部分是确定阈值的大小,另一部分就是依据延迟梯度和阈值的判断,估计出当前的网络状态,一共有三种网络状态: overuse underuse normal,我们先看网络状态的判断。
其中 m ( t i ) m(t_i) m(ti)表示的过去一段时间计算出来的延迟梯度的平均值。
这里用 γ ( t i ) \gamma(t_i) γ(ti)表示阈值,阈值根据时间自适应。
这样计算的依据是,网络发生拥塞时,数据包会在中间网络设备中排队等待转发,这会造成延迟梯度的增长,当网络流量回落时,网络设备快速消耗(转发)其发送队列中的数据包,而后续的包排队时间更短,这时延迟梯度减小或为负值。
γ ( t i ) \gamma(t_i) γ(ti),它是判断当前网络状况的依据,所以如何确定它的值也就非常重要了。虽然理想状况下,网络的延迟梯度是0,但是实际的网络中,不同转发路径其延迟梯度还是有波动的,波动的大小也是不一样的,这就导致如果设置固定的。 γ ( t i ) \gamma(t_i) γ(ti)太大可能无法探测到拥塞,太小又太敏感,导致速率了变化很大。同时,另外一个问题是,实验中显示固定的值会导致在和TCP链接的竞争中,自己被饿死的现象(TCP是基于丢包的拥塞控制),因此WebRTC使用了一种自适应的阈值调节算法,具体如下:
γ ( t i ) = γ ( t i − 1 ) + Δ T ⋅ K γ ( t i ) ⋅ ( ∣ m ( t i ) ∣ − γ ( t i − 1 ) ) \gamma(t_i) = \gamma(t_{i-1}) + \Delta{T} \cdot K_{\gamma(t_i)} \cdot (|m(t_i)| - \gamma(t_i -1)) γ(ti)=γ(ti−1)+ΔT⋅Kγ(ti)⋅(∣m(ti)∣−γ(ti−1))
Δ T = t i − t i − 1 \Delta{T} = t_i - t_{i-1} ΔT=ti−ti−1
K γ ( t i ) = { k d ∣ m ( t i ) ∣ < γ ( t i − 1 ) k u o t h e r w i s e K_{\gamma(t_i)}=\left\{ \begin{array}{rcl} k_d & & |m(t_i)| < \gamma(t_{i} -1) \\ k_u & & {otherwise} \end{array} \right. Kγ(ti)={kdku∣m(ti)∣<γ(ti−1)otherwise
建议
k u > k d k_{u} > k_{d} ku>kd
推荐值
k u = 0.01 k_{u} = 0.01 ku=0.01 k d = 0.00018 k_d = 0.00018 kd=0.00018
从这个式子可以看出,当延迟梯度减小时,阈值会以一个更慢的速率减小;延迟梯度增加时,阈值也会以一个更慢的速度增加。不过相对而言,阈值的减小速度要小于增加速度。这样主要是为了防止饥饿。
在过载检测中有提到三种情况,normal, underuse, overuser。
然后estimator通过根据三个情况来更新状态。采用一定的比值,对速率进行调整。
三个状态分别是Increase, Hold, Decrease。
这三种状态的状态机如下,系统在Increase状态下启动。
一般可以认为带宽评估的更新 A s ( t k ) A_s(t_k) As(tk)按照以下公式进行。
A s ( t k ) = { η ∗ A s ( t k − 1 ) I n c r e a s e β ∗ R r ( t i ) D e c r e a s e A s ( t k − 1 ) H o l d A_s(t_k)=\left\{ \begin{array}{rcl} \eta * A_s(t_{k-1}) & & Increase\\ \beta * R_r (t_{i}) & & Decrease\\ A_s(t_{k-1}) & & {Hold} \end{array} \right. As(tk)=⎩⎨⎧η∗As(tk−1)β∗Rr(ti)As(tk−1)IncreaseDecreaseHold
其中
η = 1.05 \eta = 1.05 η=1.05
β = 0.85 \beta = 0.85 β=0.85
R r ( t i ) 指 的 是 过 去 500 m s 窗 内 的 最 大 a c k e d b i t r a t e R_r(t_{i}) 指的是过去500ms窗内的最大acked bitrate Rr(ti)指的是过去500ms窗内的最大ackedbitrate
值得注意的是,Incease状态时 A s ( t k ) A_s(t_k) As(tk)的增加策略应该权衡multiplicatively or additively
界定:
如果当前的 R r ( t i ) R_r(t_{i}) Rr(ti)比较接近我们上一次在Decrease阶段的平均的 R r ( t i ) R_r(t_{i}) Rr(ti),我们就认为现在大概率在拥塞的边缘,这时候应该选择加性增。
乘法增:
η = 1.08 ⋅ m i n ( t i m e _ s i n c e _ l a s t _ u p d a t e _ m s / 1000 , 1.0 ) \eta = 1.08 \cdot min(time\_since\_last\_update\_ms / 1000,1.0) η=1.08⋅min(time_since_last_update_ms/1000,1.0)
A s ( t k ) = η ⋅ A s ( t k − 1 ) A_s(t_k) = \eta \cdot A_s(t_{k-1}) As(tk)=η⋅As(tk−1)
加性增:
r e s p o n s e _ t i m e _ m s = 100 + r t t _ m s response\_time\_ms = 100 + rtt\_ms response_time_ms=100+rtt_ms
α = 0.5 ∗ m i n ( t i m e _ s i n c e _ l a s t _ u p d a t e _ m s / r e s p o n s e _ t i m e _ m s , 1.0 ) \alpha = 0.5 * min(time\_since\_last\_update\_ms / response\_time\_ms,1.0) α=0.5∗min(time_since_last_update_ms/response_time_ms,1.0)
A s ( t k ) = A s ( t k − 1 ) + m a x ( 1000 , α ∗ e x p e c t e d _ p a c k e t _ s i z e _ b i t s ) A_s(t_k)= A_s(t_{k-1})+ max(1000,\alpha * expected\_packet\_size\_bits) As(tk)=As(tk−1)+max(1000,α∗expected_packet_size_bits)
最后:
带宽评估不应该过于剧烈
所以最后要有:
A s ( t k ) < 1.5 ⋅ R r ( t i ) A_s(t_k) < 1.5 \cdot R_r (t_{i}) As(tk)<1.5⋅Rr(ti)
R r ( t i ) 指 的 是 过 去 一 段 时 间 内 最 大 a c k e d b i t r a t e R_r(t_{i}) 指的是过去一段时间内最大acked bitrate Rr(ti)指的是过去一段时间内最大ackedbitrate
带宽评估触发的时间间隔 t i + 1 − t i t_{i+1} - t_{i} ti+1−ti应该尽量均匀
WebRTC会根据上述丢包得到的带宽base_bitrate和基于延迟得到的bwe_bitrate得到的最小值,这个最小值作为estimator最终评估出来的码率。
https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02#section-1.1
http://www.sohu.com/a/210713395_629429
http://www.ctiforum.com/news/guandian/535764.html