文 / Boris Grozev
译 / 元宝
审校 / 刘连响
原文 https://webrtchacks.com/sfu-cascading/
部署WebRTC媒体服务器有两个主要挑战,一个是扩展到多个服务器,另一个是优化会议中所有用户的媒体延迟。虽然像“将会议X中的所有用户发送到服务器Y”这样的简单分片方法很容易横向扩展,但就媒体延迟而言,它们远不是最佳的,而媒体延迟是用户体验的关键因素。将会议分发到位于用户附近并在可靠骨干网上相互连接的服务器,可以同时解决这两个问题。来自Jitsi团队的Boris Grozev深入描述了级联SFU问题,并展示了他们的方法以及他们遇到的一些挑战。
“老鼠的神经元”,图片来自NIHD(CC-BY-2.0)
实时通信应用程序对吞吐量、延迟和丢包等网络条件非常敏感。较低的比特率会导致较低的视频质量,更长的网络延时会导致端到端的音视频延迟, 数据丢包会引起音频的不连贯以及视频的卡顿。
因此,在会议中选择端点之间的最佳路径非常重要。当只有两个参与者时,这就比较简单了——WebRTC使用ICE协议在两个端点之间建立连接以交换多媒体。如果可能,两个端点直接连接,否则在不太典型的情况下使用TURN中继服务器。WebRTC支持解析域名以获取TURN服务器地址,这使得可以轻松地选择基于DNS的本地TURN服务器,例如使用AWS Route53的路由选项。
但是,当一个会议有更多的参与者通过中央媒体服务器路由时,情况就复杂得多。许多WebRTC服务,如Hangouts,seem.in,Slack和我们自己的meet.jit.si,使用选择性转发单元(SFU)来更有效地在3个或更多参与者之间传递音频和视频。
星形拓扑问题
在这种情况下,所有端点都连接到一个中央服务器(采用星形拓扑结构),与之交换多媒体。很明显,选择服务器的位置会对用户体验产生巨大影响——如果会议中的所有参与者都位于美国,这时候使用一台在悉尼的服务器就不是一个好的主意。
大多数服务使用一种在很多时候都能很好地运行的简单方法——它们选择靠近会议中第一个参与者的服务器。但是,在某些情况下,这并不是最优的。例如,假设我们有三个参与者,如上图所示,其中两个位于美国东海岸,第三个是在澳大利亚。如果澳大利亚参与者(来电者C)首先加入会议,则此算法选择澳大利亚的服务器(服务器2),但美国的服务器1是更好的选择,因为它更接近大多数参与者。
诸如此类的场景并不常见,但确实会发生。假设参与者加入的顺序是随机的,这种情况发生在有3名参与者的会议中,其中一个是在一个偏远的位置。
另一种更常发生的情况如下图所示:我们在两个地点有两组参与者。在这种情况下,加入的顺序无关紧要,我们将始终拥有一些彼此接近的用户,但他们的媒体必须通过远程位置的服务器。例如,在下图中,有2名澳大利亚来电者(C&D)和2名美国来电者(A&B)。
切换到服务器1对于呼叫者C和D来说不是最佳的选择。对于呼叫者A和B,服务器2不是最佳的选择。无论我们使用服务器1还是服务器2,都会有一些参与者通过非最佳远程服务器连接。
如果我们不限于使用一台服务器呢?我们可以让每个参与者都连接到本地服务器,我们只需要互连服务器。
解决方案:级联
稍后再说我们如何实际互连服务器的问题,让我们首先看看它对会议的影响。
从C到D的SFU连接没有改变——仍然通过服务器2。对于A和B之间的连接,我们使用服务器1而不是服务器2,如上图所示,这显然更好。有趣的部分实际上是从A到C(或任何其他效果类似的连接)的连接。我们使用A <=>服务器1 <=>服务器2 <=> C而不是使用A <=>服务器2 <=> C.
非直连传输时间影响
像这样连接SFU网桥既有优点也有缺点。一方面,我们的研究结果表明,在这种情况下当我们添加额外的跳数时,端到端往返时间会更高。另一方面,减少从客户端到它连接的第一个服务器的往返时间本身就具有优势,因为我们可以在逐跳基础上以更低的延迟执行流修复。
这是如何运作的?WebRTC使用RTP(通常通过UDP)传输媒体。这意味着运输不可靠。当UDP数据包在网络中丢失时,由应用程序决定是忽略/隐藏丢失,还是使用RTCP NACK数据包请求重传。例如,应用程序可能选择忽略丢失的音频数据包,并请求一些但不是全部视频数据包的重传(取决于它们是否需要解码后续帧)。
使用单个服务器的RTP数据包重新传输
使用级联桥接器,这些重传可以限于本地服务器。例如,在A-S1-S2-C路径中,如果包在A和S1之间丢失,则S1将通知并请求重传。如果在S2和C之间丢失数据包,C将请求重传,S2将从其高速缓存中响应。如果两个服务器之间丢失数据包,则接收服务器可以请求重传。
使用两台服务器进行RTP数据包重传。请注意,服务器2不会重新传输数据包2,因为NACK在数据包发送后很快就会到达。
客户端使用抖动缓冲器来延迟视频的播放,以便允许延迟或重传的数据包到达。此缓冲区的大小部分基于往返时间动态变化。当逐跳执行重传时,延迟较低,因此抖动缓冲区可以更短,从而降低整体延迟。
简而言之,尽管使用额外的服务器,端到端往返时间会更高,但可以使得端到端媒体延迟降低(但我们还没有在实践中探索这种影响)。
实现级联SFU
那么我们如何在Jitsi Meet中实现它,以及如何在meet.jit.si上部署它?
信号与媒体
让我们先看看信号。从一开始,Jitsi Meet就将信令服务器(现在是Jicofo)和媒体服务器/ SFU(jitsi-videobridge)的概念分开。这种分离允许我们相对容易地实现对级联桥的支持。首先,我们可以将所有信号逻辑保持在一个中心位置——Jicofo。其次,我们已经拥有了Jicofo和Jitsi Videobridge(COLIBRI)之间的信令协议。我们只需要为它添加一个小扩展。我们已经支持连接到一个信令服务器的多个SFU(用于负载平衡)。现在我们必须为一个SFU添加选项以连接到多个信令服务器。
我们最终得到了两个独立的服务器池——一个jicofo实例池和一个jitsi-videobridge实例池。下图说明了部分内容。
AWS上的Jitsi Meet Setup示例允许跨不同数据中心进行桥接级联
我们系统的第二部分是桥到桥通信。我们希望保持这部分尽可能简单,因此我们决定不在桥之间做任何明确的信号传递。所有信令都发生在jicofo和jitsi-videobridge之间,两个网桥之间的连接仅用于来自客户端的音频/视频和数据信道消息。
Octo协议
为了协调这种通信,我们提出了Octo协议,它将RTP数据包封装在一个简单的固定长度报头中,并允许传输字符串消息。在当前的实现中,桥接器以全网状连接到彼此,但是该设计也允许其他拓扑。例如,使用中央中继服务器(桥的星形)或为每个桥使用树结构。
脚注:请注意,不是预先添加Octo标头,而是可以将其添加为RTP标头扩展,使网桥之间的流成为纯RTP。未来版本的Octo可能会使用这种方法
第二个脚注:Octo并不真正代表什么。我们最初计划使用中央继电器,出于某种原因,它让我们想起了一只章鱼,所以我们为这个项目保留了这个名字。
Octo标题格式
在Jitsi Videobridge术语中,当桥接器是多桥会议的一部分时,它有一个额外的Octo通道(实际上是一个音频通道和一个视频通道)。该通道负责将媒体转发到所有其他网桥,以及接收来自所有其他网桥的媒体。每个网桥绑定到Octo的单个端口(默认为4096),这就是为什么我们需要会议ID字段能够同时处理多个会议。
目前,该协议没有自己的安全机制,我们将这个责任委托给更低的层。这是我们希望接下来要做的事情,但目前桥梁需要在一个安全的网络中(我们使用单独的AWS VPC)。
与Simulcast一起使用
Jitsi Meet的一个显着特征是支持 simulcast ,其中每个参与者发送多个不同比特率的流,并且桥帮助选择所需的比特。我们希望确保它继续稳健地工作,因此我们转发桥之间的所有联播流。这允许在流之间更快地切换(因为本地桥不必请求新流)。但是,它在桥到桥流量方面并不是最优的,因为有些流通常不会被使用,只是消耗额外的带宽而没有任何好处。
活跃发言人选择
我们还希望继续支持会议中的活跃发言人。事实证明这很简单——我们只是让每个桥接器独立地进行主导说话人识别,并通知其本地客户端(这也是其他人使用过的方法)。这意味着计算需要多次完成,但它并不昂贵,并且允许我们简化事情(例如,我们不必决定哪个桥接DSI,并且担心路由消息)。
桥的选择
通过当前的实现,桥的选择算法很简单。当新参与者加入时,Jicofo需要决定分配给它的桥。它是基于客户端的区域以及可用桥梁的区域和负载来实现的。如果在与客户端相同的区域中存在可用的桥,则使用它。否则,使用现有的一个会议桥。
有关设置Octo的文档,请参见此处(https://github.com/jitsi/jitsi-videobridge/blob/master/doc/octo.md)。
部署级联SFU
我们现在已经在meet.jit.si上启用了地理桥级联,如上所述。
对于此部署,我们在Amazon AWS中运行所有计算机。我们在六个地区拥有服务器(信令和媒体):
▪ us-east-1(弗吉尼亚北部),
▪ us-west-2(俄勒冈州),
▪ eu-west-1(爱尔兰),
▪ eu-central-1(法兰克福),
▪ ap-se-1(新加坡),
▪ ap-se-2(悉尼)。
我们使用一层 地理定位的HAProxy实例 来帮助确定客户端来自哪个区域。meet.jit.si域由Route53管理并解析为HAProxy实例,该实例将其自己的区域添加到它转发的请求的HTTP头。然后这个头用于设置变量 config.deploymentInfo.userRegion的值,这个值通过/config.js文件提供给客户端 。
对于诊断和演示此功能,meet.jit.si上的用户界面显示了正在使用的桥数以及每个参与者连接的位置。本地缩略图的左上角部分滚动显示服务器数量以及所连接服务器的区域。滚动远程缩略图会显示远程参与者所连接的服务器区域,以及浏览器与他们之间的端到端往返时间(如E2E RTT)。
您可以通过检查Jitsi Meet中每个人的连接位置来查看是否正在使用桥接级联。
结论
我们最初是在8月份,在meet.jit.si上推出了Octo作为A / B测试。初步结果看起来不错,现在每个人都可以使用。我们需要处理大量数据,我们计划详细了解Octo的执行情况并撰写更多相关信息。我们还计划将这项工作作为支持大型会议的第一步(单个SFU是不够的)。所以在接下来的几个月里,请继续关注这方面的更多内容。
————————————————
版权声明:本文为CSDN博主「LiveVideoStack_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/vn9PLgZvnPs1522s82g/article/details/84669933
「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。