Apache Hudi 从入门到放弃(2) —— MOR表的文件结构分析

写在开始

  • 本篇带大家分析一下Hudi中MOR表的文件结构
  • 刚开始看Hudi一周,有什么不对的地方欢迎大家指出

事前准备

建表
-- 先准备一张Hudi MOR表
CREATE TABLE hudi_test_dijie(
 id bigint,
 dt string,
 ts TIMESTAMP(3),
 PRIMARY KEY(id) NOT ENFORCED
)
PARTITIONED BY (`dt`)
WITH (
'connector'= 'hudi',
'path'= 'hdfs:///hudi/hudi_test_dijie',
'table.type'= 'MERGE_ON_READ',
'read.streaming.enabled'= 'true',  
-- 'read.streaming.start-commit'= '20210401134557',
'read.streaming.check-interval'= '4'
);
-- 再准备一张有数据的Kafka表
CREATE TABLE kafka_test (
  id bigint,
  dt string,
  ts as localtimestamp
) WITH (
  'connector' = 'kafka',
  'topic' = 'a_dijie_test',
  'properties.bootstrap.servers' = 'localhost:9092',
  'properties.group.id' = 'testGroup',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'json'
);

插入数据
-- 我的任务开了checkpoint,并且周期是一秒;写入Hudi请开启checkpoint
-- 我分别在15点、18点、19点执行了这段SQL,并且在19点执行的时候,使用了MiniBatch模式
-- set table.exec.mini-batch.enabled=true;
-- set table.exec.mini-batch.allow-latency=5s;
-- set table.exec.mini-batch.size=5000;
set table.dynamic-table-options.enabled=true;
insert into hudi_test_dijie select * from kafka_test /*+ options ('properties.group.id' = 'test_d') */;
数据下载
# 使用Hdfs 命令下载目录下所有数据
# 注意这里的目录用的是建Hudi表时指定的`path`,而非{DAWEHOUSE}/databases/table  
hdfs dfs -get /hudi/hudi_test_dijie
工具下载

以下适用于Mac电脑

# 用于查看avro文件
brew install avro-tools
# 用于查看parquet文件
brew install parquet-tools

非Mac电脑可以直接下载对应的Jar包,下载路径

  • avro:http://archive.apache.org/dist/avro/avro-1.9.2/java/avro-tools-1.9.2.jar
  • parquet:http://logservice-resource.oss-cn-shanghai.aliyuncs.com/tools/parquet-tools-1.6.0rc3-SNAPSHOT.jar?spm=5176.doc52798.2.7.H3s2kL&file=parquet-tools-1.6.0rc3-SNAPSHOT.jar

开始分析

先看看表下面都有什么文件
tree_1

目录下有两个文件夹,分别是.hoodie2021-05-01

首先.hoodie目录对应着表的元数据信息,包括表的版本管理(Timeline)、归档目录(存放过时的instant也就是版本)、回滚记录(.rollback)文件等等;因为我们也没有手动触发Hudi自身的savepoint操作,没有savepoint文件,一会儿会简单说一下这个文件的产生和作用

2021-05-01对应着分区路径,因为我Kafka中dt字段的数据都是指定为2021-05-01,所以只有该天的分区,分区里面存放着Base File(*.parquet)和Log File(*.log.*)以及分区信息

接下来,我们分成表元数据表数据两部分来进行分析

表元数据

之前介绍Hudi的时候和大家说过,Hudi有个Timeline的概念,它包含了在不同Instant时间所有对表的操作,一个Instant由以下3种东西构成

  • Instant action :对表执行的操作类型
  • Instant time :Instant时间通常是一个时间戳(比如:20210501182722),该时间戳按操作开始时间的顺序单调增加
  • state :Instant的状态

Hudi保证在时间轴上执行的操作的原子性和基于Instant时间的时间轴一致性。

执行的关键操作包括

  • COMMITS :一次提交表示将一组记录原子写入到表中。

  • CLEANS :删除表中不再需要的旧文件版本的后台活动。

  • DELTA_COMMIT :增量提交是指将一批记录原子写入到MOR表中,其中部分或全部数据都将只写入到日志中。

  • COMPACTION :合并日志、小文件的后台操作。合并其实是Timeline上的特殊提交。

  • ROLLBACK :表示COMMITS/DELTA_COMMIT不成功并且进行回滚,删除在写入过程中产生的所有不完整的文件。

  • SAVEPOINT :由hudi-CLI手动触发,对Instant进行备份,当后续出现提交错误时,便可ROLLBACK至指定SAVEPOINT

任何给定的Instant都可以处于以下状态之一

  • REQUESTED :表示已调度但尚未开始的操作。

  • INFLIGHT :表示当前正在执行该操作。

  • COMPLETED :表示在Timeline上完成了该操作。

以上是我对官网首页文档的翻译,认真看完了这些,再来看.hoodie下的文件会更清晰

ll1

我们按照时间顺序,依次打开有文件内容的文件
首先我们看一下./20210501150108.deltacommit文件中的内容

{
   
   
  "partitionToWriteStats": {
   
   
    "2021-05-01": [
      {
   
   
        "fileId": "817c5634-926f-41e9-a4b1-5c52ae4ce81b",
        "path": "2021-05-01/.817c5634-926f-41e9-a4b1-5c52ae4ce81b_20210501150108.log.1_1-4-0",
        "prevCommit": "20210501150108",
        "numWrites": 150159,
        "numDeletes": 0,
        "numUpdateWrites": 72544,
        "numInserts": 77615,
        "totalWriteBytes": 18470596,
        "totalWriteErrors": 0,
        "tempPath": null,
        "partitionPath": "2021-05-01",
        "totalLogRecords": 0,
        "totalLogFilesCompacted": 0,
        "totalLogSizeCompacted": 0,
        "totalUpdatedRecordsCompacted": 0
<think>好的,我现在需要回答用户关于Hudi MOR如何合并log文件和parquet文件的问题。首先,我要回忆一下Hudi的相关知识,尤其是MOR的结构和工作流程。根据用户提供的引用内容,MOR使用log文件记录增量更新,而parquet文件是基础数据文件。合并过程应该涉及到将log中的增量数据合并到parquet文件中,生成新的版本。 接下来,我需要确认合并的触发机制。用户提到的引用[4]中,提到了compact策略触发后能查询到历史数据,所以合并操作可能和compact有关。Hudi的压缩(Compaction)应该就是负责将log文件合并到parquet中的过程。我需要详细说明这个过程是如何触发的,比如自动还是手动,以及相关的配置参数。 然后,合并的具体步骤需要拆解。根据引用[2],log文件使用Avro格式存储增量记录,压缩时需要读取这些记录,并按主键合并到parquet文件中。这可能涉及版本控制,比如根据时间戳或顺序确定最新值。同时,合并后的新parquet文件会替换旧的数据,并清除已处理的log文件。 还要考虑用户可能的问题,比如如何配置压缩策略,或者合并后的数据如何体现在RO和RT中。引用[4]提到RO是压缩后的数据,而RT是实时视图,包含未合并的log数据。因此,合并操作会影响RO的查询结果,而RT在合并前仍然读取log中的最新数据。 最后,需要确保回答结构清晰,分点说明触发条件、流程和结果,并引用相关的资料来支持每个部分。可能还需要提醒用户配置压缩参数的方法,比如设置压缩调度策略和执行参数。</think>Hudi MOR的Log文件与Parquet文件合并过程主要通过**压缩(Compaction)机制**实现,具体流程如下: --- ### 一、合并触发条件 1. **自动触发** - 通过配置`compaction.delta_commits`(如设置为5,示每5次提交触发一次压缩) - 时间策略:例如`compaction.trigger.strategy= TIME_ELAPSED`,设定时间间隔触发[^2] 2. **手动触发** 通过Hudi CLI或工具调用`run compaction`命令强制执行合并 --- ### 二、合并流程 1. **选择待合并的Log文件** Hudi根据时间线(Timeline)定位需要合并的Log文件,通常选择未压缩的增量日志文件(如`.log`后缀文件) 2. **合并逻辑** - 读取Base Parquet文件中的历史数据 - 按主键(HoodieKey)合并Log文件中的增量记录,**保留最新时间戳或最高版本号的数据** [^3] - 生成新的Parquet文件(文件名版本号递增,如`xxxx_7.parquet`) 3. **原子性替换** - 新Parquet文件生成后,更新元数据(`.hoodie`目录下的时间线文件) - 删除已合并的Log文件,仅保留未合并的最新Log文件以支持实时查询[^4] --- ### 三、合并后的数据访问 1. **RO(Read Optimized)** 查询合并后的Parquet文件,提供**历史快照数据**,适用于批量分析场景 2. **RT(Real-Time)** 查询合并后的Parquet文件 + 未合并的最新Log文件,提供**近实时数据视图** --- ### 四、配置示例(Spark) ```python # 设置异步压缩策略 hudi_options = { "hoodie.compact.inline": "false", "hoodie.compact.schedule.inline": "true", "hoodie.compact.trigger.strategy": "NUM_COMMITS", "hoodie.compact.delta_commits": "5" } ``` ---
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值