Facebook Live视频直播是如何支撑百万人在线?

本文讨论当数百万用户追随名人直播时所发生的流量高峰。在分析Facebook Live架构如何扩展支撑百万人在线之前,我们先看看构建这样一个产品所面临的一些挑战:

该公司首席产品官Chris Cox 在2016年4月份接受了Wired 1采访,他列举了以下挑战,考虑到截至2016年底,Facebook上每月有超过18.6亿用户的活跃用户:

1.需要能够同时提供数百万个流
2.需要能够在同一个流上支持数百万用户

他说:“ 这就是一个非常困难的基础设施问题 ”,这使得问题的解构和分析更为激动人心。

实时视频另一个独特挑战是流量高峰,基础架构必须能够处理巨大的流量尖峰。例如,当名人开始实时视频流时,视频一直在直播用户不断加入,都将会有巨大的尖峰流量,当视频结束时流量却显著降低,因此,主要的挑战是在播放直播时优雅地处理高峰流量。

本文目的专注于当数百万用户追随名人直播时所发生的流量高峰。在这样的情况下,超过一百万人可以同时观看直播,并且假设他们都会在同一时间加入,这会对服务器和基础设施造成重大压力。

当所有这些请求立即进入 - 这被称为雷霆群体问题(the thundering herd problem) - 它可能导致各种问题,如响应滞后,数据包丢弃,甚至阻止用户加入直播。

当有可能遇到这样的问题时,您应该首先做的是防止所有请求直接访问您的流媒体服务器,因为这可能是致命的,会摧毁所有服务器。相反,您应该设法添加多个层以过滤这些请求,并确保只有必要的请求才能发送到流服务器。

这可以通过许多不同的方式实现,这取决于您的产品的大小和用户数量。在Facebook的情况下,他们选择了以下架构:


请求--->边缘缓存(Edge Cache) --->源服务器 --->流服务器

请注意,边缘缓存服务器遍布全球,以支持Facebook的全球影响力。边缘缓存和源服务器的关系是多对一,多个边缘缓存服务器可以将请求发送到同一个源服务器。

流程如下:

1.请求首先触发最接近用户的边缘缓存服务器,以减少用户和服务器之间的延迟。边缘缓存服务器本质上是一个缓存层,并不做太多的处理。

2.如果请求的数据包在边缘缓存中,则它们将返回给用户。

3.如果它们不在边缘缓存中,则将请求转发到源服务器,该服务器是另一种缓存服务器,并且与边缘缓存服务器具有类似的架构。

4.如果请求的数据包在源服务器中,那么它们将返回给边缘缓存,然后将它们返回给用户。

5.如果它们不在源服务器中,则将请求转发到处理该实况广播的特定流服务器。然后,流服务器将数据包返回给源服务器,源服务器将它们返回到边缘缓存。边缘缓存会缓存响应并将数据包返回给用户。

6. 对于未来请求的相同数据包将由边缘缓存简单地处理,这加快了流程的难度,从而降低了流服务器的负载。

我们可以看到,这个架构大大减少了使它到流媒体服务器的请求数量。举例来说,如果5个请求依次访问边缘缓存,只有第一个会一路去访问最后面的流媒体服务器,而另外4人将立刻从边缘缓存得到响应。

然而,这仍然不足以满足Facebook的需求。事实上,根据Facebook 3发布的一篇文章,这种架构仍然泄露了大约1.8%请求直接访问流服务器。在数百万的请求中,1.8%的数据泄漏是巨大的,并且对流服务器造成了很大的压力。

为什么会泄漏这么多请求?

上述架构的第一个缺陷是,多个请求第一次同时访问同一边缘缓存情况下,这些并发请求都会直接访问到原始服务器。边缘缓存会将访问缓存中没有的数据包的所有请求转发到下一层,如果同时请求都需要数据包A,并且它不在缓存中,则所有这些请求将被转发。以Facebook规模推算,我们可以快速看到如此多的请求被泄漏。这是发生在边缘缓存和原始服务器之间。

架构中的第二个缺陷是多个边缘缓存可以向原始服务器发送相同的数据包请求,原始服务器会将所有这些同时发送的请求转发到流服务器,因为数据包不在缓存中。这与第一种缺陷类似,只是它发生在原始服务器与流服务器之间级别。

再次,对于普通产品来说,1.8%似乎不是很多,但是在Facebook的规模上,确实是一个需要解决的重要问题。

Facebook解决这个问题是有创意的,但却很容易理解:

当对同一个数据包的多个请求命中边缘缓存时,它们被分组到一个请求队列中,只有一个进入到源服务器。这被称为请求合并。一旦响应来自服务器,它将被存储在缓存中,然后从缓存中响应队列中的请求。

例如,当10个并发请求访问边缘缓存时,它们都被添加到相同的请求队列中,变成一个请求队列,这有助于减少请求的泄漏。如果我们将这种情况与原来进行比较,原来情况是所有10个并发请求都将被转发到下一关,这里我们会看到性能的巨大增长。

原始服务器级别也应用了相同的概念,其中所有来自一个或多个边缘缓存端点的相同数据包的请求都分组在一起,只有其中一个通过流服务器。不用说,这大大减少了流媒体服务器的开销,特别是考虑到现场直播可能会收到巨大的请求数量。


Facebook实施的另一个重要调整是边缘缓存服务器的负载平衡。在某些情况下,尽管使用请求合并,但边缘缓存服务器可能会超载,并且不再运行。为了避免这种情况,负载平衡器将请求重定向到最接近的边缘缓存,并提供该请求的可用性。例如,如果最接近您的边缘缓存器已经服务了200 000个请求,那么负载平衡器可能会将您转发到负载较轻的只有一半的请求数量的边缘缓存,这意味着会得到很快的响应。

Facebook通过不断测量这些服务器上的负载并跟踪其性能,确定哪个边缘缓存可用。并且使用一种算法来提前预测负载发生,这是不可思议的。算法的基础是足够复杂的,它需要专门的文章介绍。


需要说明的是,前面所说的请求排队都是使用Nginx实现以防止泄漏的,配置Nginx时启用proxy_cache_lock为on(默认值为off)。文档解释在这里:

当这个配置启用时,按照proxy_cache_key缓存元素的标识符,一次只允许一个请求转发传递给后台的代理服务器。同一缓存元素的其他请求将等待缓存中出现响应,或者释放该元素的高速缓存锁,直到proxy_cache_lock_timeout指令设置的时间为止。

以上对Facebook Live的架构进行了很多有趣的研究和剖析,研究了工程师是如何能够将产品扩展到数百万用户。虽然我们可能永远不会构建达到如此大量用户的产品,但是我们可以在自己的产品中使用很多经验教训,例如在架构中添加多个层次可以帮助过滤通过的请求数量。这反过来又提高了服务器的性能和可用性,为用户提供了更好的产品,并帮助其扩展。

How Facebook Live Scales
[该贴被banq于2017-04-28 15:53修改过]