多年来Netflix一直是全球最好的在线订阅式视频服务供应商,其带宽占全球互联网带宽容量的15%以上。2019年,Netflix已经拥有了1.67亿用户,每季度新增用户超过500万,在200多个国家和地区运营。Netflix的用户每天观看视频超过1.65亿小时,每天点播了4000多部电影以及4.7万集剧集。从工程的角度来看,Netflix的技术团队为了服务于全球用户,设计了如此惊人的视频流媒体系统,该具备非常高的可用性和可扩展性。
然而,Netflix的技术团队花了8年多的时间,才打造了现有的系统([1])。实际上,Netflix的基础设施转型始于2008年8月,当时Netflix经历了一次系统宕机(在自己的机房),导致整个DVD租赁服务中断了三天。Netflix意识到,它需要没有单点故障的更可靠的基础设施。因此,它做出了两个重要的决定:将IT基础设施从自己的数据中心迁移到公共云上,用微服务架构取代单体应用程序。这两个决定直接导致了Netflix今天的成功。
Netflix之所以选择AWS云([[4])来迁移其IT基础设施,是因为AWS可以提供高度可靠的数据库、大规模云存储和全球多个数据中心。通过利用AWS构建和维护的云基础设施,Netflix没有做建设数据中心这种无差别化的重活,而是更专注于高质量流媒体的核心业务。尽管它需要重建整个技术栈,让其在AWS云上顺利运行,但同时也收获了系统的可扩展性和可用性的提升。
Netflix也是微服务架构的主要推动者之一。微服务针对单体软件设计中存在的问题,鼓励分离关注([11]),单体程序通过自身的模块化和数据封装被分解成更小的软件组件。微服务还有助于通过横向扩展和工作负载分区来提高可扩展性。通过采用微服务,Netflix的工程师可以轻松地改变任何服务,从而实现更快的部署。更重要的是,他们可以跟踪每个服务的性能,并快速将其与其他运行中的服务隔离开来。
在本文中,我试图阐述Netflix的云架构在不同工作负载和网络限制下的性能。具体来说,我想从可用性、延迟、可扩展性和从网络故障或系统中断的恢复能力等方面分析系统设计。本文的组织方式如下。第2节将描述Netflix系统架构。然后在第3节,将更详细的讨论系统组件。在第4、5、6、7节中,我将根据上述设计目标对系统进行分析。最后,我总结了从这次分析中学习到的东西以及下一步可能需要改进的地方。
Netflix基于亚马逊云计算服务(AWS)和内部CDN Open Connect(Open Connect)运营([1])。这两个系统必须无缝配合,才能在全球范围内提供高质量的视频流媒体服务。从软件架构上看,Netflix主要由三部分组成。客户端、后台和CDN。
客户端是指笔记本电脑或台式机上的任何支持的浏览器,或者智能手机或智能电视上的Netflix应用。Netflix开发自己的iOS和Android应用,为每一个客户端和设备提供最佳的观看体验。通过其SDK控制自己的应用和其他设备,Netflix可以在某些情况下透明地调整流媒体服务,比如网络速度慢或服务器过载等情况下,Netflix可以对其流媒体服务进行调整。
后端包括在AWS云上运行的服务、数据库、存储。Backend基本上可以处理所有不涉及流媒体的工作。Backend的一些组件及其对应的AWS服务如下。
可扩展计算实例(AWS EC2)
可扩展存储(AWS S3)
业务逻辑微服务(Netflix专门打造的框架)
可扩展的分布式数据库(AWS DynamoDB、Cassandra)。
大数据处理和分析工作(AWS EMR、Hadoop、Spark、Flink、Kafka和Netflix的其他专用工具)。
视频处理和转码(Netflix的专用工具)
Open Connect CDN是一个名为Open Connect Appliances (OCAs)的服务器网络,用于存储和串流大型视频。这些OCAs服务器分布在位于世界各国的ISP和IXP网络内。OCAs负责将流媒体传输到客户端。
在下面的章节中,笔者将介绍由上述3部分组成的Netflix云架构。在2.1节中,我们将描述播放架构。然后在2.2节中,将描述更详细的Backend的微服务架构,展示Netflix如何处理全球规模下的可用性和可扩展性问题。
当用户在自己的应用程序或设备上点击播放按钮时,客户端将与AWS上的Backend和Netflix CDN上的OCAs进行通信,以流化视频([[7])。) 下图说明了播放过程的工作原理。
OCA会不断向运行在AWS EC2中的Cache Control服务发送有关其工作负载状态、例行性和可用视频的健康报告,以便Playback Apps向客户端更新健康OCA信息。
从客户端向 Playback Apps 服务发送 Play 请求,以获取流媒体视频的 URL。
Playback Apps服务必须确定Play请求是否有效,才能查看特定视频。这里会验证用户计划、视频在不同国家的授权等。
Playback Apps服务会与 Steering服务进行通信,以获得所请求的视频的OCAs服务器列表。Steering服务使用客户端的IP地址和ISP信息来确定一套最适合该客户端的OCAs。
客户端从Playback Apps服务返回的10个不同的OCAs服务器列表中,测试与这些OCAs的网络连接质量,并选择一个最快、最可靠的OCA来请求视频文件流媒体。
所选的OCA服务器接受客户端的请求,并开始流化视频。
在上图中,Playback Apps服务、Steering服务和Cache Control服务完全是在AWS云上运行的微服务。在下一节中,我将介绍Netflix后端微服务架构,它提高了服务的可用性和可扩展性。
正如我在前面的章节中所描述的那样,Backen处理了从注册、登录、计费到视频转码和个性化推荐等复杂任务。为了支持在同一底层基础设施上运行的轻量级和重量级工作负载,Netflix选择了微服务架构。图2中的示意图代表了Netflix的微服务架构,这是笔者从多篇文章中总结而成。
客户端向运行在AWS上的Backend发送Play请求。该请求由 AWS ELB 处理。
AWS ELB将把该请求转发到Zuul API网关,该网关是由Netflix团队构建的,可以实现动态路由、流量监控和安全检测、抗故障弹性。请求会被应用到一些预定义的过滤器,然后转发到Application API进行进一步处理。
应用API组件是Netflix的核心业务逻辑。有几种类型的API对应于不同的用户活动,如注册API、推荐API等。在这个场景下,API网关服务的转发请求由Play API处理。
Play API会调用一个微服务或一系列微服务来完成请求。图1中的Play App服务、Steering服务和Cache控制服务都是此图中的微服务。
微服务大多是无状态的程序,可以相互调用。为了控制它的级联故障,每个微服务都使用Hystrix进行熔断,由Hystrix将其与调用进程隔离。调用结果可以缓存在本地内存中,以保证那些关键的低延迟请求。
微服务可以保存获取的数据。
微服务可以将用于跟踪用户活动或其他数据的事件发送到流处理管道中,用于实时处理个性化推荐或商业智能任务的批处理。
从流处理管道中出来的数据可以持久化到其他数据存储,如AWS S3、Hadoop HDFS、Cassandra等。
上面所描述的架构让我们大致了解了不同件是如何组织和协同工作的。然而,要分析这些架构的可用性和可扩展性,我们还需要深入到每个重要的组件,看看其在不同工作负载下的表现如何。这将在下一节中介绍。
在本节中,我想深入研究第2节中定义的组件,以分析其可用性和可扩展性。在描述每个组件时,我还会分析它是如何满足这些设计目标的。在后面的章节中会有关于整个系统的更深入的设计分析。
Netflix的技术团队在开发客户端应用上投入了大量精力。即使是在一些智能电视上,虽然Netflix没有构建专门的客户端,但是仍然通过SDK来控制其性能。事实上,任何设备环境都需要安装Netflix Ready Device Platform (NRDP),以实现最佳的Netflix观看体验。典型的客户端架构组件([[11])如图3所示。
客户端应用程序使用两种类型的连接请求后台进行内容发现和播放。客户端使用NTBA协议([[15])进行播放请求,以确保其OCA服务器位置的安全性,并消除SSL/TLS握手导致的新连接延迟。
在播放流媒体视频时,如果网络连接过载或出现错误,Client App会智能地降低视频质量或切换到不同的OCA服务器([[1])。即使所连接的OCA过载或出现故障,Client App也可以轻松地切换到另一个OCA服务器,获得更好的观看体验。Netflix SDK会持续跟踪从Playback Apps服务中获取的最新健康OCA(图1)。
API 网关服务
API网关服务组件与AWS负载均衡器(ELB)进行通信,服务来自客户端的所有请求。这个组件可以部署到不同区域的多个AWS EC2实例中,以提高Netflix服务的可用性。图4中的图是Netflix团队创建的Zuul API Gateway的开源实现。
Inbound 过滤器可用于认证、路由和装饰请求。
Endpoint 过滤器用于返回静态资源或将请求路由到适当的Origin或应用程序API进行进一步处理。
Outbound 过滤器可用于跟踪指标、装饰响应或添加自定义头。
Zuul 可以和 Eureka 集成,发现新的应用程序API。
Zuul被广泛用于各种流量路由,如新API的上线、负载测试等。
应用API
应用API在Netflix微服务中扮演着服务编排([[18])的角色。API按照需要组合调用底层微服务的逻辑,并组合其他数据存储的附加数据来构造相应的响应。由于应用API组件与Netflix的核心业务功能相对应,因此Netflix团队在设计应用API组件时花了很多时间。它还需要保证在高并发下的可扩展性和高可用性。目前,应用API被定义为三类。注册API,用于非会员请求,如注册、计费、免费试用等;探索API,用于搜索、推荐请求;播放API,用于流媒体、观看授权请求。应用API的详细结构组件图如图5所示。
在最近的Play API实现更新中,Play API和微服务之间的网络协议使用gRPC/HTTP2,"允许通过protocol buffer定义RPC方法和实体,自动生成各种语言的客户端库/SDK"([13])。这一变化使Application API能够使用双向通信并与客户端适当地集成,并 "最大限度地减少跨服务边界的代码重用"。
Application API还提供了一个基于Hystrix命令的通用弹性机制来保护其底层微服务。
由于Application API需要处理海量的请求,其内部处理需要高度并行运行。Netflix团队发现,同步执行和异步I/O的结合([13])是正确的方法。
来自API网关服务的每个请求都将被置于应用API的网络事件循环中进行处理。
每个请求将由一个专门的线程处理程序,将Hystrix命令,如getCustomerInfo,getDeviceInfo等放入传出事件循环。这个传出事件循环是每个客户端设置的,并以非阻塞I/O的方式运行。一旦调用的微服务完成或超时,专用线程将构造相应的响应。
微服务
从Martin Fowler的定义来看,"微服务是一组服务,每个服务在自己的进程中运行,并通过轻量级机制进行通信........."。这些程序是可以独立部署或升级的,并且有自己的封装数据。
图7是Netflix公司的微服务组件的实现([11])。
一个微服务可以独立工作,也可以通过REST或gRPC调用其他微服务。
微服务可以使用于图6中描述的应用程序接口的实现,其中请求会被放入网络事件循环,而来自其他被调用的微服务的结果会以异步的非阻塞式I/O方式放入结果队列。
每个微服务有自己的数据存储和缓存。在Netflix,EVCache是微服务缓存的主要选择。
数据存储
在将基础设施迁移到AWS云上时,Netflix使用了不同的数据存储(图8),包括SQL和NoSQL([6])。
正在上传…重新上传取消
MySQL 数据库用于电影标题管理和交易/计费系统。
Hadoop 用于用户日志的大数据处理。
ElasticSearch 为 Netflix 应用程序提供了搜索标题的功能。
Cassandra 是一个基于列式存储的分布式 NoSQL 数据存储,可以处理大量的读取请求,没有单点故障。为了优化写请求的延时,所以采用了Cassandra。
流处理管道
Stream Processing Data Pipeline([14,3])已经成为Netflix业务分析和个性化推荐任务的数据骨干。它负责生产、收集、处理、聚合所有微服务事件,并将所有微服务事件近乎实时地转移到其他数据处理器。图9显示了该平台的各个部分。
该数据流处理平台每天处理了数万亿事件和千万亿字节的数据。它还将随着用户数量的增加而自动扩展。
路由器模块可以将数据路由到不同的数据汇或应用,而Kafka则负责为下游系统进行消息路由以及缓冲。
流处理即服务(SPaaS)允许数据工程师建立和监控流处理应用,而平台将负责可扩展性和运维。
Open Connect是一个全球内容交付网络(CDN),负责存储并向全球范围内的用户交付Netflix电视节目和电影。Netflix通过将人们想看的内容尽可能地推送到用户附近,以保证高效推流。为了将 Netflix 视频的流量本地化,Netflix与世界各地的互联网服务提供商(ISPs)和互联网交换点(IXs或IXPs)合作,在其网络内部部署专门的设备,称为Open Connect Appliances(Open Connect Appliances,简称OCA)([7])。
OCAs是用于从IX或ISP站点直接存储流媒体文件并将其流化的服务器。这些服务器会定期向AWS上的Open Connect控制平面服务报告路线情况,以及他们在SSD磁盘上存储了哪些视频。控制平面服务会根据文件可用性、服务器健康状况和网络接近客户端的情况,将这些数据自动引导客户端设备并计算最优化的OCA。
控制平面服务还可以控制夜间在OCAs上添加新文件或更新文件的填充行为。这些填充行为([[8,9])如图11所示。
当新的视频文件被转码成功并存储在AWS S3上时,AWS上的控制平面服务会将这些文件传输到IXP内的OCAs服务器上。这些OCAs再将这些文件传输到ISPs内的OCAs服务器。
当OCAs服务器成功存储了视频文件后,如果有需要,它就可以启动对等填充,将这些文件复制到同一站点内的其他OCAs服务器上。
在2个不同的站点之间,可以看到对方的IP地址,OCAs可以应用分层填充过程,而不是普通的缓存填充。
在前面的章节中,我已经详细描述了云架构及其支撑 Netflix 视频流媒体的业务组件。在本节和后续章节中,我想深入分析一下该架构。我先从最重要的设计目标开始,具体如下。
确保流媒体服务在全球范围内的高可用性。
通过弹性来应对网络故障和系统中断。
最大限度地减少流媒体延迟。
支持高并发情况下的可扩展性。
在这几个小节中,我将分析流媒体服务的可用性和相应的最佳延迟。第6节将更深入地分析有关弹性机制,如混沌工程等,而第7节将讨论流媒体服务的可扩展性。
根据定义,系统的可用性是指在一定时间内(在不保证包含最新版本信息的情况下)完成请求的次数来衡量的。在我们的系统设计中,流媒体服务的可用性既取决于后端服务的可用性,也取决于保存流媒体视频文件的OCAs服务器。
Backend服务的目标是通过缓存或者通过微服务来获取最健康的OCAs列表。因此,其可用性取决于涉及Playback请求的不同组件:负载均衡器(AWS ELB)、代理服务器(API网关服务)、Play API、相应微服务、缓存存储(EVCache)和数据存储(Cassandra)。
负载均衡器可以通过将流量路由到不同的代理服务器,防止工作负载过载,从而提高可用性。
Play API通过Hystrix控制微服务的执行超时,这可以帮助预防级联故障。
微服务可以用缓存中的数据来响应Play API,以防止调用外部服务或数据存储的时间比预期的要长。
缓存是有副本的,以便更快地访问。
当从Backend接收到OCAs服务器列表时,客户端会探测网络到这些OCA,并选择最好的OCA连接。如果该OCA在流媒体过程中出现过载或失败,那么客户端就会切换到另一个好的OCA。因此它的可用性与其ISP或IXP中所有OCA的可用性高度相关。
Netflix流媒体服务的高可用性是以多区域AWS运维的复杂性和以及OCAs服务器的冗余为代价的。
流媒体服务的延迟主要取决于 Play API 能否快速找到健康 OCA 列表,以及客户端与所选 OCA 服务器的连接情况如何。
正如我在应用API组件部分所描述的那样,Play API不会永远等待微服务的执行,因为它使用Hystrix 来控制相应时间,如果超时就从缓存中获取老数据。这样做可以控制延迟在可接受范围内,同时也可以阻止级联故障。
如果当前选择的OCA服务器出现网络故障或该服务器过载,客户端将立即切换到附近其他可靠 OCA 服务器。如果发现网络连接质量下降,它还可以降低视频质量。
在上面描述的系统设计中,考虑如下的取舍。
低延时高于一致性
高可用性高于一致性
低延时高于一致性是内置于后端服务的架构设计中。Play API可以从EVCache存储中获取老数据,也可以从Cassandra等最终一致的数据存储中获取。
同样的,可用性优于一致性,宁愿在可接受的延迟下响应请求,而不需要在像Cassandra这样的数据存储中的最新数据上执行微服务。
在可扩展性和性能之间还有一个并不相关的取舍([21])。在这种取舍中,通过增加实例数量来提高可扩展性,以处理更多的工作负载,可能会导致系统预期性能不断提高。这可能存在工作负载在可用worker之间没有很好地平衡。然而,Netflix已经通过AWS自动扩展解决了该问题。我们将在第7节中更详细地讨论这一解决方法。
设计一个能够从故障或中断中自我恢复的云系统,一直是Netflix长期以来的目标。这套系统常见的一些故障,主要有以下几点。
解决服务依赖关系的故障。
执行一个微服务失败会导致其他服务的级联故障。
由于过载导致API请求失败。
连接到一个实例或服务器(如OCA)失败。
为了检测和解决这些故障,API网关服务Zuul([[20])内置了自适应重试、限制并发调用Application API等功能。相应的,Application API使用Hystrix 来熔断调用微服务,以防止级联故障,并将故障点与其他故障点隔离。
Netflix的技术团队也以混沌工程实践闻名。其想法是将伪随机错误注入生产环境中,并构建解决方案来自动检测、隔离和恢复此类故障。错误可能会导致延迟增加,终止服务,服务器或实例暂停,甚至拖垮一个区域的整个基础设施([5])。通过有目的地将现实生产故障引入到受监控的环境中,用工具检测和解决这类故障,Netflix 可以在引起更大的问题之前迅速发现并解决这类故障。
在本节中,我将分析Netflix流媒体服务的可扩展性,包括水平扩展、并行执行和数据库分区。其他部分如缓存和负载均衡等也有助于提高可扩展性。
首先,Netflix的EC2实例的水平扩展是由 AWS 自动扩展服务提供的。该AWS服务会在请求量增加时自动增加更多实例,并关闭未使用的实例。更具体地说,在这些成千上万的实例之上,Netflix构建了一个开源的容器管理平台Titus([17]),每周运行约300万个容器。而且,架构图2中的任何组件都可以部署在容器内部。此外,Titus允许容器在全球不同大洲的多区域运行。
其次,在3.2.2节中实现的应用API或微服务,通过在网络事件循环和异步输出事件循环上并行执行任务,增强可扩展性。
最后,像 Cassandra 这样的列存储和像ElasticSearch这样的键值对象存储也提供了高可用性和高可扩展性,没有单点故障。
本文描述了Netflix公司的流媒体服务的云架构。分析了可用性、延迟、可扩展性和对网络故障或系统中断的恢复能力等方面的不同设计目标。简而言之,Netflix的云架构,经过他们的生产系统的验证,可以在数千台服务器上运行,为数百万用户提供服务,在全球范围内,通过与AWS云服务的集成,表现出了高可用性,低延迟、强大的可扩展性,以及对网络故障和系统中断的恢复能力。
参考链接:
Netflix: What Happens When You Press Play? By Todd Hoff on Dec 11, 2017. Link
High Quality Video Encoding at Scale. By Anne Aaron and David Ronca on HighScalability. Dec 9, 2015. Link
Building and Scaling Data Lineage at Netflix to Improve Data Infrastructure Reliability, and Efficiency. By Di Lin, Girish Lingappa, Jitender Aswani on The Netflix Tech Blog. Mar 25, 2019. Link
Ten years on: How Netflix completed a historic cloud migration with AWS. By Tom Macaulay on Computerworld. Sep 10, 2018. Link
The Netflix Simian Army. By Yury Izrailevsky and Ariel Tseitlin on The Netflix Tech Blog. Link
Globally Cloud Distributed Applications at Netflix. By Adrian Cockcroft. Oct 2012. Link
Open Connect Overview. By Netflix. Link
Open Connect Deployment Guide. By Netflix. Link
Netflix and Fill. By Michael Costello and Ellen Livengood. Aug 11, 2016. Link
Automating Operations of a Global CDN. By Robert Fernandes at Strange Loop. Sep 14, 2019. Link
Mastering Chaos — A Netflix Guide to Microservices. By Josh Evans at QCon. Dec 07, 2016. Link
Netflix Revenue and Usage Statistics. By Mansoor Iqbal on BusinessofApps. March 6, 2020. Link
Netflix Play API — Why we build an Evolutionary Architecture. By Suudhan Rangarajan at QCon 2018. Dec 12, 2018. Link
Keystone Real-time Stream Processing Platform. By Zhenzhong Xu on The Netflix Tech Blog. Sep 10, 2018. Link
Netflix Releases Open Source Message Security Layer. By Chris Swan on InfoQ. Nov 24th, 2014. Link
Netflix Open Source. Link
Titus, the Netflix container management platform, is now open source. By Amit Joshi and others. Link
Engineering Trade-Offs and The Netflix API Re-Architecture. By Katharina Probst and Justin Becker on The Netflix Tech Blog. Aug 23, 2016. Link
Kafka Inside Keystone Pipeline. By Real-Time Data Infrastructure Team. April 27, 2016. Link
Open Sourcing Zuul 2. By Arthur Gonigberg and others on The Netflix Tech Blog. May 21, 2018. Link
Performance Vs Scalability. By Beekums. Aug 19, 2017. Link
探寻繁杂定时任务的解决方案:分布式任务调度系统
深入解读HTTP3的原理及应用
比特币减半6行代码解读
如何写出简洁的 CQRS 代码?