Apache Hudi 想象成一个非常智能的**"超级文件柜"**。这个文件柜不仅要存东西,还要能改东西、查东西。
咱们今天要聊的,就是怎么设计这个文件柜的核心机制。我会用最通俗的例子,带你把 Copy On Write (COW)、Merge On Read (MOR) 以及主键分区这些概念彻底搞懂。
一、 Copy On Write (COW) ------ "完美主义者"模式
想象一下,你的文件柜里存着一页页的客户资料,每一页都是一张纸。
1. 写入流程与重写机制
场景:客户"张三"搬家了,他的地址要从"北京"改成"上海"。这页资料目前锁在文件夹"第1号文件"里。
- COW 的做法 :
- 取出:把"第1号文件"整个拿出来。
- 修改 :找到张三那行,把地址改成"上海"。但是!COW 不允许在原文件上涂改。它必须打印一张全新的、完美无缺的"第1号文件",里面包含所有原来的数据 + 张三的新地址。
- 替换:把旧的"第1号文件"扔进碎纸机,把这张新的放回去。
核心逻辑 :任何修改,都伴随着包含该数据的整个文件的重写。
2. 适用场景与读性能优势
- 读性能极快:因为文件柜里永远是最新的、整理好的、干干净净的文件。你伸手去拿,拿出来就能看,不用做任何额外处理。
- 适用场景 :
- 读多写少:比如每天只更新一次数据,但这一整天要被分析师查几百次。
- 数据量适中:因为每次写都要重写文件,如果你总是一秒钟改一次数据,光打印文件就累死了。
二、 Merge On Read (MOR) ------ "灵活便利贴"模式
还是那个文件柜。MOR 模式觉得 COW 太死板,改个地址还要重打整张纸,太浪费了。
1. Base File 与 Log File 的协作
在 MOR 模式下,文件柜里出现了两种东西:
- Base File (基础文件):这就是那张整理好的正式资料纸(Parquet 格式),它是基础。
- Log File (日志文件) :这就是**"便利贴"**(Avro 格式)。
场景:客户"李四"的电话号码变了。
- MOR 的做法 :
- 它不去动那张正式资料纸。
- 它快速拿出一张便利贴,写上:"李四的新电话是 138xxxx",然后啪地贴在文件夹旁边。
- 完事儿!写入速度极快。
2. 读时合并与写时压缩
那我要查"李四"的电话怎么办?
-
读时合并:
- 你先拿出那张正式的资料纸,看到上面写着李四的旧电话。
- 你发现旁边贴着一张便利贴。
- 你必须在脑子里(或者电脑里)把这两部分拼起来:哦,旧电话作废,用便利贴上的新电话。
- 代价:这就比直接读那张干净的纸要慢一点点,因为你多了一步"合并"的动作。
-
写时压缩 :
便利贴贴多了会怎么样?资料就乱了,查起来越来越慢。所以,MOR 有一个后台清洁工。
-
这个清洁工会定期(比如每隔几个小时)过来,把所有便利贴撕下来,真正地改写进那张正式资料纸里,然后把便利贴扔掉。
-
这个过程,就叫 Compaction(压缩/合并)。
-
3. 场景选择:如何在 Latency(延迟)与 Throughput(吞吐)间权衡?
这个选择就像选快递:
| 模式 | Latency (数据延迟/多久能看到新数据) | Throughput (写入吞吐量/每秒能写多少) | 适合场景 |
|---|---|---|---|
| COW | 高 (因为要重写文件,慢) | 低 (重写太费劲,写不动) | 追求秒级查询,数据更新不频繁(如日报表)。 |
| MOR | 低 (贴个便利贴就行,极快) | 高 (贴便利贴非常轻松,能抗住大流量) | 追求秒级写入,数据变化极快(如订单状态、实时日志)。 |
一句话总结 :如果你要快 (写),选 MOR;如果你要稳(读),选 COW。
三、 Primary Key 与 Partition 的关系
现在我们知道怎么存文件了,下一步是怎么整理这些文件。这就涉及到 Primary Key(主键)和 Partition(分区)。
1. RecordKey 的设计原则
RecordKey 就是每一行数据的身份证号。
-
唯一性(最重要!):
- 比如你的主键是"用户ID"。
- 假如你来了两条数据:用户ID=1001,说名字叫"Alice";过了一会儿又来一条用户ID=1001,说名字叫"Bob"。
- Hudi 怎么知道这两条数据其实是同一个人的不同状态?全靠 RecordKey! 它看到 ID 都是 1001,就知道这是"更新"操作,而不是"新增"两个人。
- 如果你的 RecordKey 选错了(比如选了"性别"),那所有男的记录都会打架,所有女的记录也会打架,数据就全乱套了。
-
分布性:
- 如果你的身份证号前几位都是"110"(比如北京户口),那么"110"这个文件夹就会特别大,挤死了;而"330"(浙江)的文件夹可能没人去。
- 好的主键应该让数据尽量均匀地散落在各个文件里,这样大家干活才不累。
2. 分区策略对查询性能的影响
Partition(分区) 就像是文件柜上的大抽屉标签。
- 怎么分区:通常按照时间(天、小时)或者业务属性(城市、部门)来分。
- 对查询的影响 :
- 场景 A(好的分区) :你的数据按"省份"分区。老板问:"给我看广东省的所有订单。"
- Hudi 太开心了,它直接走到标着"广东省"的那个抽屉,其他抽屉看都不看。速度极快!
- 场景 B(坏的分区) :你的数据按"性别"分区(只有男、女两个抽屉)。老板问:"给我看订单金额大于 100 元的数据。"
- Hudi 傻眼了。它不知道金额大于 100 的人是男是女啊!它只能把"男抽屉"和"女抽屉"里的所有文件都翻一遍。速度极慢!
- 场景 A(好的分区) :你的数据按"省份"分区。老板问:"给我看广东省的所有订单。"
总结一下关系:
- 分区 是为了让你一下子扔掉一大堆不需要的数据(大范围搜索)。
- 主键 是为了让你在剩下的数据里,精确找到那一条要修改的数据(精准定位)。
高阶口诀:
先分区缩小范围,再主键精准定位。
COW 适合读,MOR 适合写。
RecordKey 要唯一,分区字段要常查。