写入模式概览:COW 与 MOR 模式的区别、适用场景
核心原理:两种模式如何组织数据文件
Apache Hudi 提供两种核心表类型(Table Type),即 Copy-on-Write(COW,写时复制) 与 Merge-on-Read(MOR,读时合并)。它们决定了数据在存储层如何被写入、更新与读取,也直接影响了查询延迟、写入放大与文件管理策略。
COW 模式的核心思想是“更新即重写”。每次对已有记录执行更新或删除时,Hudi 会找到包含该记录的所有基础文件(Base File,Parquet 格式),将新数据与旧数据合并后生成一批新的基础文件,并原子性地替换旧文件。因此,COW 表在任何时刻读取到的都是最新且完整的数据,无需额外合并过程。
MOR 模式则采用“增量日志 + 基础文件”的组合。更新记录首先被追加写入 Avro 格式的日志文件(Log File),而基础文件保持原样。查询时,系统需要将基础文件与日志文件进行合并,以呈现最新视图。MOR 表可以选择两种查询类型:读优化查询(Read Optimized) 只读取基础文件,返回快照数据但可能滞后;快照查询(Snapshot Query) 则实时合并日志与基础文件,返回最新数据。
关键差异速览:
- 写入路径:COW 直接重写 Parquet 文件;MOR 先写 Avro 日志,后台再异步压缩(Compaction)成 Parquet。
- 读取路径:COW 只读 Parquet;MOR 读优化查询只读 Parquet,快照查询需合并 Parquet + Avro。
- 写入放大:COW 写入放大高(每次更新都重写整个文件);MOR 写入放大低(顺序追加日志)。
- 查询延迟:COW 查询延迟稳定;MOR 快照查询可能因合并产生额外开销。
方法流程:COW 与 MOR 的写入与查询路径
理解两种模式的最佳方式,是追踪一条数据从写入到被查询的完整路径。
COW 写入流程:
- 客户端发起 upsert(更新插入)操作,指定目标分区。
- Hudi 索引机制定位记录所在的基础文件(File Group)。
- 读取旧基础文件,将新记录与旧记录合并,生成新版本的基础文件。
- 提交(Commit)新文件版本,并原子性地将旧文件标记为删除。
- 查询时直接扫描最新版本的基础文件,无需任何额外合并。
MOR 写入流程:
- 客户端发起 upsert,索引定位目标 File Group。
- 更新记录以追加方式写入该 File Group 的 Avro 日志文件,不触碰基础文件。
- 写入操作快速返回,日志文件持续增长。
- 后台压缩任务定期将日志文件合并到新的基础文件,并清理旧日志。
- 查询时:读优化查询只扫描基础文件;快照查询则动态合并基础文件与日志文件。
实操建议:在 Hudi 中创建表时,通过 TABLE TYPE 属性指定模式:
-- COW 表
CREATE TABLE cow_table (...) USING HUDI
TBLPROPERTIES ('type' = 'COPY_ON_WRITE');
-- MOR 表
CREATE TABLE mor_table (...) USING HUDI
TBLPROPERTIES ('type' = 'MERGE_ON_READ');
案例与场景:如何选择正确的模式
选择 COW 还是 MOR,本质上是在查询延迟与写入吞吐之间做权衡。以下典型场景可作参考:
| 场景特征 | 推荐模式 | 原因 |
|---|---|---|
| 数据仓库 ODS 层,批量导入后较少更新 | COW | 写入频率低,查询性能最优,文件管理简单 |
| 用户画像、订单状态频繁变更 | MOR | 高频率 upsert 场景,避免反复重写大文件 |
| 近实时数据分析,要求秒级数据可见 | MOR(快照查询) | 日志追加后立即可见,无需等待压缩 |
| 下游使用 Presto/Spark 做批量报表 | COW | 读优化查询无合并成本,扫描效率高 |
| 数据湖中存储海量 IoT 传感器数据 | MOR | 写入吞吐要求高,且更新集中在最近分区 |
案例:电商订单表
某电商平台维护订单状态表,每天新增约 5000 万条订单,同时有约 10% 的订单会经历状态流转(待支付→已支付→已发货→已完成)。如果采用 COW 模式,每次状态更新都需要重写包含该订单的整个 Parquet 文件,导致严重的写入放大。改用 MOR 模式后,状态更新以日志追加方式写入,写入吞吐提升约 3 倍,同时通过每 30 分钟一次的压缩任务控制日志大小,查询侧使用快照模式保证数据实时性。
误区与复盘:常见理解偏差
误区一:MOR 一定比 COW 快
这是最常见的误解。MOR 只在写入路径上更快,但快照查询需要合并日志与基础文件,查询延迟可能比 COW 高 2~5 倍。如果业务以读为主且更新不频繁,COW 反而整体性能更优。
误区二:COW 不支持增量查询
两种模式都支持增量查询(Incremental Query),区别在于 COW 的增量数据来自新提交的基础文件版本,而 MOR 的增量数据来自日志文件。COW 的增量查询粒度受限于提交频率,MOR 则可以提供更细粒度的变更流。
误区三:MOR 不需要关心文件数量
如果压缩策略配置不当,MOR 表的日志文件会无限增长,导致快照查询性能急剧下降。必须设置合理的压缩触发策略(如基于时间、日志大小或记录数),并监控 File Group 的数量。
复盘建议:在技术选型时,不要仅凭“写入频繁就选 MOR”的简单规则。建议先用业务数据做压测:模拟真实 upsert 比例、查询频率和延迟要求,分别测量两种模式在 COW 与 MOR 下的写入吞吐、查询 P95 延迟以及存储成本,再做出最终决策。同时,Hudi 支持表类型在后续版本中通过 ALTER TABLE 进行转换,但转换过程涉及全表重写,成本较高,因此初期选型仍需谨慎。