系统设计::设计YOUTUBE
设计 YOUTUBE
在本章中,你被要求设计 YouTube。这个问题的解决方案可以应用于其他面试问题,如设计一个视频共享平台,如 Netflix 和 Hulu。图 14-1 显示了 YouTube 的主页。
YouTube 看起来很简单:内容创作者上传视频,观众点击播放。它真的那么简单吗?并非如此。在简单的背后有很多复杂的技术。让我们看看 2020 年 YouTube 的一些令人印象深刻的统计数据、人口统计学和有趣的事实[1] [2]。
- 每月活跃用户总数:20 亿。
- 每天观看的视频数量。50 亿。
- 73%的美国成年人使用 YouTube。
- YouTube 上有 5000 万创作者。
- 2019 年全年,YouTube 的广告收入为 151 亿美元,比 2018 年增长 36%。
- YouTube 占所有移动互联网流量的 37%。
- YouTube 有 80 种不同的语言。
从这些统计数据中,我们知道 YouTube 是巨大的,全球性的,并且赚了很多钱。
理解问题,确立设计范围
如图 14-1 所示,除了观看视频,你还可以在 YouTube 上做很多事情。例如,评论、分享或喜欢一个视频,将一个视频保存到播放列表中,订阅一个频道等等。在 45 或 60 分钟的采访中,不可能设计所有内容。因此,提出问题以缩小范围是很重要的。
应聘者:哪些功能是重要的?
面试官:上传视频和观看视频的能力。
应聘者:我们需要支持哪些客户?
面试官:移动应用、网络浏览器和智能电视。
应聘者:我们有多少日活跃用户?
面试官:500 万
应聘者:每天花在产品上的平均时间是多少?
面试官:30 分钟。
应聘者:我们需要支持国际用户吗?
面试官:是的,很大比例的用户是国际用户。
应聘者:支持的视频分辨率是多少?
面试官:系统可以接受大部分的视频分辨率和格式。
应聘者:是否需要加密?
面试官:是的
应聘者:对视频的文件大小有要求吗?
面试官:是的。我们的平台专注于小型和中型的视频。允许的最大视频尺寸是 1GB。
应聘者:我们能否利用亚马逊、谷歌或微软提供的一些现有云计算基础设施?
面试官:这是个好问题。对于大多数公司来说,从头开始建立一切是不现实的,建议利用一些现有的云服务。
在本章中,我们重点设计一个具有以下特点的视频流媒体服务。
- 快速上传视频的能力
- 流畅的视频流
- 改变视频质量的能力
- 基础设施成本低
- 高可用性、可扩展性和可靠性要求
- 支持的客户端:移动应用程序、网络浏览器和智能电视
粗略估计
下面的估计是基于许多假设,所以必须与面试官沟通,以确保她和你达成共识。
- 假设该产品有 500 万日活跃用户(DAU)。
- 用户每天观看 5 个视频。
- 10%的用户每天上传 1 个视频。
- 假设平均视频大小为 300MB。
- 每天需要的总存储空间。500 万*10%*300MB=150TB
- CDN 成本。
- 当云 CDN 提供视频时,你要为从 CDN 传输出来的数据收费。
- 让我们使用亚马逊的 CDN CloudFront 进行成本估算(图 14-2)[3]。假设 100%的流量都来自美国。每 GB 的平均成本是 0.02 美元。为简单起见,我们只计算视频流的成本。
- 500 万 * 5 个视频 * 0.3GB * 0.02 美元 = 每天 150,000 美元。
从粗略的成本估算中,我们知道从 CDN 提供视频服务需要花费很多钱。即使云供应商愿意为大客户大幅降低 CDN 成本,但成本仍然很高。我们将深入讨论降低 CDN 成本的方法。
提出高层次的设计并获得认同
如前所述,面试官建议利用现有的云服务,而不是从头开始建立一切。CDN 和 blob 存储是我们要利用的云服务。有些读者可能会问,为什么不自己建立一切?下面列出了原因。
- 系统设计面试不是要从头开始建立一切。在有限的时间内,选择正确的技术来做好一项工作,比详细解释技术的工作原理更重要。例如,提到用于存储源视频的 blob 存储就足以应付面试。谈论 blob 存储的详细设计可能是一种矫枉过正。
- 建立可扩展的 blob 存储或 CDN 是非常复杂和昂贵的。即使像 Netflix 或 Facebook 这样的大公司也不会自己建立一切。Netflix 利用亚马逊的云服务[4],而 Facebook 使用 Akamai 的 CDN[5]。
在高层次上,该系统包括三个组成部分(图 14-3)。
客户端:你可以在你的电脑、移动电话和智能电视上观看 YouTube。
CDN:视频存储在 CDN 中。当你按下播放键时,视频会从 CDN 上流传下来。
API 服务器。除了视频流之外,其他一切都要通过 API 服务器。这包括订阅推荐、生成视频上传 URL、更新元数据数据库和缓存、用户注册等。
在问答环节,面试官表现出对两个流程的兴趣。
- 视频上传流程
- 视频流媒体流程
我们将分别探讨它们的高层设计。
视频上传流程
图 14-4 显示了视频上传的高级设计。
它由以下部分组成。
- 用户:用户在电脑、移动电话或智能电视等设备上观看 YouTube。
- 负载平衡器:负载平衡器在 API 服务器之间均匀地分配请求。
- API 服务器:除了视频流,所有的用户请求都要通过 API 服务器。
- 元数据数据库:视频元数据存储在元数据数据库中。它是分片和复制的,以满足性能和高可用性要求。
- 元数据缓存:为了提高性能,视频元数据和用户对象被缓存起来。
- 原始存储:一个 blob 存储系统被用来存储原始视频。维基百科中关于 blob 存储的一段引文显示。“二进制大对象(BLOB)是数据库管理系统中作为单一实体存储的二进制数据的集合” [6]。
- 转码服务器:视频转码也被称为视频编码。它是将一种视频格式转换为其他格式(MPEG、HLS 等)的过程,为不同的设备和带宽能力提供可能的最佳视频流。- 转码存储。它是一个存储转码视频文件的 blob 存储。
- CDN:视频被缓存在 CDN 中。当你点击播放按钮时,视频会从 CDN 中流出来。
- 完成队列:它是一个消息队列,存储有关视频转码完成事件的信息。
- 完成处理程序:它包括一个工作列表,从完成队列中提取事件数据并更新元数据缓存和数据库。
现在我们已经单独了解了每个组件,让我们来看看视频上传流程是如何工作的。该流程被分解为两个平行运行的过程。
a. 上传实际的视频。
b. 更新视频元数据。元数据包含关于视频 URL、大小、分辨率、格式、用户信息等信息。
流程 a:上传实际视频
图 14-5 显示了如何上传实际视频。解释如下。
- 视频被上传到原始存储器。
- 转码服务器从原始存储中获取视频并开始转码。
- 一旦转码完成,以下两个步骤将平行执行。
3a. 转码后的视频被发送到转码后的存储器。
3b. 转码完成事件被排入完成队列。
3a.1. 转码后的视频被分发到 CDN。
3b.1. 完成处理程序包含一堆工作线程,不断从队列中提取事件数据。 3b.1.a.和 3b.1.b. 完成处理程序在视频转码完成后更新元数据数据库和缓存。 - API 服务器通知客户端,视频已经成功上传,可以进行流媒体播放。
流程 b:更新元数据
当文件被上传到原始存储区时,并行的客户端会发送一个更新视频元数据的请求,如图 14-6 所示。该请求包含视频元数据,包括文件名、大小、格式等。API 服务器更新元数据缓存和数据库。
视频流流程
每当你在 YouTube 上观看一个视频时,它通常立即开始流媒体,你不会等到整个视频被下载。下载意味着整个视频被复制到你的设备上,而流媒体意味着你的设备不断接收来自远程源视频的视频流。当你观看流媒体视频时,你的客户端每次加载一点数据,所以你可以立即和连续地观看视频。
在我们讨论视频流流程之前,让我们看看一个重要的概念:流媒体协议。这是一种控制视频流媒体数据传输的标准化方式。流行的流媒体协议有。
- MPEG-DASH。MPEG 代表 “移动图像专家组”,DASH 代表 “HTTP 动态自适应流”。
- 苹果 HLS。HLS 是 “HTTP Live Streaming “的缩写。
- Microsoft Smooth Streaming.
- Adobe HTTP 动态流(HDS)。你不需要完全理解甚至记住这些流媒体协议名称,因为它们是需要特定领域知识的低级细节。这里重要的是要理解不同的流媒体协议支持不同的视频编码和播放机。当我们设计一个视频流媒体服务时,我们必须选择正确的流媒体协议来支持我们的用例。要了解更多关于流媒体协议的信息,这里有一篇很好的文章[7]。
视频直接从 CDN 进行流式传输。离你最近的边缘服务器将提供视频。因此,延迟非常小。图 14-7 显示了视频流的高水平设计。
深入设计
在高层设计中,整个系统被分解成两个部分:视频上传流和视频流。在本节中,我们将通过重要的优化来完善这两个流程,并引入错误处理机制。
视频转码
当你录制视频时,设备(通常是手机或相机)会给视频文件一个特定的格式。如果你想让视频在其他设备上顺利播放,视频必须被编码成兼容的比特率和格式。比特率是指随着时间推移,比特被处理的速度。更高的比特率通常意味着更高的视频质量。高比特率流需要更多的处理能力和快速的互联网速度。
视频转码的重要性在于以下原因。
原始视频消耗大量的存储空间。一段长达一小时的高清视频以每秒 60 帧的速度录制,可以占用几百 GB 的空间。
许多设备和浏览器只支持某些类型的视频格式。因此,出于兼容性的考虑,将视频编码为不同的格式很重要。
为了确保用户观看高质量的视频,同时保持流畅的播放,向拥有高网络带宽的用户提供更高分辨率的视频,向拥有低带宽的用户提供低分辨率的视频是一个好主意。
网络条件可能改变,特别是在移动设备上。为了确保视频能够连续播放,根据网络条件自动或手动切换视频质量对用户的流畅体验至关重要。有许多类型的编码格式,然而,它们中的大多数包含两部分。
容器。这就像一个篮子,包含视频文件、音频和元数据。你可以通过文件扩展名来判断容器格式,如.avi、.mov 或.mp4。
编解码器。这些是压缩和解压算法,旨在减少视频尺寸,同时保留视频质量。最常用的视频编解码器是 H.264、VP9 和 HEVC。
有向无环图(DAG)模型
转码视频的计算成本很高,而且很耗时。此外,不同的内容创作者可能有不同的视频处理要求。例如,有些内容创作者需要在视频上面加水印,有些自己提供缩略图,有些上传高清视频,而有些则不需要。
为了支持不同的视频处理管道并保持高度的并行性,必须增加一些抽象层次,让客户端程序员定义要执行哪些任务。例如,Facebook 的流媒体视频引擎使用了一个有向无环图(DAG)编程模型,该模型分阶段定义任务,因此它们可以按顺序或平行地执行[8]。在我们的设计中,我们采用类似的 DAG 模型来实现灵活性和并行性。图 14-8 表示一个用于视频转码的 DAG。
在图 14-8 中,原始视频被分割成视频、音频和元数据。下面是一些可以应用于视频文件的任务。
- 检查。确保视频有良好的质量,没有畸形。
- 视频编码。视频被转换以支持不同的分辨率、编解码、比特率等。图 14-9 显示了一个视频编码文件的例子。
- 缩略图。缩略图可以由用户上传或由系统自动生成。
- 水印。在你的视频上面叠加一个图像,包含关于你视频的识别信息。
视频转码架构
拟议的视频转码架构利用云服务,如图 14-10 所示。
该架构有六个主要组成部分:预处理器、DAG 调度器、资源管理器、任务者、临时存储和作为输出的编码视频。让我们仔细看看每个组件。
预处理器
预处理器有 4 个职责。
- 视频拆分。视频流被分割或进一步分割成更小的图片组(GOP)排列。GOP 是一组/大块的帧按特定顺序排列。每个块是一个独立的可播放单元,通常是几秒钟的长度。
- 一些旧的移动设备或浏览器可能不支持视频分割。预处理程序通过 GOP 对齐方式为老客户分割视频。
- DAG 生成。处理器根据客户程序员编写的配置文件生成 DAG。图 14-12 是一个简化的 DAG 表示,它有 2 个节点和 1 条边。
这个 DAG 表示法是由下面两个配置文件生成的(图 14-13)。
- 缓存数据。预处理器是一个分段视频的缓存器。为了提高可靠性,预处理器将 GOPs 和元数据存储在临时存储中。如果视频编码失败,系统可以使用持久化的数据进行重试操作。
DAG 调度器把 DAG 图分割成各阶段的任务,并把它们放在资源管理器的任务队列中。图 14-15 显示了 DAG 调度器如何工作的一个例子。
如图 14-15 所示,原始视频被分割成三个阶段。第 1 阶段:视频、音频和元数据。视频文件在第 2 阶段被进一步分成两个任务:视频编码和缩略图。音频文件需要进行音频编码,作为第 2 阶段任务的一部分。
资源管理器
资源管理器负责管理资源分配的效率。它包含 3 个队列和一个任务调度器,如图 14-17 所示。
- 任务队列。它是一个优先级队列,包含要执行的任务。
- 工作队列。它是一个优先级队列,包含工人的利用信息。
- 运行队列。它包含关于当前运行的任务和运行任务的工作者的信息。
- 任务调度器。它挑选最佳任务/工作者,并指示所选的任务工作者执行工作。
资源管理器的工作方式如下。
- 任务调度器从任务队列中获得最高优先级的任务。
- 任务调度器从工作线程队列中获得运行任务的最佳任务工作线程。
- 任务调度器指示选择的任务工作线程运行任务。
- 任务调度器绑定任务/工作线程信息并将其放入运行队列。
- 一旦任务完成,任务调度器就会将任务从运行队列中移除。
任务组
任务工作者运行在 DAG 中定义的任务。不同的任务工作线程可以运行不同的任务,如图 14-19 所示。
临时存储
这里使用了多种存储系统。存储系统的选择取决于数据类型、数据大小、访问频率、数据寿命等因素。例如,元数据经常被工作者访问,而且数据大小通常很小。因此,在内存中缓存元数据是一个好主意。对于视频或音频数据,我们把它们放在 blob 存储中。一旦相应的视频处理完成,临时存储中的数据就会被释放出来。
编码视频
编码后的视频是编码管道的最终输出。下面是一个输出的例子: funny_720p.mp4 。
系统优化
在这一点上,你应该对视频上传流程、视频流媒体流程和视频转码有良好的理解。接下来,我们将通过优化来完善系统,包括速度、安全和节约成本。
速度优化:并行化视频上传
将一个视频作为一个整体上传是低效的。我们可以通过 GOP 对齐将视频分成小块,如图 14-22 所示。
这允许在前一次上传失败时快速恢复上传。按 GOP 分割视频文件的工作可以由客户端实现,以提高上传速度,如图 14-23 所示。
速度优化:将上传中心放在靠近用户的地方 另一个提高上传速度的方法是在全球范围内建立多个上传中心(图 14-24)。美国的人可以把视频上传到北美的上传中心,而中国的人可以把视频上传到亚洲的上传中心。为了实现这一目标,我们使用 CDN 作为上传中心。
速度优化:无处不在的并行性 实现低延迟需要认真努力。另一个优化是建立一个松散耦合的系统,并实现高并行性。
我们的设计需要进行一些修改以实现高并行性。让我们放大视频如何从原始存储空间传输到 CDN 的流程。该流程如图 14-25 所示,显示了输出取决于前一步的输入。这种依赖性使并行化变得困难。
为了使系统更加松散耦合,我们引入了消息队列,如图 14-26 所示。让我们用一个例子来解释消息队列是如何使系统更加松散耦合的。
- 在引入消息队列之前,编码模块必须等待下载模块的输出。
- 引入消息队列后,编码模块不需要再等待下载模块的输出。如果消息队列中存在事件,编码模块可以并行地执行这些工作。
安全优化:预签署的上传 URL 安全是任何产品最重要的方面之一。为了确保只有授权用户将视频上传到正确的位置,我们引入了预签名的 URL,如图 14-27 所示。
上传流程更新如下。
- 客户端向 API 服务器发出 HTTP 请求,以获取预签名的 URL,该 URL 赋予了对 URL 中标识的对象的访问许可。预签名的 URL 一词是通过上传文件到 Amazon S3 使用的。其他云服务提供商可能使用不同的名称。例如,微软 Azure blob 存储支持同样的功能,但称之为 “共享访问签名”[10]。
- API 服务器用一个预先签名的 URL 来响应。
- 一旦客户端收到响应,它就使用预先签署的 URL 上传视频。
安全优化:保护你的视频 许多内容制作者不愿意在网上发布视频,因为他们担心自己的原创视频会被盗。为了保护有版权的视频,我们可以采用以下三种安全方案之一。
- 数字版权管理(DRM)系统。三个主要的 DRM 系统是苹果 FairPlay、谷歌 Widevine 和微软 PlayReady。
- AES 加密。你可以对视频进行加密并配置一个授权策略。加密的视频将在播放时被解密。这确保了只有授权用户才能观看加密的视频。
- 视觉水印。这是一个覆盖在你的视频上面的图像,包含你视频的识别信息。它可以是你的公司标志或公司名称。
节省成本的优化 CDN 是我们系统的一个重要组成部分。它确保了在全球范围内的快速视频传输。然而,从背面计算,我们知道 CDN 是昂贵的,特别是当数据量很大时。我们如何才能减少成本?
以前的研究表明,YouTube 视频流遵循长尾分布[11] [12]。这意味着少数流行的视频被频繁访问,但其他许多视频的观看者很少或没有。基于这一观察,我们实施了一些优化。
- 只从 CDN 提供最受欢迎的视频,其他视频从我们的高容量存储视频服务器提供(图 14-28)。
- 对于不太受欢迎的内容,我们可能不需要存储许多编码的视频版本。短视频可以按需编码。
- 一些视频只在某些地区流行。没有必要将这些视频分发到其他地区。
- 像 Netflix 一样建立自己的 CDN,并与互联网服务提供商(ISP)合作。建立你的 CDN 是一个巨大的项目;然而,这对大型流媒体公司来说可能是有意义的。ISP 可以是 Comcast、AT&T、Verizon 或其他互联网供应商。ISP 分布在世界各地,离用户很近。通过与 ISP 合作,你可以改善观看体验,减少带宽费用。
所有这些优化都是基于内容流行度、用户访问模式、视频大小等。在做任何优化之前,分析历史观看模式是很重要的。这里有一些关于这个主题的有趣文章。[12] [13].
错误处理
对于一个大规模的系统,系统错误是不可避免的。为了建立一个高度容错的系统,我们必须优雅地处理错误并快速恢复。存在两种类型的错误。
- 可恢复的错误。对于可恢复的错误,如视频段转码失败,一般的想法是重试几次操作。如果任务继续失败,而且系统认为它无法恢复,它就会向客户返回一个适当的错误代码。
- 不可恢复的错误。对于不可恢复的错误,如畸形的视频格式,系统会停止与视频相关的运行任务,并向客户端返回适当的错误代码。
每个系统组件的典型错误由以下游戏规则涵盖。
- 上传错误:重试几次。
- 分割视频错误:如果旧版本的客户端不能按 GOP 对齐方式分割视频,整个视频就会被传递给服务器。分割视频的工作是在服务器端完成的。
- 转码错误:重试。
- 预处理程序错误:重新生成 DAG 图。
- DAG 调度器错误:重新调度一个任务。
- 资源管理器队列故障:使用一个副本。
- 任务工作者故障:在一个新的工作者上重试任务。
- API 服务器宕机。API 服务器是无状态的,所以请求将被引导到不同的 API 服务器。
- 元数据缓存服务器宕机:数据被多次复制。如果一个节点发生故障,你仍然可以访问其他节点来获取数据。我们可以调出一个新的缓存服务器来代替死去的那个。
- 元数据 DB 服务器宕机。
- 主服务器宕机了。如果主服务器宕机了,可以提升其中一个从服务器作为新的主服务器。
- 从属服务器坏了。如果一个从属服务器坏了,你可以使用另一个从属服务器来读取数据,并建立另一个数据库服务器来代替死去的那个。
总结
在本章中,我们介绍了 YouTube 等视频流服务的架构设计。如果在采访结束时有多余的时间,这里有几个补充要点。
- 扩展 API 层:因为 API 服务器是无状态的,所以很容易水平地扩展 API 层。
- 扩大数据库的规模。你可以谈谈数据库的复制和分片。
- 实时流媒体。它指的是一个视频如何被录制和实时播放的过程。虽然我们的系统不是专门为直播设计的,但直播和非直播有一些相似之处:都需要上传、编码和流媒体。显著的区别是。
- 直播流媒体有更高的延迟要求,所以它可能需要不同的流媒体协议。
- 直播流对并行性的要求较低,因为小块的数据已经被实时处理了。
- 实时流媒体需要不同的错误处理集。任何花费太多时间的错误处理都是不可接受的。
- 视频撤下。侵犯版权、色情或其他非法行为的视频应被删除。有些可以在上传过程中被系统发现,而有些则可能通过用户标记发现。
祝贺你走到这一步!现在给自己拍拍手吧。现在给自己拍拍背。干得好!
参考资料
[1] YouTube by the numbers
[2] 2019 YouTube Demographics
[3] Cloudfront Pricing
[4] Netflix on AWS
[5] Akamai homepage
[6] Binary large object
[7] Here’s What You Need to Know About Streaming Protocols
[8] SVE: Distributed Video Processing at Facebook Scale
[9] Weibo video processing architecture (in Chinese)
[10] Delegate access with a shared access signature
[11] [YouTube scalability talk by early YouTube employee](https://www.youtube.com/watch? v=w5WVu624fY8)
[12] Understanding the characteristics of internet short video sharing: A youtube-based measurement study
[13] Content Popularity for Open Connect