就像我们会定期打理房子以保持最佳状态一样,维护 Apache Hudi 表对一个运转良好的数据湖仓至关重要。正如房子需要定期整理、清理与重置,才能保持通透易找,表也必须周期性地审视与组织,才能保持高效与易用。
在写入数据时,用户往往更关注降低读写延迟,而不是把数据组织到"最完美"的布局------对于高吞吐量的表,这样的忽视会带来严重后果。正如我们在第 1 章开头讨论的那样,Hudi 被设计为一种能从一开始就预见这些陷阱并加以防范的数据湖仓平台,从而避免日后在运营数据湖仓时的低效与困境。
例如,未维护的 Hudi 表可能会出现:
存储成本上升
过多的小文件会导致高存储访问时延与较差的压缩效果,从而推高湖仓的存储成本。云存储对象数过多也会显著抬升存储 API 的调用费用。
查询性能变慢
欠佳的表组织会导致查询执行时间过长,原因包括数据布局未聚类、分区不合理。大量小文件还会造成元数据膨胀,尤其是对保留多个版本的湖仓表更为明显。
计算成本增加
如果不维护索引,写入端与查询端可能不得不扫描整张表才能定位目标记录,长时间占用计算资源,造成集群费用大增。
读放大偏高
若不频繁压缩以控制日志文件增长,MOR 表上的查询每次都需要读取过多数据。
就像不要等家里完全乱套才行动一样,主动的表维护对于确保数据可访问性与查询性能至关重要。
这正是**表服务(table services)**的用武之地。它们负责定期的维护操作,让数据湖仓保持整洁、有序与高效。没有这些服务,我们的湖仓可能会蜕变为效率低下的"数据沼泽"------虽然技术上"应有尽有",却难以及时找到并获取所需信息。
本章将带你走进 Hudi 的表服务世界------这些内建、自动化的平台服务会为你的湖仓执行必要的维护操作。我们将先定义什么是表服务,并说明它们在保持表健康与高性能方面的根本作用;接着介绍这些服务的多种部署方式以适配不同运维需求;核心部分将深入四大表服务------压缩(compaction) 、聚类(clustering) 、清理(cleaning)与索引(indexing) ------它们协同工作,让你的湖仓长期保持最佳状态。读完本章,你将系统掌握如何高效维护与优化 Hudi 表。
表服务概览
Hudi 的表服务是一组在数据写入之后 或依据可配置的表服务策略执行的优化与管理服务。例如,你可以配置一条策略:定期按某个高频查询所用列对表进行排序。
不同于新增记录的常规写操作,表服务聚焦"家务"任务:优化存储布局、梳理表结构、增强后续查询性能。图 6-1 展示了表服务工作流的高层概览。

(图 6-1 表服务工作流概览:略)
典型的表服务操作包含两个步骤:先**调度(scheduling)生成完整的维护计划,明确如何达成维护目标;再 执行(execution)**该计划,对表做出实际变更。为适配不同的运维需求与约束,Hudi 提供三种部署模式:内联(inline) 、异步执行(async execution)与独立(standalone) 。下面分别介绍其特性,帮助你选型。
部署模式:Inline(内联)
在 inline 模式下,表服务与触发它的写入作业同步运行,紧跟在该写操作之后(图 6-2)。这是最简单的部署方式:将表服务的两个步骤(先调度、再执行)与数据写入打包到一起,确保每次写入后表都能得到优化,无需额外作业或基础设施。可以把它想象成"写完就自动做家务"。
需要理解的是,无论表服务以内联还是其他模式运行,它都会修改表 ,且这些修改会记录到 Hudi 时间线(timeline)上。例如,写操作的 commit 完成后,内联配置的 cleaning 表服务会启动,并创建自己的 clean 动作。这说明表服务是独立事务,而非写入事务的一部分。

(图 6-2 内联模式工作流:略)
表服务的动作也会经历 Hudi 的通用状态流转:requested ⇒ inflight ⇒ completed 。维护计划(包含目标文件组等信息)会写入该动作的 requested 时刻,从而让执行步骤在重试时具备幂等性:重试会优先执行既有的待处理计划,再生成或执行新的计划。执行成功后,动作转为 completed。
内联模式的优势是极简,并且完全不存在写入与表服务之间的并发 问题。代价是:因为表服务顺序 跟在写后执行,会拉长整体写延迟 ;同时写与维护共享同一套计算资源,可能造成资源利用低效。例如,为重写负载配置的大集群,在跑轻量的表服务时会被"浪费"。
部署模式:Async Execution(异步执行)
异步执行 模式采取混合策略:调度 仍与写入内联 ,而执行 由独立作业异步进行(图 6-3)。这非常合理,因为调度主要是读取文件组元数据并生成计划,通常比 I/O 密集的执行要轻得多。通过把调度留在写入路径内,我们既保持了与写操作的紧密协同,也简化了编排;而把重的执行工作分离出去,则可以:
- 用专用计算资源跑执行,优化资源配置
- 不阻塞写入流水线,加快数据落地
- 独立扩缩执行与写入资源

(图 6-3 异步执行模式工作流:略)
这种折中在生产环境里很实用。但也要注意,收集文件组元数据并按策略组装计划的调度时间并非为零 ,仍会在一定程度上减慢写入 。若应用对写入时延极致敏感,异步模式可能不是最佳选择。Hudi 的 Hudi Streamer 与基于 Apache Flink 的 Hudi Flink Streamer 提供了内建的异步执行 能力,可在同一集群的独立资源池中执行表服务。
部署模式:Standalone(独立)
独立 模式将表服务的调度与执行完全从写入进程中解耦(图 6-4)。在该模式下,你可以:
- 让调度与执行完全独立于写入流程运行
- 实施更复杂的调度策略,综合考虑资源可用性与表的优先级
- 将表服务基础设施与数据管道分开扩展
本质上,独立模式认可"家务"无需绑死在写频或同一套资源上。相反,它们可以作为集中式平台维护 来管理,按自定义节奏(每几分钟、每几小时或夜间)跨表优化。可把它想象为一个独立的保洁团队,与常规的摄取/ETL 团队互不干扰:这支团队按自己的日程与资源,评估、规划并执行优化任务,实现最大化效率与可控性。

(图 6-4 独立模式工作流:略)
当然,独立模式带来更高的运维复杂度:你需要管理独立的基础设施,并配置锁提供者(lock provider) ,以协调并发的写作业与表服务作业,确保这些动作的事务性。第 7 章会讨论锁提供者。对大规模湖仓来说,这些投入通常会换来更好的资源利用与更优化的维护节奏。
如何选型
选择部署模式,本质上是给写入作业与表服务作业提供合适的配置:
- Inline 模式 :把所有表服务配置直接提供给写入作业。写入作业将同时负责调度与执行。
- Async Execution 模式 :把调度相关配置 提供给写入作业;写入作业随后提交另一作业 ,使用执行相关配置异步执行该计划。
- Standalone 模式 :把调度与执行全部配置 提供给 Hudi 提供的独立可运行应用 ,它独立于任何写入作业运行。另外,你需要为写入作业与表服务作业配置锁提供者属性。
三种模式在"简单 vs. 灵活 "的光谱上各有定位:Inline 胜在"开箱即用 ",适合小规模;Async 与 Standalone 则提供越来越强的灵活性,适合需要资源精细化优化的大规模部署。表 6-1 为三种模式的快照对比。
表 6-1 部署模式对比
| 特性 | Inline | Async execution | Standalone | 
|---|---|---|---|
| 运维复杂度 | 极低 | 中等 | 高 | 
| 调度与执行灵活性 | 低 | 中 | 高 | 
| 写入延迟增加 | 高 | 低 | 最小 | 
| 资源优化便利度 | 低 | 中 | 高 | 
理解这些取舍后,你就能选出最契合自身运维与数据处理需求的模式。接下来各节将详细介绍 Hudi 的四大表服务。对每种服务,我们会说明其目的与机制,给出 inline 模式的示例配置,并指向官方文档获取更多样例。
压缩(Compaction)
正如前几章所述,MOR(Merge-on-Read,读时合并)表通过将更新与删除写入行式日志文件来实现快速摄取。不过,这一设计带来了查询端的权衡:随着日志文件不断累积,快照查询需要在查询时将它们与基文件按需合并,这会削弱读性能。
压缩(Compaction)正是为 MOR 表解决这一问题的表服务。它会把某个基文件与其对应的日志文件合并,生成一个新的、带版本 的基文件,里面包含数据的最新状态(见图 6-5)。这个过程等价于把行式的更新与删除"固化"为优化过的列式格式,在保持 MOR 高写入吞吐的同时,大幅提升快照查询性能。

(图 6-5 Hudi MOR 表中的压缩流程:压缩调度器与执行器如何管理文件切片并更新时间线)
把 MOR 的压缩与 COW(Copy-on-Write,写时复制)表的写入过程对比,会更清楚两者的本质差异(见图 6-6)。在 COW 表中,任何更新或删除都会触发一次 commit ,重写整个文件切片;而在 MOR 表中,这些变更会被高效地追加 到日志文件中,并由压缩 定期运行,将日志与基文件合并、优化该文件切片以便读取,并产出一次 commit 动作。从本质上说,COW 表等于每次写入都在做隐式的压缩 ;这在功能上相当于:MOR 表在每次 deltacommit 之后都配置为内联压缩。

(图 6-6 MOR 表中的压缩 vs COW 表中的写入(upsert))
你可以通过选择与表的更新频率与数据量相匹配的**节奏(cadence)与策略(strategy)**来调优压缩过程。下面介绍相关配置选项。
提示
就目前而言,Hudi 是唯一 能够在不阻塞且不导致失败 的情况下(即使并发写入正在更新同一文件组的同一条记录 )异步执行压缩的湖仓存储系统。这使得 Hudi 在实时或近实时复制可变数据流(例如 RDBMS CDC 日志、频繁更新的增量 ETL 管道)方面具有独特优势。
调度压缩(Schedule Compaction)
压缩的触发由可配置的策略控制:hoodie.compact.inline.trigger.strategy。Hudi 提供多种调度选项:
- NUM_COMMITS
 默认策略。自上次完成压缩以来,累计达到指定数量的 deltacommit(默认 5 次)后触发压缩。
- NUM_COMMITS_AFTER_LAST_REQUEST
 依据自上一次压缩被请求或完成 以来的 deltacommit 次数来触发。相比 NUM_COMMITS 节奏更稳定:若前一次压缩计划失败或仍在等待,就不会再排新的计划,避免压缩请求积压。
- TIME_ELAPSED
 距上次完成压缩经过指定秒数后触发。
- NUM_AND_TIME
 同时满足:至少发生了最少次数的 deltacommit ,且最少时间已过去。用于防止压缩过于频繁或过于稀疏。
- NUM_OR_TIME
 满足二者之一即触发:达到最少 deltacommit 次数,或达到最少时间。可确保压缩定期运行,避免长时间不压缩。
一旦触发,压缩计划的执行 由 hoodie.compaction.strategy 指定的策略指导,用于识别与排序待压缩的文件切片。常用策略包括:
- LogFileSizeBasedCompactionStrategy (默认)
 优先处理日志文件总体积 最大的文件切片,瞄准未合并数据最多的地方。可配置最小日志体积阈值(默认 0)来筛选文件切片,并限制单次运行处理的数据总量(默认 500 GB),以控制 I/O 与内存消耗。
- LogFileNumBasedCompactionStrategy
 优先处理日志文件个数 最多的文件切片,适合大量累积小更新的情况。同样提供按最小日志文件数 (默认 0)筛选的阈值,并将单次运行处理总量(默认 500 GB)加以限制。
- PartitionRegexBasedCompactionStrategy
 通过分区路径的正则匹配来选择压缩分区,便于对不同分区组实施差异化维护策略。
下面是一个内联压缩 的示例配置:每发生 10 次 deltacommit 触发压缩;采用 LogFileNumBasedCompactionStrategy 优先处理日志文件数最多的文件切片;选择至少含 1 个日志文件 的切片;并将本次压缩运行的总 I/O (读写之和)封顶为 100 GB:
            
            
              ini
              
              
            
          
          hoodie.compact.inline=true
hoodie.compact.inline.max.delta.commits=10
hoodie.compact.inline.trigger.strategy=NUM_COMMITS_AFTER_LAST_REQUEST
hoodie.compaction.strategy=\
org.apache.hudi.table.action.compact.strategy.LogFileNumBasedCompactionStrategy
hoodie.compaction.logfile.num.threshold=0
hoodie.compaction.target.io=102400为提升灵活性,Hudi 还提供 CompositeCompactionStrategy ,可以把多个策略**串联(AND)**使用来选择候选文件切片。若需完全自定义,你也可以实现 CompactionStrategy API,向调度器提供自定义策略。
执行压缩(Execute Compaction)
- 若配置为内联模式 ,调度器生成计划后会立即执行,由同一写入作业(如 Spark 或 Flink)继续完成压缩。
- 若配置为异步执行模式 ,写入作业会提交另一个作业,在后台异步执行压缩计划。
- 若配置为独立模式 ,需要单独起一个作业,使用 Hudi 的工具应用执行计划,例如 Spark 的 HoodieCompactor 或 Flink 的 HoodieFlinkCompactor。更多示例见官方文档。
需要注意,压缩在资源上天然是重负载的,主要体现在:
- 合并 过程计算密集,需要大量 CPU 来合并与排序记录;
- 可能需要从基文件与日志文件 读取大体量数据;
- 按计划可能会在重写 过程中同时生成很多新基文件。
这些特性使压缩与 MOR 表日常的写入有本质不同:写入往往是高频小批次 、可在中等规模集群 上高效运行;而压缩更像一个批处理 作业,更适合用专用计算资源 来运行。理解这种差异对于大规模场景下的资源规划至关重要。
聚类(Clustering)
Hudi 中的 Clustering(聚类) 通过把"相似记录"物理聚在一起,来优化数据布局,从而提升查询性能并提高数据湖仓的存储效率。它主要解决小文件过多与记录组织不合理的问题:依据指定列对数据进行合并与排序,输出更优的文件布局。
在高速度写入(尤其是流式)场景下,为了降低端到端延迟,我们往往会产生大量小文件。这能带来更快的数据新鲜度,却会显著拖慢查询,因为系统需要打开并处理大量小文件,而非少量的大文件。即便有第 3 章介绍的小文件处理机制,表仍可能因为初始文件组分配不理想、以及该机制无法通过排序提升"数据邻近性"而导致布局欠佳。Clustering 通过把小文件智能整并 为合适大小、并按指定列排序后的文件来解决这些问题。
这里的"邻近性(proximity) "指:具有相同(或相近)列值的记录被物理地 存放在一起。比如在销售数据集中,按 region(地区)聚类会把加州(California)的销售记录放进同一个或相邻的少数文件中。这样,针对该地区的查询只需读取极少量数据,性能大幅提升。
Hudi 的聚类流程会挑选符合条件的文件切片 ,读出记录,按指定列排序,并重写为新的、已优化的文件组(见图 6-7)。带来两方面关键收益:
- 更强的数据跳读(data skipping)
 通过把相关记录物理聚集,查询引擎可以直接跳过不含相关数据的整个文件。例如你的查询常按日期范围过滤,按日期聚类就能显著提高"同日记录"同文件存放的概率,从而快速跳过目标范围之外的文件。
- 更好的压缩率
 相似数据放在一起有利于 Parquet 等列式格式的编码与压缩,相同/相近取值段更容易压缩,降低存储成本。

(图 6-7 聚类过程示意:把无序提交的数据按 City_id 范围排序并聚类,以提升存储效率)
与压缩(Compaction)类似,聚类也可配置多种策略。下面逐一说明。
调度聚类(Schedule Clustering)
聚类的触发基于自上次聚类以来累积的 commit 或 deltacommit 次数。例如,写入作业的内联模式可这样配置:
            
            
              ini
              
              
            
          
          hoodie.clustering.inline=true
hoodie.clustering.inline.max.commits=4触发后,Hudi 会按聚类计划策略 寻找候选文件切片。默认提供基于大小 的计划策略,它按每个聚类分组允许的最大字节数分组,并参考以下关键阈值:
            
            
              ini
              
              
            
          
          # 聚类输出目标的最大文件大小
hoodie.clustering.plan.strategy.target.file.max.bytes=1073741824  # 1GB
# 认定为小文件的阈值
hoodie.clustering.plan.strategy.small.file.limit=314572800  # 300MB
# 本次聚类计划中允许的最大分组数
hoodie.clustering.plan.strategy.max.num.groups=30
# 每个分组的最大字节数上限
hoodie.clustering.plan.strategy.max.bytes.per.group=2147483648  # 2GB
# 排序列
hoodie.clustering.plan.strategy.sort.columns=a,b基于上述配置,聚类计划如下:
- 在各分区内 找出所有 < 300MB 的文件切片;
- 将这些小切片分组 ,保证每组总大小不超过 2GB ,且总分组数 ≤ 30;
- 对每个分组按列 a, b 排序后重写为新的、更大的文件切片,目标单文件大小 1GB。
还可通过 hoodie.clustering.plan.partition.filter.mode 配置需要参与聚类的分区筛选模式:
- NONE:包含所有有聚类候选的分区
- RECENT_DAYS:仅包含指定日期范围内的分区
- SELECTED_PARTITIONS:仅包含手动列出的分区路径
- DAY_ROLLING:按滚动日程包含分区
执行聚类(Execute Clustering)
- 内联模式 :调度器生成计划后立即执行,仍由同一写入作业(Spark 或 Flink)完成聚类;
- 异步执行模式 :写入作业提交另一个作业在后台异步执行聚类计划;
- 独立模式 :需单独启动作业,使用 Hudi 提供的工具应用执行聚类计划(如 Spark 的 HoodieClusteringJob 、Flink 的 HoodieFlinkClusteringJob)。更多示例见官方文档。
布局优化策略(Layout Optimization Strategies)
Hudi 默认使用线性(字典序)排序指定列来组织记录,但这并不总是最优。何时需要替代策略?
线性排序(Linear sorting)
当"记录邻近性"主要由单列 决定时(例如基于时间戳的交易表,经常按时间范围查询),按该列做线性排序通常非常有效,能很好地保持局部性。
但若邻近性依赖多列 (例如房源数据用经纬度共同决定空间邻近),简单的"按纬度后按经度"的字典序可能把地理上相距很远 的记录排在一起。此时需要能处理 N 维 点的排序算法------Z-order 与 Hilbert 正适用。
空间填充曲线(Space-filling curves)
空间填充曲线是在多维空间中"走遍所有点"的曲线,把多维点映射 到一维序列,同时较好地保留空间邻近性。常见的 Z-order 与 Hilbert(见图 6-8)能有效保持这种局部性:曲线上相近的点,在原空间里也大概率相近。

(图 6-8 二维平面上的 Z-order 与 Hilbert 曲线对比)
将记录视作多维点后,按 Z-order/Hilbert 的一维序值排序,便能让"原本空间上接近"的记录更可能落在同一文件中,从而显著增强文件级跳读,提升读取效率。
通过将 hoodie.layout.optimize.strategy 设为 ZORDER 或 HILBERT,即可指示聚类过程按这些高级算法排序,使多维空间中彼此接近的记录在磁盘上也物理相邻,进而高效支持范围/半径类查询。
聚类 vs 压缩(Clustering Versus Compaction)
二者都通过重写数据来优化表,但目的与方式不同:
- 适用表类型 :
 聚类适用于 COW 与 MOR ;压缩仅适用于 MOR。因此聚类的适用面更广。
- 组织方式 :
 压缩在单个文件组内部 进行:把日志与其基文件合并,产出该文件组的新版本 文件切片;
 聚类则跨文件组 重排记录:按目标大小与排序规则重建新的文件组,同时实现"合并小文件 + 保持(或增强)排序邻近性"。
清理(Cleaning)
Hudi 通过 MVCC (多版本并发控制)在写入者与读取者之间实现快照隔离 ,即维护数据文件的多个版本。多版本文件使得时间旅行、增量查询等强大能力成为可能,但随着时间推移也会显著抬高存储成本。随着新数据不断到来,Hudi 表会持续创建文件切片来表示更新的版本 ,从而不可避免地占用更多存储空间。清理服务(Cleaning)正是为此而生:它会删除更早的、无需保留的文件版本,以控制存储成本(见图 6-9)。

(图 6-9 清理过程示意)
清理服务对包含更新或删除 的表最为关键,因为每次修改都会产生受影响数据的一个新版本 。借助清理,我们可以控制历史版本的保留周期 ,在时间旅行/增量处理窗口 与存储成本之间取得平衡。
仅追加(append-only)的表不需要清理服务,因为它们不会产生同一数据的多个版本。对此类表运行清理将是空操作。此外,清理与 TTL(到期删除)也不同:TTL 可能按阈值直接删除整段日期分区 ;而清理服务专门管理并移除已修改记录的过期版本。
调度清理(Schedule Cleaning)
调度清理时,Hudi 采用触发式方式来决定何时需要维护。下面是将清理调度与表维护需求相匹配的配置方法。
内联清理的配置为:
            
            
              ini
              
              
            
          
          hoodie.clean.automatic=true
hoodie.clean.async.enabled=false对 Spark 写入者,这是默认模式;对 Flink ,默认是异步执行模式。
清理通过设置 CleaningTriggerStrategy (当前基于 commit 触发)来开启。可指定每隔多少个 commit评估一次清理。例如设为每 10 次提交评估一次:
            
            
              ini
              
              
            
          
          # 配置清理触发间隔
hoodie.clean.trigger.strategy=NUM_COMMITS
hoodie.clean.trigger.commits=10一旦触发,清理规划器 会扫描相关分区,依据所选 HoodieCleaningPolicy 判定符合清理条件的文件切片。
可按需求在三种清理策略中选择:
基于提交(Commit-based retention)
            
            
              ini
              
              
            
          
          # 保留最近 24 次提交
hoodie.cleaner.policy=KEEP_LATEST_COMMITS
hoodie.cleaner.commits.retained=24适合需要保障长时运行查询可访问历史数据的场景。比如每 30 分钟一次写入、最长查询用时 12 小时,那么至少应保留 24 次提交,确保查询安全窗口。
基于版本(Version-based retention)
            
            
              ini
              
              
            
          
          # 每个文件保留最近 3 个版本
hoodie.cleaner.policy=KEEP_LATEST_FILE_VERSIONS
hoodie.cleaner.fileversions.retained=3当希望与时间无关地固定保留若干最新版本时很有用(如为优化存储只保留最近版本)。
基于时间(Time-based retention)
            
            
              ini
              
              
            
          
          # 保留最近 72 小时内的版本
hoodie.cleaner.policy=KEEP_LATEST_BY_HOURS
hoodie.cleaner.hours.retained=72以数据年龄为准,便于实现简单直接的时间保留策略。
执行清理(Execute Cleaning)
完成清理调度与策略 配置后,执行阶段将实际删除旧文件切片。
- 内联模式 :调度器生成计划后立即执行,仍由同一写作业(Spark/Flink)完成清理;
- 异步执行模式 :写作业提交另一个作业在后台异步执行清理计划;
- 独立模式 :需单独启动作业,使用 Hudi 的工具应用 HoodieCleaner(Spark,当前无 Flink 工具)执行清理计划。更多示例见官方文档。
合理配置清理的调度与执行 参数,可在保证数据可用于相关操作的同时,维持最佳的存储效率。
索引(Indexing)
如第 5 章所述,Hudi 提供多种索引方案,其中元数据表(metadata table)是 Hudi 表内的多模态索引 核心子系统,可同时提升读写性能。
但对于 record index 与 secondary index 这类索引,元数据表中的索引项会随表的记录数 线性增长。因而在大型存量表 上启用这些索引,意味着需要扫描大量文件切片来从零构建索引 ------这既耗时 ,又不允许在索引构建期间中断 写入或查询;相反,读写应在此期间照常运行 ,至多出现性能降级 。此外,索引构建完成时,还必须保证索引与最新写入的数据一致。这些挑战正是**索引表服务(Indexing Table Service)**存在的动机。
索引操作会在数据表时间线 上创建一条 indexing 动作记录;同时在同一事务 中对元数据表 执行一次 deltacommit ,把索引数据写入到相应索引的分区(见图 6-10)。在第 5 章中,我们使用 CREATE INDEX SQL 在元数据表中构建多种索引类型。该命令本质上是以内联模式 运行索引表服务,这需要在索引期间停止所有写入者,容易造成服务中断与业务影响。

(图 6-10 索引流程示意)
因此,索引表服务的主要用法是以独立模式(standalone)运行:让数据持续写入的同时,索引器(indexer)并行构建历史数据的索引。由于写入者在索引器构建历史索引的同时,仍需更新元数据表 中已启用索引的分区,这属于多写入者并发场景,必须配置**锁(lock provider)**来协调并确保事务正确性。
为便于以独立模式运行索引服务,Hudi 提供了 Spark 工具应用 HoodieIndexer ,支持调度 与执行两步。其关键参数包括:
            
            
              css
              
              
            
          
          --mode <schedule or execute>
--index-types <要构建的索引类型>
--props </path/to/indexer/properties/file>- --mode设为- schedule或- execute,分别表示生成计划 或据计划执行;
- --index-types指定要在元数据表中构建的索引类型,如- RECORD_INDEX,可用逗号分隔多个类型;
- --props指向包含 HoodieIndexer 配置的- .properties文件。示例:
            
            
              ini
              
              
            
          
          hoodie.metadata.index.async=true                 # 1 使用独立模式构建索引
hoodie.metadata.index.record.index.enable=true   # 2 启用要构建的索引类型
# 3 多写入者并发配置(锁)
hoodie.write.concurrency.mode=optimistic_concurrency_control
hoodie.write.lock.provider=\
org.apache.hudi.client.transaction.lock.ZookeeperBasedLockProvider
hoodie.write.lock.zookeeper.url=<zk_url>
hoodie.write.lock.zookeeper.port=<zk_port>
hoodie.write.lock.zookeeper.lock_key=<zk_key>
hoodie.write.lock.zookeeper.base_path=<zk_base_path>1:表示采用独立模式进行索引。
2:需将对应索引类型的启用开关同时置为
true。3:以下参数配置多写入者场景所需的锁。
运行索引器时,索引器 与写入作业 应使用相同的锁提供者 ,并且启用相同的索引类型。更多示例请参阅官方文档。
总结
本章强调了维护与优化 Hudi 表对保持数据湖仓高效运行的重要性。就像我们需要定期整理家务一样,也应定期清理与重组 数据表,以确保其始终可访问且性能良好 。为此我们引入了 Hudi 的表服务 ------完成这些工作的关键工具集------包括:压缩(compaction) 、聚类(clustering) 、清理(cleaning)与索引(indexing) 。
我们考察了这些服务可用的多种部署模式 ------内联(inline) 、异步执行(async execution)与独立运行(standalone) ------并讨论了如何在简单易用 与灵活可控之间取得平衡以满足运维需求。各表服务的作用分别是:
- 压缩(Compaction) :通过将 MOR 表中的日志文件与基文件合并为优化后的列式格式,提升读取性能。
- 聚类(Clustering) :重组并排序记录,增强查询性能、降低存储成本。
- 清理(Cleaning) :移除不必要的历史版本以回收存储,同时保留所需的历史数据窗口。
- 索引(Indexing) :在元数据表 中构建索引数据。
贯穿全章,我们回顾了为这些服务制定调度与执行策略 的思路与配置方法,帮助你结合自身工作负载与基础设施进行定制化运维。通过实施这些维护操作,你可以让数据湖仓在当前与未来 都保持可扩展、成本高效、性能优异。