3、环境准备:Hudi 版本选择、Spark/Flink 集成、依赖配置
做增量查询调优,第一步不是调参数,而是先把环境搭对。我见过太多人花了两周调优,最后发现是 Hudi 版本和 Spark 不兼容——白忙一场。这一节,咱们就把地基打牢。
3.1 Hudi 版本怎么选?
Hudi 版本迭代很快,每个版本都有不同的特性。我个人习惯是:不追新,只求稳。选版本时,主要看三点:
- 你的 Spark/Flink 版本——Hudi 对 Spark 3.x 支持最好,Flink 1.13+ 也稳
- 你需要的特性——比如增量查询在 0.9.0 之后才成熟
- 社区活跃度——别选太老的版本,bug 没人修
我推荐几个经过实战检验的组合:
| Hudi 版本 | Spark 版本 | Flink 版本 | 我的评价 |
|---|---|---|---|
| 0.12.x | 3.2.x / 3.3.x | 1.14.x | 最稳,生产首选 |
| 0.13.x | 3.3.x / 3.4.x | 1.15.x / 1.16.x | 新特性多,但注意兼容性 |
| 0.14.x | 3.4.x / 3.5.x | 1.17.x / 1.18.x | 最新,适合尝鲜 |
⚠️ 避坑提醒: 我曾经在生产环境用了 Hudi 0.10.0 + Spark 3.1.2,结果增量查询的
beginInstantTime 参数一直报错。后来发现是 0.10.0 的 bug,升级到 0.10.1 才解决。所以,别用 .0 版本,至少等一个小版本。
3.2 Spark 集成:依赖配置详解
Spark 集成 Hudi,说白了就是把 Hudi 的 jar 包放到 Spark 的 classpath 里。有两种方式:
方式一:启动时指定(推荐)
我习惯用 --packages 或 --jars,这样不影响 Spark 的默认环境。
# 用 --packages(自动下载依赖)
spark-shell \
--packages org.apache.hudi:hudi-spark3.3-bundle_2.12:0.13.1 \
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer \
--conf spark.sql.catalog.spark_catalog=org.apache.spark.sql.hudi.catalog.HoodieCatalog
# 用 --jars(本地已有 jar)
spark-submit \
--jars /path/to/hudi-spark3.3-bundle_2.12-0.13.1.jar \
--class com.example.MyApp my-app.jar
💡 小技巧: 用
--packages 时,Maven 坐标要写对。格式是:org.apache.hudi:hudi-{spark版本}-bundle_{scala版本}:{hudi版本}。比如 Spark 3.3 + Scala 2.12 + Hudi 0.13.1,就是 hudi-spark3.3-bundle_2.12:0.13.1。
方式二:全局配置(生产环境)
如果你管理着集群,可以把 Hudi jar 放到 Spark 的 jars/ 目录下。这样每个任务都能用,不用每次指定。
# 把 jar 复制到所有节点的 Spark 目录
cp hudi-spark3.3-bundle_2.12-0.13.1.jar $SPARK_HOME/jars/
# 在 spark-defaults.conf 里加序列化器
echo "spark.serializer org.apache.spark.serializer.KryoSerializer" >> $SPARK_HOME/conf/spark-defaults.conf
⚠️ 注意: 全局配置虽然方便,但升级 Hudi 版本时要同步更新所有节点。我遇到过只更新了部分节点,结果任务跑着跑着就报
ClassNotFoundException——那叫一个头疼。
3.3 Flink 集成:依赖配置详解
Flink 集成 Hudi 稍微复杂一点。因为 Flink 的 SQL 客户端和 DataStream API 用的依赖不一样。
Flink SQL 客户端
用 SQL 客户端时,我建议把 Hudi 的 jar 放到 lib/ 目录下:
# 下载 Hudi Flink bundle
wget https://repo1.maven.org/maven2/org/apache/hudi/hudi-flink1.16-bundle_2.12/0.13.1/hudi-flink1.16-bundle_2.12-0.13.1.jar
# 复制到 Flink lib 目录
cp hudi-flink1.16-bundle_2.12-0.13.1.jar $FLINK_HOME/lib/
# 启动 SQL 客户端
$FLINK_HOME/bin/sql-client.sh
然后在 SQL 里创建 Hudi 表:
CREATE TABLE hudi_table (
id INT,
name STRING,
ts TIMESTAMP(3),
PRIMARY KEY (id) NOT ENFORCED
) WITH (
'connector' = 'hudi',
'path' = 'hdfs:///user/hudi/table',
'table.type' = 'MERGE_ON_READ',
'read.streaming.enabled' = 'true',
'read.streaming.start-commit' = '20240101000000'
);
Flink DataStream API
用 DataStream API 时,依赖要加在 pom.xml 里:
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-flink1.16-bundle_2.12</artifactId>
<version>0.13.1</version>
</dependency>
💡 我的经验: Flink 的 Hudi connector 在 0.12.0 之后才支持增量读取。如果你用 Flink 做实时增量查询,至少用 0.12.x。我之前用 0.11.x 踩过坑,
read.streaming.enabled 参数根本不生效。
3.4 依赖冲突处理
依赖冲突是集成时最烦人的问题。说白了,就是 Hudi 和 Spark/Flink 用了不同版本的同一类库。
常见的冲突有:
- Jackson:Hudi 用 2.12.x,Spark 可能用 2.10.x
- Avro:Hudi 用 1.11.x,Flink 可能用 1.10.x
- Hadoop:Hudi 用 3.x,你的集群可能用 2.x
我一般这样处理:
- 用 bundle jar——Hudi 官方提供的 bundle 已经 shade 了依赖,冲突最少
- 调整加载顺序——在
spark-defaults.conf里设置spark.driver.userClassPathFirst=true - 排除冲突依赖——用 Maven 的
<exclusions>排除不需要的版本
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-spark3.3-bundle_2.12</artifactId>
<version>0.13.1</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
⚠️ 避坑指南: 我曾经在 Flink 集群上同时跑了多个任务,有的用 Hudi 0.12,有的用 0.13。结果 classloader 打架,任务随机挂。后来统一了版本,世界清净了。一个集群,一个 Hudi 版本,这是铁律。
3.5 环境验证:跑一个增量查询
环境搭好之后,我习惯跑一个简单的增量查询来验证。这样能快速发现配置问题。
// Spark 增量查询验证
val hoodieIncViewDF = spark.read
.format("hudi")
.option(DataSourceReadOptions.QUERY_TYPE.key, DataSourceReadOptions.QUERY_TYPE_INCREMENTAL)
.option(DataSourceReadOptions.BEGIN_INSTANTTIME.key, "20240101000000")
.load("/user/hudi/table")
hoodieIncViewDF.show()
如果能看到数据,说明环境没问题。如果报错,先检查:
- jar 包有没有放对位置
- 序列化器有没有配置
- Hudi 版本和 Spark/Flink 版本是否兼容
💡 我的习惯: 每次搭完环境,我都会在测试表上跑一次全量查询 + 一次增量查询。全量查询验证基础连通性,增量查询验证核心功能。两个都过了,我才放心上线。
3.6 知识体系总览
下面这张图,把环境准备的核心逻辑串起来了。你照着这个思路走,不会乱。