WebRTC的拥塞控制技术(Congestion Control)
Posted 音视频开发老马
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebRTC的拥塞控制技术(Congestion Control)相关的知识,希望对你有一定的参考价值。
\\1. 概述 对于共享网络资源的各类应用来说,拥塞控制技术的使用有利于提高带宽利用率,同时也使得终端用户在使用网络时能够获得更好的体验。在协议层面上拥塞控制是TCP的一个总要的组成部分;但是对于非面向链接的传输层协议,如UDP,其在协议层面上并没有对拥塞控制进行强制性的要求,这样做保证了最优的传输性能,且在拥塞控制的设计上也保留了更大的灵活性。 WebRTC为我们提供了强大的音视频媒体引擎,前端开发者可以通过调用几个简单的js接口就能实现基于Web浏览器的实时音视频通信。而在媒体数据传输上,WebRTC采用了实时性较强UDP协议,并使用了RTP/RTCP技术。本文的主要内容就是介绍WebRTC中基于RTP/RTCP实现的拥塞控制技术。
\\2. 拥塞控制算法 WebRTC采用了两种拥塞控制算法:(1)基于延迟(delay-based)的拥塞控制算法;(2)基于丢包(loss-based)的拥塞控制算法。算法(1)由数据的接收方实现,接收方需要记录每个数据包到达的时间和大小,并计算每个数据分组之间(inter-group)的延迟的变化,由此判断当前网络的拥塞情况,并最终输出码率估计值由RTCP feedback(TMMBR或 REMB)反馈给发送方;算法(2)则由数据的发送方来实现,发送方通过从接收方周期性发来的RTCP RR(Receiver Report)中获取丢包信息以及计算RTT,并结合TMMBR或REMB中携带的码率信息算得最终的码率值,然后由媒体引擎根据码率来配置编码器,从而实现码率的自适应调整。从上面的描述可以看出,这两个算法在系统中并不是孤立存在的。
2.1 基于延迟(delay-based)的拥塞控制算法
基于延迟的拥塞控制算法可以分成以下4个部分:(1)到达时间模型(arrive-time model);(2)预过滤(Pre-filtering);(3)到达时间滤波器(arrive-time filter);(4)过载检测器(over-use detector)。
2.1.1 到达时间模型(arrive-time model)
设相邻两个数据分组到达接收方的时间间隔为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,就说明数据在网络传输时存在延迟的现象。 在WebRTC中延迟变量d(i) = w(i)被视为随机过程W中一个采样点,并且是链路承载能力、网络当前传输状况以及当前发送速率等因素综合作用的结果。该随机过程W符合正态分布。当网络发生过载(over-use)时,我们期望w(i)会上升;当网络空闲(Under-use)时,则期望w(i)会下降。 测量方程进一步改写为 d(i) = m(i) + v(i),其中m(i)符合均值为0的正态分布(标准正态分布),v(i)表示为网络抖动等因素带来的对数据延迟的影响。
2.1.2 预过滤(Pre-filtering)
预过滤的目的是处理由于通道中断造成的延迟瞬间变大的情况。在通道发生中断时,数据包会持续进入网络队列中,而当通道恢复时,所有的数据包会在一个burst时间(5 ms)里面全部发送,而这些数据包可能原先包分布于多个数据分组。而预过滤所要做的就是将这些在同一个burst时间里发送的数据包合为一个数据分组。 这里涉及到了WebRTC中关于数据传输的一个设计--PacedSender。Encoded数据完成RTP封装之后先是被保存在本地应用的队列中,而不是直接发送到网络。此时可以将PacedSender视为一个数据发送的节拍器,它每隔一个burst时间启动一次,启动之后会将队列中的RTP包全数发出。 数据包会在下面两种情况下被划分到一个数据分组:
-
在同一个burst时间区间内被发送的数据包序列;
-
一个数据包与相邻数据包的到达时间间隔小于一个burst时间,同时d(i) < 0,那么这个数据包将会被划到当前的分组中。
★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
2.1.3 到达时间滤波器(arrive-time filter)
在此系统希望通过预测m(i)来检测当前的网络是否过载;而这里所采用的预测方法是卡尔曼滤波(Kalman filter)。
状态方程:m(i+1) = m(i) + u(i), 其中u(i)表示为状态噪声,符合0均值正态分布。
测量方程:d(i) = m(i) + v(i), 其中v(i)表示为测量噪声,符合0均值正态分布。 卡尔曼滤波器根据“5组公式”来迭代更新m(i) 的估计值m_hat(i),该估计值m_hat(i)则是下文过载检测器的检测依据。关于卡尔曼滤波器如何实现预测的详细介绍在这里就不做展开了,可参考文献[3]。
2.1.4 过载检测器(over-use detector)
通过Kalman 滤波器能够获得延迟变量m(i)的估计值,而过载检测器的工作原理其实就是通过m(i)与阈值del_var_th进行比较来对当前的网络拥塞状况进行检测。如果m(i) > del_var_th且m(i) > m(i-1),同时该状态至少持续了overuse_time_th毫秒,则判断为网络过载(Over-use);如果m(i) < -del_var_th,则判断为网络空闲(Under-use);剩余的情况都被判断为Normal状态。
由此可见,阈值del_var_th的设计对于整个算法的性能来说至关重要。如果del_var_th的值设得过大,那么整个算法的动态就会显得过于平滑,此时只有在数据分组严重delay时检测器才会触发over-use的信号;相反的,如果del_var_th的值设得过小,那么检测器就会对delay非常敏感,从而导致频繁触发over-use信号。因此,WebRTC提出了针对阈值del_var_th的动态调整算法: del_vat_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-1)时K(i)=K_d;否则,K(i)=K_u。 在WebRTC中本小节所涉及的各参数的参考值如下: del_var_th(0) = 12.5 ms, overuse_time_th = 10 ms, K_u=0.01, K_d=0.00018
2.1.5 速率控制(rate control)
速率控制子系统根据当前网络的拥塞情况(由过载检测器提供),计算带宽估计值并请求发送方对速率进行调整。该子系统通过有限状态机对速率进行自适应调整。其状态迁移如下图所示:
-
状态 Increase: 表明当前没有检测到网络拥塞,在此状态下传输速率需要逐步增加;它先是通过乘性增加来调整速率(乘性因子为1.08),当速率接近临界值时再通过加性增加逐步收敛,而这里所谓的临界值是指上一次在状态Decrease 时统计的下行码率;
-
状态 Decrease: 表明当前检测到了网络拥塞,在此状态下传输速率需要逐步下降;在这里,WebRTC所采用的方法是乘性下降,其乘性因子为0.85;
-
状态 Hold: 表明保持当前的速率不做改变。
速率控制子系统最终会输出一个带宽估计值A_hat,并通过RTCP Feedback(TMMBR/REMB)请求发送方进行速率调整。 2.2 基于丢包(Loss-based)的拥塞控制算法 基于丢包的拥塞控制是通过对丢包率,RTT和带宽估计值A_hat这三个参数进行决策而实现的。其中带宽估计值A_hat正是由上节中的速率控制子系统所提供。 基于丢包的拥塞控制在每次收到对方发送RTCP之后都会运行:
-
当丢包率保持在[2%, 10%]时,当前数据发送方的带宽估计值As_hat保持不变;
-
当丢包率大于10%时,带宽估计值将会降低:As_hat(i) = As(i-1)*(1-p),其中p为丢包率;
-
当丢包率小于2%时,带宽估计值将会上升:As_hat(i) = As(i-1)*1.05。
As_hat更新之后将与A_hat进行比较,然后取两者中的较小值作为最终的带带宽估计值。 其实在原生的代码中,系统还会将丢包率和RTT作为参数,通过TFRC [RFC 5348]的吞吐率计算公式对当前的带宽进行估计,而最终的估计值则是取三者中的最小值。
\\3. 后语 通过上文的介绍,我们知道WebRTC中的拥塞控制算法还是非常完备的。其分别针对数据包的延迟和丢包设计了delay-based和loss-based拥塞控制算法,在两者的共同作用之下,WebRTC能够满足大部分场景下的实时视频通话业务。但是,如果有要对WebRTC中的媒体引擎进行移植的朋友,首先要分析一下WebRTC的拥塞控制算法是否满足你的业务需求:如果是开发独立应用,由于业务闭环,直接使用现有的算法应该问题不大;但是,如果是用于开发提供类似VoLTE/VoWIFI这样的运营商增值服务的应用,需要依据运营商的技术手册和3GGP协议等来对拥塞控制算法进行适配。
Reference
[1] A Google Congestion Control Algorithm for Real-Time Communication draft-ietf-rmcat-gcc-02
[2] RFC 5348
[3] http://blog.csdn.net/xiahouzuoxin/article/details/39582483
[4] 3GPP TS 26.114
作者:qiuyi943
★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
TCP Congestion Control
参考技术Arfc5681 详细说明了TCP的四个拥塞控制算法:慢启动、拥塞避免、快速重传和快速恢复。
或者,利用选择性确认 (SACK) 的 TCP 可以利用 SACK 信息来确定何时传入的ACK是“重复”。
慢启动和拥塞避免算法在TCP发送端使用,用于控制进入网络的数据量。
为了实现这两个算法,在TCP的per-connection阶段引入了两个变量:
开始向未知情况的网络进行传输时要求TCP 缓慢探测网络以确定可用带宽 ,从而避免不适当的爆发数据造成网络拥塞。慢启动算法的目标:在 传输开始阶段(采用慢启动算法) 和 重传定时器检测到丢包之后(重启慢启动算法) 避免网络拥塞。另外,慢启动使用"ACK clock"。"ACK clock"在TCP发送端使用,被用于 慢启动、拥塞避免 以及 丢包恢复算法。
cwnd 的初始值 IW 根据 SMSS 的大小而设置 :
ssthresh 可以设置为任意高度 ,但 ssthresh 在遇到拥塞时必须降低。将 ssthresh 设置尽可能高可以自适应网络条件,而不是一些采用任意的主机限制来决定发送速率。在某些 cases 下,例如系统对网络路径有充分的了解,那么更谨慎地设置 ssthresh 初始值可能有好处。
何时使用慢启动算法、拥塞避免算法
在慢启动期间,TCP的cwnd在每接收到一个新数据的递增确认的ACK后至少增长SMSS个字节。当cwnd的大小超过ssthresh后或当观察到拥塞后 慢启动结束。虽然传统的 TCP 实现会在收到覆盖新数据的 ACK 后精确地通过 SMSS 字节增加 cwnd,但我们建议 TCP 实现增加 cwnd:
其中 N 是在到来的 ACK 中确认的先前未确认的字节数(接收端会采用累积确认、延迟确认等算法,因此存在先前未确认的字节数)。并且不能每个ACK都增加cwnd的大小,毕竟会存在重复的ACK。
在拥塞避免期间,TCP的cwnd在每个往返时间(RTT)增加一个 full-sized segment。拥塞避免算法持续到发生拥塞。在拥塞避免期间增加 cwnd 的基本准则是:
在拥塞避免期间增加 cwnd 的推荐方法是计算新数据的 ACK 已确认的字节数 (同 slow start),但不能每个 RTT 触发的 cwnd 的增长不能超过 SMSS bytes。当确认的字节数达到 cwnd,可以增长 SMSS bytes 。
在拥塞避免期间,TCP可以使用的另一个通用的公式是:
在每个确认新数据的 ACK 到来时执行此调整。该公式为每个 RTT 将 cwnd 增加 1 个 full-sized segment 的基本原理提供了可接受的近似值。
实现说明:
同:
异:
当TCP发送端通过重传定时器检测到 segment loss 且该 segment 尚未通过重传定时器重新发送时, 此时 ssthresh 的值必须重新设置为不超过下列等式中给出的值:
其中,FlightSize 是网络中未完成数据的数量。
另一方面,当TCP发送端通过重传定时器检测到 segment loss 且该 segment 已经通过重传定时器重新发送至少一次时,此时 ssthresh 的值保持不变。
实现说明:
此外,在超时(Retransimission Timer)时,cwnd 必须设置为不超过丢失窗口 LW,LW 等于 1 个 full-sized segment(无论 IW 的值如何)。 因此,在重传 loss segment 后,TCP 发送方使用慢启动算法将窗口从1 个 full-sized segment 增加到新的 ssthresh 值,此后再次使用拥塞避免算法。
超时后基于慢启动的丢失恢复(loss recovery)可能会导致虚假重传,从而触发重复确认。 在 TCP 实现中,对这些重复 ACK 到达的反应差异很大。 本文档没有具体说明如何处理此类确认,但可以指出这是一个可以从额外关注、实验和规范中受益的领域。
当一个乱序的 segment 到达时,TCP的接收端立即发送一个重复的 ACK 。这个 ACK 的目的是通知 发送端:接收端接收到了一个乱序的 segment 以及接收端目前期待收到的序列号。从发送端的视角来看,重复的 ACK 可能会引起一些网络问题。
另外,当TCP 的接收端接收到的 segment 填充空间中全部或部分间隙时,TCP接收端应该立即发送 ACK 。这将为发送方的超时重传、快速重传或高级丢失恢复算法等方法提供更及时的信息。
TCP发送端基于到来的重复ACK,使用快速重传算法来检测和修复丢包。
快速重传算法 :快速重传算法使用3个重复的ACK作为一个segment已丢失的指示,在接收到3个重复的ACK后,TCP重新传输看似丢失的segment,而无需等待重传计时器的触发。
快速恢复算法 :在快速重传算法发送看似丢失的 segment 之后,快速恢复算法控制新数据的传输,直到非重复的ACK到达。
收到重复的ACK不执行慢启动的原因:收到重复的ACK不能完全表明一个 segment 已经丢失,因为该部分 segment 最可能已经离开了网络(segment 在接收端的缓冲区中,不再被视作网络资源)。此外,由于保留了 ACK 的时钟(重传定时器),TCP发送端可以继续传输新的 segments 。
上面描述的 TCP 拥塞控制算法的一个已知问题是:TCP在空闲一段相对长的时间之后,TCP将被允许传输潜在的不适当的流量突发。
[Jac88] 建议 TCP 在相对较长的空闲期后使用慢启动来重新启动传输。 慢启动用于重新启动 ACK 时钟,就像它在传输开始时所做的那样。 该机制已以下列方式广泛部署。 当 TCP 在超过一次重传超时时长后仍未收到一个 segment 时,cwnd 会在传输开始前减小到重新启动窗口 (RW) 的值。
出于本标准的目的,我们定义RW = min(IW,cwnd)。
因此,如果 TCP 在超过重传超时的时间间隔内没有发送数据,则 TCP 应该在开始传输之前将 cwnd 设置为不超过 RW。
[RFC112] 提出的 延迟应答算法 可以应用在TCP的接收端。当然在采用 延迟应答 时,TCP的接收端不必过度延迟应答。
延迟应答的算法:
在某些情况下,发送方和接收方可能无法就什么构成 full-sized segment 达成一致。 如果每次从发送方接收到 2*RMSS 字节的新数据时至少发送一个 ACK,则认为实现符合此要求,其中 RMSS 是接收方指定给发送方的最大段大小(或默认值 536 字节,根据 [RFC1122],如果接收方在连接建立期间未指定 MSS 选项)。
当检测到数据窗口中的第一次丢失时,ssthresh 必须设置为不超过等式 给出的值。 其次,在修复新的数据窗口中的所有 lost segments 之前,每个 RTT 中传输的segments 必须不超过检测到丢失时未完成的segment的数量的一半。 最后,在给定的段窗口中的所有损失
最后,在给定的段窗口中的所有丢失都已成功重传后,cwnd 必须设置为不超过 ssthresh,并且必须使用拥塞避免来进一步增加 cwnd。 在两个连续的数据窗口中丢失,或丢失重传,应被视为拥塞的两个指示,因此,在这种情况下,cwnd(和 ssthresh)必须降低两次。
我们建议 TCP 实施者采用某种形式的高级丢失恢复,可以应对数据窗口中的多个丢失。 [RFC3782] 和 [RFC3517] 中详述的算法符合上述一般原则。 我们注意到,虽然这不是符合上述一般原则的仅有的两种算法,但这两种算法已经过社区审查,目前处于标准轨道上。
本文档要求 TCP 在重传超时和重复确认到达的情况下降低其发送速率。 因此,攻击者可以通过导致数据包或其确认丢失,或者通过伪造过多的重复确认来损害 TCP 连接的性能。
为了响应 [SCWA99] 中概述的 ACK 分割攻击,本文档建议根据每个到达的 ACK 中新确认的字节数而不是每个到达的 ACK 上的特定常量来增加拥塞窗口( cwnd += min (N, SMSS) ,N 是在到来的 ACK 中确认的先前未确认的字节数)。
互联网在很大程度上依赖于这些算法的正确实施,以保持网络稳定性并避免拥塞崩溃。 攻击者可以通过伪造过多的重复确认或对新数据的过多确认,使 TCP 端点在面对拥塞时做出更积极的响应。 可以想象,这样的攻击可能会使网络的一部分陷入拥塞崩溃。
以上是关于WebRTC的拥塞控制技术(Congestion Control)的主要内容,如果未能解决你的问题,请参考以下文章