考虑到Delta Lake在数据应用中的灵活性和适用性,试图涵盖所有可以使用Delta Lake的场景,就像试图描述纸张的所有潜在用途一样。其种类似乎是无限的,价值也极其巨大。尽管如此,在本章中,我们将尽力展示使用Delta Lake的典型案例,并突出其价值。
我们将首先展示Delta Lake中的性能优化和简化的维护操作,如何帮助Comcast将运行智能遥控器过程所需的资源削减了10倍。接着,我们将描述Scribd如何推动Delta Lake生态系统的发展,并创建了Delta Rust实现,其成本比等效的结构化流应用便宜100倍。最后,我们将看到Delta Lake如何支持DoorDash高流量的操作性CDC摄取,并支持来自Flink的实时工作负载,从多个不同的操作系统中创建一个统一的真实数据湖(lakehouse)。每一部分都附有一些资源,您可以查看这些资源,以便深入探讨这里的故事。
削减计算成本
本节的重点面向广泛的受众——字面意思!近年来,流媒体娱乐服务的数量激增这一点已经不是什么秘密。支持这些服务的组织通常需要管理大量的高吞吐量流数据,以支持服务的运营。
高速解决方案
流媒体服务通常从各个终端用户设备捕获数据,这些设备包括多个不同的组件。为了成功运营这样的服务,您可能需要获取设备健康状况、应用状态、播放事件信息和交互信息等多种类型的数据。这通常意味着需要构建高吞吐量的流处理应用程序和解决方案。
这些流处理应用程序的一个关键组成部分是确保数据的可靠性和高效性捕获。在第7章中,几种实现方法及其优势展示了Delta Lake如何在执行这些数据捕获任务时发挥至关重要的作用。Delta Lake通常是许多摄取过程的目标,因为它提供ACID事务保证以及像优化写入等功能,使得高流量流处理变得更加高效和简便。
假设您想要实时监控所有用户的服务质量(QoS)。为完成这一任务,您通常不仅需要播放事件信息,还需要每个用户会话中的相关上下文信息,这是通过一定时间范围内的交互序列绑定在一起的。会话化(Sessionization)通常是许多下游操作的一个重要基础,它通常位于较大数据流程的数据工程阶段,如图11-1所示。通过Delta Lake中的会话信息和其他系统信息,您可以为下游分析用例提供支持,例如服务质量测量或趋势项目推荐,同时保持低延迟的处理时间。
构建这些数据管道通常是相当复杂的,涉及多个管道和过程的交互。核心是,您会发现每个组件最终归结为需要构建一个强健的数据处理管道,以满足多个业务需求的思想。
智能设备集成
Comcast开发了一款成功的智能遥控器,旨在改变人们观看电视的方式。该公司面临的数据问题的关键在于,这种系统需要大量的数据处理,并且带来了一些技术和组织上的挑战。通过使用Delta Lake作为数据格式,许多这些挑战得以克服,Comcast能够将其最关键的工作负载所需的云基础设施需求减少90%。此外,它还解决了许多围绕这些数据处理过程的生活质量问题。下面将展示Comcast是如何解决这些挑战的。
Comcast的智能遥控器
Comcast是美国最大的跨国电信和媒体集团,本节中将展示该公司如何大幅减少其最重要工作负载所需的云资源。Comcast一直致力于通过其Xfinity语音遥控器改变人们与电视互动的方式,这款遥控器充当了一个集中访问点。因此,正如您所料,围绕设备在边缘的许多关键数据工作负载都集中在此。图11-2展示了交互流程的高层示例。
在我们探讨Comcast如何基于Delta Lake构建其解决方案之前,了解其运营规模的更多具体信息可能会有所帮助。Comcast通过其语音遥控器推动用户交互,而其客户在2018-2019年间共使用了该遥控器140亿次(图11-3展示了这一规模在数据处理中的相对影响)。用户在使用应用时有许多期望,例如能够得到准确的搜索结果,并且能够轻松找到适合消费的内容。每个用户的个性化体验也应该具有一定的个性化元素,让用户的体验变得独一无二。通过语音遥控器,用户可以与整个系统进行互动;他们想要的一切,只需一句简短的指令。除此之外,Comcast还利用用户数据来创造个性化的体验。
考虑一下支持这些服务在幕后运行的技术组件。首先,接收语音命令作为输入(这一功能最近越来越受欢迎)是一个技术挑战。需要将语音转化为数字信号,然后将其映射到每个需要的命令上。通常,这一映射还需要进行意图的修正。比如说,用户更有可能是在搜索一档名为《How It’s Made》的节目,还是在询问其他介绍如何制作某物的节目?如果是搜索命令,仍然需要通过匹配算法来找到类似的内容。所有这些都需要通过一个单一的接口点整合在一起,在这种环境中,用户体验需要根据准确性进行衡量,因此获取这些过程的数据,并启用分析来评估即时问题或长期趋势也是至关重要的。
现在,我们需要将语音输入转换为嵌入向量(捕捉语义意义的数字数据向量,作为“令牌”),以及每次与遥控器交互时的上下文数据(例如用户所在页面的类型、其他最近的搜索、日期时间参数等)。目标是收集所有这些数据,并通过用户界面(UI)几乎实时地提供推断。从功能角度来看,还需要收集大量的遥测信息,以维护对设备健康、连接状态、观看会话数据等内容的洞察。
一旦解决了将这些数据从各个设备传输到集中处理平台的问题,仍然面临如何标准化数据源的挑战,因为不同版本的设备可能有不同的可用信息,或者使用地区可能有不同的收集法律,意味着捕获的事件内容可能更全或更少。标准化之后,仍然需要组织数据,并以适应功能的格式创建可操作的步骤。
为了让这一切从一个团队完成,将需要大量的努力和长时间的投入,因此让多个团队协作处理复杂性将是有益的,甚至是绝对必要的。
早期的尝试
为了支持语音遥控器,Comcast需要能够分析查询并查看用户旅程,以实现例如衡量查询意图的功能。以每秒最多1500万次事务的速度,Comcast需要在数十亿个会话上启用会话化,并处理数PB的数据。在原生AWS服务上运行时,它会超出限制,并增加并发使用,直到最终在640个虚拟机上运行32个并发作业,以便达到所需的会话化规模。处理流程如图11-4所示。这促使Comcast寻找一个可扩展、可靠且高性能的解决方案。
Delta Lake简化复杂性
Delta Lake的构建旨在帮助解决这些类型的问题。ACID事务和对多个写入者的支持,以及优化写入和自动压缩等特性,都在简化并克服大规模流处理任务中的挑战中发挥了作用。这里的问题源于数据的性质以及按键值进行的分区。许多自然键(例如用户ID值)会导致数据倾斜。这意味着,随着数据量的增加,高频率的键查找变得越来越繁重,且最高频率的键可能会成为应用程序的瓶颈。
启用诸如delta.randomFilePrefixes等特性,可以在云服务提供商环境下实现高事务率,从而使工程师能够在提高效率的同时实现大规模处理,因为这样可以消除由前缀限制引起的潜在障碍。通过让分布式框架处理键分区,而不是强制手动并行化任务,您可以获得显著的性能提升。通过做出这一改变,Comcast能够使用单个Spark作业在仅64个虚拟机上运行相同的摄取过程。 resulting process flow is shown in Figure 11-5.
如果这就是整个故事,您可能已经对Delta Lake在减轻处理负担方面的价值感到信服。更棒的是,这还不是全部。在Comcast的Databricks环境中,Comcast能够轻松访问这些会话化数据,用于多个下游目的。
前面提到,构建这样的过程可能涉及不同类型的机器学习任务,比如嵌入向量的创建或模型推理。特别是,需要将语音输入转化为有意义的操作。通过捕获会话化数据并高效存储,数据科学家可以快速且轻松地构建建模管道。
备注
MLflow是另一个开源产品,提供了许多功能来改进端到端的MLOps流程。MLflow的关键特性包括在实验中跟踪和比较多个模型版本、用于管理的注册表,以及支持更轻松地部署模型对象的机制。除了传统的机器学习模型,MLflow还支持大语言模型(LLMs)、其他生成模型和AI代理。
由于Comcast使用了MLflow,它在机器学习过程中从Delta Lake中获得了额外的好处。通过项目实验中的数据源跟踪,MLflow可以跟踪与实验相关的Delta Lake表的信息,而无需像处理CSV文件或其他数据源时那样复制数据。图11-6展示了MLflow在数据生命周期中的位置。由于Delta Lake还具有时间旅行功能,机器学习实验的可重复性得到了增强,这将有利于维护生产中数据科学产品的任何人。
另一个重要目标是能够监控与质量服务(QoS)或类似类型的分析应用相关的遥测数据。在Comcast的案例中,公司使用Databricks SQL直接在Delta Lake表上运行分析工作负载,而不是像之前那样使用Redshift。该公司在这一方法的试点中选择了10个表现最差的查询进行评估,结果发现运行查询的时间减少了超过70%(见图11-7)。
最终,对于Comcast来说,继续在Delta Lake上进行创新看起来是非常有利的。到目前为止,它在数据摄取过程中已获得了巨大的节省,并对改善报告的前景充满信心。这应该能进一步提升Comcast的智能遥控器终端用户体验,并提高整体满意度。
高效的流式数据摄取
假设你有一些大型摄取管道在Kafka和Databricks上运行,为Delta Lake环境提供数据。现在假设你有一个优秀的工程团队,决定投入大量精力通过设计一个不需要Spark重负担能力的小型流解决方案来降低成本。你还希望将所有这些数据在摄取过程下游集中处理。那么,你可能在寻找类似于Scribd团队所做的工作。
流式数据摄取
用于摄取任务的流处理应用程序是相对常见的。我们有许多流处理框架可供选择。其中最常见的是开源的Apache Kafka、AWS的Kinesis、Azure的Event Hubs以及Google的Pub/Sub。
虽然这些流处理框架的适用场景非常广泛,涵盖了如物联网设备的实时遥测监控、欺诈交易监控或警报等有趣的话题,但流处理最常见的应用之一是大规模和动态数据摄取。对于许多组织来说,收集有关移动应用程序终端用户活动或零售商的销售点(POS)数据,直接意味着支持关键业务分析应用程序的成功。快速且准确地从广泛分布的来源获取大量数据,还能使企业更迅速地适应不断变化的环境(图11-8展示了来自多个流源的统一架构)。
通过启用实时流程和使用人工智能应用程序实现的巨大灵活性,通常由动态且弹性的数据管道提供支持,这些管道往往属于这一类别。在所有这些流程中,通常会涉及捕获传入数据以供后续分析或评估使用,因此,尽管某些处理管道中可能会有额外组件,但归根结底,这个过程适用于大多数流处理应用程序。
考虑一下来自设备的物联网(IoT)数据的情况。如果你将所有数据发送到Kafka中,你可以构建一个Spark应用程序来消费这个流,并捕获所有原始数据,按接收到数据的方式进行处理,遵循勋章架构(medallion architecture)的模型。然后,你可以创建业务级别的报告,并将这些结果发送到下游应用程序进行消费。自然,这种方法有很多变体,但总体的管道模型是相似的,如图11-9所示。在Scribd,这个应用场景非常常见,以至于他们围绕实现这个过程构建了一个新的框架。
Delta Rust的诞生
虽然Scribd最初是一个开放的出版平台,但现在它已经发展成为一个数字文档库,拥有超过1.7亿份文档,涵盖150多个类别,并且这个数字还在不断增长。Scribd的使命之一是改变全球人们的阅读方式。它旨在通过提供丰富的阅读材料,以合理的价格满足创作者和消费者的需求,同时为创作者提供知识产权保护,并保持低成本运营,偏向于通过社区而非广告建立品牌。
作为数字图书馆的一部分,Scribd运营着其网站和移动应用程序。用户可以通过Scribd的网站和移动应用浏览数百万份文档,包括演示文稿、研究论文、模板等各种文档。这些文档由创作者、作家和编辑上传,支持多种常见文档格式,如.pdf、.txt、.doc、.ppt、.xls和.docx。Scribd还提供订阅系统。这些不同的系统组件会生成事件,这些事件需要被收集和处理。为此,Scribd使用了大量通过Kafka传输的事件流。
构建流处理管道通常需要多个组件。在Scribd的具体背景下,一个简单的设计方法是为每个来自Kafka的主题流构建一个流处理应用程序。在Scribd的情况下,我们可以轻松列出一些可能的事件主题流:创作者上传、阅读事件、系统登录或认证事件、订阅事件、网页流量事件、搜索事件、项目书签或保存事件、项目共享事件等。这意味着将涉及许多不同的流处理应用程序,这通常会导致开发某种框架来减少所有应用程序的开发和维护工作。
维护一个针对多个事件流的流处理框架是一个相当复杂的任务,如果没有精心的规划,也可能变得非常昂贵。接下来是Scribd流处理框架的演变故事,展示了它如何创建了kafka-delta-ingest库,并通过该库将数据摄取成本降低了95%。
摄取的演变
Scribd的流处理平台经历了几次不同的改革。最初,所有的处理都是在Kafka和Hadoop上完成的,这曾经是一个相当标准的流处理方法。该平台的这一版本后来被Kafka和Databricks替代,使用了Spark Structured Streaming和Delta Lake。这一变化对Scribd来说是有利的,部分原因在于Delta Lake的特性,如优化和清理工具,以及ACID事务的支持。
然而,在Scribd的情况下,有许多主题流,而且很多主题流的数据量较小。这导致了减少不断上升的摄取成本的尝试。在Scribd,大型的专用集群仍然在“不会浪费资源”的情况下使用——即,当有大任务时,这些任务能够高效地利用集群资源。许多小流则堆叠在一起(在同一个集群上同时运行),这产生了类似的资源利用效率,从而降低了整体处理成本。然而,这样做依然存在一些挑战。如何对主题进行逻辑分组是一个令人头痛的问题。始终存在某个处理任务失败的可能,这可能导致集群中所有堆叠的流都随之失败。此外,摄取过程中如何进行维护任务的调整也已经是一个相对复杂的任务。
Scribd团队希望改进以下几个方面:
- 如果可能,进一步降低成本;
- 更好地观察摄取过程;
- 更好地处理作业失败;
- 更灵活地应对事件流吞吐量的变化。
这也促使团队开始思考如何解决问题。是否可能在不使用Spark的情况下解决,或者找到一种更小开销的方法?如何在保持Delta Lake标准化的前提下,继续使其简化管理?
对于当时的Scribd团队来说,经过一些投入,似乎有另一种方式可以解决问题。团队的摄取过程相对简单,只有追加操作,没有过滤、连接或聚合,并且只使用了Delta Lake的部分功能,这简化了开发替代方案的过程。
Scribd的场景促使其投资开发了两个项目,这些项目现在已成为更大Delta Lake生态系统的重要组成部分。第一个项目是delta-rs,这是基于Rust的Delta Lake协议实现,已经在第六章中深入探讨。第二个项目是kafka-delta-ingest(第4章提供了使用kafka-delta-ingest的简要指南),这是一个轻量级的辅助框架,旨在快速且轻松地将Kafka主题流中的数据摄取到Delta Lake表中。这两个项目形成了高效的操作配对(简化的数据流如图11-10所示)。
进行这样的努力并非没有风险或潜在的阻碍问题。Delta日志损坏的风险是一个挑战,此外,还需要手动控制Kafka中的偏移量追踪,以避免重复或丢失记录。Scribd还需要支持多个写入者写入表,并且AWS S3的一些限制也需要特定的处理(例如,S3锁协调)。
Scribd在生产环境中运行着70到90个kafka-delta-ingest和delta-rs管道。它通过AWS Fargate运行这些管道的无服务器计算,并通过Datadog对一切进行监控。它监控的内容包括消息反序列化日志和几个指标:转换和失败的数量、内存中Arrow批次的数量、写入的Parquet数据文件大小,以及Kafka流中的当前时间延迟。
所有这些都带来了显著的成本节省,因为通过Scribd团队构建的工具,运行某些流处理应用程序的成本降低了多达100倍(如图11-11所示)。另一个使这一成就更加完善的特点是,Scribd通过保持Delta Lake的标准化,使得摄取的数据可以立即用于分析和机器学习过程,或者进一步集成到Scribd的Databricks环境中的其他批处理流程,并保持可查询性。
协调复杂系统
从智能设备、娱乐到安全和数字支付系统,高量级数据源层出不穷。对于Scribd来说,重点是简单的事件捕获,且对操作系统的要求较低,其中kafka-delta-ingest是一个可行的解决方案。现在,让我们考虑一些情况,在这些情况下,与外部世界的交互边界不那么直接,需要更多的服务。这更加复杂,也更具人性化。持续演变的复杂应用程序通常拥有更多集成的操作组件,这些组件需要随着时间保持和谐,否则你可能会发现自己花费过多时间去整理现有数据,而不是关注新的需求、数据源或流程,这应该是你更愿意做的事情。
包括多个实时操作数据库并要求创造业务价值,通常意味着需要将这些数据库中的信息收集到一个统一的位置,用于开发分析和机器学习应用程序。其他系统可能没有操作数据库,但依赖事件驱动系统。通常,这些数据将需要与其他系统的数据结合使用,形成一个相对复杂的数据生态系统,例如,客户交易数据与可在公开市场上获取的匿名化趋势数据。图11-12展示了如何将这些数据源结合起来,以支持多个下游应用程序。依赖像Delta Lake这样的湖仓格式,利用其广泛的不同系统连接器,减少了这种复杂性,并使分析和人工智能应用程序得以实现。
在DoorDash中结合操作数据存储
许多人都曾遇到过这样的情况:如果有人能为他们取餐、买菜、购买电子产品或几乎任何其他物品,可能会节省他们出门的时间。DoorDash通过其配送服务为各种需求提供了灵活性和便利性。虽然大多数人对DoorDash基于零工经济的运营模式比较熟悉,但考虑以下几个点可能会更有帮助。
在DoorDash的购买流程中,涉及多个方。通常有请求者、配送员,以及准备订单或提供产品的餐厅或商家。在不深入DoorDash更大的IT生态系统的前提下,可以明显看出,已经存在对大规模低延迟数据管道的需求,即流数据应用程序,因为每个“事件”本身是许多事件的汇总,它会在整个过程中一步步推进。
DoorDash在其数据生态系统中以两种方式利用Delta Lake。第一种是简化大规模变更数据捕获(CDC)的管理,并将数据暴露给下游进行分析。第二种是在Flink中支持实时工作负载。两者都在架构设计中捕获了使用Delta Lake的一些好处。
变更数据捕获
变更数据捕获(Change Data Capture,简称CDC)是一种常见的应用模式,通常需要支持各种原因(见第7章,关于CDC的额外讨论)。DoorDash使用CDC来复制支持多个服务的操作数据库到分析环境中。这项需求源于历史上要回答“DoorDash昨天做了多少订单?”的问题。早期,回答这个问题比较容易,因为只需创建数据库的副本,并对副本进行查询以回答分析问题或执行数据科学任务。
随着DoorDash的成长,它的服务架构不断演进,最终形成了一个包含多个操作数据库的环境,这些数据库种类繁多,例如CockroachDB、PostgreSQL和Apache Cassandra。为了以最简单的方式从这些数据库中获取数据,DoorDash团队最初从数据库中获取快照并每日拉取。虽然这种方法奏效,但也带来了一些问题——特别是数据版本控制的挑战,以及需要过滤快照以有效地增量化数据处理。经过多次调整环境后,团队最终开始开发一个更强大的系统。
对于我们的目的,关键的系统需求是:
- 保持一天以内的数据延迟
- 使用湖仓设计模式
- 支持模式演化
- 支持数据回填
- 支持分析工作负载
- 一次写入,多次读取
- 避免延迟到达的数据
- 使用开源软件构建
基于这些需求(见图11-13),最终设计出了一种基于Spark Structured Streaming的流式CDC框架,将变更数据流复制到基于Delta Lake的统一真实数据源中,支持各种查询接口的下游集成。诸如合并支持和ACID事务等特性,帮助Delta Lake成为该设计的关键组件。
这个设计的成功可以通过多种方式来衡量,但团队突出强调了几个方面。该系统支持450个流(与表一一对应),并在超过1000个EC2节点上全天候运行。这意味着每天从Kafka摄取约800 GB的数据,总体每日处理量大约为80 TB。该设计大大超出了最初的需求,并达到了不到30分钟的数据新鲜度。团队已经使得数据用户可以自助创建表,并且在不到一个小时内,这些表就可以使用。
Delta 和 Flink 的和谐共存
由于实时事件对DoorDash至关重要,DoorDash重度使用Kafka并不令人意外。Apache Spark是许多流处理应用程序的自然选择;然而,它并不是唯一的选择。DoorDash的一些团队使用Apache Flink进行许多实时处理,因此它也应该容易被支持。在第4章中,您已经了解了Flink/Delta连接器的操作原理,但在这里,看看如何将它拉入更大的数据生态系统,以提供灵活性和可靠性,可能会更有帮助。
DoorDash的实时平台团队每天管理着数PB的重要客户事件,并需要提供一个平台,使数据用户和应用程序能够捕获、创建或访问这些信息(见图11-14)。通过添加Flink/Delta连接器,扩展了用户和应用程序与Delta Lake互动的方式,这结合了Flink的快速操作特性,并提供了一种专为处理这类工作负载而构建的存储格式,且可以跨整个数据平台使用,即使不同的团队选择使用不同的应用程序处理框架。
图11-15展示了DoorDash这一变更所带来的成果:通过添加ACID保证,实现了与现有工具的轻松集成,且在大规模下运行。之前,这一过程是使用常规的Parquet文件进行的,这导致了额外的复杂性,例如写锁和其他挑战。此外,通过易于使用的压缩操作以及在流处理应用程序仍在运行时执行这些操作的能力,DoorDash获得了显著的生活质量提升。同样,通过在数据中包含Z排序簇来实现高效查询的状态,也是一个非常有价值的成果。
DoorDash决定采用Delta Lake的故事教训是:即使对于拥有多种工具并在大规模下运行的数据系统,且需要支持高效捕获实时事件流数据或通过操作数据库进行的数据变更,Delta Lake也能提供可靠性和可用性,因此它是一个值得选择的解决方案。
总结
数据应用有多种不同的形式和格式。开发这些数据应用可能是复杂且痛苦的。在本章中,你已经了解了通过Delta Lake的诸多优势来缓解这种痛苦的一些方法。特别是,Delta Lake的特性帮助创建了一个强大的数据环境,支持广泛的工具选择,降低了成本,并改善了作为开发者的工作质量。