Apache Hudi 学习笔记 01:Hudi 是什么?为什么数据湖需要 Hudi?


前面整理 Hadoop、Hive、Spark、Flink 这些组件时,更多关注的是计算引擎怎么跑、任务怎么提交、SQL 怎么查询。真正把数据长期沉淀到 HDFS 或对象存储之后,还会遇到另一个问题:文件系统只负责存文件,并不天然知道一张表的更新、删除、事务、增量消费和文件版本应该怎么管理。

普通 Hive 表或直接写 Parquet 文件,在纯追加场景下很好用。每天写一个分区,下游按天查询,逻辑简单,成本也低。但是一旦数据来自 MySQL binlog、Kafka 事件流、业务状态表或者需要修正历史分区,问题就会变复杂:同一条记录可能重复到达,历史记录可能要更新,错误数据可能要删除,下游任务又希望只消费上一次之后的变化。

Apache Hudi 主要解决的就是这类问题。它不是一个新的计算引擎,也不是简单替代 Parquet 的文件格式,而是在 HDFS、S3 这类存储系统之上,为数据湖表补上一层事务、索引、文件版本、表服务和增量读取能力。本文先不急着安装和写代码,先把 Hudi 放到整个大数据链路中看清楚:它到底解决什么问题,和 Spark、Flink、Hive、Trino 这些组件是什么关系。

本文只解释 Hudi 的定位、核心能力和适用场景,不展开具体安装命令。Hadoop、Hive、Spark、Flink、Kafka、MySQL 与 Hudi 的实际部署、依赖冲突和截图,会放到后续环境安装文章中记录。

1. 背景与定位

1.1 背景问题

传统离线数仓里,Hive 表通常按日期分区存放:

/warehouse/ods/order_info/dt=2025-06-03/part-00000.parquet
/warehouse/ods/order_info/dt=2025-06-04/part-00000.parquet

如果业务只是每天离线导入一次订单快照,或者只追加日志明细,这种方式没什么问题。Spark、Hive、Presto、Trino 都能直接读取 Parquet 文件,压缩率和查询性能也不错。

麻烦通常出现在三个场景。

第一个场景是 CDC 入湖。MySQL 里的订单状态会从 CREATED 变成 PAID,再变成 SHIPPED。如果每次变更都直接追加到 Hive 表里,下游查询最新订单状态时就要自己去重、排序、取最新版本。一旦多个任务对“最新”的理解不一致,数据口径就会乱。

第二个场景是 历史数据修复。比如某一天的用户维表字段解析错了,只修正几万条记录。普通 Parquet 文件不能原地更新,常见做法是重算整个分区,或者写一份修正表再在查询时关联。数据量小的时候还能忍,表大以后就会变成明显的计算和存储浪费。

第三个场景是 增量 Pipeline。下游任务并不想每天全量扫描一张大表,只想知道从上一次运行之后,哪些记录发生了变化。普通 Hive 表可以通过分区或业务时间字段做近似增量,但这不是表自身提供的变更日志,下游很难统一处理乱序、补数、回滚和删除。

所以数据湖真正需要的不只是“能存很多文件”,还需要下面这些表级能力:

能力 普通文件表的问题 Hudi 的处理方向
更新 Parquet 文件不能原地更新 通过 FileGroup 和新版本文件表达更新
删除 删除通常要重写分区 支持 delete 操作,并通过新的 commit 表达记录在新表版本中不可见
事务 文件写到一半时缺少统一可见性 通过 Timeline 管理 Instant 状态
增量读取 依赖业务字段或分区约定 通过 commit time 读取变化
小文件治理 需要外部任务合并 表服务负责 Compaction、Clustering、Clean
记录定位 更新前不知道记录在哪个文件 通过 Index 降低定位成本
表结构变化 字段增删容易和历史文件不一致 通过 Schema Evolution 兼容表结构演进

这也是 Hudi 出现的背景:让数据湖不只是便宜的大文件仓库,而是能支撑持续变更的数据湖表。

1.2 Hudi 的定位

Hudi 的全称是 Hadoop Upserts Deletes and Incrementals。这个名字基本把它的核心能力写出来了:在 Hadoop 生态或类似分布式存储上,支持 Upsert、Delete 和 Incremental Query。

从类别上看,Hudi、Iceberg、Delta Lake 都属于开放数据湖表格式 / 湖仓表管理方向,只是 Hudi 更早围绕 upsert、delete 和 incremental processing 展开。

如果用一句话概括,我更愿意把 Hudi 理解成:

Hudi 是运行在开放存储之上的数据湖表管理系统,它用 Timeline、Index、FileGroup 和表服务,把一堆数据文件组织成可以更新、删除、回放和增量消费的表。

这个定位很重要。Hudi 不是 Spark 的一个普通插件,也不是 Flink 的一个 sink,更不是 Hive 的一种存储格式。Spark、Flink、Hive、Trino 这些组件分别从不同角度使用 Hudi 表:

组件 在 Hudi 链路中的常见作用
Spark 批量写入、离线初始化、SQL DML、历史修复、增量查询
Flink 实时写入、CDC 入湖、流式读取、长时间运行任务
Hive 元数据管理、离线查询、和已有数仓体系打通
Trino / Presto 交互式查询、BI 查询、联邦查询
Kafka 作为 CDC 或事件流中间层
HDFS / S3 存放 Hudi 表的 Base File、Log File 和 Timeline 元数据

Hudi 站在这些组件中间,既不替代计算引擎,也不替代底层存储。它更像是数据湖上的表层协议:告诉写入端怎么提交变更,告诉读取端什么版本的数据可见,告诉运维任务什么时候压缩、清理和重排文件。

1.2.1 Hudi 的发展脉络

刚开始看 Hudi 时,我不太建议死记版本历史,但它的发展脉络能解释一个问题:为什么 Hudi 一开始就特别强调 Upsert、Delete 和 Incremental Query。

时间 关键变化 判断
2015 年前后 增量处理思想逐渐成型 大数据任务不能一直靠全量重跑解决问题
2016 年 Uber 内部开始围绕大规模数据湖更新构建 Hudi 业务数据库数据入湖后,更新和删除是刚需
2017 年 Hudi 开源 记录级更新、增量消费不再只是单家公司内部问题
2019 年 进入 Apache 孵化器 生态集成开始成为重点,Spark、Hive、Presto 等引擎都需要对接
2020 年 成为 Apache 顶级项目 Hudi 从“一个写入工具”变成更完整的数据湖表项目
2021 年以后 Flink、SQL DML、元数据表、索引和表服务持续增强 实时入湖、湖仓查询和生产治理能力变得更重要

从这个过程可以看出,Hudi 并不是先有一个文件格式,然后再想办法接入计算引擎。它更像是从真实数据湖痛点里长出来的表管理系统:先解决更新、删除和增量,再逐步补齐 SQL、Flink、Metadata、Clustering、Catalog 等生态能力。

1.3 Hudi 在数据湖架构中的位置

下面这张图是本文对 Hudi 位置的理解。

Hudi 在数据湖架构中的位置

这张图主要说明 Hudi 位于存储层和计算 / 查询引擎之间,补齐普通文件系统缺少的表级管理语义。

如果把外部组件再展开一层,Hudi 在数据湖链路里的关系大致如下:

Hudi 在大数据系统中的位置

这张架构图主要用于说明 Apache Hudi 在湖仓架构中的位置。整体来看,Hudi 位于底层开放存储层之上、计算查询层之下,承担的是“数据湖表管理层”的角色。它不是传统数据库,也不是单纯的文件格式,而是在 HDFS、S3、OSS 等开放存储之上,为数据湖中的 Parquet、ORC、Log File 等文件提供表级管理能力。

在数据进入湖仓之后,业务库 CDC、Kafka 事件流、日志文件、离线文件等数据会先落到开放存储层。Hudi 在这些文件之上提供 Record Key、Index、Timeline、File Group、File Slice 等机制,使数据湖支持 Upsert、Delete、增量读取、事务提交、版本管理和文件生命周期管理。这样,原本只是“文件堆积”的数据湖,就具备了接近数据库表的管理能力。

在 Hudi 之上,Spark、Flink、Hive、Trino、Presto 等计算和查询引擎可以对 Hudi 表进行写入、处理和查询。其中 Spark 常用于批处理和离线 SQL,Flink 常用于实时写入和 CDC 入湖,Hive 适合离线查询,Trino / Presto 适合交互式分析。Hudi Streamer 则可以用于将 Kafka、DFS 等数据源持续写入 Hudi 表。

上层的数据开发 IDE、调度系统、数据质量、元数据检索、数据报表、运营分析、风控推荐和数据服务 API,都可以基于 Hudi 管理后的数据展开。同时,右侧的平台治理与运维能力用于保障湖仓系统稳定运行,包括 Catalog / Schema 管理、权限控制、监控告警、数据质量校验、表服务治理和成本管理。整体来说,Hudi 的核心价值就是在开放数据湖之上提供可靠的表管理能力,让数据湖能够更好地支撑实时入湖、增量处理和上层分析应用。

2. 核心能力与使用场景

2.1 Hudi 与普通 Hive / Parquet 表的区别

普通 Hive / Parquet 表和 Hudi 表都可以存放在 HDFS 上,也都可以被 SQL 引擎读取。区别在于:普通表更多是文件集合,Hudi 表则有自己的 Timeline、索引、文件版本和表服务。

对比点 普通 Hive / Parquet 表 Apache Hudi 表
表的本质 更像开放存储目录里的文件集合,表语义主要依赖目录、分区和 Metastore。 在开放存储之上增加表管理层,把文件组织成可更新、可回放、可增量消费的湖仓表。
写入语义 insert、追加文件、覆盖分区为主;记录级更新通常要靠外部逻辑处理。 支持 upsertdeleteinsert_overwrite 等表级写操作,能围绕 record key 管理变化。
事务可见性 写入失败、部分文件可见、历史版本判断通常依赖计算引擎提交协议或外部约束。 通过 Timeline / Instant 管理提交状态,查询侧基于已完成 instant 构造一致视图。
记录定位 更新前不知道 record key 在哪个文件里,常见做法是扫描、重算分区或依赖外部索引。 通过 Index 辅助定位 record key 对应的候选 FileGroup,降低更新定位成本。
文件版本 文件之间缺少统一的表级版本关系,旧文件什么时候仍然有效不够明确。 通过 FileGroup / FileSlice 管理 Base File、Log File 和不同时间点的文件视图。
增量消费 通常只能按分区、业务时间或文件时间做近似增量,容易漏读或重复读。 可以围绕 commit / deltacommit 做 Incremental Query,更适合下游持续消费变化。
文件治理 小文件合并、历史文件清理、分区重算多由外部任务完成。 通过 Compaction、Clean、Clustering、Metadata Table 等表服务持续维护文件布局。

这个表主要强调:普通文件表缺少 Timeline、Index、FileGroup / FileSlice 和表服务等表级能力。

可以从几个角度看这个差异。

2.1.1 写入语义不同

普通 Hive 表通常以追加或覆盖分区为主:

INSERT INTO TABLE ods_order PARTITION (dt = '2025-06-03')
SELECT *
FROM tmp_order_delta;

如果要修复一个分区,常见写法是 INSERT OVERWRITE

INSERT OVERWRITE TABLE ods_order PARTITION (dt = '2025-06-03')
SELECT *
FROM tmp_order_rebuild;

这种方式能解决问题,但它的粒度是分区,不是单条记录。哪怕只改几千条数据,也可能要重写一个很大的分区。

Hudi 更关注记录级别的变更。写入时通常会指定 record key、partition path 和 precombine 字段:

val hudiOptions = Map(
  "hoodie.table.name" -> "ods_order_hudi",
  "hoodie.datasource.write.recordkey.field" -> "order_id",
  "hoodie.datasource.write.partitionpath.field" -> "dt",
  "hoodie.datasource.write.precombine.field" -> "update_time",
  "hoodie.datasource.write.operation" -> "upsert",
  "hoodie.datasource.write.table.type" -> "COPY_ON_WRITE"
)

这几个字段决定了 Hudi 如何识别一条记录、如何分区、同一个 key 多次到达时谁更新、以及本次写入使用什么操作语义。

2.1.2 事务可见性不同

普通文件写入最怕写到一半。比如 Spark 任务已经生成了一部分 Parquet 文件,但任务失败了,下游如果直接扫描目录,就可能读到不完整数据。Hive 和 Spark 自身有一些提交协议可以降低这个问题,但表级历史、回滚、增量读取和后台服务状态并不是普通文件表天然具备的。

Hudi 通过 Timeline 管理表上的动作。一次写入、一次 compaction、一次 clean、一次 rollback,都会在 Timeline 上形成 Instant。Instant 通常会经历这些状态:

REQUESTED -> INFLIGHT -> COMPLETED

在正常的 Snapshot / Read Optimized 等查询视图下,查询侧主要基于 Timeline 中已经完成的 Instant 构造可见表状态,避免读到未完成写入。也就是说,下游读的不是“目录里碰巧有什么文件”,而是“Timeline 上已经完成的表版本”。这个差异是理解 Hudi 的关键。

2.1.3 增量消费方式不同

普通 Hive 表要做增量,常见做法是按分区读取:

SELECT *
FROM ods_order
WHERE dt >= '2025-06-03';

这种方式简单,但它只能表达分区级增量。如果一条历史分区里的记录在今天被修正,单纯按 dt 过滤可能读不到。如果按 update_time 过滤,又要依赖业务字段质量。

Hudi 的 Incremental Query 是围绕 commit time 展开的。下游任务可以记录上一次消费到的 commit,然后继续读取之后的变化。工程上通常会记录上一次消费到的 instant / commit,并在下一次任务中以 begin instant、end instant 或类似参数继续读取后续变化。这种方式更适合增量 Pipeline。

2.2 Hudi 的核心能力

这一节只做概念总览,后面的文章会逐篇拆开。

2.2.1 Upsert

Upsert 是 insert 和 update 的组合。新 key 到来时插入,已有 key 到来时更新。对于 CDC 入湖来说,这几乎是最核心的能力。

例如订单表里 order_id = 1001 先到达一条创建记录,后面又到达一条支付记录。普通追加表会保留两行;Hudi 表可以根据 order_idupdate_time 合并出最新状态。

2.2.2 Delete

数据湖里做删除并不容易,因为底层文件通常不可变。Hudi 的删除不是简单调用文件系统删除某一行,而是通过新的提交表达“这条记录在新版本中不可见”。在 COW 表中可能表现为重写 Base File,在 MOR 表中可能表现为写入 Log File,最终由查询和 compaction 合并语义。

这类能力对于 GDPR 删除、业务撤单、脏数据清理都很重要。

2.2.3 Incremental Query

Hudi 的增量查询面向的是“表发生了哪些变化”,而不是“某个分区有哪些文件”。这让下游任务可以把 Hudi 表当成增量数据源使用:

上游 CDC -> Hudi 表 -> 下游宽表 / 搜索索引 / ClickHouse / 其他数据湖表

如果没有增量查询,下游经常只能全量扫描大表,或者自己维护复杂的水位线。

2.2.4 Transaction

Hudi 通过 Timeline 管理事务提交。写入任务生成数据文件后,还需要提交 Instant。查询侧根据完成的 Instant 构造表视图,从而避免读到未完成写入。

这不等于 Hudi 变成了关系型数据库。它仍然运行在分布式文件系统上,事务模型和 MySQL 这类数据库不同。但对于数据湖表来说,原子提交、快照读取和回滚能力已经能解决很多生产问题。

2.2.5 Index

更新一条记录之前,系统必须判断这条记录可能落在哪些文件里。普通数据湖没有这层映射,只能靠扫描或外部索引。Hudi 的 Index 负责帮助写入端判断某个 HoodieKey 可能落在哪些 FileGroup 中,从而减少更新定位时的扫描成本。

不同索引适合不同场景:

索引 常见场景
Bloom Index Spark 写入、非全局更新、通用场景
Simple Index 小表或测试场景,逻辑直接但成本较高
HBase Index 外部索引,适合随机查询但有额外运维成本;这类外部索引有额外组件依赖,入门和单机测试环境通常不会优先选择
Flink State Index Flink 实时写入中保存 key 到文件组的映射
Bucket Index 通过哈希分桶降低状态和定位成本

索引不是越强越好。全局索引能处理跨分区更新,但成本也更高。大表通常要先判断记录是否会跨分区变化,再决定是否使用全局索引。

2.2.6 Compaction

Merge On Read 表为了降低写入延迟,会先把更新写到 Log File。查询时如果每次都合并 Base File 和很多 Log File,读性能会下降。Compaction 的作用就是把 Log File 中的变更合并回新的 Base File。

可以把 MOR 理解成一种延迟整理策略:优先降低写入延迟,后面再通过 compaction 把文件整理成更适合查询的形态。

2.2.7 Clustering

Compaction 主要解决 MOR 表中 Log File 和 Base File 的合并问题,Clustering 更关注文件布局优化。比如数据写入时比较乱,后续可以按某些字段重新排序、合并小文件、优化查询过滤效率。

对于大表来说,Clustering 不是锦上添花。分区内小文件太多、文件排序混乱、查询经常扫描大量无关数据时,Clustering 会直接影响查询成本。

2.2.8 Metadata Table

大表上直接列目录成本很高,尤其是在对象存储上。Hudi Metadata Table 用来加速文件列表、列统计、索引等元数据访问。后面写到生产调优时会专门展开。

2.2.9 Schema Evolution

数据湖表不是一次建好后就永远不变。业务表经常会新增字段、调整可选字段,CDC 链路里还可能遇到上游 DDL 变化。如果只是一堆普通 Parquet 文件,历史文件和新文件的 Schema 不一致时,读写端很容易出现字段缺失、类型不兼容或查询结果不稳定的问题。

Hudi 支持以兼容方式处理表结构演进。这里先记住一个原则:Schema Evolution 不是让我们随意改字段类型,而是让数据湖表在可控范围内面对业务字段变化。后面写 Spark、Flink 和 Hive 集成时,还会看到它和 Avro Schema、Hive Metastore、Flink SQL 类型映射之间的关系。

2.3 典型使用场景

Hudi 不是所有数据湖表的默认答案。判断是否需要 Hudi,可以先看数据是否持续变化、是否需要增量消费、是否需要记录级更新。

2.3.1 CDC 入湖

这是 Hudi 最典型的场景。MySQL binlog 通过 Flink CDC 或 Kafka 进入实时链路,最终写入 Hudi 表。Hudi 负责根据主键做 upsert,下游查询得到最新状态。

一个简化链路如下:

MySQL binlog -> Kafka -> Flink SQL -> Hudi 表 -> Hive / Spark / Trino 查询

这个场景最关注四件事:

  1. 主键是否稳定。
  2. 事件顺序如何处理。
  3. 删除事件如何表达。
  4. 下游能不能按 commit 增量消费。

2.3.2 近实时分析

如果业务希望几分钟内看到最新数据,但又不想把所有分析都放到实时数据库里,Hudi MOR 表是一种选择。Flink 持续写入 Log File,查询侧通过 Snapshot Query 看到近实时结果,后台 compaction 定期整理文件。

这种方案不是没有代价。MOR 的读写平衡依赖 compaction 策略,如果压缩不及时,查询会被 Log File 拖慢;如果压缩太频繁,写入和资源成本又会上升。

2.3.3 增量 Pipeline

很多数据任务并不是面向最终用户查询,而是作为中间层继续加工。比如 ODS 层订单表变化后,下游 DWD、DWS、搜索索引、ClickHouse 明细表都需要同步变化。Hudi 的 Incremental Query 可以减少全量扫描。

这类场景里,Hudi 表既是存储结果,也是变更源。

在这里还要注意一个很容易混淆的点:业务事件时间和数据到达时间不一定相同。比如一条订单变更发生在 10:00,但因为网络、任务重启或 Kafka 堆积,真正写入 Hudi 的时间可能是 10:08。增量消费如果只看业务时间,容易漏掉迟到数据;Hudi 的 Timeline 则让下游可以围绕提交时间继续消费变化。后面讲 Timeline 时会专门拆这个问题。

2.3.4 数据修复和分区重算

离线数仓经常遇到历史分区修复。Hudi 支持 insert_overwritedelete_partition、replace commit 等能力,可以用更明确的表语义表达修复过程。相比直接删除目录再重跑,Timeline 中有更清晰的提交记录。

这些能力在不同 Hudi 版本和不同引擎入口中的参数或语法可能不同,后续以实测命令为准。

2.3.5 增量导出

还有一类场景是把数据湖里的变化继续导出到外部系统,比如 Elasticsearch、ClickHouse、Redis 缓存或另一个湖表。传统做法可能会让下游直接消费 Kafka,但 Kafka 更适合保存一段时间内的事件流,不适合承载长期历史状态。

Hudi 表可以同时保存最新状态和提交历史,下游通过 Incremental Query 拉取上一次 commit 之后的变化,再写到目标系统。这样做的好处是:如果下游任务失败,可以从已记录的 commit 继续恢复,而不是重新扫全表,也不是完全依赖 Kafka 保留时间。

生产环境中还需要配合 cleaner / archive 保留策略,避免下游任务停太久后需要的增量提交历史已经被清理或归档。

2.4 版本选择先说明

组件 计划版本 选择原因
Hadoop 3.4.1 已经是比较新的 Hadoop 3.x,适合作为 HDFS / YARN 测试底座
Hive 4.0.x 主要用于验证新版 Metastore 和查询链路,具体兼容性以后续安装实测结果为准
Spark 3.5.x Hudi 1.0.x 支持 Spark 3.3、3.4、3.5 等 Spark 3.x 组合,其中 Spark 3.5.x 是默认 / 优先验证方向;实际安装时需要选择匹配 Spark 版本和 Scala 版本的 Hudi bundle
Flink 1.20.x Hudi 1.0.x 提供 Flink 1.20 支持,是实时写入测试的优先组合;实际安装时需要使用与 Flink 1.20 匹配的 Hudi Flink bundle / profile,不要混用旧版 Flink connector
Hudi 1.0.2 使用 1.0.2
Kafka 3.8.x / 3.9.x 用于 Kafka Source、DeltaStreamer 和 CDC 链路测试
MySQL 8.0.x 用作 Hive Metastore 存储和 CDC 测试源
JDK OpenJDK 11 先用 OpenJDK 11 作为单机测试环境的保守选择,减少 Hadoop、Spark、Flink、Hive 混合部署时的兼容变量;JDK 17 后续单独验证

这里先只给方向。第 2 篇会在服务器上真实安装并验证,最终以能跑通 HDFS、YARN、Hive、Spark、Flink、Kafka、MySQL 和 Hudi 表读写为准。如果某个组件组合实际不兼容,会在安装文章里记录降级原因、报错现象和修复方式。后续安装文章中也会记录 Hive 查询 Hudi 表时使用的 bundle、classpath 和 metastore sync 参数。

3. 理解模型与常见误解

3.1 一个最小理解模型

刚开始学 Hudi 时,不建议先陷进几十个参数里。可以先记住下面这个模型:

Hudi 表 = 数据文件 + Timeline + Index + 表服务

其中:

  1. 数据文件负责存储真实数据,通常是 Base File 和 Log File。
  2. Timeline 负责记录表上发生过的动作。
  3. Index 负责定位记录在哪个 FileGroup。
  4. 表服务负责 compaction、clean、clustering、metadata 等后台治理。

如果一张表只有数据文件,它更像普通 Hive 表。如果一张表同时有 Timeline、Index 和表服务,它才开始具备 Hudi 的核心能力。

这个模型也能解释为什么 Hudi 不是单纯的文件格式。Parquet 只回答“数据怎么编码存储”,Hudi 回答的是“这张表如何持续变化,并且让读写双方看到一致的表状态”。

3.2 常见误解

3.2.1 Hudi 是不是只能配合 Spark 使用

不是。Spark 是 Hudi 很常用的批处理入口,尤其适合初始化、SQL DML、历史修复和离线写入。但 Hudi 同时支持 Flink 写入和读取,也可以和 Hive、Trino、Presto 等查询引擎配合。

这个系列里,Spark 和 Flink 都会写。Spark 更偏批处理,Flink 更偏实时入湖。

3.2.2 Hudi 是不是会替代 Hive

不会。Hive 可以继续作为 Metastore 和查询入口。Hudi 表可以同步到 Hive Metastore,让 Hive 或其他兼容 Metastore 的引擎看到表结构。对很多现有数仓来说,Hudi 更像是增强底层表能力,而不是推翻上层查询体系。

3.2.3 Hudi 表是不是一定比普通 Parquet 表快

不一定。Hudi 的优势是更新、删除、事务和增量能力,不是所有查询都天然更快。如果一张表永远只追加、从不更新、也没有增量消费需求,普通 Parquet 表可能更简单。

Hudi 会引入 Timeline、索引、元数据、compaction 等额外复杂度。只有当这些能力能解决真实问题时,引入 Hudi 才值得。

3.2.4 选 COW 还是 MOR

简单理解:

  1. Copy On Write 更适合读多写少、查询稳定的场景。
  2. Merge On Read 更适合写入频繁、希望降低写延迟的场景。

但这只是第一层判断。实际还要看更新比例、查询延迟要求、compaction 资源、下游引擎支持情况。第 5 篇会专门讲 COW、MOR 和三种查询方式。

4. 引入判断与总结

4.1 引入 Hudi 的判断

Hudi 的核心价值,不是“又多了一种大数据组件”,而是它把数据湖里长期靠约定和调度脚本维持的东西,收敛成了表自身的能力。

以前在 Hive 表上做更新,常见做法是:先找受影响分区,重跑临时表,覆盖目标分区,再让下游重新消费。这个流程能跑,但很多状态散在脚本、调度系统、临时目录和业务约定里。谁覆盖了哪个分区,哪些文件应该被清理,下游从哪里继续读,这些问题并没有统一落在表本身。

Hudi 的做法是把这些变化写进 Timeline,把记录定位交给 Index,把文件版本交给 FileGroup 和 FileSlice,把清理、压缩、聚簇变成表服务。这样一来,数据湖表更接近一个有生命周期管理的系统,而不是一个不断堆文件的目录。

当然,Hudi 也不是免费的。它会带来更多参数、更多 bundle 兼容问题、更多表服务调优工作。特别是在 Spark、Flink、Hive、Hadoop 版本混在一起时,依赖冲突会很常见。所以这个系列后面不会只写概念,也会把真实安装、报错、截图和修复过程记录下来。

对我来说,是否引入 Hudi 可以用一句话判断:

如果这张数据湖表需要持续接收变更,并且下游希望稳定读取最新状态或增量变化,就应该认真考虑 Hudi;如果只是低频追加的离线归档表,普通 Parquet / Hive 表可能更直接。

4.2 总结

本文先从整体上解释了 Hudi 的定位。

  1. Hudi 不是简单的文件格式,而是数据湖表管理系统。
  2. 普通 Hive / Parquet 表适合追加场景,但在更新、删除、事务和增量消费上能力不足。
  3. Hudi 通过 Timeline、Index、FileGroup、FileSlice 和表服务,让数据湖具备更接近数据库的表管理能力。
  4. Spark、Flink、Hive、Trino 不是 Hudi 的替代品,而是从不同角度读写 Hudi 表的计算和查询引擎。
  5. CDC 入湖、近实时分析、增量 Pipeline、数据修复和增量导出,是 Hudi 比普通文件表更有价值的典型场景。

文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录