Netflix 系统架构
Netflix 是全球最大的在线视频网站之一,它是怎么设计的呢?这篇文章介绍了 Netflix 系统架构的设计方案。原文:Netflix System Architecture[1]
我们来讨论一下如何设计 Netflix。
相信每个人都会通过某些网站或应用在线追剧或者看电影,而 Netflix 是我最喜欢的在线视频网站,不过今天我不推荐任何电影,相反,我想展示的是 Netflix 背后令人惊艳的系统逻辑。
功能性需求
创建帐户、登录、删除帐户
订阅或取消订阅不同的计划
允许用户拥有和处理多个帐户
允许用户观看视频
允许用户下载视频并离线观看
允许用户通过视频标题搜索和发现视频
Netflix 制作人可以从后台上传视频并在平台上展示
平台可以显示趋势、最受欢迎的视频和分类,以方便用户选择
可以选择不同语言的字幕,这样用户即使听不懂这些语言,也可以观看视频
视频分组(剧集、娱乐节目、电影,单独处理每个视频)
根据用户行为进行分析,为用户推荐类似的视频
在同一账号下的不同设备之间进行同步,用户可以使用不同的设备继续观看同一视频而无需重播
支持全天候(24/7)回放
支持回退
非功能性需求
用户可以观看实时视频流,没有任何卡顿或延迟问题
系统是高度可靠的
高可用
可扩展
视频数据持久化且易于访问
容量预估
我们可以基于一些数学计算来估计所需的带宽和存储空间。
假设
日活用户总数 = 1 亿
日活峰值用户:1 亿 * 3 = 3 亿
3 个月最大日活峰值用户:3 亿 * 2 = 6 亿
每个用户每天平均观看的视频数 = 5
视频平均大小 = 500 MB
后台平均每天上传的视频数 = 1000
每天观看的总视频数 = 1 亿*5 = 5 亿
每天观看的总视频峰值 = 15 亿
每天观看的最大视频峰值 = 30 亿
每天总出口流量 = 5 亿* 500 MB = 250 PB (Peta Byte)
出口带宽 = 29.1 GB/秒
每天上传总入口流量 = 1000 * 500MB = 500 GB
入口带宽 = 5.8 MB/秒
5 年所需的总存储空间 = 500 GB * 5 * 365 = 912.5 TB(请注意,Netflix 会为每个视频准备多种格式和分辨率的版本,可针对不同类型设备进行优化,所以存储空间将超过 912.5 TB)。
系统组件
系统组件详细设计
1. 客户端应用
手机(iOS,Android,华为,等等)
平板(iPad,Android,Windows)
电视
电脑
基于 React.js 实现的前端可以拥有较好的加载/启动速度、持久性/模块化和运行时性能。
2. 后端
Netflix 从 2011 年开始实施微服务架构,完全基于云来管理工作负载。通过小型、可管理的 API 组件支持并处理来自应用程序和网站的请求,微服务内部通过请求和获取数据而相互依赖。后端技术栈包括了 Java, MySQL, Gluster, Apache Tomcat, Chukwa, Cassandra, KAFKA 和 Hadoop。后端系统不单单需要处理流媒体视频,还需要处理其他所有事情,比方说数据处理、加载新内容、网络流量管理、全球资源分发等。Netflix 目前部署在 AWS 之上。
数据处理涉及点击视频后发生的所有事件,系统需要在几纳秒的时间内处理完视频并将其传输给用户。整个系统每天大约需要处理 6000 亿个事件,产生 1.5PB 的数据,在高峰期(傍晚和夜间)每秒大约需要处理 800 万个事件。这些事件包括 UI 活动、视频查看活动、日志错误、故障排除、诊断事件、处理事件和性能事件等。所有这些事件都是通过 Kafka 和 Apache Chukwe 完成的。
Kafka 和 Apache Chukwe
从系统的不同部分获取产生的数据。
Apache Chukwe 是一个开源数据收集系统,用于从分布式系统中收集日志或事件。它建立在 HDFS 和 Map-reduce 框架之上,具有 Hadoop 的可伸缩性和健壮性特性。此外,它还包含许多功能强大、灵活的工具箱,用于显示、监控和分析结果。Chukwe 从系统的不同部分收集事件,并提供仪表盘帮助我们进行事件的查看、监控和分析。Chukwe 以 Hadoop 文件序列格式(S3)写入事件,大数据团队可以处理这些 S3 Hadoop 文件,并以 Parque 格式将数据写入 Hive。这个过程被称为批处理,基本上以每小时或每天的频率扫描整个数据。为了将在线事件上传到 EMR/S3, Chukwa 还向 Kafka(实时数据处理的入口)提供流量。Kafka 负责将数据从前端 Kafka 注入到不同的后端: S3, Elasticsearch 和下游 Kafka,消息的路由可以通过 Apache Samja 框架完成。通过 Chukwe 发送的流量既可以是完整的流也可以是过滤过的流,所以有时候你可能需要对 Kafka 流量进行进一步过滤,这就是我们需要考虑将流量从一个 Kafka topic 路由到另一个 Kafka topic 的原因。
Elastic Search
Netflix 目前有大约 150 个 Elastic Search 集群,其实例分布在 3500 个主机上。
Netflix 通过 Elastic Search 来实现数据的可视化、客户支持以及系统中的错误检测。例如,如果客户无法播放视频,那么客户服务主管将利用 Elastic Search 来解决问题。回放团队会去 Elastic Search 搜索该用户,试图找到为什么视频不能在用户设备上播放的原因。他们可以了解特定用户所发生的所有信息和事件,知道是什么导致了视频流出错。系统管理员还可以基于 Elastic Search 跟踪某些信息,比如跟踪资源使用情况、检测注册或登录问题等。
后端服务
用户和认证服务(主要负责用户认证和配置文件)。数据存储在关系型数据库中,如 MySQL 或 PostgreSQL。
订阅管理服务(管理用户的订阅)。由于该服务处理的数据本质上是高度事务性的,因此 RDBMS 是一个合适的选择。
视频服务(向终端用户提供视频)。这个服务将视频元数据存储在 RDBMS 中,比如 MySQL 或 PostgreSQL。为了获得更快的响应时间,该服务将使用 Redis 或 Memcached 这样的内存缓存来实现绕写(write-around)缓存。
转码服务(检查上传视频的质量,用不同的编解码器压缩视频,创建不同分辨率版本)。一旦视频被上传到 Transcoder 服务,它将把视频上传到内部分布式存储,比如 S3,并向数据库添加条目。Kafka 或 RabbitMQ 在队列中处理消息,后端工作组件收到队列的消息,内部 S3 下载视频,并将其转码为不同的格式。转码完成后,后端工作组件将视频上传到外部 S3,并将数据库中的视频状态更新为 active,供终端用户查看。后端工作组件还会在支持全文搜索的搜索数据库中添加视频元数据条目,这样终端用户就能够使用标题或摘要搜索视频。外部 S3 存储的视频也将通过 CDN 缓存,以减少延迟,提高播放性能。
全球搜索服务(允许终端用户使用元数据,如标题、摘要等搜索视频)。元数据存储在 Elastic Search 数据库中,因此可以基于 Elasticsearch 或 Solr 支持全文搜索,用户可以根据标题搜索电影、剧集或与视频相关的任何元数据。该服务还可以根据最近观看、评论、推荐和流行程度对结果进行排名,以获得更好的用户体验。此外,Elastic Search 可以在失败的情况下跟踪用户事件,客户服务团队可以使用 Elastic Search 来解决问题。
3. 云
Netflix 将其 IT 基础设施迁移到公共云上。使用的云服务是 AWS 和 Open connect (Netflix 的定制 CDN)。这两种云服务并行工作,用于视频处理和向终端用户分发内容。
4. CDN
一个全球分布的服务器网络集群。当我们播放视频的时候,设备上显示的视频将从最近的 CDN 服务器获取,从而极大降低响应时间。
CDN 在多个地方复制内容,这样视频可以更贴近用户,传输距离更短。
CDN 机器大量使用缓存,所以即使没有从服务器上找到视频,也可以从缓存中获取。
CDN 不会缓存不太受欢迎的视频(比方说每天只有不到 20 次观看量的视频)
5. Open connect[2]
Netflix 的内部定制全球 CDN,负责向全球 Netflix 用户存储和传送电影和电视节目。当我们按下播放按钮,视频就会从全球不同位置的 Open connect 服务器中传输给我们。如果视频已经缓存在 Open connect 服务器上,客户端可以轻松访问到,而如果视频没有被缓存,Netflix 必须从 AWS 的 S3 存储中获取并处理该视频,然后 Open connect 才可以将该视频流推送到客户端应用程序。
6. 缓存
Redis 和 Memcached 以键值对的方式缓存数据库中的数据,可以有效减少对数据库的访问。客户端通过服务器访问数据库之前,系统会检查缓存中是否有数据,如果有,就可以绕过数据库访问。但是,如果数据不在缓存中,必须访问数据库并获取数据,并在缓存中填充相同的数据。因此,随后的请求就不需要访问数据库了。这种缓存策略称为绕写(write-around)缓存。我们使用最近最少使用(LRU)策略作为缓存数据的驱逐策略,最早获取的缓存将会被丢弃。
EV 缓存实际上是 Memcached 的包装器
Netflix 在 AWS EC2 上部署了很多集群,这些集群包含有很多 Memcached 节点以及缓存客户端。数据在同一个分区的集群中共享,多个缓存副本存储在分片节点中。每次当客户端写入数据时,所有集群中的所有节点都会被更新,但当读取数据时,读取操作只会被发送到最近的集群及其节点上,如果某个节点不可用,则从另一个可用节点读取。这种方法提高了性能、可用性和可靠性。
7. 可扩展性
水平扩展——在负载均衡器后面增加更多的应用服务器,以增加服务的容量。
数据库备份——关系数据库配置为主从关系,写操作发生在主数据库上,从从数据库读取数据。读操作不会因为写操作而被锁住,因此可以提高读查询的性能。当数据写入主数据库并复制到从数据库时,会有轻微的复制延迟(几毫秒)。
数据库分片——将数据分布到多个服务器上,以便高效的进行读写操作。比方说,我们可以使用 video_id 对视频元数据数据库进行分片,哈希函数把每个 video_id 随机映射到一个服务器上,从而存储对应的视频元数据。
缓存分片——将缓存分发到多个服务器上。Redis 支持跨多个实例划分数据,为数据分布使用一致的哈希算法确保在一个实例消失时保持负载均匀分布。
搜索数据库分片——Elasticsearch 原生支持分片和备份。通过在多个分片上并行运行分片,有助于改进查询运行时。
8. 安全
HTTPS——通过 HTTPS 加密客户端和服务器之间的通信,确保中间没有人能够看到数据(特别是密码)。
身份验证——每个 API 请求必须完成登录验证,通过检查授权 HTTP 报头中 auth_token 的有效性来进行身份验证,确保请求是合法的。
9. 弹性
备份——通过主从部署备份数据库。如果一个节点宕机,其他节点将按预期提供服务并继续运行。
队列——在处理上传的视频时使用。
10. 负载均衡
一个负载均衡器后面有多个服务器,包括冗余资源。负载均衡器将持续对其背后的服务器进行健康检查,如果发现任意一个服务器停止工作,负载均衡器将停止向它转发流量,并将其从集群中移除,从而确保请求不会因为服务器没有响应而失败。
负载均衡器负责将流量路由到前端服务。ELB(Elastic load balancing,弹性负载均衡)执行两层负载均衡方案,首先基于区域(zone)进行负载均衡,然后对实例(服务器)进行负载均衡。
第一级由基础 DNS 组成,提供基于轮询的负载均衡(Round Robin Balancing)。当请求到达第一个负载均衡器时,它会根据配置选择一个区域(使用轮询机制)。
第二级是一组负载均衡器实例,执行轮询负载均衡,将请求分发到位于同一区域的多个业务实例中。
11. Geo-redundancy
在跨多个地理位置的数据中心部署服务的精确副本,一旦某个数据中心无法提供服务,仍然可以由其他数据中心提供服务。
12. ZUUL
提供动态路由、监控、弹性和安全性,支持基于查询参数、URL 路径的简单路由。
Netty 服务器负责处理网络协议、web 服务、连接管理和代理工作。当请求到达 Netty 服务器时,它负责将请求转发到入口过滤器。
入口过滤器(The inbound filter)负责身份验证、路由或装饰请求。然后将请求转发给端点过滤器。
端点过滤器(Endpoint filter)用于返回静态响应,或者将请求转发到后端服务。一旦它从后端服务接收到响应,就将请求发送到出口过滤器。
出口过滤器(Outbound filter)用于压缩内容、计算指标或添加/删除自定义标头。在此之后,响应被发送回 Netty 服务器,然后发送给客户端。
优势:
可以创建规则,将流量的不同部分分配到不同的服务器,从而实现对流量的分片。
开发人员可以在某些机器上对新部署的集群进行负载测试,可以在这些集群上路由部分现网流量,并检查特定服务器可以承受多少负载。
可以用于测试新服务。当我们需要升级服务并希望检查该服务如何处理实时 API 请求时,可以将特定服务部署在一台服务器上,并将部分流量重定向到新服务,以便实时检查该服务状态。
可以通过在端点过滤器或防火墙上设置自定义规则来过滤恶意请求。
13. Hystrix
在一个复杂的分布式系统中,一个服务器可能依赖于另一个服务器的响应。这些服务器之间的依赖关系可能会造成延迟,如果其中一个服务器在某个时刻不可避免的出现故障,整个系统可能都会停止工作。为了解决这个问题,可以将主机应用程序与这些外部故障隔离开来。Hystrix 库就是为此而设计的,通过添加延迟容忍和容错逻辑,帮助我们控制分布式服务之间的交互。Hystrix 通过隔离服务、远程系统和第三方库之间的访问点来实现这一点。Hystrix 可以帮助我们实现:
阻止复杂分布式系统中的级联故障。
控制由于第三方客户端访问(通常通过网络)依赖项带来的延迟和故障。
快速失败、快速恢复。
在可能的情况下,回滚以及优雅降级。
启用近实时监控、警报和运维控制。
并发感知的请求缓存,通过请求崩溃实现自动批处理
数据库组件
Netflix 使用不同的 DB 来存储不同类型的文件,例如用于不同目的的 SQL 和 NoSQL。
1. MySQL
符合 ACID,因此可用于管理影片标题、计费和事务用途。
在 AWS EC2 上部署 MySQL 来存储数据
MySQL 配置为主主模式,在大型 AWS EC2 实例上使用 InnoDB 引擎构建。
设置遵循“同步复制协议(Synchronous replication protocol)”。数据复制是同步完成的,表明节点之间存在主主关系,只有当数据由本地和远程节点同步以确保高可用性时,才会认为主节点上的任何写操作已经完成。读查询不是由主节点处理,而是由副本处理,只有写查询是由主数据库处理。在故障转移的情况下,副节点将作为主节点,并将负责处理写操作。
2. Cassandra (NoSQL)
Cassandra 是开源的、分布式的、基于列的 NoSQL 数据库,可以在服务器上存储大量数据。Netflix 使用 Cassandra 来存储用户历史。它可以有效处理大量读请求,并优化大量读请求的延迟。随着用户群的增长,存储多行数据变得越来越困难,而且成本高且速度慢。所以,Netflix 设计了基于时间框架和最近使用的新数据库。
当 Netflix 的用户越来越多时,每个用户的观看历史数据也开始增加。
更小的存储空间开销。
随着用户查看次数的增长而增长的一致性读写性能(在 Cassandra 中查看历史数据写读比约为 9:1)。
非规范化数据模型
超过 50 个 Cassandra 集群
超过 500 个节点
每天超过 30TB 的备份数据
最大集群有 72 个节点
每个集群超过 250K 每秒写操作
最初,观看历史记录存储在 Cassandra 的单行中。当 Netflix 的用户越来越多,行数和总体数据大小都增加了。这导致了更高的存储成本、更高的操作成本和更低的应用程序性能。解决方案是压缩旧的行…
LiveVH(实时观看历史记录)——只保存更新频繁的最近的数据,以未压缩的形式存储较少的行,可用于许多分析操作,比如在执行 ETL(提取,转换和加载)后对用户提供建议。
CompressedVH(压缩观看历史)——压缩后保存的用户浏览及观看历史旧数据,几乎不更新。存储大小也减少了,每行只存储一列。
数据库定义
API
使用 REST API
用户注册
请求:
通过 HTTP POST 方法,在数据库中创建一个资源或新条目。X-API-Key 是传递给 HTTP 报头的 API key,用于识别不同的客户端并进行速率限制。
响应:
HTTP 状态码 201 告诉用户已成功注册。用于失败情况的其他可能的 HTTP 状态码:
用户登录
请求:
响应:
API 应该返回一个 auth_token,它可以在 header 中传递给需要认证的后续 API 调用。auth_token 可以使用 JWT[3]生成。
用户登出
请求:
使用 HTTP DELETE 方法删除数据库中的行条目,意味着我们正在终止一个会话。
响应:
HTTP 状态码 200 表示成功登出。
订阅
请求:
HTTP POST 方法创建一个新的订阅,在 Authorization 头中传递 auth-token 来验证用户。
响应:
HTTP 状态码 201 与 subcription_id、plan_name 和 valid_till 一起在用户界面中呈现。
可能的 HTTP 失败状态码:
取消订阅
请求:
HTTP DELETE 方法是可以取消订阅,该接口将从订阅数据库中删除一个行条目。
响应:
HTTP 状态码 200 意味着成功完成。
批量获取视频
请求:
该 API 用于在登录后呈现主页,包含了由机器学习模型确定的推荐视频。page_id 用于 API 中的分页,next_page_id 用于从下一页请求结果。
响应:
HTTP 状态码 200 表示操作成功。
其他故障状态码:
HTTP 状态码 429 意味着用户达到速率限制,需要等待一段时间才能再次发出请求,以避免拒绝服务攻击。
搜索 API
请求:
通过标题搜索视频。
响应:
HTTP 状态码 200 表示操作成功,响应中包括了 id、title、summary、url 和 watched_till 等信息,不过也有可能找不到相关视频。
获取视频
请求:
播放特定视频。
响应:
HTTP 状态码 200 表示匹配到了视频。
其他故障状态码:
上传 API
请求:
从后台上传视频。
响应:
HTTP 状态代码 202 表示视频已经排队进行异步处理和质量检查,处理结果可以通过电子邮件或其他告警机制发送给用户。
一些 HTTP 失败的场景:
更新观看时间戳
请求:
之所以使用 HTTP PUT 方法,是因为我们需要用其他数据替换同一个数据库表中的行条目,或者我们需要更新服务器上的资源。这个 API 将用于更新时间戳,直到用户看完了特定的视频。
响应:
HTTP 状态码 200 表示操作成功。
其他 HTTP 失败状态码:
微服务架构
由于服务中的任何更改都可以很容易完成,因此微服务可以更快的完成部署。可以跟踪每个服务的性能,如果有任何问题,则可以快速将其与其他正在运行的服务隔离开来。
关键服务——为经常与该服务交互的用户提供服务。这些服务独立于其他服务,以便在进行任何故障转移时,用户可以继续执行基本操作。
无状态服务——向客户端提供 API 请求,即使有任何服务器出现故障,也可以继续与其他实例一起工作,从而确保高可用性。例如,REST API 服务为最多的用户提供服务。
上传内容
上传的内容是视频格式的电影或剧集,处理单元包括了输入协议、输入编解码器、输出编解码器和输出协议,以服务于各种设备和不同的网络速度。当我们在高速网络上观看视频时,视频的质量很好。Netflix 为同一部电影创建不同分辨率的多个副本(大约 1100-1200 个)。Netflix 将原始视频分成不同的小块,并在 AWS 中使用并行工作单元将这些小块转换成不同的格式。这些处理单元用于编码或转码,即将视频从一种格式转换为另一种格式,如改变分辨率,高宽比,减少文件大小等。在转码之后,一旦我们拥有同一电影的多个文件副本,这些文件就被传输到 Open connect 服务器。
系统架构概要设计
数据架构
电影推荐
电影推荐使用 Apache Spark 和机器学习。当载入所观看的首页时,会有好几行不同类型的电影。
Netflix 希望用户最大限度的点击视频,而这些点击取决于标题图像。Netflix 必须为特定的视频选择正确的引人注目的标题图像。为了做到这一点,Netflix 为一部特定的电影创建了多个艺术作品,并随机向用户展示这些图像。对于同一部电影,不同的用户可以使用不同的图像。根据用户的喜好和观看历史,Netflix 会预测用户最喜欢哪类电影,或者最喜欢哪位演员。Netflix 将根据用户的口味,显示合适的图像。
Netflix 会分析数据,从而决定应该向用户展示什么样的电影,这是基于用户的历史数据和偏好计算的。此外,Netflix 还会对电影进行排序,并计算这些电影在其平台上的相关性排名。大多数机器学习流水线都运行在这些大型 Spark 集群上,然后使用这些流水线进行选择、排序、标题相关性排名和艺术品个性化等操作。当用户打开 Netflix 的首页时,用户就会被每个视频显式的图像所吸引。
现在,Netflix 还会计算特定图像被点击的次数。如果电影的中心图像的点击量是 1500 次,而其他图像的点击量更少,那么 Netflix 就会让中心图像永远作为电影《心灵捕手》的标题图像。这被称为数据驱动,Netflix 用这种方法执行数据分析。为了做出正确的决策,需要根据与每张图片关联的访问数量计算数据。
用户与服务的交互(观看历史记录以及评价)。
有相似品味和喜好的其他用户。
用户先前观看的视频的元数据信息,如标题、类型、类别、演员、发行年份等。
用户的设备、活跃时间以及活跃时长。
两种类型的算法:
1. 协同过滤算法:这种算法的思想是,如果两个用户有相似的评级历史,那么他们将在未来的行为相似。例如,假设有两个人,一个人喜欢这部电影,给它打了高分,那么另一个人也很可能会喜欢这部电影。
2. 基于内容的推荐:这个算法的思想是,过滤那些与用户之前喜欢的视频相似的视频。基于内容的过滤高度依赖于电影名称、发行年份、演员、类型等信息。因此,要实现这种过滤,重要的是要知道描述每个项目的信息,还需要一些描述用户喜好的用户配置文件。
更多资源
https://towardsdatascience.com/deep-dive-into-netflixs-recommender-system-341806ae3b48
https://netflixtechblog.com/announcing-suro-backbone-of-netflixs-data-pipeline-5c660ca917b6
https://keypointt.com/2020-05-16-Netflix-playback-dive-deep/
https://www.nexsoftsys.com/articles/how-netflix-backend-system-operates.html
https://elatov.github.io/2021/02/distributed-systems-design-netflix/
https://developpaper.com/design-and-analysis-of-netflix-microservice-architecture/
https://www.codingninjas.com/blog/2020/12/04/learn-what-is-rest-api-in-10-minutes/
https://www.infoq.com/news/2019/01/netflix-evolution-architecture/
https://www.codekarle.com/system-design/netflix-system-design.html
http://highscalability.com/blog/2015/11/9/a-360-degree-view-of-the-entire-netflix-stack.html
References:
[1] Netflix System Architecture: https://medium.com/interviewnoodle/netflix-system-architecture-bedfc1d4bce5
[2] Netflix Open Connect: https://openconnect.netflix.com/en/
[3] JSON Web Tokens Introduction: https://jwt.io/introduction/
你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。微信公众号:DeepNoMind
版权声明: 本文为 InfoQ 作者【俞凡】的原创文章。
原文链接:【http://xie.infoq.cn/article/354c0b5f78619f86d43552394】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论