Apache Hudi 1.1.0 正式发布,开源数据湖平台
Apache Hudi 1.1.0 是一个重大版本更新,为平台带来了显著的性能提升、新功能和重要变更。此版本重点增强了表格式支持、改进了索引功能、扩展了引擎支持,并改进了记录合并 API。
发布重点
- 可插拔表格格式框架- 多种表格格式的原生集成与统一的元数据管理
- 支持 Spark 4.0 和 Flink 2.0 - 全面支持最新主要计算引擎版本
- 增强型索引- 分区记录索引、分区级桶索引、原生 HFile 写入器和列统计信息 V2
- 性能提升——Flink写入吞吐量提升2-3倍,元数据表读取速度提升4倍
- 表服务优化- Parquet 二进制复制和增量调度以实现压缩/聚簇
- 基于存储的锁提供程序- 无需外部依赖的多写入器并发控制
- 记录合并演进——弃用有效负载类,转而采用合并模式和合并 API
新功能
表格格式
可插拔表格式支持
Hudi 1.1.0 引入了全新的可插拔表格式框架,实现了系统内多种表格式的原生集成。该框架包含一个可插拔表格式的基础接口,旨在简化扩展并实现不同存储后端之间的无缝互操作性。元数据表 (MDT) 集成也得到了增强,以支持可插拔性,确保所有受支持的表格式的模块化和统一的元数据管理。
此版本通过新框架引入了 Hudi 的原生集成,使用户能够直接利用 Hudi 的高级功能,同时保持语义和性能的一致性。默认情况下,配置设置hoodie.table.format为nativeHudi 表格格式。现有和新建的 Hudi 表格均无需进行任何配置更改。随着未来版本对更多表格格式的支持,用户可以设置此配置以使其原生兼容其他格式。Apache XTable(孵化中)为 Iceberg 和 Delta Lake 等格式提供了可插拔的格式适配器。
表版本 9(带索引版本控制)
Hudi 1.1.0 引入了表版本 9,并支持索引版本控制。元数据表中的索引(列统计信息、二级索引、表达式索引等)现在支持版本跟踪。在 1.1.0 版本中,这些索引使用 V2 布局,并增强了功能,包括全面的逻辑数据类型支持。从旧版本迁移的表将保留 V1 索引布局,而使用 1.1.0 创建的新表将使用 V2 布局。两个版本均保持向下兼容,升级到 1.1.0 时无需任何操作。
索引
分区记录索引
除了 0.14.0 版本中引入的全局记录索引之外,Hudi 1.1.0 还新增了一个分区索引,保证了分区路径和记录键对的唯一性。该索引能够加快对超大型分区数据集的查找速度。更多详情请参阅记录索引[3]。
在 1.1.0 版本之前,仅提供全局记录索引,配置方式如下:
hoodie.metadata.record.index.enable=true
hoodie.index.type=RECORD_INDEX
从 1.1.0 版本开始,全局版本和分区版本均可用:
对于分区记录索引:
-
元数据表:
hoodie.metadata.record.level.index.enable=true -
写入索引:
hoodie.index.type=RECORD_LEVEL_INDEX
全局记录索引:
-
元数据表:
hoodie.metadata.global.record.level.index.enable=true -
写入索引:
hoodie.index.type=GLOBAL_RECORD_LEVEL_INDEX
分区级桶索引
一种新的存储桶索引类型,旨在解决存储桶重新扩展的挑战。用户可以通过规则引擎(正则表达式模式匹配)为不同的分区设置特定的存储桶编号。现有的存储桶索引表可以平滑无缝地升级。
主要配置:
-
hoodie.bucket.index.partition.rule.type- 表达式规则解析器(默认:正则表达式) -
hoodie.bucket.index.partition.expressions- 表达式和桶号对 -
hoodie.bucket.index.num.buckets- 分区默认存储桶数量
原生 HFile 写入器
Hudi 现在内置了 HFile 写入器,消除了对 HBase 的依赖,同时确保与 HBase 的 HFile 读取器和 Hudi 的原生读取器兼容。这显著减小了 Hudi 二进制包的大小,并增强了 Hudi 优化 HFile 性能。
HFile性能增强
多项改进措施,旨在加快元数据表读取速度:
-
HFile 块缓存(默认启用):在同一 JVM 内重复读取 HFile 数据块时对其进行缓存,基准测试显示速度提升约 4 倍。配置方法如下:
hoodie.hfile.block.cache.enabled -
HFile 预取:对于小于 50MB 的文件(可通过配置
hoodie.metadata.file.cache.max.size.mb),会预先下载整个 HFile 文件,而不是多次 RPC 调用。 -
布隆过滤器支持:通过避免不必要的块下载来加快 HFile 查找速度。配置方式
hoodie.metadata.bloom.filter.enable
列统计信息 V2,增强了数据类型支持
列统计信息 V2 显著提升了写入和统计信息收集期间对逻辑数据类型的支持。诸如带精度/小数位数的十进制数和时间戳等逻辑类型现在可以保留正确的元数据,从而提高查询规划和谓词下推的准确性。
表服务
Parquet 二进制复制
这项优化使得在聚簇等操作期间可以直接从 Parquet 文件中复制 RowGroup 级别的数据,从而绕过了耗时的压缩/解压缩、编码/解码以及列到行的转换。该优化支持正确的模式演化,并确保 Hudi 元数据能够被正确收集和聚合。实验结果表明,聚类操作的计算量减少了 95% 。
增量式表服务调度
显著提升对具有大量分区的表进行压缩和聚簇操作的性能。增量调度不再在每次调度运行时扫描所有分区,而是仅处理自上次完成的表服务操作以来发生更改的分区。默认情况下通过以下方式启用hoodie.table.services.incremental.enabled
并发控制
基于存储的锁提供商
新的基于存储的锁提供程序使 Hudi 能够直接使用.hoodie底层存储中的目录来管理多写入者并发,从而无需 DynamoDB 或 ZooKeeper 等外部锁提供程序。目前支持 S3 和 GCS,锁信息维护在 <lock_name>目录下.hoodie/.lock。更多详情,请参阅“基于存储的锁提供程序”。
写入与读取端
多个排序字段
支持使用逗号分隔的列表来设置多个排序字段(也称为预合并字段,该名称已弃用)。当记录具有相同的键时,Hudi 会按顺序比较这些字段,并保留具有最新值的记录。
配置:hoodie.table.ordering.fields = field1,field2,field3
高效的数据块流式读取
支持高效流式读取 HoodieDataBlocks(目前为 AvroDataBlock)可减少内存使用量,提高 HDFS 上的读取稳定性,并降低读取日志文件时出现超时和 OOM 错误的风险。
FileGroupReader 中的 ORC 支持
HoodieFileGroupReader 增强了对多种基本文件格式(ORC 和 Parquet)的支持。1.1.0 版本引入了 SparkColumnarFileReader 接口 和 MultipleColumnarFileFormatReader,以统一处理 Merge-on-Read (MOR) 和 Copy-on-Write (COW) 表中的 ORC 和 Parquet 记录。
Hive Schema 演化支持
现在当使用写时模式时,Hive 读取器可以处理模式演变。
Spark
Spark 4.0 支持
Spark 4.0 现已支持,并进行了必要的兼容性和依赖项更改。可通过新hudi-spark4.0-bundle_2.13版本组件获取。更多详情请参阅Spark 快速入门[9]。
元数据表流式写入
流式写入元数据表可以在同一执行链中处理数据表和元数据表的写入操作,从而提高元数据记录的生成效率,避免按需查找。默认情况下,Spark 已启用此功能hoodie.metadata.streaming.write.enabled。
SQL 过程增强
新的清理流程:
-
show_cleans- 显示已完成的清理操作及其元数据 -
show_clean_plans- 显示所有状态(已请求、进行中、已完成)的正常操作 -
show_cleans_metadata- 提供分区级清洁详情
增强功能:
-
run_clustering通过partition_regex_pattern参数支持正则表达式模式 -
SHOW具有高级谓词表达式的所有非操作过程的基本路径和过滤器参数
Flink
支持 Flink 2.0
全面支持 Flink 2.0,包括 sink、read、catalog 和新的 bundle artifact hudi-flink2.0-bundle。修复了旧版 API 的兼容性问题,并默认支持 sinkV2 API。弃用:已移除对 Flink 1.14、1.15 和 1.16 的支持
性能改进
-
引擎原生记录支持:无需 Avro 转换,直接使用 RowData 实现更高效的序列化/反序列化。读写性能平均提升 2-3 倍。
-
异步即时时间生成:通过避免即时时间生成阻塞,显著提高高吞吐量工作负载的稳定性。
-
元字段控制:支持
hoodie.populate.meta.fields追加模式,禁用时写入速度提升 14%。
新功能
-
内存缓冲区排序:对于无主键表,可提高列式格式的压缩率(
write.buffer.sort.enabled) -
分段速率限制:配置流式读取每次即时检查的最大分段数(
read.splits.limit)
产品目录
Polaris集成
通过将表创建委托给 Polaris Spark 客户端,实现与 Polaris 目录的集成,从而允许在 Polaris 目录中注册 Hudi 表。
配置:(hoodie.datasource.polaris.catalog.class默认值org.apache.polaris.spark.SparkCatalog)。更多详情请参阅Polaris 产品目录。
AWS Glue 和 DataHub 同步增强功能
-
CatalogId 对跨目录场景的支持
-
显式数据库和表名配置
-
Glue 数据库和表的资源标记
-
DataHub 支持 TLS/HTTPS,包括自定义 CA 证书和双向 TLS。
平台组件
增强 HudiStreamer 的 JSON 到 Avro 转换功能
改进了 JSON 到 Avro 的转换层,以提高 Kafka JSON 源的可靠性。
Prometheus 多表支持
改进了 PrometheusReporter,增加了引用计数机制,以防止在停止单个表的指标时关闭共享的 HTTP 服务器。
API变更与弃用
HoodieRecordPayload 已弃用
有效载荷类现已弃用,取而代之的是合并模式和合并 API。基于有效载荷的方法与 Avro 格式的记录紧密相关,因此与 Spark InternalRow 等原生查询引擎格式的兼容性较差。
迁移路径:
-
标准用例:使用合并模式配置(
COMMIT_TIME_ORDERING或EVENT_TIME_ORDERING) -
自定义逻辑:实现
HoodieRecordMerger接口而非自定义有效负载 -
自动迁移:升级到最新表版本时,已知有效负载将自动迁移到相应的合并模式。
合并模式支持:
-
提交时间和事件时间排序
-
部分更新策略(替换
OverwriteNonDefaultsWithLatestAvroPayload和PostgresDebeziumAvroPayload已标记值处理) -
跨引擎的语义合并一致性
-
性能优化
BufferedRecordMerger API:该HoodieRecordMerger接口已更新,以利用BufferedRecord记录合并期间使用的新类。
重大变更
复杂Key生成器回退修复
已修复影响具有单个记录键字段的复杂键生成器的回退问题。该回退问题在 0.14.1、0.15.0 和 1.0.x 版本中引入,导致记录键编码从 field_name:field_value` ` 变为 ` `field_value,这可能导致在执行 upsert 操作时出现重复记录。
受影响对象:使用复杂键生成器(ComplexAvroKeyGenerator或ComplexKeyGenerator)且具有单个记录键字段的表。
1.1.0 中的默认行为field_name:field_value:恢复为与0.14.0 及更早版本匹配的正确编码格式。
迁移路径:
-
从 ≤0.14.0 版本升级:无需任何操作,默认行为正确
-
0.15.0/1.0.x 版本中创建的新表:设置
hoodie.write.complex.keygen.new.encoding=true为保持当前编码 -
从 0.14.0 升级到 0.15.0/1.0.x:如果遇到数据重复的问题,可能需要修复数据。修复工具预计将在 1.1.1 版本中发布。
验证:默认情况下,写入操作会验证表配置,如果受到影响则会发出警报。hoodie.write.complex.keygen.validation.enable=false如有需要,可以禁用此功能(读取操作不受影响)。
关于表版本 9 的说明:对于升级到版本 9 的表,键编码格式已锁定,以防止将来出现回退问题,并确保记录索引和二级索引的正确行为。
移除 WriteClient 中的自动提交支持
对于HoodieWriteClient直接使用该功能的开发者,自动提交支持已被移除。该hoodie.auto.commit配置不再生效。
需要迁移:
// Previous (with auto-commit)
HoodieWriteConfig config = // instantiate config
SparkRDDWriteClient writeClient = new SparkRDDWriteClient(engineContext, config);
String instantTime = writeClient.startCommit();
writeClient.upsert(JavaRDD<HoodieRecord>, instantTime);
// Now Required (explicit commit)
HoodieWriteConfig config = // instantiate config
SparkRDDWriteClient writeClient = new SparkRDDWriteClient(engineContext, config);
String instantTime = writeClient.startCommit();
JavaRDD<WriteStatus> writeStatus = writeClient.upsert(RDD<HoodieRecord>, instantTime);
writeClient.commit(instantTime, writeStatus); // Explicit commit now mandatory
这项变更同样适用于表服务。
INSERT INTO 行为变更
Spark SQL 命令的默认行为INSERT INTO已更改。此前对于包含排序字段的表,它会使用“upsert”操作,从而实现数据去重。从 1.1.0 版本开始,INSERT INTO默认执行“insert”操作,直接导入记录,不进行数据去重。
例子:
Commit1:
Partition1, recordKey1, val1, orderingValue1
Partition1, recordKey1, val2, orderingValue2
Pre-1.1.0: Returns one record (based on ordering field)
From 1.1.0: Returns both records
要恢复之前的行为:设置hoodie.spark.sql.insert.into.operation = upsert
使用简易桶式 COW 的多个Bulk Insert的限制
当满足以下所有条件时bulk_insert,对写时复制表的多项操作将受到限制:
-
1. 表格类型为 COW
-
2. 索引类型
BUCKET为引擎设置为SIMPLE -
3. Spark 原生行写入器已禁用(
hoodie.datasource.write.row.writer.enable = false)
解决方法:upsert在初始操作之后使用操作bulk_insert,或者启用 Spark 原生行写入器。
Flink 桶索引限制
桶索引现在仅支持 UPSERT 操作,不能与 Flink 中的追加写入模式一起使用。
行为变更
默认合并模式已更改
默认的记录合并行为已根据是否设置了排序字段而改变:
-
无排序字段:默认
COMMIT_TIME_ORDERING使用OverwriteWithLatestAvroPayload(后写优先) -
排序字段集:默认
EVENT_TIME_ORDERING使用DefaultHoodieRecordPayload(经典的基于事件时间的比较)
用户应使用hoodie.table.ordering.fields(hoodie.datasource.write.precombine.field已弃用)。
hoodie.datasource.write.precombine.field(先前)的默认值ts已被移除。
变更原因:之前的默认设置要求用户ts即使在简单的 upsert 操作(即后写优先)中也必须在模式中包含一个字段。新的行为使得 Hudi 能够开箱即用地处理简单的 upsert 操作,同时在显式配置的情况下仍然支持事件时间排序。
对 HoodieStreamer 的影响:该--source-ordering-field参数不再默认为ts。
-
之前:自动启用
EVENT_TIME_ORDERING -
现在:
COMMIT_TIME_ORDERING如果未指定,则使用默认值 -
需要采取的操作:对于需要事件时间合并的新 Deltastreamer 作业,请明确提供
--source-ordering-field ts(或你的排序字段)。
验证变更:配置不匹配现在会记录警告,而不是导致作业失败:
-
使用
COMMIT_TIME_ORDERING排序字段时,会记录一条警告,提示该字段已被忽略。 -
不使用
EVENT_TIME_ORDERING排序字段时,系统会记录警告而不是报错。
增量查询回退行为
默认值hoodie.datasource.read.incr.fallback.fulltablescan.enable已从更改false为true。现在,找不到必要提交/数据文件的增量查询将自动回退到全表扫描,而不是失败。
性能影响:以前快速失败的查询现在会成功,但由于全表扫描,运行速度可能会明显变慢。
要恢复快速失败行为:设置hoodie.datasource.read.incr.fallback.fulltablescan.enable = false
增量查询开始时间语义
配置hoodie.datasource.read.begin.instanttime行为已恢复为互斥(与 0.x 版本行为一致),纠正了 1.0.0 版本中引入的包含行为。
时间戳逻辑类型处理
列统计信息 V2 版本现已正确处理时间戳字段(与 0.15.0 及更早的 1.x 版本timestamp_millis不同timestamp_micros)。此版本在读取使用旧版本编写的表时保持向后兼容性。
Flink 桶索引追加模式限制
桶索引现在仅支持 UPSERT 操作,不能与 Flink 中的追加写入模式一起使用。
升级说明
-
检查复杂Key生成器使用情况:从 0.14.0 或更早版本升级的用户应检查其配置。
-
更新 WriteClient 用法:如果直接使用
HoodieWriteClient,请添加显式提交调用 -
检查 INSERT INTO 行为:验证您的管道是否依赖于旧的 upsert 行为
-
检查合并模式配置:尤其是在新建表格或使用 HoodieStreamer 时。
-
测试增量查询:注意新的回退行为及其潜在的性能影响
-
Flink 版本:请确保您使用的是 Flink 1.17 或更高版本,或 2.0 版本(1.14-1.16 版本已不再支持)。
Hudi 版本支持
Hudi 0.14.0 之前的版本已停止维护
自本次发布起,Hudi 0.14.0 之前的版本已停止维护。使用这些旧版本的用户应计划升级到 1.1.0 或更高版本,以获得持续的支持、错误修复和新功能。Hudi 社区将把支持工作重点放在 0.14.0 及更高版本上。