Facebook Live 的扩展之道

阅读数:517 2017 年 5 月 8 日

话题:Facebook语言 & 开发架构

2017 年 4 月 18 日和 19 日,Facebook 在 San Jose 召开了一年一度的F8 大会,本次大会通过 Facebook Live 进行了直播。Designing for Scale的博主 Wissam Abirached 通过 Facebook Live 观看了这届 F8 大会,他对 Facebook Live 是如何扩展以支持 F8 的这个问题产生了十分浓厚的兴趣,因此撰写了一篇名为《How Facebook Live Scales》的文章,由此也引出了 Facebook Live 的很多细节。

早在 2015 年底,Facebook 的工程师就在《Under the hood: Broadcasting live video to millions》一文中介绍了 Faceook Live 的一些细节。Facebook 拥有庞大的用户群,在面对流量尖刺的同时,还要尽可能降低延时以带来更强的参与感,他们遇到了什么问题,又是如何解决的呢?

首先是“惊群问题”(Thundering Herd Problem),它会造成延时、丢帧,甚至是掉线,为了避免直播流服务器(Live Stream Server)被大量请求冲垮,Facebook 构建了由直播流服务器、源服务器(Origin Server)和边缘缓存(Edge Cache)组成的三层结构。用户访问最近的边缘缓存,边缘缓存负责回源,源服务器向直播流服务器取得实际的内容。

Facebook 的 Arun Moorthy 在《Connecting the World: A look inside Facebook’s Networking Infrastructure》中对 Facebook 的全球节点做过介绍,数据中心主要在北美和欧洲,而边缘节点更是几乎遍布全球(除了南北极),加之还有自己定制的服务器、机柜与网络结构。在这样的基础设施支持下,Facebook Live 的服务器能尽可能地靠近用户。

如果某个边缘缓存负载过高,负载均衡器会将请求重定向到离该节点最近的另一个尚可提供服务的边缘缓存上,负载均衡器能够预测目标节点的负载情况,这是一个非常实用的功能。

在这种情况下,仍然会有 1.8% 的请求透过边缘缓存落到源服务器上,在海量请求下,1.8% 也是一个很大的数字。为了应对这个问题,边缘缓存只会让第一个请求回源,其他的相同请求则放在一个队列中,等第一个请求的结果返回了,它们也就不用再回源了。源服务器上也有类似的请求合并回源处理机制。Wissam Abirached 在文章中提到,如果使用 Nginx,可以将proxy_cache_lock设置为on开启请求合并功能。

另一方面,为了让直播的感受更加实时,Facebook 使用 RTMP 流协议每隔 2 到 3 秒就传输一次数据,RTMP 通过播放器与服务端的 TCP 长连接将音频与视频数据连续不断地推送给用户。在 RTMP 中,音频流与视频流是分开的,但都以 4KB 为单位,推模式与小数据块的结合,大大降低了延时,给用户带来更流畅的体验。

值得一提的是,国内的一些直播服务提供商也拥有与 Facebook 类似的架构,针对海量请求做了各种优化,可以说不亚于 Facebook。比如,七牛云白顺龙的《移动 CDN 及直播性能优化》(这篇《七牛直播云性能优化实践》博客的内容也是一样的),又拍云黄慧攀的《云直播系统架构与实施》,两者都提到了类似 Facebook 的多层服务器结构和网络智能调度系统(可能大家在节点部署上略有不同,毕竟服务的目标更多是在国内),能够在极大程度上保证用户的体验。大家也都对直播常用的协议进行了说明,介绍了 RTMP、HLS 和 HTTP-FLV,以及它们分别适用的场景,在各自系统中的位置。

此外,上述两个演讲中还提到了一些其他的优化,比如 GOP 缓存的权衡、多码率支持和 HTTP-DNS 等等,相信 Facebook 也有类似的处理。

如果您对 Facebook Live 的更多细节感兴趣,可以看看 Facebook 的 Federico Larumbe 在 @Scale 2016 上的这个演讲。在直播盛行的今天,相信一定有很多读者从事直播相关的工作,也欢迎大家分享自己的直播系统优化经验。