在本章中,我们将探讨几种扩展 Delta Live Tables (DLT) 管道的方法,以应对典型生产环境中的处理需求。我们将涵盖调优 DLT 管道的多个方面,从优化 DLT 集群设置,使管道能够迅速扩展以应对处理需求的高峰,到优化云存储中基础表的数据布局。通过本章的学习,您应该掌握如何使 DLT 集群自动扩展以应对需求。您还应了解由 DLT 系统在后台自动运行的表维护任务对数据管道性能的影响。最后,您应该了解如何利用 Delta Lake 优化技术进一步提高 DLT 管道的执行性能。
本章将覆盖以下主要内容:
- 扩展计算以应对需求
- 实战示例——使用 Databricks REST API 设置自动扩展属性
- 自动化的表维护任务
- 优化表布局以加速表更新
- 无服务器 DLT 管道
- 介绍 Enzyme:一个性能优化层
技术要求
要跟随本章的内容,您需要具有 Databricks 工作区权限,以创建并启动一个通用集群,并且至少需要具有集群策略权限来创建新的 DLT 管道。所有代码示例可以从本章的 GitHub 仓库下载,地址为 GitHub 链接。本章将创建并运行几个新的笔记本,以及使用核心产品版本创建一个新的 DLT 管道。因此,本章的代码示例预计将消耗约 10-15 个 Databricks 单位(DBUs)。
扩展计算以应对需求
数据管道的不同部分可能涉及繁重的计算,当执行计算时,某些部分可能不需要太多处理能力。为了在优化成本的同时获得最佳性能,任何数据管道都应能够在需要时增加额外的计算能力,并在处理需求减少时释放计算资源。幸运的是,Databricks 提供了一个内置的自动扩展功能,用于 DLT 管道,这样虚拟机(VM)可以根据数据管道执行期间的处理需求动态地添加到管道集群中或从中移除。
实际上,Databricks 为 DLT 管道提供了两种类型的集群自动扩展模式:传统模式和增强模式。两种自动扩展模式都会根据处理需求的增加或减少自动添加或删除虚拟机。然而,添加和移除虚拟机的时机在这两种模式之间有所不同。
在传统自动扩展模式下,当处理需求在一段时间内持续增加时,管道集群会添加额外的虚拟机。此外,在传统模式下,管道集群只有在虚拟机空闲且当前没有正在执行的 Spark 任务时,才会进行缩减。
另一方面,在增强自动扩展模式下,DLT 系统只有在预测添加额外的计算资源可以加速管道更新执行时才会添加虚拟机——例如,当 Spark 作业受到可用 CPU 核心数量的限制,并且通过增加更多 CPU 来并行执行大量 Spark 任务会有所改善。此外,增强自动扩展功能将主动寻找管道集群的缩减机会,通过驱逐正在运行的 Spark 任务并减少云操作成本。在驱逐过程中,增强自动扩展模式会确保被驱逐的 Spark 任务在剩余的运行虚拟机上成功恢复,然后再终止过度配置的虚拟机。
最后,增强自动扩展仅适用于用于管道更新任务的集群,而传统自动扩展模式则用于 DLT 系统执行维护任务。
下表列出了 DLT 管道集群的两种自动扩展模式的区别,以及每种自动扩展模式支持的 DLT 任务。
| 自动扩展模式 | 预测自动扩展 | 主动缩减 | 更新任务 | 维护任务 |
|---|---|---|---|---|
| 传统模式 | ✖️ | ✖️ | ✔️ | ✔️ |
| 增强模式 | ✔️ | ✔️ | ✔️ | ✖️ |
表 4.1 – DLT 管道集群可用的自动扩展模式的区别
您可以通过 DLT UI 或 Databricks REST API 配置集群自动扩展模式。在下一节中,让我们使用 Databricks REST API 来更新现有数据管道集群的自动扩展模式。
实战示例 — 使用 Databricks REST API 设置自动扩展属性
在本节中,您需要从本章的 GitHub 仓库下载代码示例,地址为 GitHub 链接。在仓库中有一个名为 Random Taxi Trip Data Generator.py 的帮助笔记本,我们将使用它来生成数据突发,模拟生产环境中的不可预测行为。
首先,导入本章的管道定义笔记本 Taxi Trip Data Pipeline.py 到您的 Databricks 工作区,并打开该笔记本。
您会注意到我们在数据管道中定义了两个数据集。第一个数据集使用 Databricks Auto Loader 功能来摄取新的 JSON 文件,一旦数据被摄取,第二个数据集——我们的银表——将包含转换后的出租车行程数据的结果,并添加了包含财务分析的额外列:
@dlt.table(
name="random_trip_data_raw",
comment="The raw taxi trip data ingested from a landing zone.",
table_properties={
"quality": "bronze"
}
)
def random_trip_data_raw():
raw_trip_data_schema = StructType([
StructField('Id', IntegerType(), True),
StructField('driver_id', IntegerType(), True),
StructField('Trip_Pickup_DateTime',
TimestampType(), True),
StructField('Trip_Dropoff_DateTime',
TimestampType(), True),
StructField('Passenger_Count', IntegerType(), True),
StructField('Trip_Distance', DoubleType(), True),
StructField('Start_Lon', DoubleType(), True),
StructField('Start_Lat', DoubleType(), True),
StructField('Rate_Code', StringType(), True),
StructField('store_and_forward', IntegerType(), True),
StructField('End_Lon', DoubleType(), True),
StructField('End_Lat', DoubleType(), True),
StructField('Payment_Type', StringType(), True),
StructField('Fare_Amt', DoubleType(), True),
StructField('surcharge', DoubleType(), True),
StructField('mta_tax', StringType(), True),
StructField('Tip_Amt', DoubleType(), True),
StructField('Tolls_Amt', DoubleType(), True),
StructField('Total_Amt', DoubleType(), True)
])
return (spark.readStream
.format("cloudFiles")
.option("cloudFiles.format", "json")
.schema(raw_trip_data_schema)
.load(raw_landing_zone))
接下来,将笔记本附加到一个通用集群并执行所有笔记本单元,确保所有单元都成功执行。当被提示时,创建一个新的 DLT 管道,选择核心产品版,并选择连续处理模式作为管道执行模式。接下来,选择 Unity Catalog 中的目标位置来存储数据管道的数据集,并接受其余的默认值。最后,记下新创建的 DLT 管道的管道 ID。
接下来,我们将使用流行的 Python 库 requests 与 Databricks REST API 进行交互。创建一个新的笔记本并在笔记本的第一单元中导入 requests 库:
import requests
接下来,让我们创建一个新的请求,通过 Databricks REST API 更新数据管道集群的设置。在请求负载中,我们将指定自动扩展模式、管道集群的最小工作节点数以及最大工作节点数。根据 Databricks 的公开文档,我们还需要使用 PUT 动词来更新 DLT 管道的设置。将以下代码片段添加到新创建的笔记本中,并用您的环境特定值更新变量:
databricks_workspace_url = "<your_databricks_workspace>"
pipeline_id = "<your_pipeline_id>"
pat_token = "<your_api_token>"
response = requests.put(
f"{databricks_workspace_url}/api/2.0/pipelines/{pipeline_id}",
headers={"Authentication": pat_token},
json={
...
"clusters":[{
"autoscale": {
"min_workers": 2,
"max_workers": 5,
"mode": "ENHANCED"
}
}]
...
}
)
print(response.json())
或者,您也可以通过 DLT UI 导航到管道设置并将自动扩展模式更新为 ENHANCED。更新完 DLT 管道以使用增强自动扩展模式后,让我们执行一次管道更新。返回到您创建的 DLT 数据管道的 UI,点击右上角的 Start 按钮,触发数据管道更新执行。
与此同时,我们还将使用随机数据生成器模拟处理需求的高峰。导入本章的 GitHub 仓库中的 Random Taxi Trip Data Generator.py 数据生成器笔记本,随机生成出租车行程数据,模拟生产环境中的典型工作负载。将笔记本附加到通用集群,并点击 Run all 按钮以执行所有单元。确保笔记本单元已成功执行。
接下来,切换回 DLT UI,监控管道的事件日志,确保 DLT 集群会自动增加工作实例数量。
同样,监控事件日志以确保在额外数据流结束且处理需求减少后,DLT 更新集群会缩减回去。
到目前为止,您应该已经掌握了 DLT 集群如何根据处理需求的波动进行扩展和缩减的基本原理。正如您所看到的,我们的 DLT 管道只会配置它所需的计算资源,以有效地保持数据集的最新状态,并在数据处理需求减弱时释放额外的计算实例,以最小化我们的运营成本。接下来,我们将关注 DLT 系统自动为我们完成的其他效率任务,比如 DLT 系统如何自动维护我们底层 Delta 表的最佳状态。
自动化的表维护任务
如前几章所述,每个 DLT 管道都将与两个集群相关联——一个集群用于执行管道定义中每个数据集的更新,另一个集群用于执行每个数据集的维护活动。这些维护任务包括执行每个 Delta 表的 VACUUM 和 OPTIMIZE 操作。在以前,数据工程师需要负责创建并维护一个单独的 Databricks 工作流,该工作流会为每个 Delta 表执行 VACUUM 和 OPTIMIZE 命令,通常这些命令会安排在夜间运行。可以想象,当您开始在管道中添加更多的表时,这可能会变成一项相当繁琐的任务。幸运的是,DLT 框架为我们自动完成了这些繁重的任务。此外,每次 VACUUM 和 OPTIMIZE 维护活动都会在上次管道执行后的 24 小时内执行。
让我们逐个了解每个操作,以便理解这些维护任务对底层数据集的整体益处。
为什么自动合并很重要
在每次更新某个特定的 DLT 管道时,DLT 管道会初始化数据流图,并执行每个数据集定义中列出的基础计算。结果,新的数据要么追加到表中,要么合并到特定的 Delta 表中。每次写入数据时,Apache Spark 会将写操作分发到执行器,这可能会生成许多小文件。随着更多更新的执行,这些小文件会在云存储中不断增加。当下游进程读取这些 Delta 表时,每个独特的文件都需要耗费一个 Spark 任务来处理,回答特定表的查询。文件越多,Spark 任务就越多——换句话说,Spark 引擎需要处理的工作就越多。这通常被称为“小文件问题”,因为当表中产生大量新数据时,会生成许多小文件,从而导致整体查询性能的下降。为了解决这个问题,最好将这些小文件合并成更大的文件,这一过程被称为文件合并(file compaction)。
幸运的是,作为数据工程师,我们不需要自己编写工具来将较小的文件合并成较大的文件。实际上,Delta Lake 提供了一个非常有用的命令叫做 OPTIMIZE,专门用于执行这样的维护任务。默认情况下,Delta Lake 的 OPTIMIZE 命令会尝试将较小的文件合并为更大的 1GB 文件。
当然,你可以选择通过在 DLT 管道的表定义中禁用 auto-optimize 功能来关闭自动优化特性:
@dlt.table(
name="random_trip_data_raw",
comment="The raw taxi trip data ingested from a landing zone.",
table_properties={
"quality": "bronze",
"pipelines.autoOptimize.managed": "false"
}
)
在某些情况下,你可能希望覆盖默认行为,例如实现你自己的表优化工作流。
每当执行 OPTIMIZE 维护操作时,它也会为每个 Delta 表生成额外的文件。为了防止云存储成本失控,我们还必须处理删除过时的表文件,以确保作为一个组织,我们不会为不必要的云存储付费。
清理过时的表文件
VACUUM 操作旨在删除 Delta 表中不再处于最新快照中的、并且比保留阈值属性更旧的表文件。默认情况下,所有 Delta 表的保留阈值为七天,这意味着 VACUUM 操作会删除当前快照日期之前七天以上的过时表文件。在运行时,VACUUM 工具将搜索 Delta 表的根目录以及所有子目录,删除所有超过保留阈值的表文件。
这是一种很好的方式,可以平衡云存储成本和维护、查看特定 Delta 表较旧快照的能力。如第一章所述,Delta Lake 的时间旅行功能依赖于表历史记录来查询 Delta 表的旧版本。然而,该功能并不支持长期归档用例,而是用于较短时间内的表历史。因此,合理的期望是我们不需要存储 Delta 表的所有历史记录,也不需要为此支付相关的存储费用,这可能会变得非常昂贵。
像自动优化功能一样,Delta 表的历史保留阈值是由表属性确定的,并且可以通过 deletedFileRetentionDuration 表属性在表定义中指定:
@dlt.table(
name="random_trip_data_silver",
comment="Taxi trip data transformed with financial data.",
table_properties={
"quality": "silver",
"pipelines.autoOptimize.zOrderCols": "driver_id",
"delta.deletedFileRetentionDuration": "INTERVAL 14 days"
}
)
类似地,Delta 事务日志——记录每个已提交的表事务详细信息的元数据文件(第一章中有介绍)——也可能导致不必要的存储费用。然而,这些日志文件会在日志检查点操作期间自动删除(每十次事务提交时)。默认情况下,Delta Lake 会保留最多 30 天的表历史记录在事务日志中。
由于事务日志文件仅包含元数据,它们通常较小,仅包含几兆字节的信息。然而,这种历史记录保留也可以通过设置 logRetentionDuration 表属性进行配置:
@dlt.table(
name="random_trip_data_silver",
comment="Taxi trip data transformed with financial data.",
table_properties={
"quality": "silver",
"pipelines.autoOptimize.zOrderCols": "driver_id",
"delta.deletedFileRetentionDuration": "INTERVAL 9 days",
"delta.logRetentionDuration": "INTERVAL 35 days"
}
)
删除过时的云文件是控制云成本的一个很好的方法,能够防止组织为不必要的云存储费用支付。接下来,让我们看看如何优化 DLT 管道的其他方面,以提高操作效率,同时继续降低运营成本。
将计算迁移到数据更近的地方
确保数据管道高效执行的最简单方法之一是确保 DLT 管道集群启动在与数据存储相同的全球区域内。这是一个老生常谈的调优概念,即将硬件移近数据,以最小化数据处理过程中的网络延迟。例如,你不希望你的 DLT 管道集群在云服务提供商的美国西部地区执行,而数据却存储在同一云服务提供商的美国东部地区。这将导致在地理区域之间传输数据时产生相当大的网络延迟,进行数据转换或其他计算,然后将结果存储回原始地理区域。此外,大多数云服务提供商会对地理数据传输相关的数据出站和入站流量收取费用。
DLT 集群的地理区域可以通过在管道集群策略定义中设置云区位置来配置。例如,以下代码片段定义了一个集群策略,可以用于配置 DLT 管道集群,使其在 AWS 云提供商的美国东部区域启动:
{
...
"aws_attributes.zone_id": "us-east-1",
"custom_tags.lob": {
"type": "fixed",
"value": "ad analytics team"
}
}
通过确保 DLT 集群在与组织数据相同的地理区域内进行配置,可以确保从管道集群中获得最佳的操作性能。同时,由于管道运行更快并且使用云资源的时间更短,这意味着组织可以节省更多成本。除了优化数据管道的计算资源外,我们还可以有效地组织表数据,以进一步提高数据管道更新的性能。接下来,让我们看一些优化表数据布局的技术,以提高 DLT 管道的处理效率。
优化表布局以加速表更新
典型的 DLT 管道可能包括一个或多个数据集,这些数据集会追加新数据,并使用新的值更新现有数据,甚至完全删除某些行。让我们深入了解后一种情况,并分析“幕后”发生了什么,以便我们在向 DLT 表中添加新数据时优化 DLT 数据集以获得更快的性能。
更新过程中重写表文件
在表更新期间,DLT 引擎将执行两次扫描,以识别所有符合特定更新条件的行,并相应地重写更改的表数据。在第一次表扫描期间,DLT 引擎将识别所有包含匹配 apply_changes()(或者如果使用 SQL,则为 APPLY CHANGES)表达式中谓词条件的行的表文件。例如,
接下来,DLT 引擎将编译一个包含这些行的所有表文件的列表。利用这个表文件的列表,DLT 引擎将在第二次表扫描操作中重写包含新更新行的每个文件。正如你所想,随着你向 DLT 表中添加更多数据,定位这些匹配行并确定需要重写的文件列表的过程可能会随着时间的推移变得非常昂贵。幸运的是,Delta Lake 提供了一些功能,我们可以利用它们来优化搜索过程并加速匹配过程。
使用表分区进行数据跳过
加速此搜索过程的一种方法是限制 DLT 引擎的搜索空间。一种这样的技术是使用 Hive 风格的表分区。表分区将相关数据组织到表的根存储位置中的物理子目录中。这些子目录与一个或多个表列相对应。
在匹配过程中,DLT 引擎可以消除不符合谓词条件的整个子目录,从而避免扫描不必要的数据。
通过 MERGE 列对表进行分区,MERGE 列用于将数据更改应用于表,可以显著提高更新过程的性能。另一方面,由于表分区创建了物理上分开的目录,因此表分区可能很难正确设置,而且修改起来很昂贵,需要重写整个表以调整分区方案。
另一个挑战是识别一种表分区方案,这种方案将导致分区目录中的数据量保持平衡。很容易通过 MERGE 列对表进行分区,但最终可能会遇到一些分区目录包含少量数据,而其他分区目录包含大量数据的情况。这通常被称为数据倾斜(data skew)。尽管如此,表分区仍然是数据管道调优工具中的一个强大工具。让我们看看如何将表分区与另一种表优化技术结合起来,以进一步提高管道性能。
Delta Lake 的 MERGE 列 Z-order 排序
优化 Delta 表的表布局的一种方法是组织表文件中的数据,使其在文件扫描操作期间可以高效地读取。这通常被称为数据聚类。幸运的是,Delta Lake 提供了一种名为 Z-order 聚类的数据聚类算法。Z-order 聚类会通过将相关数据聚集在一起,形成一个“Z”形状的模式来写入表数据。按照这种模式存储表数据将提高 DLT 引擎跳过表文件中不相关数据的概率,从而只读取在更新匹配过程中与合并条件匹配的数据。
传统上,在没有 Z-order 聚类的情况下,Delta Lake 会以线性模式存储数据。因此,在更新匹配过程中,Delta Lake 需要打开表的每个文件,并按线性排序顺序扫描每一行。有时,只有一行可能与合并条件匹配。接下来,DLT 引擎将读取所有不匹配的无关行,最终可能只找到 1 或 2 行与更新条件匹配。
通过使用 Z-order 聚类技术将数据聚集在文件中,DLT 引擎可以精确定位特定文件中相关数据的位置,限制必须扫描的数据量。对于需要大量扫描的大型表,这可以显著提高 DLT 管道的更新过程。
Z-order 聚类可以通过在数据集定义中设置适当的表属性来启用。让我们看一下如何为我们的银色表格 yellow_taxi_transformed 配置 Z-order 聚类,该表格每天接收许多更新。
首先,我们像定义任何数据集一样定义数据集。你会注意到,我们为数据集 yellow_taxi_transformed 添加了一个名称,并且在注释中提供了一些描述表格的文本。然而,在 DLT 函数注解中,我们添加了几个额外的参数,其中可以为这个数据集设置表属性。在 table_properties 参数中,我们添加了一些描述数据集的属性。首先,我们添加了一个描述此数据集质量的表属性,它是我们金银架构中的银色表。接着,我们还添加了另一个表属性,指定了我们希望应用 Z-order 聚类的表列:
import dlt
@dlt.table(
name="yellow_taxi_transformed",
comment="Taxi cab trip data containing additional columns about the financial data.",
table_properties={
"quality": "silver",
"pipelines.autoOptimize.zOrderCols": "zip_code, driver_id"
}
)
在我们的日常维护任务执行期间,维护任务会动态解析这些 Z-order 列,并将在此 DLT 数据集后面的 Delta 表上运行以下 Z-order 命令:
OPTIMIZE yellow_taxi_transformed
ZORDER BY (zip_code, driver_id)
那么,应该按哪些表列进行 Z-order 排序?建议的列数是 1 到 3 列,但不超过 5 列。随着列数的增加,表文件中的数据聚类会变得更复杂,从而降低任何可能的数据跳过效果。
此外,你应该尽量选择数据类型为数字的列。原因是,每当新数据写入 Delta 表时,Delta 引擎将捕获前 32 列的统计信息——例如最小值、最大值和空值数量。这些统计信息将在更新搜索过程中使用,有效地定位哪些行匹配更新谓词。例如,对于字符串数据类型,这些统计信息不会提供非常有用的信息,因为字符串没有平均值(例如)。然而,对于浮动数据类型的列来说,就可以计算平均值。
此外,用于 APPLY CHANGES 谓词、联接列以及执行聚合的列都是理想的 Z-order 候选列。最后,这些列的基数应该高于用于创建表分区方案的列。
重要注意事项:
有时你可能希望尝试不同的列或不同的列集来进行 Z-order 排序。改变这个 Z-order 排序方案非常简单——只需更新 DLT 管道定义中的table_properties参数。然而,需要注意的是,新的 Z-order 聚类只会对写入表的最新数据生效。要将新的 Z-order 聚类应用于现有数据,需要完全刷新整个表,以便根据聚类模式重新组织表文件。因此,你可能需要权衡重写表数据所花费的时间和成本与通过表 Z-order 优化可能获得的性能收益。
正如你所看到的,Z-order 优化是优化 DLT 表布局的一种绝佳方式,可以提升数据管道的性能。有效的数据布局可以提高 DLT 引擎的数据跳过效率,限制 DLT 引擎需要扫描的数据量,从而在管道中应用更新。结合 Hive 风格的表分区,这是一种确保从数据管道中获得最佳性能的好方法,从而缩短执行时间,并减少保持更新集群运行所花费的时间和金钱。
然而,如果你只更新了某个特定表文件中的少量数据怎么办?这意味着为了更新 1 或 2 行数据,必须重写整个文件。让我们看看如何进一步优化 DLT 管道的性能,以避免这一成本高昂的操作。
通过删除向量提高写入性能
在表更新过程中,DLT 引擎通过将匹配的文件与新更新的行重新写入新目标文件来应用更新。在这种类型的表更新策略中,称为写时复制(Copy-on-Write, COW),没有接收到任何更新的行需要复制到新文件中,正如名字所示。对于需要更改少量行而跨多个文件进行的表更新,这种方式可能效率低下。
一种更好的优化技术是跟踪所有更改过的行,使用单独的数据结构,并将新更新的行写入单独的文件中。然后,在执行表查询时,表客户端可以使用此数据结构来过滤掉任何更新的行。这种技术被称为读取时合并(Merge-on-Read, MOR),并且在 Delta Lake 中通过名为删除向量(deletion vectors)的特性实现。
删除向量是一种特殊的数据结构,用于跟踪在 Delta 表上进行 UPDATE 或 MERGE 操作时所有更新的行 ID。通过设置基础 Delta 表的表属性,可以启用删除向量。与 Delta 表列的统计信息一样,删除向量与表数据一起存储在云存储中。
此外,删除向量可以在 Databricks 工作区中为所有新创建的表自动启用。工作区管理员可以通过工作区管理员设置 UI 的高级选项卡启用或禁用此行为。
删除向量可以通过在 DLT 表定义中设置 enableDeletionVectors 表属性显式设置在数据集上:
@dlt.table(
name="random_trip_data_silver",
comment="Taxi trip data transformed with financial data.",
table_properties={
"quality": "silver",
"pipelines.autoOptimize.zOrderCols": "driver_id",
"delta.enableDeletionVectors": "true"
}
)
此外,删除向量解锁了 Databricks 数据智能平台上的一类新的更新性能特性,统称为预测 I/O(Predictive I/O)。预测 I/O 利用深度学习和文件统计信息来准确预测文件中匹配更新条件的行的位置。因此,在更新、合并和删除期间扫描匹配文件并重写数据的时间大大减少。
Hive 风格的表分区、Z-order 数据聚类和删除向量都是优化技术,可用于高效存储我们的表数据并提高管道更新的速度。接下来,我们将回到数据管道的计算资源,分析另一种提高 DLT 管道性能的技术,尤其是在处理需求可能激增并变得不可预测时。
无服务器 DLT 管道
在第 2 章中,我们简要描述了什么是无服务器 DLT 集群,以及它们如何快速高效地扩展计算资源以处理需求高峰,并在处理需求减小时缩减资源。虽然我们不会再次介绍无服务器集群的架构,但我们将介绍无服务器 DLT 集群如何帮助组织随着越来越多的数据管道的加入扩展其数据管道。
使用无服务器 DLT 集群时,集群的基础设施和设置由 Databricks 云提供商账户自动处理。这意味着不再需要选择虚拟机实例类型来平衡性能和成本。无服务器计算的成本是固定的平价,使得成本可以预测。此外,由于计算资源由 Databricks 云提供商账户管理,Databricks 可以以折扣价格为每个云提供商预留大量虚拟机实例。这些折扣价格随后可以传递给 DLT 无服务器消费者。
此外,无服务器 DLT 集群通过减少每个数据管道所需的配置,简化了数据管道的维护。配置减少后,数据工程团队可以将更多精力集中在业务相关的任务上,如更改业务逻辑、数据验证以及添加更多数据管道等。此外,随着数据管道的增长以及数据集的不断增加,您可能需要配置更多的虚拟机实例。最终,您可能会达到某些实例类型的云提供商限制,这需要一个额外的过程来增加这些限制。而对于无服务器 DLT 计算,这些限制已经与云提供商协商好,意味着 DLT 无服务器消费者无需担心这一负担。
无服务器数据管道还可以帮助降低数据管道的成本。例如,在传统的客户管理计算中,集群只能根据云提供商配置额外实例的速度添加虚拟机实例,并定期运行诊断检查。而且,Databricks 运行时容器和用户库需要安装在额外的实例上,这需要更多时间。这可能导致很多分钟——有时是 15 分钟甚至更长时间,才能扩展 DLT 集群以应对计算需求的不可预测的高峰。因此,与传统计算相比,运行在传统计算上的 DLT 管道执行时间会更长。而使用无服务器 DLT 集群时,虚拟机实例已预配置,并且已经安装并启动在预分配的实例池中。在处理需求激增时,DLT 管道可以在几秒钟内响应,并扩展资源以满足需求,而不是几分钟。与传统计算相比,这些时间差异会在多个数据管道运行和整个云账单周期中累积。通过减少扩展额外资源所需的时间,并能通过增强型自动扩展进行积极缩减,无服务器 DLT 管道可以显著降低运营成本,同时提高湖仓中 ETL 处理的效率。
移除管理数据管道计算设置和控制云成本的基础设施负担是选择无服务器 DLT 管道而不是传统客户管理计算的动因之一。然而,让我们看看选择无服务器 DLT 集群的另一个动因,例如此类计算资源带来的性能特性。
引入 Enzyme,性能优化层
在某些情况下,数据管道已经部署到生产环境中,但随着业务需求的变化,可能需要重新计算数据集的历史数据。在这种情况下,重新计算这些数据集的历史数据可能会变得成本过高。
Enzyme 是一个全新的优化层,仅适用于无服务器 DLT 管道,旨在通过动态计算保持数据集物化结果最新的成本模型来减少 ETL 成本。与 Spark 查询规划中的成本模型类似,Enzyme 计算几种 ETL 技术之间的成本模型,从传统的物化视图 DLT 到 Delta 流式表,再到另一种 Delta 流式表,或手动 ETL 技术。例如,Enzyme 引擎可能会建模使用物化技术刷新数据集的成本,这可能会转化为 10 个 Spark 作业,每个作业有 200 个 Spark 任务。这个成本模型可能会节省两个 Spark 作业,并将总执行时间减少五分钟,如另一个建模的 ETL 技术所预测的那样,因此 Enzyme 引擎将选择第一个技术。
Enzyme 层将动态选择最有效和具有成本效益的方法来重新计算给定数据集的结果。由于 Enzyme 是一个无服务器 DLT 功能,它默认已启用,因此 DLT 管理员无需管理管道集群设置。
到现在为止,您应该已经理解了无服务器 DLT 管道所具备的强大功能,如 Enzyme 优化层,以及它带来的基础设施管理和节省成本的好处。
总结
在本章中,我们探讨了多种扩展数据管道的方法,以应对大规模数据处理并在高需求和不可预测的处理负载下表现良好。我们考察了扩展 DLT 管道的两个关键属性——计算能力和数据布局。我们分析了 Databricks 数据智能平台的增强型自动扩展功能,自动扩展数据管道执行所需的计算资源。我们还研究了优化底层表数据存储的方法,通过在表文件中聚类相关数据,从而加速表查询并缩短管道处理时间。此外,我们还审视了定期维护活动,以保持高效的表查询性能,并防止过时的数据文件导致云存储费用膨胀。
数据安全至关重要,通常在湖仓实施的最后阶段才会被重视。然而,这可能意味着一个成功的湖仓和上报纸头条之间的区别——而且通常是坏的原因。在下一章中,我们将探讨如何在湖仓中有效实施强有力的数据治理,无论是在单一地理区域内,还是跨越全球其他区域的容灾区域。