原文:Globo.com’s Live Video Platform for FIFA World Cup 2014- Part I: Delivery and Caching
译者:杰微刊兼职翻译汪建
下文改编自环球网的Leandro Moreira 和Juarez Bochi两位工程师 2015年九月份在San Francisco市举办的NGINX会议的演讲。这篇博客是两部分的第一部分,它主要关注与使用NGINX作为流媒体传输和缓存,你可以从YouTube上观看完整的研究视频。
内容表
0:03介绍
1:51议程
2:14 2010的架构
4:08好的部分–低延迟
4:19问题–缺乏关键点监测器
4:44问题–可扩展性
5:52国际足联2010–关键数量
6:18移动设备的支持
7:29 HLS协议如何工作?
9:18 基于HLS协议的首次实现
10:14内容的生成与分布
10:55首个解决方案的架构
11:12 采用HLS协议
11:54 HLS缓冲VS RTMP缓冲
12:34监测器
13:22仪表板
13:45缓存配置
15:30 OS微调
17:50从NGINX和HLS中获益
18:43我们的搭配
0:03介绍
Leandro:早上好,我叫Leandro,这里这位是我的朋友Juarez,我们都受雇于环球网,我们所在的团队负责提供最近一届世界杯在互联网上的现场直播功能,是足球的世界杯,而不是橄榄球。
虽然大家只看到我们两个在这里,但实际上我们是团队的一部分,所以今天我们展示的工作不仅仅是由我们完成的,而是由我们整个令人惊奇的团队完成的。
另一件事我们需要提的是,我们只限于对巴西直播,所以,我们不负责向全世界现场直播实况。
1:51议程
我们希望通过一个时间轴来展示我们的工作,向大家展示自从我们加入这个团队以来的过去到现在的一些情况。展示如何把以前的视频平台打造成如今的平台。让我们看看过去——在2010年非洲世界杯我们使用了什么技术。
Juarez:感谢Leandro,我们将简要地讨论下我们在2010年的时候的经验,为什么当时系统工作得不是很好,为什么我们决定采用NGINX。
2010年,我们使用了Flash媒体服务器,作为流媒体视频直播,它基本上是这样工作的:
首先,场上的摄像机将原始视频信号发送给编码器,然后编码器会使用视频和音频编解码并转换成RTMP协议资源,我们使用了H.264,我们通过FMS服务器使用RTMP协议将信号编码往外推送。
为了将这些信号传送给观众,我们将这些信号发送到另外一个服务器或一个服务器集群,这些服务器再次使用RTMP协议将视频信号直接传输给用户,用户通过Flash视频播放器接收观看,RTMP协议使用它专属的端口1935,所以有时我们会因为防火墙导致一些问题。
大家可以看到我们我们整个过程都使用了RTMP协议,这是一个有状态的协议,使得它很难做到冗余和故障转移,以及其他的一些缺陷。
4:08好的部分–低延迟
使用RTMP协议的好处是视频直播的延迟相当低,仅仅只有2到5秒。
4:19问题–缺乏关键点监测器
除了实现冗余和故障转移困难以外还有一个缺点,就是Flash媒体服务器是闭源代码软件,这意味着我们无法对它进行调试,不能对关键点添加性能监测器,我们能做的仅仅是使用tail命令跟踪log或使用shell脚本监控服务的运行状态。
4:44问题–可扩展性
由于RTMP是一个有状态的协议,所以另外一个问题就是可扩展性,如果有若干用户正在连接者某个服务器,而这个服务器宕机了,所有在这台服务器的用户需要重新连接到另外一台服务器。
由于他已经处于高负载状态下,第二个服务器很可能也会接着宕掉,接着所有的服务器都将产生连锁效应导致宕机。
当我们看到这些发生时,我们就看到了我们的声誉和金钱在往窗外飞走了。
这里大家可以看到一张过去我们正在直播一场比赛的图表,在中场休息的时候,我们遭遇了一个流量高峰,服务器就宕机了,于是我们流失了一半以上的观众。像这种现场直播的事我们不可能有机会去恢复,我们仅有一次机会把事情做好做对。
5:52国际足联2010–关键数量
仍然,我们取得了一些值得尊敬的数字,至少对于巴西来说是一个值得尊敬的数字。我们有将近300000同时在线的用户,虽然最大比特率还不是很高,但它的质量还算不错。
6:18移动设备的支持
Leandro:上面介绍的是过去,我们在2012年加入了团队,而就在这时,互联网一直在成长并且蔓延到智能手机和平板电脑,所以瞬间我们很有必要要提供实时的视频到移动设备上。
我们注意到并非所有的移动设备都可以播放RTMP协议的视频,这个仅仅是Flash的东西,iphone电话和ipad平台属于IOS系统设备,他们要求你必须使用HLS协议去播放直播内容。
7:29 HLS协议如何工作?
HLS是苹果公司提出的一个协议,它的工作原理是这样的,当用户想要观看视频播放时,视频播放器首先需要的是一个播放列表,这个列表中包含了很多连接的文本文件,这个列表连接了其他播放列表,而且这些列表各自代表着视频连接的质量和播放比特率的不同资源。
现在该协议会根据当前的网络速度计算出哪个级别质量的视频可以播放,例如,假如你的移动设备使用的是4G网络,那么你的移动设备网络决定了你可以观看720p的视频资源,它会得到720p资源的播放列表,它包含了一系列视频片段。然后播放器开始获取视频资源,将缓冲区填满,最后它就开始播放视频了。
接着它会通过再次调用720p播放列表去更新播放列表资源,获取更多的视频片段,此后不断通过这个过程循环获取其他视频片段。所以基本上我们使用基于HTTP协议的HLS协议去取代RTMP协议,这也就意味着用一个无状态的协议取代原来有状态的协议。
9:18 基于HLS协议的首次实现
在我们第一个基于HLS协议实现的版本中,在视频端采集工作中我们仍然采用了相同的过程,我们仍然使用RTMP协议推送视频流,我们仍然使用了一个专用的服务器,它可以很容易集成。通过EvoStream你可以使用RTMP协议进行推送,你也可以获取到基于HLS协议的流资源,这些流资源就是前面我展示给大家的在播放列表中的资源片段。
EvoSteam将这些片段保存到一个普通的文件夹目录下面,然后我们引入了NGINX作为负载均衡器对负载进行分配。现在,我们可以向苹果设备、基于安卓系统的设备及安装了Flash播放器的设备上进行视频直播。当时市面上没有一个基于HLS协议的Flash播放器,所以我们必须要自己去做,这个挺有趣的。
10:14内容的生成与分配
我们的第一个基于HLS协议实现的版本相对简单基础,仅仅是使用根目录并且保证其可用。让我们深入研究这部分,我喜欢称这个过程为内容的产生和分配。我们将结构划分为前端和后端,我们的NGINX负载均衡器只做了很简单的一些事,我们使用Evostream在指定的目录下去生成HLS协议的视频流,我们也正是使用这个目录通过Evostream把视频资源推给用户,这里的目录就是前面提到的根目录。
10:55首个解决方案的架构
这个简单的解决方案十分地奏效,我们的所有架构都是很基础的,在每个层都使用多个负载均衡器做负载均衡,例如像缓存、认证和生成等工作,这种模式工作得很良好。
11:12 采用HLS协议
在这一点上,我们做了一个实验,我们将HLS协议作为唯一的协议,这个实验仅仅面向2%的用户。我们发现结果相当好,于是我们将RTMP协议换成HLS协议并面向100%用户,至此我们将我们的协议从多协议版本变成了单协议。
11:54 HLS缓冲VS RTMP缓冲
我们收集了一些指标信息看看这个改变给我们的用户带来了更好的体验还是更坏的体验,我们发现使用HLS协议后的缓冲比RTMP协议的缓冲好很多。除了缓冲方面,我们还有大量的指标信息显示使用HLS协议给用户体验带来了提升。
Juarez:是的,启动时间更低了,平均而言,播放时间更长了,我们确信HLS协议能比RTMP协议运行地更好。
Leandro:是的,有了这些指标信息,我们决定100%地转换成HLS协议。
12:34监测器
由于我们改成了使用基于HTTP协议,使用监测器将给我们带来巨大的好处,我们可以安装一个logstash软件去获取日志信息并且发送给redis缓存。此外,我们再安装另外一个logstash将日志信息发送到Graphite监控软件。我们也有一些其他代理,使用SNMP协议去了解CPU的工作情况,并将指标信息发送给Graphite监控软件。有了这个,我们就可以建立一个仪表板。
13:22仪表板
我们将这个仪表板称为索伦。我们通过Graphite监控软件、Rails框架和Angular框架实现了这个仪表板。这不是一件太复杂或难以做到的事情,但是它确实是一个十分有用的仪表板,因为我们可以通过一张图片看到整块生产的情况。我们可以看到我们是否有很多缓存没有命中,它是一个很标准的仪表板指标,拥有它事情就好办多了,当我们切换到HLS协议时就可以通过这个观察缓存指标。
13:45缓存配置
将协议从RTMP切换成HLS几乎是完美的,但我们也遇到了一些问题。由于我们使用NGINX作为缓存软件,当我们缓存数据时我们就将精力都放到你的缓存中了,所以你想将所有请求都挡在缓存前不让他们到达后端,这种事情是我们常见而且常做的,但我们很容易忽略了一个很简单的事情。比如说,一个请求可能是请求一个过期的视频,这个请求就会被穿透到后端,但如果越来越多的请求都是此访问过期的视频的话,而NGINX还在处在更新缓冲区的信息的状态,这时将会发生什么情况?
如果你没有将它的配置设置地合适,这些所有的请求都会穿透你的缓存层直接导致你的后端处于高负载情况。所以别忘了使用proxy_cache_use_stale配置,特别是在更新时。
15:30 OS微调
我们也做了一些负载测试,看看我们单独一台机器能获取多少的网络流量,而且我们注意到只是使用了NGINX和我们服务器需要的软件,我们虽然有10G的网卡,但我们只能获取到最多5Gbps的网络吞吐量,这样的性能不是很好。
我们开始在互联网上查找问题出在哪里,最终我们解决了此问题,而且问题不在NGINX上。每当一个请求到达你的网络时,它会触发一个中断,而这需要做一些处理,我不知道这个问题是不是所有服务器都会出现,但如果你不特意在我们的服务器上进行配置,你将会发现这个问题,因为所有的请求都跑到同一个CPU上去了。所以我们将这个问题解决了而且使用了irqbalance服务,然后,我们就能够达到10Gbps的吞吐量了。
然后我们意识到我们其实可以获取到更多的比特流量,但使用了irqbalance服务,我们丢失了很多包,经过进一步深入研究,我们发现使用CPU的亲和力是更好的方式。
Juarez:是的,我们为每个网卡都创建了若干个中断,每个中断都被固定到一个CPU上,所以我们用此方式替代了原来一个CPU处理所有中断,这时就可以将负载分散到多个CPU上,通过这种方式我们可以将网卡的吞吐量提高到网卡的极限。
Leandro:是的,因为我们有两个网卡,我们可以把他们结合在一起,这样每台机器就有了20Gbps的吞吐量。
Juarez:所以主要的结论就是,我们不需要对NGINX本身做调整,而仅仅是对操作系统微调,NGINX就能工作的异常成功。
17:50从NGINX和HLS中获益
Leandro:来个总结,通过将协议从RTMP换成HLS和使用NGINX我们摆脱了端口被防火墙阻止的情况,因为我们都是使用HTTP协议端口80。NGINX给了我们神奇的缓存,它也让我们系统拥有容易的可扩展性,因为它只是与另一个机器或虚拟机热插拔的事。我们能在用户体验上取得更好的成功,因为HLS协议擅长根据用户带宽确定哪个比特率的流资源。而且我们也很喜欢仪表板,它让我们掌握整个系统的运作。
18:43我们的搭配
这些就是我们的搭配,拥有80个节点,而且我们使用了CentOS。
这篇博客是两部分的第一部分,重点是使用NGINX为流媒体进行传输和缓存。第二部分很快也会发布出来,它主要讨论环球网团队如何使用搭载了LUA第三方模块的NGINX来为视频平台搭建微服务。