04月09日
CODING 技术小馆 | 快速设计和构建一个高可靠、高扩展性的直播答题系统

本文为 青云 QingCloud 对象存储研发负责人 王煜(William Wang) 在 CODING 技术小馆 · 广州站 的演讲内容整理。

大家好!我是青云的王煜。我目前在公司负责存储产品线的研发团队,我们团队包括了对象存储、分布式文件存储以及企业云盘,除此之外,我们还在做 CDN、云直播、云点播等多媒体相关的工作。今天我带来青云平台上的一个真实的客户案例 - 直播答题,话题比较轻松,但是所面临的技术挑战很大。

直播互动技术的应用

图片

从 2018 年开始直播答题这种新型的直播应用就突然火起来了,比较流行的有芝士超人、百万英雄、冲顶大会等等,他们都是基于 App 来开发的。坦率来讲,直播答题应用我不确定可以火多久,因为互联网热点都是一波接一波的,每一波不会持续太长时间,但是抽离出直播答题的业务场景,我们能看到一个趋势:直播互动相关的技术,在未来会成为整个视频行业的标配,最近一段时间最流行的是直播答题,再之前还流行过一阵手机远程夹娃娃,用手机来控制娃娃机,夹到可以快递给你,还有远程投篮机等等。也许未来大家在看世界杯直播的时候,可以通过手机跟主持人互动以及球员互动,这些都是直播互动技术的应用。

一个月前有客户找到青云,名叫新世相,他们最知名的品牌是微信公众号,传播范围非常广,每一篇文章阅读量都超过 10 万,后来他们成为一家文化传播公司,成功举办过多场互联网爆款活动,吸睛无数,比如四小时逃离北上广、地铁丢书大作战,以及最近的佛系青年话题,都是新世相发起的活动和话题。除此以外他们还运营自己的 App 应用新世相读书会,做知识阅读和分享相关内容。一个月前他们找到青云,说要做基于微信小程序的直播答题,这个直播答题的应用很简单,相信在座大多数同学都玩过,没有玩过的我可以讲一下,每一场 20 分钟,主持人在直播过程中依次出 12 道题,全部答对的观众可以瓜分奖金,普通场是十万奖金,明星场有上百万奖金。商业模式主要是它在题目中会插一些广告题,或者把用户流量倒流回自己的 App,比如说新世相有自己的新世相读书会 App 和公众号。

直播答题往往界面比较简单,通过小程序实现,对于用户来说不需要安装非常方便。主持人在念完题目后,留给用户的答题时间很短,只有 10 秒钟,10 秒钟没有回答就淘汰了,如果答对 12 道题就可以分钱。场景很简单,但是背后的应用技术很复杂。直播答题应用有很多家都在做,工程师们都没有想到这个应用一夜之间就火了,虽然人气飙升,后端服务开始频繁的宕机,直播中断、题目弹不出来、数字算错在这些应用的初期都经历过。所以功能虽然简单,但面临的技术挑战是非常大的。

直播答题面临的技术挑战

图片

主要有四大技术难点,第一它的后端系统要支持高并发,这个并发量非常大,一般直播只有二十分钟的时间,每道题要在几秒钟内推给所有用户。并且答题时间只有 10 秒,上百万人在同一时间提交答案。如果延迟几秒钟的话,用户就错过答题时间了。

第二,要达到 99.999% 的高可用能力,因为直播的时间是比较紧凑的,在这短短的 20 分钟时间里,1 秒钟的宕机都是不能接受的。并且流媒体传输对于网络丢包的容忍度也是比较差的,所以系统和网络的高可用能力都至关重要。

还有一个需求是高带宽,跟视频沾边的应用带宽消耗都是非常高,而且它有明显的流量高峰期和低峰期,直播答题的用户会有两路流,一路是视频流,能达到上百 GB 的带宽峰值,一般是用直播 CDN 来抗。推题的部分,可以使用云服务的 BGP 网络来推,文字内容不会消耗太高的带宽。

最后一个非常严苛的需求,低延迟,因为答题时间只有 10 秒,如果你的题目延迟 5 秒才推到对方,对方只有 5 秒的时间答题。所以用户有时候会报答题的时间不够 10 秒,或者题已经答了,服务器判定我超时了,这就是延迟太高造成的。

这四个技术难点哪怕解决一个都很难,同时完成四个是非常艰巨的技术挑战。

技术架构关键点

图片

从这张图可以看到整个技术架构的一些关键点,从中间用户这一块开始是用户端,也就是用户的手机。他们做的是小程序,所以主要在微信里面。用户往上是直播 CDN,然后往下是派题系统。其实这个应用场景里面,视频和题目是两路不同的流,只是在界面上叠加在一起,实现直播交互的效果。但是视频要跟题目同步,不能主持人说完以后题没有出现,或者主持人没有说下一题的时候题就出来了,后面我们会讲怎么实现。

左边是演播厅,演播厅会有摄像机,摄像机把视频音频采集到导播台,导播台把流推到流媒体服务器,再分发到 CDN。演播厅还有一个裁判,他会操作 Dashboard 控制推题。并且能看到一些统计信息,比如显示这一道题有多少人回答,多少人回答对了。每道题回答完以后就会看到答题人数,反馈到主持人的 Dashboard 里,主播要实时播报这道题多少人答对,多少人答错。

往下就是派题系统,用一些云资源的组建,包括负载均衡器集群。青云的负载均衡器集群支持高可用和水平扩展,可以动态增加节点,并且支持 Websocket 协议的负载均衡。提高每台应用程序服务器的并发能力是重点。这个客户的后端采用 Node.JS 实现,使用 Websocket 协议,因为服务器要给手机主动推题,要和客户端维持一个长连接。

底下的数据库并不是很复杂,因为本身是一个即时性的在线应用,没有太多沉淀的数据在里面,基本上单机数据库就可以承载整个数据量。但针对一些高并发写操作的场景,也要适当做切分。旁边还有一块 API 服务器,用户进来以后有一些查看余额和用户信息的功能要请求 API。还有分享功能,分享功能是单独拆出来的,客户一开始把分享功能和主业务放在一起,但是在分享过程中因为要调微信的服务,你的系统如果强依赖第三方服务,那你就危险了,万一第三方的服务出问题或是网络延迟高,你的服务也会被拖挂。后来他们把这部分单独拆出来了,挂了也不会影响主业务。下面我来详细讲讲这幅图里的四大块内容。

硬件及流媒体技术参数

图片

首先是演播厅,这块很专业,一般会雇一个摄像团队来做。你需要准备一些东西,一是绿幕背景,绿的背景容易抠图。视频录下来以后需要要把背景抠出来变成动态的背景。反光板就是右上角的这个东西,还有监视器,主持人可以通过监视器看到自己。然后是题词版,主持人直播过程需要用它来题词。还有摄像机和话筒,有一些是摄像机里面直接有话筒,有一些是分开的,分开的话可能有声音和视频不同步的现象,但更多的音画不同现象,是由于在软件中,视频编码和音频编码的花费的时间不一样,一般音频编得快,视频编得慢,声音和视频不同步的现象是很正常的,一般要在软件里设置一下声音延迟的差值,等一等视频,同步以后再推到流媒体服务器。

图片

这是采集端。专业设备很多,主要是几部分,一个是视频采集卡,连摄像机和话筒。这个需要非线编软件来编辑,编辑好再往外推,还会辅助特效控制器,加入鼓掌和口哨的声音。然后还需要推流客户端,常用的开源软件有 OBS,自带推流和简单的编辑功能。最后很重要的一点是有一个高质量的有线网络,客户在前期直播时经常播着播着就黑屏了,后来才知道是因为办公室网络环境太差了,他用 WIFI 无线网络往外推流,后来变成有线的就好很多。

图片

设置导播软件的时候,有一些参数要自己设置,给大家简单介绍一下。一个是分辨率,分辨率决定了视频清晰度上限和视频尺寸,可以把它理解为一个泳池,容积是确定的,但具体装了多少水不是它决定的,所以分辨率并不能体现视频清晰度,比如大家下载的电影,1080P 不一定就比 720P 清楚,就是因为分辨率不决定视频的质量,它只决定视频的尺寸以及所能承载的码率。

直接影响视频质量是码率或者叫码流,会直接影响视频清晰度。如果你网络不好可能会看的很卡,这时候你需要把清晰度调低可以增加流畅度,但画面质量就会下降,这里面就看你需要流畅还是需要好画质。

还有帧率,帧率是每一秒钟播放的图片数量,直接决定了视频的流畅度。大家可能尝试自己做过动画,你要画很多幅画,一个跑步的小人,每一张画的动作都跟上一张有细微差别,连起来翻就是跑起来的动画。翻得越快,动作就会越流畅,慢了就会很卡。

右边的话就是几个指标,一个是编码格式,编码格式和封装格式不一样。有很多人会把 H.264 和 H.265 跟 MP4 混淆,如果把视频看成是一张张图片连起来,编码格式相当于编排图片的方式,比如 I 帧是关键帧,它是完整的一副画面,后面几个帧是 P 帧,也就是相对于前一帧的变化量。如果你的视频丢了 P 帧这是丢失了一些变化的部分,整个画面还是能看到的。但丢了 I 帧就看不到。

如果是体育类型的直播,画面变化很快,I 帧间隔可以设置短一些,很大的话就会丢失一些细节。如果是一些不会快速变化的画面内容,比如自然风景,它的 I 帧间隔可以长一些,整个文件的大小就会下来。所以编码主要是干这些事情。

然后它会把编码封装在一起,不仅仅是有视频,还有音频,它们有对应关系。因为你这个里面几秒钟和你的视频哪几秒对在一起,这个需要合起来,合起来就需要封装,国际上有一些通用的标准,比如说 MP4,MP4 是 HTML5 的御用格式。而直播行业是用 FLV 格式去封装直播流,TS 据说在广电用得比较多,是一个很老的格式。下面就是传输协议,RTMP 传输协议用得比较多,RTSP 主要用于监控的场景,它可以基于 UDP,对于监控摄像头也不太在乎丢祯。而 HLS 是苹果设计的协议。这些都是常用的网络传输协议。

图片

下面来介绍一下音视频的数据流。最开始的摄像机代表了整个演播厅,会将编辑好的视频流推到发布节点,发布节点相当于流媒体服务器,推流客户端通过 RTMP 推到这些节点,比如我们现在在做的分享直播,肯定是推到广州的发布节点上去的。之后发布节点推到核心节点,核心节点在国内几个大区有。观众端有一个拉流的地址,会从一些边缘节点上拉取,边缘节点没有就回源到核心节点上取,这样用户就可以顺利拉到直播内容了。

派题与推题策略

图片

派题有三个策略,第一种做法就是视频流插入题目内容,需要 SDK 端的支持,但是题目不能太多,基本 1000 字节以下可以用这种方式,这种方式最高效,不涉及到画面和题目同步的问题,它的题画顺序是完全自然确定的。但是它的问题在于它需要客户端 SDK 的支持。青云目前有一个很好的合作伙伴叫即构 ZEGO,做得很不错,不但可以在视频流插入题目的内容,推流端也有很多优化,在弱网的环境下推流也会处理的比较好。

第二种方式,也是很多厂商常用的一种方式,就是在视频流中插入控制帧,用户端解析控制针,回调到派题服务器获取题目的内容。这也是比较自然同步的过程。但有一个问题,当主持人在把控制帧插入到视频协议推给大家的时候,全部用户几乎在同一时间内去服务器去请求这个题目,并发量非常大。如果在线人数 10 万,就要有 10 万的并发量,在线 100 万就有 100 万的并发量。

第三种方式是与派题服务器保持一个长连接,通过 Websocket 协议主动推送,这个有一个好处和一个坏处。坏处是需要自己去做题画同步,这个过程当中视频要走 CDN,有一些云服务 CDN 要达到 5 秒以上的延迟(青云能做到 1-2 秒)。但推题目是毫秒级的,因为是从青云的 BGP 带宽推过去的。这就需要计算一个时间差,再来展现题目,通过一些参数可以计算出这个时间差,题目到了不是马上展现,而是等待这个时间差后才会展现出来,这就做到和视频同步了。

图片

推题系统完整的搭建在青云平台上,使用了青云的带宽、负载均衡集群、主机、数据库等资源。架构其实并不复杂,应用服务器用 Node.js 实现,跟手机端维持一个 Websocket 长连接,中间经过负载均衡器集群。为了保证应用服务器可以水平扩展,把一些状态信息下发到 Redis。我们花了很多经历优化每个应用节点的并发能力,优化到差不多每台能撑 30-50k 的并发量,整个系统可以随着在线人数的增多水平扩容。

题目的部分要放到 Redis,Redis 的题目基本上不会变。但是题目不能提前派发客户端,不然会造成作弊。所以每一道题是要主持人说下一题的时候才推上来,题目可以从 Redis 预取到业务进程内存里,当收到推题的指令,就可以直接往外推。

API 服务器这边并发量并不是特别高,主要是获取余额信息和用户信息,这些数据比较重要,要放到 MySQL 里持久化。

应用服务器的优化

图片

接下来讲一下应用服务器的优化,主要是三个方面。第一要使用事件驱动模型。如果使用多进程或多线程模型,连 10K 并发量都做不到,几 K 就已经把内存吃满了。用 Node.js 的事件驱动模型可以做到更高的并发量。

其次是系统架构优化,第一是简化关联,如果你的系统跟数据库或者是第三方服务关联越多,就越容易受牵连而挂掉,所以要保证业务很简单,直接就是一个服务搞定了,不需要做很多微服务化的事。

第二是无状态化场景,使用多级缓存,那么多的服务器来进行查询,你可以把应用服务器的内存应用起来,推题的时候从 Nodejs 进程内存里直接取就行了,不要查数据库。还有提前计算,比如有一个场景是观众回答以后,把答案存入数据库,主持人需要去统计谁答对和谁答错了,如果每次从系统里取出来后再计算答对和答错的数量就太慢了。服务器其实是知道正确答案的,可以提前把对或者是错的判断出来,只要存一个计数器就好了。没有统计的过程,查询就会变的很快。还有一些改进,比如尽量异步处理不需要马上返回结果的任务,比如说提取帐户余额,这部分需要依赖微信的服务,告诉用户一个小时提款成功或一天后提款成功,大家也是可以接受的。

最后是内核参数优化,可优化的参数有很多。幻灯片里列出了一些应该重点调整的内核参数。记得要把 tcp keepalive 配置上,因为互联网环境比较复杂,一个长连接如果几十秒没有收发报文,中间路由节点可能会把连接状态清掉。所以可以通过配置 keepavlive 让内核隔几秒发一下心跳包。但是应用层面也应该要做心跳,可以提早发现连接断掉并重连,不要等到客户端接受题目的时候才发现,那就已经晚了。

优雅地薅云服务羊毛

图片

最后讲一下如何优雅地媷云服务的羊毛,作为云平台,青云可以做到资源按秒计费,包括主机、带宽、数据库等全部资源。非直播的时候是可以关闭的,数据是保留的,但是主机你不用或者只留一台。关闭的主机只收磁盘费用。包括负载均衡器集群的节点也可以非直播时间往下减,比如 8 个节点减到了 1-2 个就可以了,这样就会非常省钱。

主机弹性扩容,可以配置自动伸缩功能,当你的带宽跑多少阀值,或者并发量达到阀值就触发,触发后进行系统的自动横向扩张。

网络可以调整为按流量计费,直播答题有明显的流量高峰期和低峰期,使用带宽计费不划算,按照流量计费就非常适合峰值很高,但平均值较低的场景,因为不是所有的应用都 24 小时随时有用户使用的。在这些方面青云的云服务都是可以帮助大家省钱的。

以上是我本次的分享内容,希望能帮助大家了解到如何使用云服务快速地构建一个高可用、可扩展的直播答题应用系统,谢谢大家。

扫码关注 扣钉CODING 微信号,获得 CODING 技术小馆和产品更新 第一手信息。
图片

coding1741

1条评论

支持!这么好的文章,为什么没人看呢? = =

满天星1 年前回复