FacebookLive是Facebook的视频直播产品,这个产品开始试水时只向名人大V开放,让他们可以通过直播和粉丝互动;对公众开放以后,并发访问量极大,一个热门的直播可能有上百万的人同时在线观看。应对这样多的并发访问,还要保证视频低延迟,是一个很难以解决的架构问题。
来自Facebook流量团队的Federico Laramie在Networking@Scale会议上分享了Facebook Live的缓存以及负载均衡系统的设计:
Facebook Live 在2015年4月上线,只向名人开放,之后的一年产品不断演进,技术团队从10人扩张到150人。在2015年底,向多个国家的用户同时开放。
协议选型
在协议层面上,他们一开始选用了HLS(HTTP Live Streaming),iPhone对于这个协议有很好的支持,而且由于它是基于HTTP,可以利用现有的CDN架构。同时,他们也开始调研RTMP协议(基于TCP),它在手机和服务器之间建立一个视频流和一个音频流。RTMP的好处在于从发布者到观众端到端的延迟较小,延迟在支持交互的直播中对用户体验影响很大;但是缺点在于协议不是HTTP的,因此需要开发RTMP的代理服务,以方便扩展。同时调研的还有MPEG-DASH协议,相对于HLS,它更加节省空间。
直播的技术挑战
直播的流量和其他互联网产品相比有其独特之处,见下图:
直播开始时,并发访问量有一个陡峭的上升,然后继续攀升,直到直播结束,访问量直线下降。也就是说访问量上升极快。此外,很多产品的因素导致直播的观看量比普通视频要大很多,一般要3倍以上。
瞬间增加的访问会给缓存系统和负载均衡系统带来很多问题。
- 缓存的问题
相信大家都听过Thundering Herd问题,在缓存失效的时候,大量的访问意味着大量的回源请求,导致数据源处的请求大量堆积。
视频是分割成一秒钟的片段文件传输给用户的,缓存系统会缓存这些片段,但是当访问量过大的时候,缓存也会过载。 - 负载均衡的问题
Facebook有很多PoP服务器遍布世界各地(边缘服务器),用于分发Facebook在全世界各处的流量。在流量过大的时候,PoP服务器都有可能过载。
整体架构
直播流从播主到观众的过程是这样的:
- 播主在手机上启动直播
- 手机向直播服务器建立一个RTMP的音频视频流
- 直播流服务器解码这个视频,并转换成多种不同码率
- 对于每一种码率,持续生产一秒钟的MPEGDASH片段
- 这些1秒钟的片段存储在数据中心的缓存中
- 数据中心的缓存把片段发给多个PoP服务器的缓存
- 用户看到直播信息,开始收看
- 用户手机开始从PoP服务不断获取1秒钟的片段播放
怎样扩展?
在这样大的并发流量面前,必须引入多层次的缓存和负载均衡。在数据中心的缓存和多个PoP缓存之间有一个流量放大(multiplication),在每个PoP节点上,还有另一层流量放大:PoP包含两个层次,一层HTTP代理和一层缓存。观众是从HTTP代理处获取片段的,代理层检查片段是否在PoP的缓存中,如果在,直接返回;如果不在,向数据中心缓存发送请求。因为不同的片段可能存放于不同的缓存中,这有助于在缓存层次均衡负载。
如果很多观众同时请求同样一个片段,而这个片段不在PoP缓存中,就会导致有很多请求(每个用户一个请求)发往数据中心的缓存,造成Thundering Herd问题。解决的方案是引入请求合并(Request Coalescing),即只把第一个请求发往数据中心,其他请求在PoP排队等待第一个请求的响应,然后数据被回复给所有请求者。
即使如此,所有的观众都在一个PoP的cache服务等待,也会造成这个服务的过载。所以在代理层次又增加了一个本地的缓存,同样使用了请求合并的技巧,让代理本身直接挡住了大量的请求。
即使有了上面的措施,PoP还存在过载的风险。因为直播流量上升极快,PoP的负载还来不及通知到负载均衡系统的时候,就可能出现过载。这时只能依靠全球的负载均衡系统Cartographer。
Cartographer这个系统把全球的子网映射到PoP,它会度量各个子网和PoP之间的延迟,同时也会度量各个PoP的负载情况(每个代理节点上有请求的计数器,一个PoP所有代理节点的计数器求和就是这个PoP的负载)。用这两项数据,Cartographer面对的就是一个最优化问题:在保证PoP不超过负载的前提下,最小化用户请求的延迟。
因为直播流量会急速上升,这个控制系统的度量和反应时间也要极快,为此,他们把Cartographer的度量时间窗从1.5分钟缩小到3秒钟,但是, 3秒的时间PoP仍然有过载威胁。怎么办?只能在流量到来之前想办法预测。
他们用三次样条曲线实现了一个流量的预测程序,通过对于前面的负载和当前的负载拟合出未来流量的走势。这样,即使当前流量处于上升态势,也能预测未来流量的下降:对曲线取一阶和二阶导数,如果速率为正,但是加速度为负,就说明上升速率在减小,最终会变成0,这就是负载下降的开始。
实验证明三次样条比线性插值可以预测更为复杂的流量情况。而且对于抖动的容忍性更高。
怎样测试?
前面讲到如何防止PoP过载,但是测试的目的是,如何使PoP过载?
他们研发了一个压力测试服务,部署在全球的所有PoP上,模拟真实的用户流量,最高可以制造生产环境10倍以上的流量压力。这个测试系统帮助团队发现和解决了流量预测程序的bug,也验证了几个缓存层次对于Thundering Herd的承受能力。
上传稳定性问题
上传稳定性也是一个棘手的问题。因为用户的上传带宽是有限的,音频需要64Kbps的带宽,而标准分辨率视频需要500Kbps。
解决问题的方法就是适应性地调整编码,手机应用根据当前的可用带宽动态调整视频的比特率,而当前带宽的估算是由过去多个时段RTMP连接上的上传速率加权平均算得。