Apache Hudi权威指南——构建端到端的湖仓解决方案

73 阅读42分钟

在已经为生产级湖仓打下运维基础之后,我们就可以在 Hudi 之上构建一个全面、集成的一体化解决方案。本章将展示如何以 Apache Hudi 为基石,搭建一套端到端的生产级数据湖仓架构。我们不再孤立地审视单个组件,而是跟随一份数据从最初摄取一路到分析洞察AI 驱动应用的完整生命周期。

现代数据架构需要:与上游来源的无缝集成、对流批一体(streaming & batch)的统一支持、对多样数据类型的可靠处理,以及同时服务于多种下游消费者(需求各异)。关键不在于“数据完美”,而在于灵活拼装核心能力,在现实世界的数据孤岛与运维挑战中,仍能交付新颖洞察。你需要让数据在组织内“变得容易”,并赋能团队在其之上快速构建。

本章将说明如何在统一湖仓之上组合多种处理框架,优雅地化解这些挑战。Hudi 的多样性既支持这种集成级别,也让你更容易“正确地做事”,兼顾数据一致性、性能与治理

在本章中,我们将构建一套完整的数据平台,使原始数据逐步转化为业务价值。你将学习如何:

  • 使用 Apache Flink 与 Hudi Streamer 处理流式变更,在保持事务保障的同时应对复杂的更新模式。
  • 通过 Hudi Kafka Connect sink 摄取大体量日志数据,高效捕获仅追加事件流(append-only)
  • 借助 SQL 能力完成转换并提取业务洞察,从增量处理交互式分析
  • 将数据用于 AI 应用,为 LLM(大语言模型) 构建上下文知识库以产出业务洞察。

Note
第 8 章讨论过的 Hudi Streamer 也可用于本架构各层的摄取功能。本章额外展示 FlinkKafka Connect,以体现 Hudi 工具链的丰富多样。

你将看到,Hudi 的流式摄取、表存储格式、增量处理与查询优化如何共同支撑一个整洁的数据架构:高效服务多方干系人,同时抑制数据蔓延与处理开销

架构总览(Architecture Overview)

本章以一家虚构公司 RetailMax Corp. 为例,实践性地演示从数据摄取应用 AI 获得业务洞察的数据平台构建。通过该场景,你将看到 Hudi 的特性如何解决促使你翻开本书的那些真实世界问题

图 10-1 展示了我们的架构,它以 Medallion 架构 为蓝本。读完本章,你将获得一套用 Hudi 实现端到端湖仓的蓝图。这里的模式与技术可适配不同行业的多样用例,为组织的数据战略提供灵活基础。

图示:基于 Medallion 的架构图,展示数据从上游来源流经 Bronze、Silver、Gold 各层,并集成 Hudi 表与 AI 工作流。

image.png

图 10-1. 使用 Hudi 工具、组件与集成的 Medallion 架构

RetailMax Corp:一个真实的湖仓场景

RetailMax 经营蒸蒸日上的业务,拥有重要的线上阵地——电商网站与移动应用。当前战略目标聚焦于:提升客户体验、优化运营、推动收入增长。正在推进的一些关键举措包括:

  • 360° 客户视图
    汇总所有触点的客户数据(线上交互、购买、会员计划、门店交易),全面理解客户行为与偏好。
  • 实时个性化
    在网站与 App 上为用户提供个性化商品推荐、优惠与内容。
  • 库存与供应链优化
    跨渠道维持实时且准确的库存可视性,减少缺货/积压,提升履约效率。
  • 欺诈检测
    实时识别并阻断欺诈交易。
  • 自助式分析
    让业务用户(市场、销售、运营)可自助做临时分析与报表,而不过度依赖 IT。

RetailMax 数据很多,而且分散各处

与第 8 章的航空公司类似,RetailMax 同样遭遇数据孤岛问题。它的一些关键关系表保存在“古早但好用”的 PostgreSQL 中,包括:

  • customer_master
    客户画像、人口统计、联系方式。
  • product_catalog
    商品详情(SKU、描述、品类、定价)。
  • sales_transactions
    线上订单与门店 POS 的历史销售数据。

公司还有两个 Kafka topic,代表频繁且近实时变化的对象更新:

  • web_clickstreams
    高吞吐、仅追加的实时用户交互流;包含页面浏览、商品详情页浏览、推荐点击、加购、搜索等。
  • inventory_updates
    来自仓库与门店 POS 的库存变动事件;对及时的库存管理至关重要,且对特定 SKU 可能频繁更新。

表 10-1 总结了 RetailMax 的数据来源及其在基于 Hudi 的湖仓中的计划摄取方式。

表 10-1. RetailMax 的数据源与特性

数据源权威系统(System of record)数据类型/模型摄取方式目标 Hudi 表速度/体量
customer_masterPostgreSQL结构化/可变通过 Debezium/Flink 的 CDChudi_customer_master_bronze中/中
product_catalogPostgreSQL结构化/可变CDC(Debezium/Flink)hudi_product_catalog_bronze低/中
sales_transactionsPostgreSQL结构化/可变CDC(Debezium/Flink)hudi_sales_transactions_bronze中/高
web_clickstreamsApache Kafka半结构化/仅追加Kafka Connecthudi_web_clickstreams_bronze很高/很高
inventory_updatesKafka半结构化/可变Kafka Connect 或 Flinkhudi_inventory_updates_bronze高/高

用 Hudi 实现 Medallion 架构

Medallion 架构是湖仓中常见的数据组织模式:将数据按层次划分为 Bronze / Silver / Gold,以实现结构化与逐步精炼

  • Bronze 层:存放来自源系统的原始、不可变数据,用于审计与重放(reprocessing)。
  • Silver 层:对数据进行清洗、标准化与转换,在强 schema 约束基础质量校验下,形成统一一致视图。
  • Gold 层:存放高度精炼聚合宽表化(denormalized) 的数据,面向 BI/分析/机器学习 的高效查询。

这种分层方法促进数据治理、复用与可扩展性,避免数据湖“沦为数据沼泽(data swamp) ”。

配置 RetailMax 的 Hudi 表

RetailMax 将基于这套湖仓做关键业务决策,因此湖仓必须高度可靠,而这并不容易。事件流与关系型数据库是两类截然不同的系统,在规模与一致性上会引入各种复杂性。为确保从一开始就走在正确道路上,我们需要做出一些配置决策,以便提供相应的保证,并对这些保证有足够把握。

Record Keys(记录键)

每张 Hudi 表都需要一种可靠方式来唯一标识记录。这是其高效更新与删除能力的根基。可以把 record key(第 2 章介绍)视作表在后续所有更新中的“锚点”。

有时锚点很直观:例如在 RetailMax 的 Bronze 客户表(hudi_customer_master_bronze)中,record key 就是 customer_id
有时需要更多工作:在 Bronze 销售表(hudi_sales_transactions_bronze)中,可以将 order_idline_item_id 组合成复合记录键,以粒度精确地跟踪每笔交易。
对于 Bronze 点击流表(hudi_web_clickstreams_bronze),可使用生成的 event_id,或依据上游事件追踪实现,组合 session_id + event_timestamp
若用例本身并未提供合适的唯一键,用户也可以不配置 record key,Hudi 将为每条记录分配一个高压缩性自动生成键

Ordering Field(排序字段)

在流式系统中,同一记录的多个版本时常出现(乱序到达)。这时就需要 ordering field(第 3 章介绍)来决定哪个版本“胜出”

常见选择是 updated_at 时间戳:直观易懂,也便于思考去重与数据新鲜度。它还能防范来自不同区域/可用区的过时变更记录让表状态“倒退”或变得不正确。

分区(Partitioning)

分区(第 2 章介绍)有助于下游查询引擎跳过无关数据,并让大规模数据更易管理。但这是一种平衡艺术:要提升性能,同时避免过度分区导致小文件过多。经验法则:仅当表规模 ≥ 约 250 GB 时再考虑分区。

选择合适的分区策略需要综合查询模式、数据分布与分区管理开销。起步方案可以是:

  • 将 Bronze 销售表(hudi_sales_transactions_bronze)按 order_date(如 year/month/day)分区;
  • 将 Bronze 点击流表(hudi_web_clickstreams_bronze)按 event_date 分区。

该策略契合典型时序查询(如按天分析销售或一段时间内的站点活动),并通过按时间切片来管理数据增长。

表类型(Table Types)

表类型的选择会显著影响湖仓性能(详见第 2 章)。我们将创建多张 Hudi 表,应仔细为每张表选择最合适的类型。

  • Merge-on-Read(MOR) :适合高频更新场景。写入快、更新成本低,且可异步执行 compaction。这对以流式为主的 Bronze 表(如 hudi_web_clickstreams_bronzehudi_inventory_updates_bronze)很有帮助。
  • Copy-on-Write(COW) :适合读多写少场景。写入较贵,但读取快速且省心。非常适合 Gold 表(如 hudi_daily_sales_gold,数据已清洁且不常变更),或更新不频繁的 Silver 表。

表 10-2 给出了 RetailMax 湖仓的Hudi 表设计蓝图,把概念性的 Medallion 分层与具体 Hudi 配置关联起来,便于理解 Hudi 在不同数据精炼阶段的落地方式。

表 10-2. RetailMax 湖仓蓝图

Hudi 表名来源记录键(Record key)排序字段(Ordering field)分区策略(Partitioning)
hudi_customer_master_bronzecustomer_master(Postgres)customer_idupdated_tscountry
hudi_sales_transactions_bronzesales_transactions(Postgres)order_id, line_item_idtransaction_tsdt (YYYY-MM-DD)
hudi_web_clickstreams_bronzeweb_clickstreams(Kafka)event_idevent_tsdt (YYYY-MM-DD)
hudi_inventory_updates_bronzeinventory_updates(Kafka)sku, location_idupdate_tsdt (YYYY-MM-DD)
hudi_unified_customer_orders_silverhudi_sales_transactions_bronze, hudi_customer_master_bronzeorder_id, line_item_idlast_updated_tsorder_dt
hudi_sessionized_clickstreams_silverhudi_web_clickstreams_bronzesession_idsession_end_tssession_dt
hudi_product_daily_inventory_silverhudi_inventory_updates_bronze, hudi_product_catalog_bronzesku, datelast_checked_tsdate
hudi_daily_sales_goldhudi_unified_customer_orders_silverdate, product_category, regionaggregation_tsyear, month
hudi_customer_segments_goldhudi_unified_customer_orders_silver, hudi_customer_master_bronzecustomer_idsegmentation_ts

(注:表中 表示未设置分区或按实际需要再定。)

Bronze 层:接入上游数据

Bronze 层将作为所有原始数据进入 RetailMax 基于 Hudi 的湖仓的初始落地点。其主要目标是以高保真从多样化上游来源采集数据,尽量保留原始结构,同时也要便于下游 Silver 与 Gold 层进行高效的增量处理。核心目标包括:准确采集源系统数据、保留历史归档、并在需要时支持重放/再处理

在 Bronze 层,Hudi 充当高效的落地区(landing zone) 。你既可以利用 schema-on-read 的灵活性,也可以让 Hudi 在写入时强制校验模式(Hudi 支持模式演进,可在两者之间取得良好平衡)。对于 Kafka 事件CDC 流等流式来源,建议使用 MOR 表类型,以降低写放大与写延迟;配合 记录索引(record index)异步 compaction,即便在最严苛的负载模式下也能保持平稳。相反,对于批处理且更新不频繁的来源,COW 可能更简洁、更具性价比。此外,可将 Hudi 配置为为表保存足够的版本历史,以便在出现上游脏数据(如写入了错误值)时支持回滚

搭建上游数据源

RetailMax 的数据生态既包含发生在 PostgreSQL 数据库内的交易型变化,也包含存在于 Kafka 主题中的事件。一些高频变更、支撑关键业务功能的关系表(如 customer_masterproduct_catalogsales_transactions)是结构化运营数据的来源;这些变化需要接近实时地被捕获并传播到湖仓。web_clickstreamsinventory_updates 等主题承载高吞吐、半结构化事件,反映实时业务活动。

很多公司都会同时依赖事件流关系库来驱动关键业务。正如你所想,这两类来源需要不同的接入机制,才能高效落地到 Bronze 层。我们先从事务型数据开始。

通过 Debezium、Flink 与 Hudi 流式接入“可变的、事务型”数据

事务型数据库并不会天然地产生事件流,因此我们需要重建变更时间线,使其与 Kafka 主题站到同一赛道。对 RetailMax 的 PostgreSQL 而言,捕获并流式传递 CDC 事件是让湖仓与运营系统保持同步的关键。

从 PostgreSQL 捕获 CDC

Debezium 是一个开源的分布式 CDC 平台。对 RetailMax 来说,将配置 Debezium 连接器去监控 PostgreSQL 中的 sales_transactionscustomer_masterproduct_catalog 表。Debezium 常驻在数据库旁,读取 WAL(write-ahead logs) ,并在发生插入/更新/删除时捕获行级变更,生成相应的事件流。

这些事件随后被发布到 Kafka 主题,将数据库变更转化为结构化消息流,供下游处理引擎消费。这样即可确保源库的每次修改都被捕捉,使湖仓能保持与运营数据的一致且最新的视图。

用 Flink 处理 CDC 事件

Flink 作为强大的流处理框架,非常适合消费并处理由 Debezium 产出的 CDC 事件流。它提供低延迟处理有状态计算以及丰富的连接器。RetailMax 的 Flink 作业将会:

  • 从 Debezium 写入的 Kafka 主题消费 CDC 事件
  • 在必要时进行轻量转换/清洗:例如将 Debezium 的事件结构映射到 Hudi 目标 schema、处理更新事件的 before/after 结构、或做基本数据类型转换;
  • 将处理后的数据写入 Bronze 层 Hudi 表

Flink 的 Hudi sink 支持设置记录键写操作以及合并策略等 CDC 关键配置。常见示例会展示 Flink 处理 Debezium 数据并下沉到 Hudi。

写入 Bronze 层 Hudi 表

处理后的 CDC 事件会写入诸如 hudi_sales_transactions_bronzehudi_customer_master_bronze 等 Bronze 表。

我们建议对流式 CDC 写入使用 MOR。MOR 通过把变更追加到日志文件(log files) ,并将与列式基文件(base files)的合并推迟到异步 compaction,从而以更低的写放大与延迟优于 COW。

图 10-2 展示了使用 Flink sink 写入 Hudi 表的 CDC 管道。你需要指定若干关键设置:

  • 表类型设为 MERGE_ON_READ(便于高效流式写与异步合并);
  • base path 指明 Hudi 表的存储位置(如 S3 路径 URL);
  • 设置记录键(如销售数据用 order_id)以唯一标识记录;
  • 设定排序字段(如 update_timestamp)来决定记录合并的先后;
  • 通过分区字段(常用交易/事件日期)支持高效查询;
  • 写操作通常设为 upsert,以主键决定插入或更新。

可靠的数据接入离不开精准一次(exactly-once)语义。Flink 通过其checkpointing 机制(周期性快照应用状态与输入位点)实现精确一次;结合 Hudi 的事务性提交协议(每批写入原子地提交到 Hudi 时间线),即可实现端到端的精确一次,保证即使发生故障,每条 CDC 事件也只影响一次 Hudi 表。

image.png

(图 10-2:Flink 驱动的 CDC 接入管线示意)

处理模式演进(Schema Evolution)

源库 schema 随业务演进很少一成不变:会新增字段、类型扩展等。可靠的 CDC 管道必须在不破坏数据流的前提下处理这些变化。Flink 的 CDC 连接器(包括基于 Debezium 的)能够检测上游 schema 变更向下游传播

Hudi 推荐向后兼容的模式演进策略。通过在处理引擎(Spark/Flink)中设置表 schema,并开启写时模式演进(见第 3 章),Hudi 能自动接纳新字段,避免管道故障。这种适配力对保持接入稳定性至关重要,使管道能随着源系统增长变化而持续工作,而无需引入脆弱点或大量手工改造。

使用 Hudi Kafka Connect Sink 接入应用事件流

前文我们已接好了事务型表,现在轮到 RetailMax 的高吞吐实时数据

对来自 Kafka 的应用事件流(如 web_clickstreamsinventory_updates),Hudi Sink Connector for Kafka Connect 提供高效、可扩展的接入路径。这些主题中的事件通常是仅追加(append-only) (如点击流),或基于某个键的更新(如某 SKU 的库存变动)。Hudi Kafka Connect sink 被设计为将这些记录流式写入 Hudi 表

使用 Hudi Sink Connector for Kafka Connect

该 sink 提供一种无需额外处理引擎(如 Spark/Flink)即可把 Kafka 主题直接写入 Hudi 表的直连方式,适用于“简单透传”的场景(见图 10-3)。

关键配置包括:

  • connector.class='org.apache.hudi.connect.HudiSinkConnector'
  • tasks.max 控制并行任务数;
  • topicstopics.regex 指定源主题;
  • target.base.path 指向目标存储位置;
  • target.table.name 指定目标 Hudi 表名(如 hudi_web_clickstreams_bronze)。

大多数流式负载建议使用 MOR;需要定义记录键,选择诸如 event_timestamp 作为排序/合并字段,并设置分区策略

还需注意几个 Kafka 相关设置:

  • hoodie.kafka.control.topic 用于在任务间协调事务
  • hoodie.kafka.commit.interval.secs 控制 sink 向 Hudi 提交的频率(默认 60 秒)。

配置完成后,connector 便可简洁地写入 Bronze 表(如 hudi_web_clickstreams_bronzehudi_inventory_updates_bronze),避免不必要的管道复杂度。

image.png

(图 10-3:基于 Kafka Connect 的接入架构示意)

事务协调与性能

Hudi Kafka Connect sink 的一项重要能力是分布式事务协调机制:源主题的 partition 0 所在任务充当协调者,通过 hoodie.kafka.control.topic 管理跨 worker 的两阶段提交。该设计在保证高吞吐与低延迟的同时,将 Hudi 时间线上的写动作(commit)限制为每个提交间隔仅一次——与“每个 worker 独立提交”相比,这对大流量写入时控制时间线膨胀(小 commit 泛滥)至关重要。

默认使用 MOR 表型:Kafka 记录被直接追加到 Hudi log files,延迟低;随后由异步 compaction/clustering 将其合并为列式基文件。该方式降低了流式直接写列式文件常见的内存压力

在性能调优方面,可结合标准的 Kafka Connect worker 配置与 Kafka producer 覆盖项(如 batch.sizelinger.mscompression.type)来优化吞吐。这些通用配置会影响数据送达 Hudi sink 的方式,进而影响整体接入性能。

Silver 层:构建派生数据集

Silver 层为商业智能(BI)、报表与临时分析提供干净、规范、富化后的数据,是面向业务消费的主要来源。

来自 Bronze 层 的数据会在 Silver 层被转换、清洗、校验并规范化。如图 10-4 所示,这一过程包含:过滤坏数据、处理空值、标准化数据类型与格式、解决数据不一致、以及对不同来源的数据集进行关联以形成一体化视图。Silver 表通常会建模为类似企业数仓中的 维度/事实,适合 BI 报表与临时分析。

image.png

(图 10-4:在 Silver 层中,利用 Spark 与 Hudi Streamer 将 Bronze 层 Hudi 表转换为 Silver 层 Hudi 表,完成清洗、富化与一致化,并通过 ACID 事务保障数据完整性)

该层涉及大量数据处理(如 join、聚合、数据质量约束),因此 Hudi 的增量处理能力是高效更新这些表的关键。选择 MOR 还是 COW 取决于具体表的特性:若 Silver 表由流式 ETL 作业频繁更新且需近实时查询,MOR 可能更合适;若更新不频繁(如每日批处理)且以读为主,COW 可提供更佳读取性能。Hudi 的 ACID 事务可确保转换操作原子落地,同时在同一存储表上无缝统一批与流两种处理模式,保持一致性。

RetailMax 的 Silver 层目标

Silver 层旨在弥合“原始且常常杂乱”的源数据,与“可靠、结构化”的决策数据之间的鸿沟。对 RetailMax 而言,关键目标包括:

  • 数据清洗(Data cleansing)
    处理不一致、缺失值(null)、纠正错误数据、标准化格式(如日期格式、枚举值)。
  • 数据富化(Enrichment)
    跨 Bronze 表进行关联,例如将 hudi_customer_master_bronze 的客户画像与 hudi_sales_transactions_bronze 的交易历史进行整合。
  • 过滤(Filtering)
    去除无关或不符合质量标准的记录。
  • 一致化(Harmonization)
    将不同来源的数据对齐到统一的 schema 或业务定义(如确保线上/线下的商品分类口径一致)。
  • 轻量聚合(Light aggregations)
    例如基于原始 web_clickstreams 生成会话级汇总,或计算每日库存快照。

RetailMax 的一些 Silver 层 Hudi 表示例:

  • hudi_unified_customer_orders_silver
    将线上与门店销售数据与客户、商品信息整合,形成每个订单的全景视图。
  • hudi_sessionized_clickstreams_silver
    从 Bronze 层的原始点击流中识别会话并聚合关键会话指标(浏览页数、会话时长、转化事件等)。
  • hudi_product_daily_inventory_silver
    基于实时的 hudi_inventory_updates_bronze 计算每日各商品在不同地点的库存快照
  • hudi_customer_profiles_silver
    客户画像的富化视图,可包含LTV购买频次等衍生属性。

基于流的转换:使用 Hudi Streamer

鉴于 Bronze 层存在实时/近实时处理需求,RetailMax 可在 Silver 层选择 Hudi Streamer(基于 Spark)Flink 进行接入,两者都支持原生流式写入。RetailMax 基于简便性与原生能力选择 Hudi Streamer(第 8 章已介绍其搭建与用法)。由于 Bronze 表本身是 Hudi 表,Streamer 可配置 HoodieIncrSource:它依据源表时间线,仅从上次 checkpoint 之后的 commit 读取数据,因而可对 hudi_web_clickstreams_bronzehudi_inventory_updates_bronzeMOR 表进行持续增量读取。

借助 Hudi Streamer,RetailMax 可以通过 Transformer 完成多表 join 与富化——例如会话化点击流,或将库存更新与商品元数据/其他维表关联——再将结果写入 Silver 表,如 hudi_sessionized_clickstreams_silverhudi_product_realtime_stock_silver。得益于 Streamer 的 checkpointing 与 Hudi 的事务性 commit,这些管道可以保证一致性

当转换逻辑变得复杂或与场景高度耦合时,可以添加自定义 Transformer,让工程师精细控制流程与复杂业务规则;多个 Transformer 也可串联。例如,RetailMax 可以从页面浏览、停留时长、加购行为中派生近实时的客户参与度特征,并写入 hudi_customer_engagement_silver

在该层,Hudi 的 upsert 语义至关重要。随着新数据不断流入 Bronze 层且既有记录被更新,Streamer 作业增量处理这些变化并同步更新 Silver 表,使下游数据集保持实时新鲜准确

批处理与增量转换:使用 Spark SQL

并非所有转换都需要实时完成。对批处理工作流与批式来源的数据,RetailMax 选择 Spark SQL 作为首选引擎。

Spark SQL 可覆盖多类批式 ETL 场景。例如,RetailMax 可运行夜间作业,将 hudi_customer_master_bronze 与从 hudi_sales_transactions_bronze 聚合的购买数据(以及低频更新的第三方人口统计数据)进行画像富化;或每日聚合生成 hudi_daily_regional_sales_silver汇总表,再把交易数据与相对“慢变”的产品目录参考数据关联。

这些 Spark SQL 作业通常读取 Bronze Hudi 表,应用业务逻辑,然后写入 Silver Hudi 表。对于读为主更新频率低(如每日一次)的 Silver 表,建议采用 COW,可获得更强读性能与更简单的存储布局。

Hudi 的增量处理进一步提升效率:无需每次批处理都扫描整表/整分区,Spark 可以发起增量查询,仅拉取自上次 checkpoint 以来新增或更新的记录。做法是使用表值函数 hudi_table_changes,并指定起始 commit 时间戳。

对 RetailMax 而言,这意味着构建 hudi_daily_sales_silver 的夜间作业仅需处理来自 hudi_sales_transactions_bronze最近 24 小时变更(无需重处理全部销售历史!)。这显著减少扫描数据量、降低计算成本、缩短 ETL 时长,将批处理从“蛮力全量”转变为更精细的增量式工作流。

下面是一个增量 ETL 的 Spark SQL 示例脚本,展示如何从两个 Bronze 表生成 hudi_daily_sales_summary_silver

首先,确定增量处理的起始 commit 时间(通常来自控制表或上次成功运行的结束 commit,如 20250608000000)。对第一份 Bronze 源 hudi_sales_transactions_bronze 发起增量读取:

CREATE OR REPLACE TEMPORARY VIEW incremental_sales_view AS
SELECT
    order_id,
    customer_id,
    product_id,
    quantity,
    price,
    transaction_ts,
    dt AS order_date
FROM
    hudi_table_changes(
        'hudi_sales_transactions_bronze', 'latest_state', '20250608000000');

接着读取客户数据,便于与交易 join

CREATE OR REPLACE TEMPORARY VIEW customer_view AS
SELECT
    customer_id,
    customer_name,
    city
FROM
    hudi_customer_master_bronze;

进行必要的转换与聚合

CREATE OR REPLACE TEMPORARY VIEW daily_sales_aggregated_view AS
SELECT
    s.order_date,
    c.city,
    p.category,
    SUM(s.quantity * s.price) as total_sales_amount,
    COUNT(DISTINCT s.order_id) as total_orders,
    MAX(s.transaction_ts) as last_transaction_ts_in_batch
FROM
    incremental_sales_view s
JOIN
    customer_view c ON s.customer_id = c.customer_id
JOIN
    hudi_product_catalog_bronze p 
      ON s.product_id = p.product_id
GROUP BY
    s.order_date,
    c.city,
    p.category;

最后将结果写入 Silver Hudi 表:

INSERT INTO hudi_daily_sales_summary_silver
-- 若业务逻辑要求可对分区做全量替换,可改用 INSERT OVERWRITE
SELECT
    order_date,
    city,
    category,
    total_sales_amount,
    total_orders
FROM
    daily_sales_aggregated_view;

在 Silver 层维护数据质量与一致性

无论使用 Flink 还是 Spark 做转换,Silver 层的数据质量与一致性都至关重要。RetailMax 可通过 Hudi 的内建保障规范的管道实践来实现:

  1. ACID 事务:每次转换(批或流)都以原子方式落地。若作业中途失败,Hudi 会阻止部分写入被提交,确保 Silver 表始终处于一致、可查询状态。
  2. 校验检查:在每个转换作业中加入校验(数据类型、外键/引用完整性、数值范围等)。不合格记录可标记或隔离,避免污染下游可信资产。
  3. 失败写入的优雅处理:若 commit 未成功,Hudi 会自动回滚;不完整数据不会对读者可见,并会在下次成功写入或后台清理过程中被清除。这种“自愈”机制对 Silver 层长期健康与可信至关重要。

基于上述能力,RetailMax 能保证 Silver 层成为可靠的分析地基干净、一致、随时可用

Gold 层:在 Lakehouse 中查询洞见

RetailMax 的用户(业务分析师、数据科学家与报表工具)需要高效方式来查询在 Silver 层已经整理好的数据。

Gold 层保存高度精炼、聚合、面向业务的数据,正是为此而生。Golden 数据集通常面向具体项目或特定下游应用(如 AI/机器学习模型、高阶分析或管理仪表盘)。Gold 表往往代表关键业务实体或指标,并针对终端用户的易用性与查询性能做过优化。

Gold 层的 Hudi 表以可消费的聚合数据为主,并常按 BI 工具或模型训练的特定读模式进行优化。由于 COW(Copy-on-Write)表把数据存储在列式 base files中、无需在读取时与 log files 合并,读性能更佳,因此 Gold 层(特别是读多写少、每日或每周聚合场景)通常使用 COW。此外,Gold 层的数据模型通常去范式化,并围绕特定业务用例设计。

RetailMax 的 Hudi lakehouse 支持多种查询引擎以满足不同分析需求(见图 10-5)。业务分析师通过 Trino 进行交互式 SQL 与临时分析;数据科学家使用 Spark SQL 做批量分析与复杂转换;自动化应用通过定时报表API 访问数据。该 lakehouse 支持 snapshot、read-optimized、incrementaltime travel 等查询类型,以覆盖组织内的多样化用例。

交互式分析:Trino

Trino 是为数据湖等多源数据提供高速分析查询的分布式 SQL 引擎。对 RetailMax 而言,Trino 是业务分析师的首选:例如从 hudi_customer_profiles_silver 探索客户行为、用 hudi_daily_sales_silver 分析销售趋势、或在 hudi_product_daily_inventory_silver 查看当前库存。

落地时需在协调节点与工作节点配置一个 catalog 属性文件(如 etc/catalog/hudi.properties)。
首先设置 connector.name=hudi 启用 Hudi 连接器;然后通过 hive.metastore.uri 指向 Hive Metastore Service,用于管理表 schema 与分区元数据;按存储后端(如 Amazon S3)补齐相应文件系统配置(如 s3.regions3.endpoint)。

完成上述配置后,Trino 可高效查询 Bronze/Silver/Gold 全层级的 Hudi 表,分析师与下游系统无需额外管道即可访问最新数据。Hudi–Trino 连接器还支持使用**多模态索引(multimodal index)**加速查询,是交互式分析的高性能选择之一。

连接完成后,Trino 用户可用熟悉的 SQL 查询 Hudi 表:

  • COW 表:Trino 直接对最新的 Parquet/ORC base filessnapshot 查询,反映最近一次已提交数据。
  • MOR 表:Trino 以矢量化方式高效合并 base files 与 log files,同样具备良好查询性能。
    若环境支持,还可执行时光回溯(time travel) :在连接器与表版本兼容时,可按指定 commit 时间戳查询历史快照,用于审计、调试或重现实验结果。

批量分析与报表:Spark SQL

虽然 Trino 满足交互查询,Apache Spark SQL 则是 RetailMax 处理复杂转换、支撑定时报表与仪表盘、以及支持数据科学家进行探索分析与特征工程的主力工具。

Spark SQL 能查询 COWMOR 两种表:

  • SELECT * FROM hudi_table 默认执行 snapshot 查询,返回最新视图。对 MOR 表,Spark 会在读时合并 base files 与 log files。
  • 若对数据新鲜度要求不高,可查询 read-optimized 视图,仅读取经压缩合并的 base files,进一步提升性能。

要让 Spark 查询更快,RetailMax 可以依赖多项优化策略:

  • 数据跳读(data skipping) :基于列统计与分区统计(详见第 5 章),Spark 可按谓词中的 min/max 值跳过无关文件,显著减少 I/O。
  • 文件尺寸:保持 base files 足够大、与存储块(通常 128MB–1GB)匹配,避免大量小文件带来的执行开销;Hudi 的写时控尺与**后台聚类(clustering)**有助于维持健康的文件形态。
  • Spark 调优:如 spark.sql.shuffle.partitions、executor 内存与核数等;同时考虑 Hudi 侧元数据缓存、读并行度等设置。
  • 分区与表达式索引:合理分区并构建相关表达式索引,可显著减少扫描量。

综合这些实践,Spark SQL 可在 RetailMax 的分析工作负载中实现可扩展、稳定的性能。

高级查询:Time Travel 与时点分析

在 RetailMax 的日常可靠性保障与长期分析中,Time Travel 十分关键。例如:当排查 hudi_inventory_updates_bronze 的异常时,团队可按历史时间点查询表,精确审计何时发生了什么变化;同理,在调试 ETL 管道时,可对比某个 Silver 表(如 hudi_unified_customer_orders_silver)在失败作业前后两个时间点的状态,定位转换逻辑或数据损坏的来源。

Time Travel 也支撑 ML 运维:当某模型在 Gold 表(如 hudi_customer_segmentation_features_gold)的特征数据上训练时,RetailMax 可以按训练所用的确切 commit 回溯查询,确保实验可复现,即使已过去数月。

分析师还可做时点(Point-in-Time)查询来理解季节性趋势:直接从销售表按不同年份取一致口径的历史切片。如此粒度的历史精确性是 RetailMax 数据平台的重要战略资产。

Hudi 的时间线(timeline)架构让上述查询既可行精准
Spark SQL 中,time travel 可用 TIMESTAMP AS OF 语法,例如:

SELECT * FROM 
hudi_unified_customer_orders_silver
TIMESTAMP AS OF '2023-01-15 10:30:00.000';

该查询返回 hudi_unified_customer_orders_silver2023-01-15 10:30:00.000 的表状态。Spark 也支持更短的时间格式(如 YYYY-MM-DD)或原始 commit 时间戳

Flink SQL 中,time travel 通常被视为基于 commit 标记的**有界(批式)**查询,通过设置选项指明历史视图:

SELECT * FROM hudi_inventory_updates_bronze 
/** OPTIONS('read.end-commit'='20230210120000000') */;

还可配合 read.start-commit 限定变化区间。Flink 将基于精确的 commit 元数据重构表状态。

上述能力的底层支撑来自 Hudi 的时间线:它为每个动作记录对应的 instant time。这份详尽历史是数据可观测性与可复现性的基石——在传统 lakehouse 体系中并不易实现。对 RetailMax 而言,这意味着更好的审计、更清晰的回滚路径,以及在关键“何时发生了什么”的问题上,能自信地给出答案(见图 10-5)。

image.png

(图 10-5:Gold 层中的查询能力示意。业务分析、数据科学与自动化应用所用工具的协作,重点展示 Trino 与 Spark SQL 如何在 Silver/Gold 表上支持多种查询类型。)

业务层:为 RetailMax 提供 AI 驱动的洞见

虽然业务层并不属于官方的 Medallion 架构,但它却是我们必须讨论的一层——也是对业务相关方价值感最强的一层。

业务层直接驱动业务价值,例如 AI 驱动的推荐个性化营销活动,以及提供实时业绩洞察的高管仪表盘。

可以把业务层视为 Gold 层之上的虚拟化层。Gold 表已经将数据转化为高度特定、面向业务的数据集。尽管这些数据集主要供高级分析、AI/机器学习应用高管仪表盘消费,但按我们的经验,每次启用一个新的数据应用,往往仍需要额外的数据工程工作。如果这些带有试验性质的聚合与转换有机会走向生产,那么通过 Hudi 来实现要远胜于把它们放在某位数据科学家的临时 Jupyter 笔记本里。

在 Gold 层为 AI/机器学习准备数据

Gold 层的首要目标,是为 AI/ML 模型训练、推理与其他专项分析任务构建优化过的数据集。这通常包括:

  • 聚合(Aggregations)
    将数据汇总到合适粒度(如:客户日度消费、区域维度的周度商品销量)。
  • 特征工程(Feature engineering)
    从现有数据构造预测特征(如客户的 RFM 分数、产品亲和度分数、用于需求预测的时序滞后与滚动均值)。
  • 去范式化(Denormalization)
    连接多个 Silver 表,生成更**宽扁(wide, flat)**的表,便于机器学习算法消费。
  • 特定格式化(Specific formatting)
    组织成特定 ML 库/平台所需的格式(如推荐系统的用户-物品交互矩阵)。

RetailMax 的 Gold Hudi 表示例:

  • hudi_customer_segmentation_features_gold
    包含 RFM 分数、平均购买金额、偏好品类、人口统计等特征,用于训练客户分群模型。
  • hudi_product_recommendation_user_item_gold
    存储用户-物品交互数据(浏览、购买、评分)或预计算的嵌入,用作协同过滤/内容推荐的输入。
  • hudi_demand_forecasting_ts_gold
    SKU/门店级别的聚合销售时序数据,用于训练需求预测模型。
  • hudi_marketing_campaign_roi_gold
    融合投放成本、客户触达与销售增量,计算各营销活动的 ROI。

这些 Gold 表通常用 Spark SQLFlink SQL 基于 Silver 数据做最后一步转换。为兼顾 ML 框架的读取性能,这些表多配置为 COW(读多写少、每日或每周更新、训练/批量推理读取密集)。

用 Ray 与 Hudi 为 LLM 应用构建知识库

市场部准备上线一个面向内部团队的 LLM AI 助手。用户可以用自然语言提问客户趋势、产品表现或活动效果(例如:“上季度加州 25–35 岁客户最畅销的品类是什么?”)。这需要基于 RetailMax 的数据构建一个专用知识库

为实现规模化,RetailMax 可能使用 Ray(面向 AI 与 Python 应用的分布式计算框架)。通过 ray.data.read_hudi(),团队可将 Gold Hudi 表(如 hudi_customer_segments_goldhudi_product_summaries_gold)的大量数据载入 Ray Datasets。Ray 的并行执行负责预处理、特征提取与必要的文本处理,为下一阶段做准备。

该内部助手的核心是 RAG(Retrieval-Augmented Generation) :把 LLM 的推理能力与对公司经治理的数据实时访问结合起来。它让非技术用户(如市场分析师)用自然语言提出复杂数据问题,并得到有根据、可溯源的回答,而无需编写 SQL 或使用 BI 报表。

构建此类系统的关键步骤:

  1. 数据选择:从 Gold Hudi 表中抽取最相关的结构化/非结构化内容:客户行为聚合、产品描述、销售摘要、用户评价等。
  2. Ray 预处理:清洗并切分数据(尤其是文本)为适合嵌入的小段。
  3. 嵌入生成:将各段数据通过高质量嵌入模型(如 sentence transformer 或 OpenAI embeddings)转换为稠密向量
  4. 向量库入库:将嵌入与元数据(来源 Hudi 表、主键等)存入向量数据库(FAISS、Milvus、Pinecone 等)。体系中包含一个 “context builder” ,从 Gold 表读取并填充推理阶段使用的知识库。

该助手的可靠性与准确性,取决于输入数据质量。Hudi 在此提供坚实基础:Gold 层不仅新鲜、一致,还能通过时光回溯增量处理实现审计与可复现性。这让 RetailMax 拥有一套可信、动态的知识库,而不是依赖脆弱且陈旧的临时 RAG 管道。

以下是 AI/RAG 工作流的幕后过程:
当有人提问“对比最近一个月会员与非会员的平均消费”时,系统先用与知识库构建阶段相同的嵌入模型对查询生成向量,这个向量就像问题语义的指纹
随后用该“指纹”在向量库中检索最相似的上下文切片——它们来自 Gold Hudi 表的小而有意义的片段(例如近期销售摘要、会员指标、客户分群统计)。
检索到的内容与原始问题拼接,形成增强后的提示(prompt),并以模板规范化格式,引导 LLM 正确理解与引用数据。
最后在生成阶段,把增强后的提示发给 LLM(如 GPT-5 或 Llama),产出既流畅又“有据可依”的回答。

这种 RAG 驱动的管道(见图 10-6)为 RetailMax 提供了快速、直观的洞察层,降低了决策摩擦。它打通了结构化数据与自然语言之间的通道,使团队可以随问随答问得更好、答得更准

image.png

(图 10-6:业务层中的 AI 工作流示意——从 Gold Hudi 表到 AI 助手洞见的全流程。)

让 Hudi Lakehouse 落地并持续优化(Operationalizing and Optimizing the Hudi Lakehouse)

搭建最初的数据摄取管道转换作业AI 应用只是 lakehouse 之旅的开始。要让 RetailMax 的 lakehouse 在长期内保持可靠、高性能且具性价比,接下来是一段持续优化的征途:不仅要做数据工程,还要在时间维度上管理性能、成本与表健康度

这项工作的核心是第 6 章深入介绍过的 Hudi 后台表服务(table services) 。必须针对不断变化的工作负载进行调优与调度。这些服务还能以不同模式部署(内联 inline异步 async独立 standalone),以便根据时延与吞吐要求做出适配。

RetailMax 将依赖 compaction(压缩合并)clustering(聚类/重写布局)cleaning(清理) 来维持各层稳定高效。例如:

  • Compaction(压缩合并)
    为写入压力大的 MOR 表(如 hudi_sales_transactions_bronzehudi_web_clickstreams_bronze)保障快速读取。通过将 delta 日志合并为 Parquet 基础文件,在不压垮查询引擎的前提下持续提供新鲜数据。可用异步、按“新增提交数”触发等策略,在摄取吞吐读性能间取得平衡。
  • Clustering(聚类/布局优化)
    改善 Silver/Gold 表(如 hudi_unified_customer_orders_silverhudi_customer_segments_gold)的查询性能,为产品分析与机器学习工作流赋能。RetailMax 可用异步 clustering 与基于 Spark 的策略,按常用过滤列排序并减少小文件问题。
  • Cleaning(清理)
    通过移除不再需要的旧版本文件,控制存储成本与元数据开销。需要与合规与调试所需的“历史保留”平衡,避免存储膨胀。

每个服务都高度可配置,工程团队可据数据新鲜度/读取时延/成本效率等目标,为摄取、转换、报表等各层量身调优

并发控制与多写入者场景

随着 RetailMax 的 lakehouse 成熟,可能出现多个进程并发写同一张 Hudi 表的场景。例如:

  • 一个 Hudi Streamer 实时更新 Silver 表,同时一个每晚的 Spark 批处理任务向同一表追加更正或富化数据。
  • 摄取写入者与**异步表服务(如 compaction 或 clustering)**同时作用于同一张表。

正如第 7 章所述,Hudi 提供了相应的并发控制机制来管理这类情形。

Lakehouse 监控

有效的监控对维持 RetailMax 的 Hudi lakehouse 的健康与性能至关重要。

如第 9 章所述,Hudi 可与 AWS CloudWatchDatadogPrometheus 等多种系统集成,覆盖的关键指标包括:提交延迟与时长插入/更新/删除记录数compaction/clustering 积压、时长与效率文件大小与数量索引查找性能时间线活动等。建议将这些指标汇入 Prometheus 并用 Grafana 仪表盘可视化,从而掌握表与摄取/转换流水线的运行态势。还应为关键异常配置告警,例如:Hudi 提交失败compaction/clustering 积压过大小文件数量快速上升存储磁盘空间告急摄取作业错误率升高等。

数据韧性(Data Resilience)

在发生数据损坏误删系统故障时保障业务连续性至关重要。Hudi 提供了有助于提交回滚与增强数据韧性的能力(见第 9 章):

  • Savepoint(保存点)
    在 Hudi 时间线为某个提交打上“保留”标记。Cleaner 不会删除与该保存点提交及其之前提交相关的任何数据文件。等同于在该时间点创建了可恢复的表状态。RetailMax 应基于 RPO(恢复点目标)为关键表(如 hudi_unified_customer_orders_silver 及关键 Gold 表)定期创建保存点。既可通过 Spark SQL(CALL create_savepoint('table_name','commit_timestamp'))也可用 Hudi CLI/Utilities 创建。
  • Restore(恢复)
    将 Hudi 表恢复到先前创建的保存点。此操作具“破坏性”:会回滚保存点之后的所有更改。恢复期间应暂停对该表的所有写入。这是从逻辑数据损坏或重大错误中恢复的有力手段。

通过切实落实这些运维实践,RetailMax 能让其 Hudi lakehouse 持续保持高性能、可靠、安全且具韧性,为各类数据驱动举措保驾护航。

性能基准与注意事项

尽管本章聚焦端到端方案构建,但必须承认任何 lakehouse 的性能都至关重要。Hudi 在多种场景下进行了评估,包括与 Apache IcebergDelta Lake 的对比,以及 TPC-DS 等行业标准基准。

这些基准通常衡量:数据装载时长一系列分析查询的执行速度、以及合并类操作(更新/删除)的性能。结果常常取决于具体工作负载(读多/写多、批/流)、表类型(COW/MOR) 、配置选择与查询引擎集成成熟度。例如,TPC-DS 的结果显示:MOR 在合并(merge)方面可能快于 COW,但若compaction 不够积极,查询性能可能下降。装载性能也会受影响:Hudi 侧重键控 upsert 与摄取时的预处理,初次装载可能不如纯追加优化的格式快,但其优势会在后续的增量更新中体现。

与其执着于某一组基准数字,RetailMax 更应聚焦下列直接影响性能的架构特性与调优策略

  • 写入侧索引(Indexing for writes)
    索引是规模化下维持读写性能的基石。Hudi 支持多种写入索引(第 5 章详述),如 record、bucket、simple、bloom,用于快速定位需更新的文件组,避免全表扫描。
  • 读取侧索引(Indexing for reads)
    借助 metadata table 维护的列统计/分区统计,查询引擎可按谓词跳过不相关的文件/分区,显著减少 I/O。启用 record indexsecondary indexexpression index 还能进一步加速等值或多样谓词查询,释放 Hudi 多模态索引的威力。
  • 文件尺寸(File sizing)
    调整 hoodie.parquet.small.file.limithoodie.parquet.max.file.size 并结合 clustering,避免小文件问题。
  • 表服务(Table services)
    异步 compaction 与 clustering 持续优化 MOR/COW 表的物理布局,减少小文件,确保数据增长下查询不降速。
  • 增量查询(Incremental queries)
    Hudi 支持基于 delta 的查询。下游作业只需处理自上次运行以来的变化,而非重扫全量。

下表总结了影响性能的 Hudi 特性及其在 RetailMax 的关键用例:

表 10-3. 影响 RetailMax Lakehouse 性能的 Hudi 特性与适用场景

Hudi 特性写入时延更新/删除速度快照查询速度(Trino/Spark)增量查询速度(ETL)RetailMax 关键用例
MOR 表型低(日志追加)高(高效处理频繁小更新)中(需合并 base+log 或读 _ro 视图)高(可从日志导出变更)流式 CDC(hudi_sales_transactions_bronze)、Kafka 事件(hudi_web_clickstreams_bronze
COW 表型高(更新需重写)低(写放大)高(直接读列式 base 文件)中(需比对快照差异)Gold(hudi_daily_sales_gold)、更新不频繁的 Silver
写入侧索引(bloom/bucket 等)提升 upsert 定位速度关键间接(通过提升写入)N/A需 upsert/删除的表,尤其 hudi_customer_master_bronzehudi_inventory_updates_bronze
Metadata table & 数据跳过对写入有轻微开销轻微很高(减少计划与扫描)中(有助定位变更分区)频繁被查询的 Silver/Gold,加速 Trino/Spark 查询
多模态索引加速高(record index 加速记录级更新)高(显著减少扫描量)N/ABronze/Silver 快速写入与 Gold 快速查询
异步 compaction(MOR)将 compaction 与摄取解耦,保持低时延N/A提升 _ro 新鲜度与性能N/A维护所有 MOR 表的查询性能、防止日志堆积
异步 clustering(COW/MOR)与摄取解耦N/A高(优化文件大小/排序)N/A查询密集的 Silver/Gold,如 hudi_unified_customer_orders_silver
增量查询N/AN/AN/A很高(只处理变化数据)Bronze→Silver、Silver→Gold 的 ETL 作业显著降本提效
优化文件尺寸合并小文件会略增写延迟通过减少大量小文件的元数据开销而提升高(更少文件、更少任务)中(更少文件需检查)所有表,避免小文件并提高查询引擎扫描效率

小结

本章贯穿了一个贴近真实复杂度的公司——RetailMax Corp. ——构建现代数据 lakehouse 的完整生命周期。Hudi 作为骨干,覆盖从摄取转换查询AI 洞见Bronze/Silver/Gold 各层。

  • 摄取层,Hudi 同时支持 Flink + Debezium 的流式 CDCKafka Connect 的高吞吐事件处理Schema 演进事务一致性端到端 exactly-once 确保管道可靠、面向未来。
  • 转换层FlinkSpark SQL 各擅胜场:前者驱动近实时整形,后者支撑批量与增量 ETL;Hudi 的增量查询让 ETL 从“重扫全量”变为“按变更处理”。
  • 查询层,分析师用 Trino 做交互式洞察,数据科学用 Spark SQL 做深度批量分析。Metadata table可插拔索引时光回溯强化性能与可观测性。
  • Gold 层,经治理的数据为 AI/ML 供能。RetailMax 借助 Ray 从 Hudi 构建 LLM 就绪的知识库,打造 RAG 系统,为自然语言问题提供有据可依的答案。

贯穿其中的 Hudi 核心能力包括:
ACID 事务记录级更新/删除Schema 演进表服务广泛的引擎集成、以及增量处理

对正在启航的读者,基于 RetailMax 的经验有以下要点:

  1. 理解你的数据:分析数据源、访问模式、更新频率,明智选择 COW vs MOR、record key、ordering field、分区策略。
  2. 拥抱 Medallion:以 Bronze→Silver→Gold 的层次渐进提升数据质量,并为特定用例定制数据集。
  3. 运营化表服务:自动化 compaction/clustering/cleaning;这不是“善后”,而是健康、高性能 Hudi 的关键部件
  4. 用好 Hudi 生态:结合 Flink/Kafka Connect/Spark 的摄取与处理,以及查询引擎,搭建一体化数据平台
  5. 从第一天就关注性能:文件尺寸最佳实践、metadata table + 索引、以及增量式思维,确保随规模增长仍可高效扩展。

以 Hudi 为代表的 lakehouse 范式,提供了统一管理多样数据与工作负载的现代路径,打破数据孤岛,释放数据资产的全部潜能。随着 Hudi 在性能、可扩展性、易用性上的持续创新,它将愈发成为现代数据架构的基石。本章的方法与范式,为你用 Hudi 构建强大而灵活的端到端解决方案提供了可靠蓝本