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
用户注册
请求:
POST /api/v1/users X-API-Key: api_key { name: email: password: }
通过 HTTP POST 方法,在数据库中创建一个资源或新条目。X-API-Key 是传递给 HTTP 报头的 API key,用于识别不同的客户端并进行速率限制。
响应:
201 Created { message: }
HTTP 状态码 201 告诉用户已成功注册。用于失败情况的其他可能的 HTTP 状态码:
400 Bad Request 409 Conflict 500 Internal Server Error
用户登录
请求:
400 Bad Request 409 Conflict 500 Internal Server Error
响应:
200 OK { auth_token: }
API 应该返回一个 auth_token,它可以在 header 中传递给需要认证的后续 API 调用。auth_token 可以使用 JWT[3]生成。
用户登出
请求:
DELETE /api/v1/users/session X-API-Key: api_key Authorization: auth_token
使用 HTTP DELETE 方法删除数据库中的行条目,意味着我们正在终止一个会话。
响应:
200 OK
HTTP 状态码 200 表示成功登出。
订阅
请求:
POST /api/v1/subscription X-API-Key: api_key Authorization: auth_token
HTTP POST 方法创建一个新的订阅,在 Authorization 头中传递 auth-token 来验证用户。
响应:
201 Created { subscription_id: plan_name: valid_till: }
HTTP 状态码 201 与 subcription_id、plan_name 和 valid_till 一起在用户界面中呈现。
可能的 HTTP 失败状态码:
401 Unauthorized 400 Bad request
取消订阅
请求:
DELETE /api/v1/subscription X-API-Key: api_key Authorization: auth_token
HTTP DELETE 方法是可以取消订阅,该接口将从订阅数据库中删除一个行条目。
响应:
200 OK
HTTP 状态码 200 意味着成功完成。
批量获取视频
请求:
GET /api/v1/videos?page_id=<page_id> X-API-Key: api_key Authorization: auth_token
该 API 用于在登录后呈现主页,包含了由机器学习模型确定的推荐视频。page_id 用于 API 中的分页,next_page_id 用于从下一页请求结果。
响应:
200 OK { page_id: next_page_id: videos: [ { id: title: summary: url: watched_till: },... ] }
HTTP 状态码 200 表示操作成功。
其他故障状态码:
401 Unauthorized 500 Bad request 429 Too many requests
HTTP 状态码 429 意味着用户达到速率限制,需要等待一段时间才能再次发出请求,以避免拒绝服务攻击。
搜索 API
请求:
GET /api/v1/search?q=<query>&page_id=<page_id> X-API-Key: api_key Authorization: auth_token
通过标题搜索视频。
响应:
200 OK { page_id: next_page_id: videos: [ { id: title: summary: url: watched_till: },... ] }
HTTP 状态码 200 表示操作成功,响应中包括了 id、title、summary、url 和 watched_till 等信息,不过也有可能找不到相关视频。
获取视频
请求:
GET /api/v1/videos/:video_id X-API-Key: api_key Authorization: auth_token
播放特定视频。
响应:
200 OK{ id: title: summary: url: watched_till: }
HTTP 状态码 200 表示匹配到了视频。
其他故障状态码:
401 Unauthorized 404 Video not found 429 Too many requests 500 Internal server error
上传 API
请求:
POST /api/v1/videos X-API-Key: api_key Authorization: auth_token { title: summary: censor_rating: video_contents: }
从后台上传视频。
响应:
202 Accepted { video_url: }
HTTP 状态代码 202 表示视频已经排队进行异步处理和质量检查,处理结果可以通过电子邮件或其他告警机制发送给用户。
一些 HTTP 失败的场景:
401 Unauthorize d400 Bad request 500 Internal server error
更新观看时间戳
请求:
PUT /api/v1/videos/:video_id/watched_till X-API-Key: api_key Authorization: auth_token { watched_till: }
之所以使用 HTTP PUT 方法,是因为我们需要用其他数据替换同一个数据库表中的行条目,或者我们需要更新服务器上的资源。这个 API 将用于更新时间戳,直到用户看完了特定的视频。
响应:
200 OK
HTTP 状态码 200 表示操作成功。
其他 HTTP 失败状态码:
401 Unauthorized 400 Bad request 500 Internal server error
微服务架构
由于服务中的任何更改都可以很容易完成,因此微服务可以更快的完成部署。可以跟踪每个服务的性能,如果有任何问题,则可以快速将其与其他正在运行的服务隔离开来。
- 关键服务——为经常与该服务交互的用户提供服务。这些服务独立于其他服务,以便在进行任何故障转移时,用户可以继续执行基本操作。
- 无状态服务——向客户端提供 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://uxdesign.cc/netflix-system-design-ef5802426ad4
- https://netflixtechblog.com/tagged/cloud-architecture
- https://www.codingninjas.com/blog/2020/12/04/learn-what-is-rest-api-in-10-minutes/
- https://about.netflix.com/en/news/how-netflix-works-with-isps-around-the-globe-to-deliver-a-great-viewing-experience
- 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
- https://www.youtube.com/watch?v=lYoSd2WCJTo
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/