38 _ 实战推演:带你实现一个支持万人同时在线的直播系统
38 _ 实战推演:带你实现一个支持万人同时在线的直播系统
本文我们将第三模块所讲的知识做一次梳理,让你在整体上了解“万人直播”到底是怎样实现的。我们将从万人直播的整体架构、主播客户端架构、观众客户端架构和流量统计这四个方面向你讲述万人直播的构建。
通过这几个方面的介绍,我想你就知道了一个真正的“万人直播”是如何构建起来的。
万人直播架构
下面这张万人直播架构图与《31 | 一对多直播系统RTMP/HLS,你该选哪个?》一文中介绍的直播架构图很类似,它们之间最大的不同在于真正的万人直播系统中并不会只使用一家 CDN网络,而是接入多家 CDN网络。在使用它们时,你可以按照一定的比例将“节目”分配到不同的CDN网络上。

多家 CDN 网络的管理一般是由信令服务器控制的。当要接入某家CDN网络时,你可以通过信令服务器的注册界面进行注册。在注册界面中,一般要求填入CDN厂商的名字、分配比例、CDN API操作地址等信息。
比如,当某个主播要分享一个节目时,信令服务器首先根据分配比例决定使用哪个CDN网络,然后获得该CDN网络的API操作地址。获取到 CDN 网络的API操作地址后,它就可以调用该CDN网络提供的 HTTP/HTTPS API 进行操作了,创建域名、生成直播地址、生成拉流地址等等。有了这些地址后,就可以将音视频流推送到CDN网络,观众端获取到观看地址后就可以“观看”节目了。
除了接入多家 CDN 网络之外,其他功能与我们之前文章中介绍的是一样的,这里我就不再赘述了。
主播客户端架构
了解了万人直播架构后,接下来我们再看一下主播端的架构。之前我们介绍过,如果在 PC 端进行直播的话,直接使用OBS工具就可以了,这个工具是一个非常专业的 PC 端推流工具,功能非常强大,很多主播都使用该工具进行推流。
但如果是移动端的话,就需要我们自己来实现了。主播端的架构如下图所示,按层级分为三层,即传输层、编码与展示层和采集层。

下面我们对各层级的模块分别做下说明。
传输层,包括了信令处理和RTMP数据传输。信令处理与业务逻辑关系紧密,比如创建房间、获得推流地址、聊天、送礼物等都属于信令处理的范畴。RTMP 数据传输就更简单了,当从信令模块获取到推流地址后,就可以将编码后的音视频数据通过 RTMP 协议推送给 CDN 网络了。
编码与展示层,该层包括的功能比较多,包括音频检测、音频编码、视频编码、视频预览以及视频美颜。接下来,我们再对这每个功能模块做一下说明。
- 音频检测,主要用于在直播开始前检测音频设备是否可用。
- 音频编码,用于将音频采集模块采集的PCM数据进行压缩编码。常见的音频编码有 AAC、MP3、Opus等。一般情况下使用 AAC 编码方式。另外,编码也分为两种,一种是软编,一种是硬编。所谓软编,就是指通过 CPU 执行压缩算法进行编码,会对CPU造成很大损耗;硬编,是指通过 GPU 或固定的集成电路进行数据的压缩,它可以将CPU资源节省出来。
- 视频编码,用于将视频采集模块采集的YUV数据进行压缩编码。常见的视频编码有 H264/H265、VP8/VP9等。大多数情况下,我们都使用 H264 对视频进行编码。视频编码同样分为软编和硬编。在移动端,一般我建议使用硬件编码,这样可以大大节省CPU资源。
- 视频预览,将采集的视频展示出来,以便让主播看到从移动端采集到的视频数据的效果。由于视频帧每秒要刷新很多次,并且视频的数据都比较大,所以在处理视频渲染时如果没有处理好,会引起性能问题,如手机反应迟顿、发烫等问题。一般情况下,我们都会使用 OpenGL ES/ Metal 对视频渲染进行加速,从而解决反应迟顿、发烫等问题。
- 视频美颜,美颜目前可以说是娱乐直播的必备功能,尤其是对于美女主播就显得更为重要。如美白、瘦脸、长腿等这些功能是美女主播最喜欢用的功能。这种特效通常也是通过 OpenGL/Metal 来实现的。当然,随着技术的发展,现在一些AR技术也逐渐应用于各种视频效果中,如雨滴、飘雪等等。
采集层,包括音频采集和视频采集。这两个功能模块非常简单,一个用于采集音频数据,另一个用于采集视频数据。它们都是与硬件打交道。
除了上面这些内容外,在主播端还会有数据统计模块。比如什么时候创建房间、什么时候开始推流、推流时音视频的码率是多少等等,这些信息都是由数据统计模块记录的。有了这个模块之后,一是便于我们分析问题,二是便于我们进行计费核算,在与各CDN厂商结算费用时会非常有用。
观众端架构
介绍完主播端的功能后,接下来我们再来看看观众端(如下图)。观众端与主播端是很类似的,但实际上我们自己并不会将每个模块都亲手实现,因为对于观众端来说,大部分模块都属于播放器的功能。因此,我们在实现观众端的时候,只需要实现信令处理模块、数据统计模块,并将播放器集成进来就可以了。

对于移动端,我们一般都使用Ijkplayer作为观众端播放器。 Ijkplayer是由bilibili公司开源的项目,地址为:https://github.com/bilibili/ijkplayer.git 。它既可以用于 Android 端又可以用于 iOS端,使用起来非常方便。
实际上,Ijkplayer就是 FFmpeg 中 FFplay 的变种,它们的基本逻辑是一致的,只不过Ijkplayer 更容易移植到移动端上。另外作为 iOS 端,它自带的 player 非常成熟,你也可以直接使用它自己的 player 来实现观众端。
在 PC 端你可以集成 VLC,它与Ijkplayer一样,也是非常优秀的一款播放器。该播放器的集成也非常简单,你在网上可以找到非常多的资料,所以这里我就不对它做更多的介绍了。
当然,Web端也是必不可少的,你可以使用我们前面文章中介绍的 flv.js 或 video.js 作为Web 端的播放器就可以了。
流量统计
下面我们再简要介绍一下流量统计。当在我们的直播系统中接入 CDN 网络时,一个非常重要的工作就是费用结算。一般情况下,都是按流量进行结算的。也就是说,CDN厂商会根据我们或我们的用户使用了多少CDN流量进行费用的结算,所以我们一定要知道自己用了多少流量。
另一方面,除了流量,我们还要监控我们的服务质量,比如是否出现了卡顿?每小时卡顿了多少次?引起卡顿的原因是什么?是否发生过分辨率切换?缓冲区还有多少数据没有播放出来?这些都与服务质量有着密切的关系。
那么接下来我们就来讲讲该如何采集数据,以达到监控服务质量和费用结算的目的。根据我的实际经验,以下信息是你在每个用户使用 CDN 网络时必须要记录下来的信息:
- 视频分辨率、帧率、码率相关信息
- 开启播放时间
- 关闭播放时间
- 暂停播放时间
- 恢复播放时间
- 缓冲区为0的时间
- 拖放时间以及拖放到的时间
- 分辨率切换的时间
- ……
通过以上这些信息,你就可以将用户使用的流量精确地计算出来了,这样再与CDN厂商核对数据时,你心里就有谱了。
举个例子,当我们想统计一个用户使用了多少流量时,最简单的公式是(关闭播放时间-开启播放时间)* 码率,通过这个公式,你就可以计算出结果了;如果中间有暂停,则计算公式就变成了((暂停播放时间-开启播放时间)+ (关闭播放时间-恢复播放时间))* 码率;如果是多次暂停和恢复,那公式就更加复杂了,你需要按照上面的方法一步一步去推导就可以了。
另外,由于统计数据是一个特别精细的活儿,把这件事儿做好不容易,而且又涉及到费用问题,所以在后端统计时一定要细致,否则当一个节目观看人数众多时,就很容易出现比较大的偏差。
通过上面的介绍,我想在你脑海中一定有了一个统计流量的雏形了,你可以在这个雏形的基础上不断完善你的算法,就可以实现商用的统计系统了。
小结
本文我们从四个方面向你全面介绍了传统直播系统是如何实现的。首先讲解了传统直播系统的架构,该架构与我们前面介绍的架构是类似的,最重要的差别是可以接入多个CDN网络。在真正商用的系统中,这个CDN网络都是按一定比例分配资源,当有某个CDN网络出现问题时,还可以进行CDN网络的切换。然后我们又详细阐述了主播客户端与观众客户端是如何实现的。最后,还讲述了流量统计模块,因为它关系到统计计费与服务质量,所以是直播系统中必不可少的一个模块。
目前国内的CDN厂商特别多,如阿里、腾讯、金山等,当然也还有很多老牌的CDN厂商,如蓝汛、网宿等,它们的质量具体如何还需要你多进行测试。从我个人经验来讲,阿里无论价格还是质量都还不错。
思考时间
今天留给你的思考题:如何判断用户在播放音视频流时是否出现过卡顿?
欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。