本文整理自网易云信多媒体资深技术架构师吴桐在 QCon 全球软件开发大会上海站的演讲内容《超高清4K视频低延时直播与RTC融合架构设计》,为该系列的第二篇文章。 回顾该系列第一篇文章 《超高清4K视频低延时直播与RTC融合架构设计①:5G与未来的网络格局》 。 本篇文章中,吴桐从传输协议、拥塞控制算法的选择说起,分享了网易云信对于BBR算法在低延时直播与RTC场景下的优化实践,以及网易云信低延时拓扑的设计方案。
直播火了,这是近几年大家最直观的感受。从2015年开始,各个平台风起云涌、百家齐放,到2016、2017年,大家开始寻求互动连麦直播的差异化体验。如今,直播已经进入下半场,低延时直播成为了新的突破口。
相信很多人都看过《疯狂动物城》,闪电虽然非常可爱,但是谁都不希望直播里的女主播,反应像他这么慢吧。
那么低延时由哪些因素决定呢?
(1)传输维度
-
传输协议
-
拥塞控制算法
-
服务器分发网络
-
第1公里:分配与选路
(2)其它维度
-
发送端采集、编码、前处理延时
-
接收端Jitterbuffer处理延时
-
接收端解码、后处理、渲染与播放延时
今天由于时间关系,我们主要来探讨一下传输维度的决定因素。
传输协议的选择
首先我们来看看传输协议的选择。
1. RTMP协议
RTMP协议是当前应用最广泛的直播推拉流协议,标准的RTMP协议传输层使用的是TCP,所以它的缺陷也是显而易见的:
(1)抗丢包能力差,丢包时发送窗口直接退避导致发送速率很慢;
(2)整体延时不可控,主要依赖于接收端的ACK的可靠传输;
(3)拥塞控制优化成本高,TCP算法拥塞控制策略是在操作系统内核层实现的,想要优化的成本很高,一般只有在服务端做内核层面TCP拥塞控制的相关优化,而客户端只能依赖各平台的操作系统自己做的拥塞控制优化。
综上,标准的RTMP不适用于低延时场景。
2. QUIC协议
想必大家对QUIC(Quick UDP Internet Connection)也不陌生,这两年随着大家对Google QUIC协议研究的深入,不少友商和项目开始用RTMP over QUIC替代传统的RTMP over TCP。
QUIC是一个非常优秀的协议,现在它已经成为HTTP3的标准协议。它的优势大家应该也都有所了解:
(1)0 RTT连接。QUIC底层使用了UDP,所以它可以非常灵活的重新设计一些协议特性,包括可以在首次以1RTT握手建连后,后续握手重连只需0RTT;
(2)支持HTTP2一样的多路复用,同时由于使用UDP协议,所以也解决了队头阻塞问题;
(3)支持FEC,所以相比于TCP抗丢包能力也有所提升;
(4)因为是应用层协议,它可以很灵活的改进拥塞控制,各类拥塞控制算法都可以以可插拔的模式在QUIC中使用。
综上,QUIC很优秀,但是我认为,QUIC作为低延时直播协议也有几点缺陷:
(1)本质上是一个可靠协议,我们没办法方便的主动控制协议延时;
(2)作为一种通用协议,对音视频媒体不友好,没办法理解音视频媒体数据的具体含义,它以一视同仁的角度来对待这些媒体数据。
3. SRT协议
这两年还有一个传输协议进入大家视野,那就是SRT(Secure Reliable Transport)。它由Haivision 和 Wowza共同创建,并于2017开源。它具备以下特点:
-
安全方面:SRT支持AES加密,保障端到端的视频传输安全;
-
可靠性方面:SRT通过前向纠正技术(FEC)保证传输的稳定性;
-
低延迟方面:SRT底层使用UDT协议,UDT协议是一个老牌的基于UDP的可靠传输协议,当然原生的UDT传输延迟是比较高的,SRT在此基础上做了不少的拥塞控制策略的相关优化以降低传输延时。
SRT协议当前还相对小众,我们没有选择它作为我们的传输协议主要原因有两个:
(1)协议复杂度较高;
(2)丢包场景下速度退避较大。
4. 自研低延时传输协议
其实无论是QUIC还是SRT,他们的设计有很多共性:
(1)他们都采用了基于UDP的底层传输协议,我认为这是一个非常正确的方向;
(2)他们都采用了FEC来提高抗丢包能力;
(3)他们都重新设计了拥塞算法来实现更准确的带宽估计、拥塞判断以降低传输延时。
因此我们的选择是:基于UDP协议,自研低延时传输协议,同时应用在低延时直播和RTC场景。
在这里和大家分享我们设计这个协议的主要特征:
(1)协议中支持描述每个包对可靠性以及优先级的不同要求,这样我们在传输的全链路上就可以区分不同可靠性和优先级的数据包做差异化处理;
(2)协议完全面向音视频媒体,可以方便描述各类音视频媒体类型,无论是H.264、H.265、VP8、VP9或者是AV1、VVC都可以直接在协议中描述;
(3)协议支持描述视频分片信息、视频时域分层信息及多流信息,这些信息用于服务器做相关分段QoS策略,以及在接收端更方便的完成视频组包;
(4)支持传输层全局统一序,简化feedback的处理,同时对丢包计算,抖动计算都非常有意义;
(5)支持FEC,特别在高RTT的场景下(如:跨国传输),FEC的合理使用对于抗击随机丢包的意义十分巨大;
(6)协议包在应用层小于MTU切片,这对于对抗丢包以及中间路由非常有意义;
(7)支持扩展丰富的媒体信息,无论是时间戳,视频旋转角度,音频音量等等,这些信息我们部分参考了RTP的设计,当然也简化了RTP的设计;
(8)协议支持携带应用层路由信息,这个对于实现方便的服务器级联以及边缘加速很有意义。
其实RTP已经是一个非常优秀的媒体传输协议了,我们设计协议的目的是在云信的场景及服务器架构下可以更方便地使用,如果大家没有特殊的需求,可以直接使用RTP协议,使用RTP Extension来实现其它相对复杂功能。
在谈好了协议后,我们进入下一步,就是如何选择一个拥塞控制算法。
拥塞控制算法选择
拥塞控制算法在音视频领域一直都是一个热门话题,而且也是业界一直在不停探索的一个方向。
1. TCP拥塞控制算法
TCP协议里,从最早的Reno、BIO到现在广泛使用的Cubic算法,都有非常巧妙的算法和数学原理,由于他们是基于丢包的,所以此类拥塞控制算法对于丢包过于敏感,同时延时不可控,因此无法用于低延时传输。
2. GCC
GCC算法是大家普遍使用的一个RTC里的拥塞控制算法,它也是开源WebRTC当前默认使用的,算法是主要基于时延+丢包,核心模块有三个:
(1)到达时间滤波器;
(2)过载检查器;
(3)速率控制器。
GCC算法这几年也在不断的更新迭代,早期带宽在接收端估计,发送端在媒体包头上需要携带abs-sendtime,接收端采用的是卡尔曼滤波器,估算出带宽后用REMB协议带回发送端;后来带宽估计在发送端来做,发送端在媒体包头上需要携带统一序transport-sequence-number,然后接收端将收包信息,主要包括收包时间等使用transportCC报文带回发送端,在发送端采用线性滤波器进行相关带宽估计。
因为GCC算法在业界比较成熟,这里我就不多做介绍,简单分享一下我们在实践的过程中发现的几个问题:
(1)带宽估计不够准确,特别是低带宽时会过降;
(2)与TCP竞争会过度退避;
(3)在时延抖动场景,带宽波动大。
当然这些问题,随着GCC的持续优化有些会逐渐被优化,但是有些问题却是在GCC框架下无法解决的。后来,我们关注到了BBR。
3. BBR
BBR(Bottleneck Bandwidth and Round-trip propagation time)是2016年由谷歌提出并推广的,BBR算法是基于带宽和延迟反馈的算法。BBR算法有很多优点,我认为其中最核心的三点是:
(1)算法思想是尽量不排队,保持低延迟;
(2)带宽估计准确;
(3)在多数场景下与传统TCP基于丢包的拥塞控制算法竞争,不吃亏。
网易云信从2018年开始,在项目中使用BBR,并进行了BBR在低延时领域的相关优化,今天想和大家简单谈谈BBR算法在低延时直播与RTC领域的一些使用心得。
BBR在低延时直播与RTC场景下的应用
BBR算法的核心就是找到当前链路的最大带宽和最小延时。最大带宽和最小延时的乘积就是BDP, BDP就是网络链路中可以存放数据的最大容量。知道了BDP就可以解决应该发送多少数据的问题,而网络最大带宽可以解决用多大速度发送的问题。因此BBR也就是解决了该不该发,以及发多快这两件事。
我们来看一张很经典的图,图片来自BBR作者的分享内容,图中横轴是网络链路中的数据量,纵轴分别是RTT和带宽。可以发现在RTT不变的时候,带宽一直在上升,因为这个时候网络没有拥塞,而带宽停止上涨的时候RTT持续变大,一直到发生丢包。因为这个时候,网络开始拥塞,报文累积在路由器的buffer中,这样RTT持续变大,而带宽不会变大。
图中红色虚线框所标识的就是理想情况下最大带宽和最小延时。很明显,要找到BDP, 很难在同一时刻找到最小的RTT和最大带宽。这样最小RTT和最大带宽必须分别探测。
探测最大带宽的方法就是不断增加发送的数据量,把网络中的buffer占满,直到带宽在一段时间内不会增加,这样可以得到此时的最大带宽。
探测最小RTT的方法就是尽量把buffer排空,让数据传输延时尽量低。
BBR的状态机分为4个阶段,Startup,Drain,ProbeBW, ProbeRTT。
-
Startup
Startup类似于普通拥塞控制里的慢启动,增益系数是 2/ln2 = 2.88,每一个来回都以这个系数增大发包速率,估测到带宽满了就进入 Drain状态,连续三个来回,测得的最大带宽没有比上一轮增大25%以上,进入Drain状态机。
-
Drain
进入 Drain状态,增益系数ln2/2小于 0.3,也就降速了。一个包来回,把 Startup状态中超发的数据排空,怎样才算队列排空了?发出去还没有 ACK 的数据包量即为 inflight,inflight < BDP 说明排空了,如果 inflght > BDP 说明还不能到下一个状态,继续保持 Drain状态。
-
ProbeBW
ProbeBW是稳定状态,这时已经测出来一个最大瓶颈带宽,而且尽量不会产生排队。之后的每个来回,在 ProbeBW状态循环(除非要进入下面提到的 ProbeRTT状态),轮询下面这些增益系数,[1.25, 0.75, 1, 1, 1, 1, 1, 1],如此,最大瓶颈带宽就会在其停止增长的地方上下徘徊。98%的时间都应该处于 ProbeBW状态。
-
ProbeRTT
前面三种状态,都可能进入 ProbeRTT状态。超过十秒没有估测到更小的 RTT 值,这时进入 ProbeRTT状态,把发包量降低,空出道路来比较准确得测一个 RTT 值,至少 200ms 或一个包的来回之后退出这个状态。检查带宽是否是满的,进入不同的状态:如果不满,进入 Startup状态,如果满,进入 ProbeBW状态。