开放表格式解析:Iceberg vs. Delta vs. Hudi
DataHot 速览
本文解析Apache Iceberg、Delta Lake和Apache Hudi三种主流开放表格式。它们作为对象存储之上的元数据层,为数据湖文件添加ACID事务、模式演进和时间旅行能力,使数据能像数据库表一样被一致读取和安全更新。文章对比了三种格式在事务支持和模式演进上的差异,并说明其与湖仓架构的关系。
为什么值得关注:开放表格式是湖仓架构的核心技术基石,理解Iceberg、Delta和Hudi的差异有助于数据平台从业者做技术选型与架构设计。
本文目录 17 节
译文
AI 逐段翻译开放表格式是位于对象存储中数据文件之上的元数据层,为数据湖中存储的数据添加了ACID事务、模式演化和时间旅行。Apache Iceberg、Delta Lake和Apache Hudi是当前生产中使用的三种主要开放表格式,每一种都将一组Parquet或ORC文件转换为行为类似数据库的表:读者看到一致的结果,写者可以安全地更新和删除行,并且每次更改都被跟踪,以便早期版本仍然可查询。
本概述解释了主要开放表格式如何工作,它们在ACID事务支持和模式演化方面的比较,以及它们与数据湖仓一体架构的关系——借鉴存储层的创新,如目录协调事务、行谱系和统一元数据,以展示Delta Lake和Apache Iceberg正在趋同的地方。
什么是数据湖,为什么开放表格式重要?
数据湖是构建在低成本对象存储上的集中式存储库——Amazon S3、Azure Data Lake Storage或Google Cloud Storage——以原始、原生形式保存结构化、半结构化和非结构化数据。组织采用数据湖是因为对象存储扩展成本低,并且将存储与计算分离,让任何查询引擎都能读取相同的数据。然而,对象存储从来不是为了保证一致性而构建的:它没有原生的表、模式或事务概念。
一个数据湖仓将类似表的结构、治理和性能分层到原始存储之上,结合了数据湖的低成本和数据仓库的可靠性。二者之间的桥梁是开放表格式:它无需将数据复制到专有仓库,就能将对象存储中的松散文件转换为受治理的、可查询的表。
在开放表格式出现之前,在传统数据湖上运行分析会导致持续的问题:并发写者可能在写入中途损坏数据,更新和删除意味着重写整个分区,并且没有可靠的方法知道哪些文件代表表当前正确的状态。开放表格式管理对象存储中数据文件的元数据,精确跟踪哪些文件属于表——这种标准化让数据湖最终支持类似数据库的功能,如记录级更新。
你需要了解的开放表格式和文件格式
Apache Iceberg
Apache Iceberg最初在Netflix开发,现在是Apache软件基金会项目,旨在使巨大、变化缓慢的表查询快速且演化安全。Apache Iceberg使用树状结构进行高效的元数据管理:清单文件和清单列表跟踪表中的每个数据文件,让查询引擎在扫描开始之前修剪不相关数据。Iceberg表支持模式演化和分区演化,无需重写底层文件。
Delta Lake
Delta Lake由Databricks创建并作为开源发布,通过预写事务日志为Apache Spark工作负载带来了ACID事务。Delta Lake起源于Databricks,并与Spark原生集成,尽管现在通过独立连接器支持广泛的引擎。Delta Lake表将每次写入记录为有序、原子的日志条目,即使在新数据写入期间,也能为读者提供一致的视图。
Apache Hudi
Apache Hudi是Hadoop Upserts Deletes和Incrementals的缩写,围绕快速、频繁的记录级更新构建。Apache Hudi通过维护索引来定位包含给定记录的确切文件,优化频繁更新和流式数据,无需全表扫描即可实现高效的记录级更新。这种设计使Hudi成为变更数据捕获管道和近实时摄入的常见选择。
Parquet和ORC
Parquet和ORC是列式文件格式,而不是表格式:它们定义单个数据文件如何组织,而不是文件如何成为受治理的表。Iceberg、Delta Lake和Hudi都构建在Parquet文件之上——Iceberg和Hudi也支持ORC——利用Parquet存储的文件级统计信息,在查询引擎读取数据之前修剪数据。这种区分,文件格式与表格式,澄清了大多数企业关于各层职责从何处开始的困惑。
Iceberg vs. Delta Lake vs. Hudi:快速比较
这三种主要的开放表格式现在共享的能力多于差异,但下表突出了设计历史仍然可见的地方。
| 能力 | Apache Iceberg | Delta Lake | Apache Hudi |
|---|---|---|---|
| ACID事务 | 是,通过目录协调提交 | 是,通过事务日志和目录提交 | 是,通过基于时间线的提交 |
| 模式演化 | 完全——添加、删除、重命名、重排列 | 完全,包括列映射 | 完全,写时模式和读时模式 |
| 分区演化 | 是,无需重写现有文件 | 有限;通常需要重新定义 | 是,通过演化索引策略 |
| 起源 | Netflix / 多引擎分析 | Databricks / Apache Spark | Uber / 流式摄入 |
| 更新/删除性能 | 删除向量和行谱系(v3) | 删除向量和行跟踪 | 原生记录级索引 |
| 多引擎支持 | 广泛——Spark、Trino、Flink、Snowflake | 通过Delta Kernel和UniForm广泛 | Spark、Flink、Presto、Trino |
Apache Iceberg内部:表和元数据
Iceberg元数据树
Iceberg表由元数据树定义,而不是单个文件:元数据文件指向清单列表,清单列表指向构成快照的实际数据文件的清单文件。这种分层结构让查询引擎使用存储的列统计信息修剪不相关的清单和数据文件,而无需打开单个文件,从而提高拥有数百万文件的表的查询性能。
快照和时间旅行
对Iceberg表的每次写入都会创建新的快照——即那一刻存在哪些数据文件的不可变记录——元数据树会保留先前快照的历史记录。这支持时间旅行:引擎可以查询表在特定快照ID或时间戳下的状态,支持审计、可复现的机器学习训练集,以及在错误写入后回滚到最后一个稳定状态。
分区演化
Iceberg通过分区演化将表的物理分区与查询模式解耦,使团队能够更改新数据的分区方式,而无需重写现有文件或破坏针对旧方案的查询。隐藏分区意味着分析师无需直接引用物理分区列即可获得分区裁剪。
Iceberg表内部机制与维护
因为每次写入都会产生带有自己清单列表的新快照,如果无人管理,频繁写入的Iceberg表可能会积累成千上万个小清单和数据文件。查询引擎仍需打开并评估每个相关的清单文件,因此清单泛滥会侵蚀元数据树旨在带来的查询性能提升。
标准的补救措施是定期压缩:一个维护作业将小数据文件重写为更少、更大的文件,并合并清单,根据摄入量每晚或每小时运行。将压缩与定期快照过期(删除超过保留窗口的元数据)相结合,可在不限制时间旅行可追溯范围的情况下控制存储和元数据大小。
Delta Lake与ACID事务
Delta Lake事务日志
Delta Lake表存储有序、仅追加的事务日志——一系列JSON条目,记录每次添加、删除和元数据更改——并附有定期检查点文件,用于汇总日志以加快读取速度。历史上,文件系统本身充当提交协调器,这意味着任何具有文件级访问权限的客户端都可以直接写入Delta表,而无需通过管理目录。
Delta Lake中的ACID事务行为
ACID事务通过要求每个写入者检查当前日志版本、生成新条目,并仅在没有发生冲突更改时提交,来确保并发写入期间的数据一致性;如果检测到冲突,写入者将重试。ACID合规性防止数据损坏,因为读取者永远不会看到Delta Lake表处于部分写入状态,并且ACID事务支持跨重叠分区无冲突的复杂数据操作。
从Spark原生到多引擎支持
由于Delta Lake最初的提交模型依赖于文件系统访问,Apache Spark之外的第三方引擎必须通过静态文件路径而非管理目录访问表——这使得这些访问不受管理,并可能悄然破坏模式关系。Databricks通过目录提交解决了这一问题,这是一个开放标准,允许诸如Unity Catalog之类的目录充当提交协调器,因此每次读取、写入和发现请求都集中授权。目录提交现已全面推出,使Delta Lake与Iceberg从一开始就采用的面向目录的方法保持一致,并支持多表事务。
文件格式基础:Parquet如何实现数据跳过
Parquet文件按列而非按行组织表格数据,将同一列的值分组到称为行组的连续块中。列式存储使查询引擎只需读取查询引用的列,跳过其余列——这是Parquet在扫描密集型工作负载中优于行式格式的主要原因。
每个行组都带有统计信息——每列的最小值和最大值、空值计数和值分布——写入文件的元数据页脚。这些统计信息使引擎无需解压缩任何数据即可确定行组是否可能匹配查询的过滤器。
开放表格式将这一原则提升了一个层次:Iceberg的清单文件和Delta Lake的事务日志都在元数据层缓存Parquet级别的统计信息,因此引擎可以在从对象存储列出文件之前跳过整个数据文件。这种两级数据跳过是大型表查询性能显著提升的主要因素。Databricks还通过Variant数据类型扩展了该模型——现已成为Parquet、Delta Lake和Iceberg的一部分——以类型化二进制形式而非原始JSON存储半结构化负载,使引擎无需昂贵的解析即可提取嵌套字段。
这篇内容对你有用吗?
反馈只用于改善内容筛选,不等同于收藏