Apache Hudi
问题
什么是 Apache Hudi?它和 Iceberg、Delta Lake 有什么区别?
答案
Hudi 核心特性
Apache Hudi(Hadoop Upserts Deletes and Incrementals)是 Uber 开源的数据湖表格式,核心优势在于高效的增量处理和 Upsert 能力。
| 特性 | 说明 |
|---|---|
| Upsert / Delete | 行级更新删除,CDC 友好 |
| 增量查询 | 只读取变更数据 |
| ACID 事务 | 快照隔离 |
| 时间旅行 | 历史版本查询 |
| 两种表类型 | CoW 和 MoR |
Copy-on-Write vs Merge-on-Read
| 维度 | CoW(Copy-on-Write) | MoR(Merge-on-Read) |
|---|---|---|
| 写入时 | 重写整个 Parquet 文件 | 增量写入 Log 文件 |
| 读取时 | 直接读 Parquet | 合并 Parquet + Log |
| 写入延迟 | 高 | 低 |
| 读取延迟 | 低 | 中(需合并) |
| 适用场景 | 读多写少 | 写多读少、实时场景 |
典型使用场景
-- Spark SQL 操作 Hudi
-- 创建 Hudi 表(MoR 类型)
CREATE TABLE events (
_hoodie_commit_time STRING,
_hoodie_record_key STRING,
event_id BIGINT,
user_id BIGINT,
event_name STRING,
event_time TIMESTAMP
) USING hudi
TBLPROPERTIES (
type = 'mor', -- MoR 表类型
primaryKey = 'event_id', -- 主键
preCombineField = 'event_time' -- 去重字段
)
PARTITIONED BY (date_format(event_time, 'yyyy-MM-dd'));
-- Upsert(有则更新,无则插入)
INSERT INTO events
SELECT * FROM source_events;
-- 增量查询:只获取某个时间点之后的变更
SELECT * FROM hudi_table_changes('events', 'latest_state', '20240101000000');
-- 时间旅行
SELECT * FROM events TIMESTAMP AS OF '2024-01-01 00:00:00';
Hudi vs Iceberg vs Delta Lake
| 维度 | Hudi | Iceberg | Delta Lake |
|---|---|---|---|
| Upsert 性能 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 增量读取 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| 分区演进 | ⚠️ 有限 | ✅ 强 | ⚠️ 有限 |
| 隐藏分区 | ❌ | ✅ | ❌ |
| 多引擎支持 | 中(Spark 为主) | 广泛 | 深度绑定 Spark |
| 运维复杂度 | 高(Compaction) | 低 | 中 |
| CDC 场景 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 社区趋势 | 稳定 | 增长最快 | Databricks 生态 |
Hudi 的挑战
- 运维复杂:MoR 表需要定期 Compaction
- 多引擎支持不如 Iceberg:主要依赖 Spark
- 学习曲线陡:概念多(CoW/MoR、Timeline、Clustering 等)
常见面试问题
Q1: 什么场景适合用 Hudi?
答案:
- CDC 数据入湖:MySQL Binlog 同步到数据湖(Upsert 友好)
- 实时数仓:Flink + Hudi 实时写入
- 频繁更新/删除:用户画像、订单状态更新
- 增量 ETL:只处理变更数据,减少计算量
Q2: Compaction 是什么?为什么需要它?
答案:
- MoR 表会产生大量 Log 文件,导致读取时合并开销增大
- Compaction 将 Base File + Log Files 合并为新的 Base File
- 需要定期调度 Compaction 任务(异步/同步)
- 类似 LSM-Tree 的后台合并机制
相关链接
- Apache Iceberg - 最流行的表格式
- Delta Lake - Databricks 表格式
- 湖仓一体 - 综合选型
- CDC 变更数据捕获 - Hudi 的典型数据源