<audio id="audio" title="38 | 实战推演：带你实现一个支持万人同时在线的直播系统" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/55/5e/5587c617bc93dd7c6d54ce5744fc3b5e.mp3"></audio>

本文我们将第三模块所讲的知识做一次梳理，让你在整体上了解“万人直播”到底是怎样实现的。我们将从万人直播的整体架构、主播客户端架构、观众客户端架构和流量统计这四个方面向你讲述万人直播的构建。

通过这几个方面的介绍，我想你就知道了一个真正的“万人直播”是如何构建起来的。

## 万人直播架构

下面这张万人直播架构图与[《31 | 一对多直播系统RTMP/HLS，你该选哪个？》](https://time.geekbang.org/column/article/140181)一文中介绍的直播架构图很类似，它们之间最大的不同在于真正的万人直播系统中并不会只使用一家 CDN网络，而是接入多家 CDN网络。在使用它们时，你可以按照一定的比例将“节目”分配到不同的CDN网络上。

<img src="https://static001.geekbang.org/resource/image/4e/bf/4e52d2ea1567a9821e1188f7bc6befbf.png" alt="">

多家 CDN 网络的管理一般是由信令服务器控制的。当要接入某家CDN网络时，你可以通过信令服务器的注册界面进行注册。在注册界面中，一般要求填入CDN厂商的名字、分配比例、CDN API操作地址等信息。

比如，当某个主播要分享一个节目时，信令服务器首先根据分配比例决定使用哪个CDN网络，然后获得该CDN网络的API操作地址。获取到 CDN 网络的API操作地址后，它就可以调用该CDN网络提供的 HTTP/HTTPS API 进行操作了，创建域名、生成直播地址、生成拉流地址等等。有了这些地址后，就可以将音视频流推送到CDN网络，观众端获取到观看地址后就可以“观看”节目了。

除了接入多家 CDN 网络之外，其他功能与我们之前文章中介绍的是一样的，这里我就不再赘述了。

## 主播客户端架构

了解了万人直播架构后，接下来我们再看一下主播端的架构。之前我们介绍过，如果在 PC 端进行直播的话，直接使用OBS工具就可以了，这个工具是一个非常专业的 PC 端推流工具，功能非常强大，很多主播都使用该工具进行推流。

但如果是移动端的话，就需要我们自己来实现了。主播端的架构如下图所示，按层级分为三层，即**传输层、编码与展示层**和**采集层**。

<img src="https://static001.geekbang.org/resource/image/5e/b6/5e0f7b59e401a1939ce3a618082e55b6.png" alt="">

下面我们对各层级的模块分别做下说明。

**传输层**，包括了信令处理和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厂商结算费用时会非常有用。

## 观众端架构

介绍完主播端的功能后，接下来我们再来看看观众端（如下图）。观众端与主播端是很类似的，但实际上我们自己并不会将每个模块都亲手实现，因为对于观众端来说，大部分模块都属于播放器的功能。因此，我们在实现观众端的时候，只需要实现信令处理模块、数据统计模块，并将播放器集成进来就可以了。

<img src="https://static001.geekbang.org/resource/image/9e/f8/9eb7c783f2ef7ae9158148d34819e1f8.png" alt="">

对于移动端，我们一般都使用Ijkplayer作为观众端播放器。 Ijkplayer是由bilibili公司开源的项目，地址为：[https://github.com/bilibili/ijkplayer.git](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厂商，如蓝汛、网宿等，它们的质量具体如何还需要你多进行测试。从我个人经验来讲，阿里无论价格还是质量都还不错。

## 思考时间

今天留给你的思考题：如何判断用户在播放音视频流时是否出现过卡顿？

欢迎在留言区与我分享你的想法，也欢迎你在留言区记录你的思考过程。感谢阅读，如果你觉得这篇文章对你有帮助的话，也欢迎把它分享给更多的朋友。


