Netflix 是一个很棒的地方,周围有许多了不起的同事。我为参与将共同信念变为现实的旅程中的每个人感到无比自豪。我想花点时间分享一下团队的主要成就:
- 我们在 Netflix 的所有组织中将流数据用例从 0 增加到 2000 多个。
- 我们构建和发展了成功的产品,例如 Keystone、托管 Flink 平台、Mantis 和托管 Kafka 平台。这些产品在数据生态系统的许多方面提供解决方案:包括数据摄取、移动、分析和操作处理以及机器学习用例。
- 我们是业内率先扩展开源 Kafka 和 Flink 部署以在 2017 年左右,每天处理 1 万亿个事件的公司之一,后来到 2021 年又扩展了 20 倍!
几个月前,我离开了 Netflix,在实时 ML 领域追求类似但扩展的愿景。我认为现在是总结我在 Netflix 构建实时数据基础架构的经验的最佳时机。我希望这篇文章能帮助平台工程师开发他们的云原生、自助式流数据平台,并在许多业务功能中扩展用例(不一定来自我们的成功,也许更多来自我们的失败)。我还相信,了解数据平台的构建方式可以帮助平台用户(例如数据科学家和机器学习工程师)充分利用他们的平台。
帖子里有什么
我将分享实时数据基础架构在 Netflix(2015-2021 年)的迭代之旅的四个阶段。
第 1 阶段:从失败的批处理管道中拯救 Netflix 日志 (2015)
在 Netflix 的全球高速增长期间,业务和运营决策比以往任何时候都更依赖于更快的记录数据。2015 年,基于 Chukwa/Hadoop/Hive 的批处理管道难以扩展。在这个阶段,我们从头开始构建了一个流优先平台来替换失败的管道。
第 2 阶段:Scale 100s 数据移动用例 (2016)
在最初的产品发布后,内部对数据移动的需求稳步上升。我们必须专注于常见的用例。在这个阶段,我们通过构建一个具有简单而强大的构建块设计的自助服务、完全托管的平台来扩展以支持 100 多个用例。
第 3 阶段:支持定制需求并扩展超过 1000 个用例(2017-2019)
随着流处理在 Netflix 中的发展势头,许多团队要求在数据工程、可观察性和机器学习领域具有更低的延迟和更高的处理灵活性。在此阶段,我们构建了新的流处理开发体验以支持自定义用例,并且我们还应对了新的工程和运营挑战。
第 4 阶段:扩展流处理职责——未来的挑战和机遇(2020 年至今)
随着行业数据平台技术的快速演进,出现了许多新的挑战:协调困难、学习曲线陡峭、流到批边界分裂等。在这个阶段,我们探索了流处理发挥更突出的作用在连接技术和提高抽象以使数据平台更易于使用方面。我们面前还有更多的机会。
对于每个阶段,我将回顾不断发展的业务动机、团队的独特挑战、战略赌注以及我们在此过程中发现的用例模式。
致谢
许多人帮助我审阅了这篇文章,如果没有他们的反馈,我永远不会深入研究许多公正的细节。特别感谢 Chip Huyen、Steven Wu、Prashanth Ramdas、Guanhua Jiang、Scott Shi、Goku Mohandas、David Sun、Astasia Myers 和 Matt Willian!
Netflix 实时数据基础架构的四个阶段
第 1 阶段:从失败的批处理管道中拯救 Netflix 日志 (2015)
语境
2015 年,Netflix 已经拥有约 60MM 的订户,并正在积极扩大其国际影响力。我们都知道,迅速扩大平台杠杆将是维持快速增长的用户增长的关键。
旁注:对于那些不熟悉的人,平台团队通过集中管理基础设施来提供杠杆作用,因此产品团队可以专注于业务逻辑。
我们的团队必须弄清楚如何帮助 Netflix 扩展日志记录实践。当时,Netflix 拥有约 500 个微服务,每天在生态系统中产生超过 10PB 的数据。
收集这些数据对 Netflix 有两个主要目的:
- 获得业务分析见解(例如,用户保留、平均会话时长、趋势等)。
- 获得运营洞察力(例如,测量每秒流媒体播放次数以快速轻松地了解 Netflix 系统的运行状况),以便开发人员可以发出警报或执行缓解措施。
您可能会问,为什么我们首先需要将日志从边缘移动到数据仓库?由于数量庞大,对在线事务数据库进行大规模按需分析是不可行的。原因是在线事务处理 (OLTP) 和在线分析处理 (OLAP) 是在不同的假设下构建的——OLTP 是为面向行的访问模式而构建的,而 OLAP 是为面向列的访问模式而构建的。在底层,他们使用不同的数据结构进行优化。
例如,假设我们想知道数亿 Netflix 用户的平均会话长度。假设我们将此按需分析查询放在面向行的 OLTP 系统上。它将导致行级粒度的全表扫描并可能锁定数据库,并且应用程序可能会变得无响应,从而导致不愉快的用户体验。这种类型的分析/报告工作负载在 OLAP 系统上完成要好得多,因此需要以低延迟方式可靠地移动日志。
(Figure: Move data from Edge to Data Warehouse)
到 2015 年,日志记录量已从 2011 年的 450 亿事件/天增加到每天 5000 亿个事件(1PB 的数据摄取)。现有的日志记录基础设施(一个使用 Chukwa、Hadoop 和 Hive 构建的简单批处理管道平台)正在失败 与每周惊人增长的订户数量相比。据估计,我们有大约六个月的时间来发展流媒体优先的解决方案。下图显示了从失败的批处理架构到新的基于流的架构的演变。
(Figure: the failing batch pipeline architecture, before migration)
我们决定用 Keystone 替换这个失败的基础设施。
(Figure: the Keystone streaming architecture, after migration)
您可能有的另一个问题是为什么要考虑流优先架构?当时,正确使用流式架构的价值超过了潜在的风险。Netflix 是一家数据驱动型公司,流媒体架构的直接重要性在于:
- 减少开发者和运营反馈回路。开发人员严重依赖查看日志来做出运营决策。访问更新的按需日志使开发人员能够更早地检测问题,从而提高生产力。
- 更好的产品体验。许多产品功能,例如个性化推荐、搜索等,都可以从更新鲜的数据中受益,从而改善用户体验,从而提高用户留存率、参与度等。
挑战
在构建流媒体平台时,我们必须考虑许多挑战。
- 挑战一:规模大,资源有限。我们有六个月的时间来构建 Keystone 以每天处理 500B 事件,并且我们必须与六个团队成员一起完成它。
- 挑战 2:不成熟的流媒体生态系统。2015 年,当传输(Apache Kafka)和处理技术(Apache Samza、Apache Flink)都相对新生时,开发和运营流媒体优先的基础设施很困难。很少有科技公司能够以我们需要的规模证明成功的流媒体优先部署,因此我们必须评估技术选项并进行试验。鉴于我们的资源有限,我们无法自己构建所有东西,必须决定构建什么以及押注哪些新生工具。
- 挑战 3:分析和运营关注点不同。
- 分析流处理侧重于正确性和可预测性。例如,将所有用户点击流移入数据仓库需要数据一致性(最少重复或丢失)和延迟的可预测性,延迟通常在分钟范围内。(Keystone 擅长这个)
- 操作流处理更多地关注成本效益、延迟和可用性。例如,了解整个 Netflix 设备生态系统的健康状态可以从亚秒级到秒级的延迟中受益,并且可以从源头对数据进行采样或分析以节省成本。(螳螂擅长这个)
- 挑战 4:有状态数据平台的云原生弹性很难。Netflix 已经在 AWS 云上运行了几年。然而,我们是第一个在容器化云基础设施上安装有状态数据平台的人。引擎盖下的每个数据中心都有数十万台物理机器为云提供动力。在这种规模下,硬件故障是不可避免的。当这些故障意外出现时,系统可能很难跟上可用性和一致性预期。在无限制的低延迟流处理环境中更具挑战性,任何故障恢复都可能导致背压累积。流优先架构的云原生弹性将意味着重大的工程挑战。
(Figure: How does stream processing help with operational and analytical data)
第 1 阶段的流处理模式总结
我包括了一些观察到的用例及其每个创新阶段各自的流处理模式。因此,您可以了解随着时间的推移而发生的演变。
+-----------------------------------------------------------------+
| Pattern | Product | Example Use Cases |
|-----------------------|----------|------------------------------|
| Data Routing | Keystone | Logging, Data Movement (MVP) |
|-----------------------|----------|------------------------------|
| RT Alerts / Dashboard | Mantis | SPS Alert |
+-----------------------------------------------------------------+
策略投注
- 赌注 1:在构建 MVP 产品时,为最初的几个客户构建它。在探索最初的产品市场契合度时,很容易分心。我们决定只帮助少数高优先级的大容量内部客户,并担心以后扩大客户群。这一决定不仅使我们能够专注于产品的核心。它还让我们意识到不应该投资什么(例如,我们使用电子表格而不是成熟的控制平面来保存每个管道的客户姓名、电子邮件地址和元数据信息,以促进 MVP 阶段的客户部署)。
- 赌注 2:与技术合作伙伴共同发展,即使不是处于理想的成熟状态,而不是自己重新发明轮子。这样,我们可以共同发展生态系统。我们很早就选择了合作。
- 流媒体合作伙伴:在外部,我们与领导行业流处理工作的合作伙伴合作,例如 LinkedIn(Kafka 和 Samza 团队)、Confluent、Data Artisan(Apache Flink 背后的构建者,后来更名为 Veverica)。这样做使我们能够在利用社区工作的同时为 OSS 做出贡献以满足我们的需求。
- 容器化合作伙伴:2015年,还是容器虚拟化技术的初期。我们需要一个快速部署的策略。在内部,我们与新创建的容器基础设施 Titus 团队合作。 Titus 建立在 Apache Mesos 之上,并通过抽象 API 提供计算资源管理、调度和隔离部署。Titus 后来在 2020 年初演变为利用 K8S,他们的团队设法透明地迁移了所有工作负载。由于这种合作关系,我们在构建数据平台时不必担心低级计算基础设施。
- 在合作过程中,我们一直保持沟通,分享经验并提供反馈。我们与密切的合作伙伴每两周举行一次同步会议,以调整目标并讨论问题和解决方案。当出现阻塞问题时,合适的人会立即参与进来。
- 赌注 3:将关注点解耦而不是忽略它们。
- 运营和分析用例之间的分离问题。我们分别发展了 Mantis(专注于运营)和 Keystone(专注于分析),但创造了空间来连接这两个系统。
- (Figure: separation of concerns for different stream processing scenarios)
- 生产者和消费者的关注点分开。我们引入了配备标准化有线协议和简单模式管理的生产者/消费者客户端,以帮助解耦生产者和消费者的开发工作流程。后来证明它是数据治理和数据质量控制的一个重要方面。
- 分离的组件职责。我们从面向微服务的单一职责原则开始,将整个基础设施划分为 Messaging(流传输)、Processing(流处理)和控制平面(控制平面在这个阶段只是一个脚本,后来演变成一个成熟的系统)。组件职责的分离使团队能够尽早在界面上保持一致,同时通过同时关注不同的部分来释放团队的生产力。
- 赌注 4:投资于构建一个预期故障并监控所有操作的系统,而不是延迟投资。由于云的弹性、不断变化、故障概率较高的特性,我们需要设计系统来监控、检测和容忍各种故障。故障范围包括网络故障、实例故障、区域故障、集群故障、服务间拥塞和背压、区域灾难故障等。我们在假设故障是恒定的情况下投资构建系统。我们很早就采用了 DevOps 实践:例如针对故障场景的设计、严格的自动化、持续部署、影子测试、自动化监控、警报等。这个 DevOps 基础使我们能够实现一天多次交付的终极工程敏捷性。
(reference: What is Chaos Money in DevOps on Quora)
学习
拥有一个心理安全的失败环境对于任何团队领导变革都是必不可少的。
我们犯了很多错误。我们在产品发布当天惨遭失败,并发生了全公司范围内的事件,导致大量数据丢失。经过调查,事实证明,尽管正确估计了流量增长,但我们构建的庞大的 Kafka 集群(拥有超过 200 个代理)太大并最终达到了其扩展极限。当一个代理死亡时,由于 Kafka(当时)对代理和分区数量的限制,集群无法自行恢复。它最终退化到无法恢复的地步。
以这种规模失败是一次可怕的经历,但由于心理安全的团队环境,我们与所有利益相关者进行了透明的沟通,并将快速的学习转化为永久的解决方案。对于这种特殊情况,我们开发了更细粒度的集群隔离功能(更小的 Kafka 集群 + 隔离的 Zookeeper)来控制爆炸半径。
还有很多其他的失败。当我们挖掘根本原因时,我们意识到我们无法完全预测所有边缘场景,尤其是当我们在托管云上构建时,其中的变化经常超出我们的控制范围,例如实例终止或租户托管,等等。同时,我们的产品被很多人使用,太重要了,不能失败。始终为最坏的情况做好准备已成为一项操作原则。
事件发生后,我们采用了每周一次的 Kafka 集群故障转移演习。每周值班人员都会模拟 Kafka 集群故障。该团队将确保故障转移自动化能够将所有流量迁移到对用户影响最小的健康集群。如果您有兴趣了解有关此练习的更多信息,此视频有更多详细信息。
第 2 阶段:Scale 100s 数据移动用例 (2016)
语境
在交付了最初的 Keystone MVP 并迁移了一些内部客户之后,我们逐渐获得了一些信任,并且消息传到了其他工程团队。流媒体在 Netflix 中获得了发展势头,因为现在可以轻松移动日志以进行分析处理并获得按需运营洞察力。
现在是我们为普通客户扩展的时候了。
(Figure: evolving Keystone architecture diagram, circa 2016. Keystone includes Kafka and Flink engines as its core components. For more technical design details, please refer to blog posts focused on Kafka and Flink)
挑战
- 挑战一:增加运营负担。我们最初为新客户提供白手套协助。然而,随着需求的增长,它很快变得不可持续。我们需要开始发展 MVP 以支持十几个客户。因此,我们需要重新构建一些组件(例如,是时候将电子表格变成适当的数据库支持的控制平面了)。
- 挑战 2:出现多样化的需求。随着我们收到更多客户要求,我们开始看到非常多样化的需求。有两大类:
- 一组更喜欢易于使用的完全托管服务。
- 另一组更喜欢灵活性,需要复杂的计算能力来解决更高级的业务问题,他们可以使用寻呼机,甚至管理一些基础设施。
- 我们不能同时做好这两件事。
- 挑战 3:我们破坏了我们接触到的一切。不开玩笑,由于规模的原因,我们在某些时候破坏了几乎所有的依赖服务。我们曾经破坏过 aws S3。我们在 Kafka 和 Flink 中发现了很多 bug。我们多次破坏了 Titus(托管容器基础设施)并发现了奇怪的 CPU 隔离和网络问题。当我们开始以编程方式管理数百个客户部署时,我们打破了 Spinnaker(持续部署平台)。
- 幸运的是,这些团队也是最好的。他们与我们一起解决了这些问题。这些努力对于成熟整个流媒体生态系统至关重要。
第 2 阶段的流处理模式总结
+-----------------------------------------------------------------+
| Pattern | Product | Example Use Cases |
|-----------------------|----------|------------------------------|
| Data Routing | Keystone | Logging, Data Movement |
| | | (+ At scale) |
|-----------------------|----------|------------------------------|
| RT Data Sampling/ | Mantis | Cost-effective RT Insights |
| Discovery | | |
|-----------------------------------------------------------------|
| RT Alerts / Dashboard | Mantis, | SPS Alert, |
| | Kafka | + Infrastructure Health |
| | | Monitoring (Cassandra & |
| | | Elasticsearch), |
| | | +RT QoE monitoring |
+-----------------------------------------------------------------+
策略投注
- 赌注 1:首先关注简单性,而不是向用户暴露基础设施的复杂性。 我们决定首先将重点放在针对一般流用例的高度抽象、完全托管的服务上,原因有二。
- 它使我们能够处理大多数数据移动和简单的流式 ETL(例如,投影、过滤)用例。为数据路由提供如此简单、高级别的抽象将使所有 Netflix 组织的工程师能够将数据路由用作与其他平台服务结合的“乐高”构建块。
- 它将使我们的用户能够专注于业务逻辑。
- 我们将在以后处理更高级的用例。
- 赌注 2:投资于完全托管的多租户自助服务,而不是继续使用手动白手套支持。 我们必须专注于自动化控制平面和工作负载部署。客户工作负载需要完全隔离。我们决定一个客户的工作量不应该以任何方式干扰另一个客户的工作量。
(Figure: Keystone UI. showing a self-serve drag-n-drop experience powered by a fully managed multi-tenant streaming infrastructure)
- 赌注 3:继续投资 DevOps,而不是拖延。我们希望根据需要每天多次发布平台更改。我们还认为,有必要让我们的客户能够随时发送更改。部署应在客户启动几分钟后自动完成并安全地投入生产。
学习
- 学习 1:决定不做什么是困难的,但却是必要的。虽然满足客户要求很重要,但有些可能会分散注意力。优先级是第一步,但有意识地决定和沟通要削减的内容更为关键。说不很难。但请注意,说不是暂时的,说是是永久的。
- 学习 2:注意缩放速度。在最初的产品与市场契合得到验证之后,这是一个激动人心的时刻。然而,过快扩展可能会使团队分心于多个方向,留下大量技术债务,并破坏客户信任。扩展太慢会使团队失去动力,客户需求无法满足太久,也会破坏他们的信任。这是一个微妙的平衡,但这里有一些你可以注意的信号:
- 软件质量。部署回滚频率是否改变?合作伙伴团队多久阻止一次团队?现在测试失败的频率更高了吗?由于任何系统瓶颈,事件多久发生一次?
- 客户情绪。客户支持请求的增加是否与用例数量成线性关系?SLO 违规趋势。客户是否在新功能公告中表现出兴奋?当客户提出“紧急”问题时,他们考虑了哪些替代方案?
- 运营开销。团队的运营与开发时间比例是否发生变化? RCA 与事故的比率会改变吗?团队是否因运营劳累而筋疲力尽?团队的创新频率是否发生变化(例如,博客文章、会议演讲)?
- 学习 3:教育您的用户并耐心纠正误解。围绕数据质量(如事件丢失或重复)或处理语义(如故障场景下的正确性保证)存在许多流处理误解。许多这些误解来自流处理不成熟的旧时代,但已经发展了很多。对你的用户要有耐心,用数据和故事教育他们!
第 3 阶段:支持定制需求并扩展超过 1000 个用例(2017-2019)
语境
在最初推出 Keystone 产品一年后,所有组织的用例数量从 2015 年的不到十几个迅速增加到 2017 年的几百个。此时我们已经建立了坚实的运营基础:客户在待命期间很少收到通知,所有基础设施问题都由平台团队密切监控和处理。我们建立了一个强大的交付平台,帮助我们的客户在几分钟后将变更引入生产。
Keystone 产品非常擅长它最初的设计目标:一个易于使用且几乎可以无限扩展的流数据路由平台。然而,很明显,流处理的全部潜力远未实现。为了满足自定义用例,我们不断发现对复杂处理能力进行更精细控制的新需求,例如流连接、窗口化等。
同时,Netflix 拥有独特的自由和责任文化,每个团队都有权做出自己的技术决策。这种文化使每个团队甚至可以投资定制解决方案。作为一个中央平台团队,我们注意到了这种增长。如果我们没有办法提供保险,这将意味着公司的长期成本很高。
是时候让团队扩大其范围了。我们再次面临一些新的挑战。