作者/ Abhishek Mathur
现任Facebook组技术PM,负责Facebook的视频和直播基础设施。曾任微软的首席项目经理和和开发经理,负责Azure Active活动目录的开发。

揭秘百万人围观的Facebook视频直播_缓存

Facebook 上有一些公众人物的粉丝多达百万。这就意味着当公众人物开始视频直播时,我们需要能够处理超过一百万人同时观看直播的潜在情况,比如范·迪塞尔的现场直播就是如此。大规模系统都不喜欢流量高峰,特别是当很多请求在一瞬间一起发生时。每到这种时候,我们就说我们遇到了一个“惊群效应”问题——太多的请求可能会使系统过载,导致直播的延迟、信息丢失,以及连接断开。


可以说,防止过载的最好方法就是不让负载穿过大门。与其让客户端直接和直播流服务器连接,我们让边缘缓存(edge caches)的网络分布到全局。


揭秘百万人围观的Facebook视频直播_缓存_02

在我们的实现中,一个视频直播被分割成了 3 秒的 HLS 段。显示直播的视频播放器会继续请求这些段。边缘数据中心的一个 HTTP 代理会处理段请求,该数据中心会检查这个段是否已经存在于一个边缘缓存中。如果在缓存中,它就会被返回。如果不在,代理就会向源缓存发出 HTTP 请求,而源缓存是另一个具有相同架构的缓存层。


揭秘百万人围观的Facebook视频直播_服务器_03


如果段不在源缓存中,就需要向处理这个特定视频流的服务器请求。


揭秘百万人围观的Facebook视频直播_缓存_04

然后服务器用段来返回 HTTP 响应,这个段就被缓存在每一层中,所以接下来客户端就会更快地收到这个段。利用这种组合,超过 98% 的段都已经存在了离用户较近的边缘缓存中,而源服务器只会收到很少部分的请求。


这个解决方案很不错,但是当你处于我们这样的规模时就会发生一些泄露——约有1.8%的请求会穿过边缘缓存。当你处理上百万个观看者时,这仍然是一个大数字。为了确保起源层不会发生故障,我们应用了一种名为请求合并的技术。


人们通常都会在不同时间观看常规的非直播视频。如果有什么东西突然爆红了,你就能看到流量高峰,所以这方面并没有分钟对分钟的平衡负载需求。但是对于视频直播来说,在事先没有通知的情况下大量的人都会在同一时间观看同一视频,这就造成了一个负载问题和一个缓存问题。人们在同一时间请求相同的视频段,而这个段可能还不在缓存中。如果没有防止惊群效应的计划,边缘缓存就会为所有客户端请求返回缓存未命中,而所有这些请求都会找到源缓存,然后进一步流向直播流服务器。这意味着一个单独的服务器会收到海量的请求。


揭秘百万人围观的Facebook视频直播_服务器_05


为了防止这种情况发生,边缘缓存为第一个请求返回缓存未命中,然后把接下来的请求放进队列中。一旦 HTTP 响应从服务器回来,这个段就被存储在了边缘缓存中,而列队中的请求也会作为缓存访问而获得边缘的响应。


揭秘百万人围观的Facebook视频直播_服务器_06

揭秘百万人围观的Facebook视频直播_服务器_07


这种方法有效地解决了惊群效应,降低了输送给源服务器的负载。源服务器反过来也用相同的机制来处理来自多个边缘缓存的请求——相同的对象既可以从芝加哥的边缘缓存中请求,也可以从迈阿密的边缘缓存中请求。


压低延迟


为 Facebook Mentions 构建 Live 功能是一种确保系统不过载的活动,而为用户构建 Live 是一种降低延迟的活动。非公众人物更有可能向一小群交互性很强的人进行直播。我们的头等大事就是,让人们拥有接近于实时效果的对话,没有尴尬的数据传输延迟。为了把延迟压缩到 2 到 3 秒的传输内,我们决定使用 RTMP。


RTMP 是一种在整个直播过程中维护播放器和服务器之间持久的 TCP 连接的流协议。和 HLS 有所不同,RTMP 使用的是推模型。与其向播放器请求每个段,还不如让服务器持续发送视频和音频数据。当人们发出暂停和继续的请求或播放器不可见时,客户端仍然可以发出这些指令。


揭秘百万人围观的Facebook视频直播_缓存_08


在 RTMP 中,直播被分成了两个流:一个视频流和一个音频流。这些流被分解成了 4KB 的区块,这些块可以在 TCP 连接中被多路复用,即视频和音频块被交叉存取。当视频比特率达到 500Kbps 时,和每个 HLS 段的 3 秒时长相比,每个块只有 64ms,它让穿过所有组件的流都更加顺畅。只要编码了 64ms 的视频数据,直播者就可以发送数据;转码服务器可以处理这个区块并且生成多种输出比特率。区块随后通过代理被转递出去,直到到达播放器。


揭秘百万人围观的Facebook视频直播_缓存_09


推模型加上小区块减少了 80% 的直播者和观看者之间的延迟,产生了顺畅并且交互的体验。大部分直播流产品使用 HLS 是因为它基于 HTTP 而且容易和所有现存的 CDN 进行整合。但是我们想要实现最佳的直播流产品,所以我们决定通过修改 nginx-rtmp 并且开发一个 RTMP 代理来实现 RTMP。从 HLS 路径上得到教训让我们实现了一个可以有效扩展到几百万直播者的 RTMP 架构。


继续向前


关于 Facebook Mentions 的 Live 功能我们已经获得了很多不错的反馈,我们很高兴能看到人们对于这个直播新功能的想法。如果你有任何关于我们如何构建 Live 的问题,请在 Facebook Engineering 的网页上跟我们取得联系。


感谢工程师、PM,以及所有其他让这一切成为可能的团队成员。


欢迎关注“互联网架构师”,我们分享最有价值的互联网技术干货文章,助力您成为有思想的全栈架构师,只聊架构,不聊其他!打造最有价值的架构师圈子和社区。

长按下方的二维码可以快速关注我们


揭秘百万人围观的Facebook视频直播_facebook_10