【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

抖音世界杯中 RTC 的技术挑战与实现

作者:叶峰峰

  • 2023-04-30
    北京
  • 本文字数:7048 字

    阅读完需:约 23 分钟

抖音世界杯中 RTC 的技术挑战与实现

本文整理自火山引擎 RTC 互娱解决方案负责人 叶峰峰 在 2022 QCon 北京站的分享《抖音世界杯中 RTC 的技术挑战与实现》


今天给大家分享的内容是抖音世界杯中 RTC 的技术挑战与实现。我们将探讨两个问题,第一个是世界杯和 RTC 有什么样的关系,或者说 RTC 在抖音世界杯里边承担了什么样的玩法。第二个问题是在这个场景下,我们会遇到什么样的技术挑战,而我们是怎么样去解决优化的。


本次演讲共分为 5 个部分:

1、抖音世界杯“边看边聊” 介绍;

2、整体方案与技术挑战 ;

3、超高并发的问题优化和实践;

4、音频体验问题的优化和实践;

5、总结与展望。

抖音世界杯“边看边聊”介绍



回顾一下过去几年我看世界杯的经历,大概分为以下几个阶段。第一个阶段是我们大学阶段,在大学里边看世界杯的时候,当出现比较精彩的进球或者比赛结束的时候,整个宿舍楼都在欢呼,有非常好的观赛体验。左下是 2018 年世界杯决赛观赛的照片,当时是在一个酒吧里边看球,有我们的同学和同事,大家一起在线下看球聊球,也有非常好的观看体验。2022 年抖音把世界杯搬到了我们的手机上,我们在移动端、PC 端以及 web 端实现了全端的 4k 超高清 50 帧高帧率 2.5 秒超低延时,实现了广播级广电级的直播体验,给广大球迷带来了很好的观赛体验,也收获了大家的好评。



但是在这个场景下,我们发现有一个比较严重的问题,就是在一个千万人在线的直播间里边,公屏消息很难承载有效的实时互动。这个问题要怎么解决,我们考虑加入一个边看边聊的功能来提升我们直播间里面的有效互动。大家可以看一下右边这个图,就是我们在世界杯直播间里的聊天频道增加了一个边看边聊的入口,用户可以去创建自己的私人频道,然后通过抖音、站内信或者是微信链接的方式,把你的频道分享给你的好友,一起来边看边聊。


业务侧做边看边聊功能提出三个诉求,首先希望提升我们直播间里面的有效互动,好友之间的互动肯定会比公屏里边的互动更加高效,我们希望整个直播间里边看边聊的互动可以提升 5 倍到 10 倍。其次大家可以通过边看边聊这个功能去分享你的直播间,让更多的用户加入到我们的直播间里面来,提升直播间的分享和看播的渗透。最后我们希望好友之间观看的时候获得更强的陪伴感,这样的话可以有效增加大家的看播时长。



在边看边聊场景里边,除了可以发送文字、表情、语音这样的信息来和其他人互动。最重要的,我们为了更进一步增强实时互动的体验,增加了实时语音互动的功能。单个频道最多允许 500 人,也就是说你可以创建一个频道,邀请 500 个好友加入你的频道里边来实时互动交流。在频道里边允许 9 个用户同时上麦聊天,另外 491 个用户不发言,并支持用户上麦下麦、本地静音、关闭远端声音等操作。这都是我们 RTC 的一些基础能力,然后为了更好支持业务目标,为了保障整体方案的稳定,我们在支持业务的时候,RTC 侧实时语音互动也定了指标。


第一个是希望我们的边看边聊的实时语音互动的 PCU 是 100 万,当然大家可能会觉得 100 万并不高,为什么没定太高?因为在直播间里边渗透到我们边看边聊玩法里边有一个渗透率的概念,在边看边聊里边可能有的人还不会开启语音互动,所以我们整体的边看边聊场景实时语音互动的 PCU 当时定义的是 100 万。

第二个是希望我们 RTC 整体的服务是稳定的,定了一个目标是 SLA 大于 99.9%。


第三个是希望我们的客户端在这个场景里边是稳定的,所以我们定义 RTC 的 SDK 的 Crash 率小于万分之一。


最后,我们希望在整体的直播整个过程中,用户的体验是良好的,所以希望我们线上用户的整体音频相关问题的反馈率低于万分之一。

整体方案与技术挑战

我们接下来看一下整体的 RTC 相关技术方案和技术挑战。

技术方案

在我们确定要做这个功能的时候,我们就开始讨论我们的技术方案。



第一个方案它是一个语音聊天室,在这个方案里边,思路是每个用户都从我们的 CDN 来拉取直播的比赛流,麦上的用户语音聊天的时候,加入我们的 RTC 系统来和麦上的用户进行语音聊天,同时后端启用一个旁路推流的功能,把聊天的内容发送到 CDN 上面去,麦下的 491 个用户可以拉取另外一路 CDN 流来收听麦上用户的聊天。


为什么会选择这个方案?因为这个方案是一个可以复用线上语音聊天室的业务架构的方案,我们业务里边的上麦下麦还有相关的流程都是比较成熟的,我们可以快速搭建这样的玩法。


但是这个方案存在一个比较严重的问题,就是没上麦的用户听到的聊天内容会有比较大的延时,比如用户会在进球后大约 1-3 秒才能听到麦上用户聊进球相关的内容,这是一个比较严重的方案缺陷。


为了更进一步让所有用户都能实时参与到实时语音互动里面去,我们最终选择了我们 RTC 的互动语聊方案。



在这个方案里,客户端每一个用户仍然会从直播 CDN 拉取直播流,在播放器上大家可以手动去选择清晰度档位,还可以观看比赛的高光时刻、精彩进球,同时所有加入实时语音互动的用户,都会加入到 RTC 系统里面去,进行实时语音交流。同时我们还提供了实时的云端审核功能和离线的人工审核功能来保障聊天内容的安全,并通过 API 的方式提供了踢人、拉黑的运维 API,来保障在一些关键的直播间里边如果有不符合预期的状态出现,可以人工干预去解决问题,保障系统的合规性。

技术挑战



确定了我们的技术方案以后,我们着重于以下两个方面进行了优化。第一个是超高并发问题,它主要体现在哪?


首先是超高并发问题就是音视频流数的高并发。我们大家都了解,RTC 里边每个用户都要去发布一路流去订阅别人的流,有多少个发布用户就要订阅多少条流。在边看边聊场景,尤其世界杯 RTC 场景有其特殊性,在抖音世界杯期间,用户在线流数会集中在比赛这段时间,大概就两个小时有几百万的人同时上线去语音聊天,这个时候对我们的系统就形成了非常大的高流数并发的压力,我们在这个场景下进行了一些优化。


其次是比赛开始的阶段会有大量的用户去进房,然后比赛中场休息和比赛结束的时候会有大量的用户退出房间,在这些阶段会有比较大的集中的进退房的请求,而这些操作在 IT 系统里边都是比较重的操作,我们希望在应对这种高 QPS 请求的时候系统保持稳定,于是我们做了一些优化。


在客户端我们还会遇到音频体验问题。第一个问题是在音频外放的时候,远端的人声和比赛的声音可能会被麦克风采集到发送到远端形成回声。第二个问题是通话的人声可能会小于比赛直播的声音,你跟远端用户通话聊天的时候,会发现他的声音比较小,听不清楚,没有实现很好的沟通效果。后面内容我们就主要针对上面这两个问题或者这两个大的优化项向大家来展开介绍。

超高并发问题的优化和实践

RTC 媒体流数高并发优化方案

高并发 - 常规方案



我们先聚焦于流数高并发问题,在 RTC 常规的方案是用户在最后一公里就近接入我们的服务器,然后服务器之间会做级联,用户从最近的边缘节点去拉流的方案。但是这种方案存在一些不合理的地方,或者说可以优化的地方:

  • 成本:并发流数高,RTC 系统开销大、成本较高

  • 扩展性:当前单房间最高并发 10w,进房 QPS50 左右;无法满足后续可能出现的超高并发热流(10w~ 100w)的需求

  • 客户端性能:弱设备观众拉 9 路流性能压力大

高并发 - 公共流扩展方案



为了应对这些问题,我们在场景下引入了一个公共流扩展方案,麦上用户依然是通过加入我们 RTC 系统来进行实时的语音互动。我们在后端引入了一个 MCU 服务器,把麦上用户的所有数据进行混合之后,麦下用户只需要订阅 MCU 流就可以了。它的优势首是是单房间的流数更低,在有限资源下可以支持更高的业务并发。最后是可以有效优化麦上用户拉流的性能。但是这个方案也存在两个问题,一是公共流转推服务也要占用后端的资源,所以并非所有的房间都开启公共流转推,二是如果用户进来的时候拉的是公共流,他想上麦发言交流的时候,势必存在一个从公共流停止拉流,加入 RTC 房间去实时拉流的过程,这个过程会出现卡一下的体验。虽然我们可以优化,但是这是无法避免的。

高并发 - 融合方案



为了解决为了解决或者优化整个系统解决这些问题,我们边看边聊最终使用的是一个融合方案。大家可以看一下左图,当用户上麦的时候,去查看一下房间里边的在线人数是多少,如果房间里面在线人数小于公共流触发阈值的话,用户直接使用静默用户角色加入房间就可以。如果发现房间里边已经有比较多的用户了,我们就可以判定它是一个热门房间,在后端启用公共流的服务,后续所有进房用户都是拉取公共流的方案。


刚才大家也了解到,公共流状态的用户在上麦的时候会出现拉流的切换,会卡一下。所以我们在公共流用户上麦以后,变成可见用户之后,如果再要下麦或者闭麦,都是让它待在 RTC 的系统里边,不会再退到公共流拉流的状态,从而保证他上麦以后,所有的上下麦都是平滑操作的体验。


所以这个方案融合了两个方案的优势,麦上用户可以低延时非常高效的沟通,对于热门房间有一个无房间流方案,可以提高更高的并发

边看边聊限流方案

接下来我们介绍一下,为了应对我们进房退房集中的高 QPS 我们做的一些限流的策略。限流主要保障什么?在我们预期外的高并发来的时候,保障系统稳定,所以很多策略就是超出预期的时候拒绝服务的策略。我们来看一下我们在限流做了哪些优化。



第一个是对进房请求做多极限流保护,其中有分布式的 QPS 限流,还有中心 QPS 限流,还有中心房间数限流。


第二个是退房请求延时处理,把退房请求超出处理的时候放到队列里面去处理。


最后一个是我们向业务侧提的需求,让业务侧配合我们一起去做保护的策略。g 一是延时关播,将退房流量打散。二是当线上语音聊天房间数超出 RTC 系统容量时,关闭新创建房间的语音聊天能力,保障已创建房间的稳定运行,保障整体稳定性。



我们再来看一下进房的限流策略,它其实和整体的 RTC 系统架构是相关的,我们整体 RTC 系统架构使用的是一个边缘接入、数据存储在中心这样的架构。所以在这套架构下面,我们把用户侧和边缘节点中间在边缘节点这儿做了分布式的 QPS 限流策略。


一个是全局分布式 QPS 限流。在边缘节点到中心机房之间,我们做了一个中心机房,这侧有一个 QPS 限流策略。边缘节点使用的是一个固定时间处理固定请求的算法,它的思路是边缘节点定期向中心信令去请求可以处理的上限,边缘节点收到进房请求的时候,如果超出这个上限,就直接向客户端返回一个错误码,拒绝服务。这个方案有一个特点就是比较简单可靠,但是它的缺点是无法处理尖峰流量。


一个是中心 QPS 限流。在中心信令,我们加上了使用令牌桶的算法,定期以恒定速率生产令牌,有请求需要处理的时候,从令牌桶里边拿一个令牌出来再去处理。这个方案有一个优势,就是如果令牌桶是满的,出现了尖峰流量,我们可以短期处理比较多的请求,能一定程度上承载监控流量的问题。


在这两个请求策略的基础上,我们还增加了一个中心房间数限流的方案,当用户创建房间的时候,如果达到了限流上限,同样也会触发系统限流保护,保障整个系统的稳定。



接下来是退房请求时候的延时处理保护,左边这个图是用户请求到边缘节点的时候,如果发现请求的 QPS 高于安全阈值,我们就把请求加入到队列里面去,为什么可以这么做?退房请求为什么可以这么做?因为进房请求需要实时处理,而退房请求是用户并不强感知的处理请求,我们可以延后对它进行处理,不会影响用户的正常使用体验。


它的基本逻辑是退房 QPS 大于阈值的时候,我们会记录当前请求的时间戳,然后把请求的上下文放到队列里边去延后执行,同时我们也会启动一个循环的任务,去取出这种延时处理的请求。然后首先进行一个判断,使用当前时间戳和请求时间对比超时的时间。如果请求已经判定超时了,就丢弃掉不处理了,中心机房也不会感知到这个请求,如果小于阈值的话就继续处理,处理成功以后就删除掉这个请求。


在我们引入这种延时处理逻辑以后,可能会遇到两个这种异常场景,大家可以考虑一下。第一个就是用户退房以后很短时间又重新加入房间,而我们退房请求又没有被处理,会不会形成退房?前面的退房可能会导致后面的进房失败的问题。解决问题其实依赖的就是请求时间戳的机制。当我们发现退房请求小于进房请求的时间戳的时候,退房请求就不用处理了,直接丢弃掉就可以了。同样,用户在我们处理的时候,中心机房说已经请求的用户已经断联了,我们不需要执行处理了,这时候也直接丢弃掉。

音频体验问题的优化和实践



接下来我们来介绍一下客户端音频体验问题的优化和实践。这边在边看边聊场景下,我们重点要讲解两个问题,第一个是回声消除问题,第二个是远端人声响度优化问题。



RTC 系统是一个双向的实时互动的系统,A 端、B 端用户的声音从扬声器播放出来,被他自己的麦克风收到,发到远端形成了回声问题,我们希望在 A 端通过合成消声算法解决掉这个问题,然后发送到网络上的信号是一个干净纯净的人声。所以我们 RTC 系统也引入了回声消除的模块,它有两个点:第一个是我们会把远端语音用户的语音送到回声消除模块,作为参考信号来做回声消除。第二个就是回声的形成是通过扬声器到麦克风的物理链路。在这个场景下我们需要通过算法来模拟回声消除的算法来逼近真实的回声路径,来对我们的回声进行预估,然后把回声消除掉。


所以大家可以看到回声消除里边有两个要素,第一个是回声消除的参考信号,第二个是回声消除的算法。



我们来看一下在边看边聊场景里回声问题有哪些回声。第一个是远端人声的回声,还有一个是直播音频的回声。为了解决这个问题,我们引入了一个音频托管的解决方案。直播播放器在解码之后并不直接播放音频,而是把音频托管到 RTC 系统,RTC 系统把远端的人声还有直播的音频混音之后送到回声消除模块进行回声消除,这样就有效解决了这个场景下面的回声参考信号的问题。接下来的一个问题是回声消除的算法问题。


涉及到回声消除算法需要向大家介绍一下移动端设备音频外放的通道模式,还有为了解决这个问题的高音质 3A 算法使用。大家如果是做移动端开发的话,可能会了解到移动端的设备存在两个音频通道模式,第一个是通话模式,第二个是媒体模式。通话模式有更好的回声消除效果,更适合用于语音聊天场景,它对人声的处理是更加清晰的,但是存在一个问题,处理音乐的时候可能会有失真,媒体模式优点是有比较好的声音的播放效果,但是没有系统的硬件回声消除或者是效果比较差,所以需要我们整个 RTC 系统去做环境消除。



我们使用通通话模式和媒体模式,在边看边聊场景下做了一个相应的验证。使用通话模式的时候,我们发现两个问题,第一个是手机的音频通道模式和通话模式的音量其实是不一样的,在手机上就有两个音量,从媒体模式直播的媒体模式切换到边看边聊的通话模式之后,它的音量会有突变,整体体验是比较差的。第二个是切换边看边聊以后,由于使用了通话模式,直播的音质会从原来的媒体模式通切换到通话模式,音质表现也变差了。为了解决这两个问题,我们最终选择的是全量使用媒体通道模式的方案,但是在这个方案里边也会遇到一个问题,系统的回音消除的效果会比较差,需要 RTC 自己去实现高音质 3A 的算法。

在这个基础上为了保障边看边聊的整体音质体验,我们使用了媒体模式。我们火山引擎 RTC 也使用了自研的基于深度学习的高音质回声消除算法,确保在无回声的基础上保障我们整体的高音质的表现。



大家可以先看一下左边这张图,两段人声过来混音之后,直接送到我们软件的回声消除模块进行回声消除。然后向大家介绍一下我们线上媒体模式和通话模式放量的进展,在 iOS 上面 iPhone6 以上机型都已经放量了,业务的各项指标都是比较正向的,在安卓系统上也放量了 85%以上的机型,而且在语音场景做到了所有机型的全量,语音聊天室社交的连线时长等业务指标也都是比较正向的。今年我们更进一步对应媒体模式的算法,还有音质画质相关做优化,期待未来可以做到更好体验。



我们在测试阶段发现的另外一个问题是直播间里边解说和比赛的声音它是比较大的,这时候远端用户聊天的时候声音可能不是那么大。这出现一个问题,直播流的声音大,当解说和远端人声同时说话的时候,出现语音人声小,然后听不清楚对端人声。为了解决这个问题,我们就引入了一个智能音频闪避的方案,大家可以看一下这个图,智能音频闪避其实是我们去检测一个信号,比如图中的远端人声,当它的声音超过一定的电平,或者检测到它是人声的时候,就触发机制,适当降低 BGM 或者直播流的播放音量。这时候我们能听清楚原来人通话说话的声音,在这种场景下就是闪避的,其实在我们 FM 电台主播应用场景是比较常见的,他说话的时候会调低音乐,实现闪避的效果。引入了闪避以后,直播流过来在做混音前进入闪避的模块,当我们接受到远端的人声的时候,会做 AI 的语音检测,让闪避模块把直播流的声音降低,突出远端的人声。



上图是我们做闪避的一些经验总结,然后大家可以看一下,就不再展开讲了。

总结与展望

最后我们对整个项目进行一个总结和展望。整个世界杯下来,我们整体的峰值房间数在这个边看边聊场景达到了 172 万,远高于赛前预估的 46 万。峰值用户数也高于 200 万,远超赛前预估的 100 万。RTC 系统也是保持了高度的稳定,整体的 SLA 大于 99.9%。公共峰值用户数达到了 16.6 万,双端的 crash 率都是在 3/10 万这样的水平,是一个非常高稳定性的状态。通过引入边看边聊玩法,我们增加了直播间的互动矩阵,就是观众和观众之间的连线互动。通过这次边看边聊的实践,我们沉淀出一起看直播成熟的方案,观众之间可以一起看直播、比赛、演出等丰富的内容,基于内容增强用户的互动性。


演讲嘉宾:

叶峰峰,毕业于北京邮电大学,毕业后一直从事 RTC 相关工作。2019 年加入火山引擎,主要负责 RTC 互娱场景解决方案的建设和业务的支持,先后支持抖音社交音视频通话、抖音连麦玩法功能的开发和优化迭代。


相关阅读:

从 QoS 到 QoE,RTC 的用户体验该如何评判?

经历过亿级 DAU 的打磨检验,抖音同款 RTC 到底有何魔力

RTC 全球化架构助力业务出海


2023-04-30 08:006537

评论

发布
暂无评论
发现更多内容

架构师训练营第五周 - 作业

桔子

直接赋值,深拷贝和浅拷贝

Leetao

Python Python基础知识

架构师训练营总结 -5

River Tree

极客大学架构师训练营 个人总结

推荐 10个 NB的 IDEA 插件,开发效率至少提升一倍

程序员小富

Java 效率 IDEA

架构师训练营第五周 - 总结

桔子

[架构师训练营] Week02 - 作业

谭方敏

Atlassian Team Playbook | OKR 好的不只是逼格

Atlassian

开发

第五周作业

一致性哈希算法Java实现

dapaul

架构师

架构师训练营第5周总结

aoeiuvzcs

week5 总结

GAC·DU

week05-作业

seki

功利学习法:我为什么要这么功利?

非著名程序员

学习 程序员 程序人生 提升认知

架构学习第5周作业

乐天

第四周课后练习

秤须苑

极客大学架构师训练营

架构师训练营第5周作业

aoeiuvzcs

再谈任务分解

松花皮蛋me

Java 精益开发

week5 coding

GAC·DU

实现一致性 hash 算法

Jeannette

架构训练营week05-总结

尔东雨田

week05-总结

seki

你真的在做持续集成吗?

冯文辉

DevOps 持续集成 CI/CD

架构师训练营 0 期第五周

Blink

小师妹学JVM之:Dirty cards和PLAB

程序那些事

Java JVM 小师妹 性能调优 签约计划第二季

创业使人成长系列 (1)- 从失败中学习

石云升

创业 个人成长 成长

深入理解CAS:以AtomicInteger为例

itlemon

Atomic CAS AtomicInteger 自旋

分布式缓存架构

Jeannette

架构师训练营第五周总结

zongbin

极客大学架构师训练营

Spring Boot 最流行的 16 条实践解读,值得收藏!

Java小咖秀

spring 学习 Spring Boot SpringBoot 2 经验分享

Homework-我的一致性Hash算法

River Tree

Homework

想怎么玩,就怎么玩!搭载桌面级十代酷睿的神舟超级战神真香!

最新动态

抖音世界杯中 RTC 的技术挑战与实现_架构_InfoQ精选文章