找回密码
 立即注册
首页 业界区 业界 Hudi 数据模型分析

Hudi 数据模型分析

兼罔 4 天前
01. Hudi 数据模型分析

主题说明

Hudi 的数据模型是整个系统的核心抽象,说白了就是定义了数据记录在系统中是怎么表示的、怎么操作的。理解数据模型是理解 Hudi 工作原理的基础,就像盖房子要先打地基一样。
在 Hudi 里,一条数据记录不是简单的字符串或者字节数组,而是一个结构化的对象,包含了记录本身的数据、唯一标识、存储位置等信息。这种设计让 Hudi 能够高效地管理数据,支持更新、删除、合并等复杂操作。
细化内容

HoodieRecord - 记录的基础抽象

HoodieRecord 是所有记录的抽象基类,它定义了记录的基本结构。简单来说,一条 HoodieRecord 包含:

  • key:记录的键,类型是 HoodieKey,用来唯一标识这条记录
  • data:记录的实际数据,类型是泛型 T,通常是 HoodieRecordPayload 的实现
  • currentLocation:记录当前在存储中的位置,包含文件ID和时间戳
  • newLocation:记录写入后的新位置
  • operation:操作类型,比如 INSERT、UPDATE、DELETE
这个设计很巧妙,把记录的标识、数据、位置信息都封装在一起了。这样在更新数据的时候,可以快速定位到记录在哪里,然后进行合并操作。
HoodieKey - 记录的唯一标识

HoodieKey 是记录的唯一标识,包含两个字段:

  • recordKey:记录的主键,比如用户ID、订单号等
  • partitionPath:分区路径,比如 2023/01/01 这样的日期分区
这两个字段组合起来就能唯一确定一条记录。比如用户ID是 user123,分区是 2023/01/01,那么这条记录在表中的位置就确定了。
HoodieRecordPayload - 数据负载的抽象

HoodieRecordPayload 是一个接口,定义了数据合并的逻辑。这是 Hudi 最核心的部分之一,因为它决定了当同一条记录有多个版本时,应该怎么合并。
主要方法包括:

  • preCombine:在写入前合并同一批次中的重复记录
  • combineAndGetUpdateValue:合并存储中的旧记录和新的更新记录
  • getInsertValue:获取要插入的新记录
不同的实现类有不同的合并策略:

  • OverwriteWithLatestAvroPayload:直接用新值覆盖旧值
  • DefaultHoodieRecordPayload:根据排序字段选择最新的值
  • EventTimeAvroPayload:基于事件时间合并
HoodieAvroRecord - 基于 Avro 的记录实现

HoodieAvroRecord 是 HoodieRecord 的具体实现,使用 Avro 格式来存储数据。
什么是 Avro?
Avro 是 Apache 的一个数据序列化系统,简单说就是把数据转换成二进制格式,方便存储和传输。Avro 有几个特点:

  • Schema 驱动:数据结构和 Schema 是分开的,Schema 可以独立存储
  • 紧凑的二进制格式:比 JSON 等文本格式更省空间
  • 支持 Schema 演化:可以修改 Schema 而不影响已有数据
  • 跨语言支持:Java、Python、C++ 等都能用
在 Hudi 里,Avro 主要用于存储增量日志(LogFile),因为它是行式存储,写入性能好。而基础文件(BaseFile)用的是 Parquet,列式存储,查询性能好。
元数据字段

每条 Hudi 记录都包含一些元数据字段,这些字段是系统自动添加的:

  • _hoodie_commit_time:提交时间,记录这条数据是什么时候写入的
  • _hoodie_commit_seqno:提交序列号,同一个提交内的记录排序
  • _hoodie_record_key:记录键
  • _hoodie_partition_path:分区路径
  • _hoodie_file_name:文件名,记录这条数据在哪个文件里
  • _hoodie_operation:操作类型(INSERT、UPDATE、DELETE)
这些元数据字段让 Hudi 能够追踪每条记录的历史,支持时间旅行查询等功能。
关键技术

记录的序列化和反序列化

Hudi 使用 Kryo 来序列化记录,Kryo 是一个高效的 Java 序列化框架。序列化就是把对象转换成字节数组,方便在网络传输或者持久化存储。
在 HoodieRecord 中,实现了 KryoSerializable 接口,可以自定义序列化逻辑。这对于大数据场景很重要,因为序列化的性能直接影响整体性能。
记录的合并策略

Hudi 支持多种合并策略,主要通过 HoodieRecordPayload 的不同实现来支持:

  • OverwriteWithLatest:直接用新值覆盖,最简单粗暴
  • EventTimeBased:基于事件时间,选择时间最新的记录
  • PartialUpdate:部分更新,只更新指定字段
  • Custom:自定义合并逻辑
合并策略的选择取决于业务需求。比如订单表,通常用 OverwriteWithLatest;而用户行为表,可能用 EventTimeBased。
记录的排序和分区

记录在写入前会进行排序,排序的依据可以是:

  • 提交时间(默认)
  • 自定义排序字段
  • 分区路径
排序的目的是优化写入性能,把相同分区的记录放在一起写入,减少文件数量。
记录的元数据管理

元数据字段是自动管理的,不需要用户手动设置。系统会在写入时自动填充这些字段,在读取时自动解析。
关键对象说明

类关系图

1.png

关键类说明


  • HoodieRecord:抽象记录类,定义了记录的基本结构和方法。它是所有记录类型的基类。
  • HoodieKey:记录键,包含 recordKey 和 partitionPath。实现了 equals 和 hashCode,用于记录的去重和查找。
  • HoodieRecordPayload:记录负载接口,定义了数据合并的核心逻辑。不同的实现类有不同的合并策略。
  • HoodieAvroRecord:基于 Avro 的记录实现,是 Hudi 中最常用的记录类型。它把数据序列化成 Avro 格式存储。
  • HoodieRecordLocation:记录位置,包含 fileId(文件ID)和 instantTime(时间戳)。用于定位记录在存储中的位置。
关键操作时序图

下面是一个记录合并操作的时序图,展示了当更新一条已存在的记录时,各个类是如何协作的:
2.png

这个时序图展示了:

  • 客户端调用 upsert 方法
  • 表通过索引查找记录位置
  • 合并器合并新旧记录
  • Payload 执行具体的合并逻辑
  • 写入合并后的记录
代码示例

创建一条记录
  1. // 创建记录键
  2. HoodieKey key = new HoodieKey("user123", "2023/01/01");
  3. // 创建 Avro 记录数据
  4. GenericRecord avroRecord = new GenericData.Record(schema);
  5. avroRecord.put("id", "user123");
  6. avroRecord.put("name", "张三");
  7. avroRecord.put("age", 25);
  8. // 创建 Payload
  9. HoodieAvroPayload payload = new HoodieAvroPayload(
  10.     Option.of(avroRecord),
  11.     System.currentTimeMillis() // 排序值
  12. );
  13. // 创建 Hudi 记录
  14. HoodieRecord<HoodieAvroPayload> record =
  15.     new HoodieAvroRecord<>(key, payload);
复制代码
记录合并示例
  1. // 假设存储中有一条旧记录
  2. IndexedRecord oldRecord = ...; // 从存储读取
  3. // 新来的更新记录
  4. HoodieAvroPayload newPayload = new HoodieAvroPayload(newRecord, timestamp);
  5. // 执行合并
  6. Option<IndexedRecord> merged = newPayload.combineAndGetUpdateValue(
  7.     oldRecord,
  8.     schema,
  9.     properties
  10. );
  11. // merged 就是合并后的结果
  12. if (merged.isPresent()) {
  13.     // 写入合并后的记录
  14.     writeRecord(merged.get());
  15. } else {
  16.     // 返回空表示删除这条记录
  17.     deleteRecord(key);
  18. }
复制代码
总结

Hudi 的数据模型设计得很巧妙,把记录的标识、数据、位置信息都封装在一起。核心要点:

  • HoodieRecord 是基础抽象,包含 key、data、location 等核心属性
  • HoodieKey 是唯一标识,由 recordKey 和 partitionPath 组成
  • HoodieRecordPayload 定义了合并逻辑,支持多种合并策略
  • Avro 是行式存储格式,适合增量日志,写入性能好
  • 元数据字段 自动管理,支持时间旅行等高级功能
理解数据模型是理解 Hudi 的基础,后续的存储、索引、查询等功能都建立在这个模型之上。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册