4、环境搭建:Spark + Iceberg + Hive Metastore + MinIO 本地开发环境部署、Catalog配置详解
说实话,很多初学者在 Iceberg 上栽跟头,不是因为概念多难,而是环境没搭对。我自己早期也踩过不少坑——明明代码逻辑没问题,就是连不上 Catalog,或者写入时报错找不到文件。所以这一章,咱们把环境彻底捋清楚。
我会带你从零搭建一套完整的本地开发环境:Spark + Iceberg + Hive Metastore + MinIO。这套组合是目前生产中最常见的轻量级方案之一。你跟着走一遍,后面所有章节的实操都能跑起来。
4.1 整体架构概览
先看一张图,搞清楚每个组件的位置和作用。
说白了,Spark 是计算引擎,Iceberg 是表格式,Hive Metastore 管元数据,MinIO 存数据文件。我习惯把 Hive Metastore 比作「通讯录」——它不存数据本身,只记录表在哪儿、有哪些文件。
4.2 组件版本选择
版本选不对,后面全是坑。我列一个经过验证的版本组合,你照着来就行。
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| Apache Spark | 3.4.x | Iceberg 1.4.x 对 Spark 3.4 支持最好 |
| Apache Iceberg | 1.4.3 | 稳定版,功能完整 |
| Hive Metastore | 3.1.3 | 独立部署,不需要 Hive Server |
| MinIO | RELEASE.2024-01-16 | 最新稳定版即可 |
| Hadoop | 3.3.6 | Hive Metastore 依赖 |
我的建议:不要追最新版。Iceberg 1.5.x 虽然新,但有些 API 变了,社区文档还没跟上。1.4.3 足够你学完整个课程。
4.3 MinIO 部署与配置
MinIO 是兼容 S3 协议的对象存储。本地开发用它模拟 AWS S3,完全免费。
4.3.1 启动 MinIO
用 Docker 启动最简单:
docker run -d \
--name minio \
-p 9000:9000 \
-p 9001:9001 \
-e MINIO_ROOT_USER=admin \
-e MINIO_ROOT_PASSWORD=admin123 \
-v /data/minio:/data \
minio/minio:RELEASE.2024-01-16T22-44-24Z \
server /data --console-address ":9001"
启动后访问 http://localhost:9001,用 admin/admin123 登录。创建一个 bucket,名字叫 iceberg-warehouse。
注意:生产环境别用 admin/admin123。本地开发无所谓,但养成好习惯——用复杂密码。
4.3.2 生成 Access Key
在 MinIO Console 的「Access Keys」页面创建一个 key。记下 access_key 和 secret_key,后面配置要用。
4.4 Hive Metastore 部署
Hive Metastore 是整个架构的「元数据中心」。Iceberg 通过它来管理表结构、分区信息、快照等。
4.4.1 下载与配置
我建议用 Apache Hive 3.1.3 的 standalone metastore 包:
wget https://downloads.apache.org/hive/hive-3.1.3/apache-hive-3.1.3-bin.tar.gz
tar -xzf apache-hive-3.1.3-bin.tar.gz
cd apache-hive-3.1.3-bin
编辑 conf/hive-site.xml:
<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:derby:;databaseName=/data/metastore_db;create=true</value>
</property>
<property>
<name>metastore.warehouse.dir</name>
<value>s3a://iceberg-warehouse/</value>
</property>
<property>
<name>fs.s3a.access.key</name>
<value>你的access_key</value>
</property>
<property>
<name>fs.s3a.secret.key</name>
<value>你的secret_key</value>
</property>
<property>
<name>fs.s3a.endpoint</name>
<value>http://localhost:9000</value>
</property>
<property>
<name>fs.s3a.path.style.access</name>
<value>true</value>
</property>
</configuration>
关键点:metastore.warehouse.dir 要指向 MinIO 的 bucket 路径。格式是 s3a://bucket-name/,不是 s3://。Hadoop 的 S3A 文件系统才能识别。
4.4.2 初始化与启动
# 初始化 Derby 数据库
bin/schematool -initSchema -dbType derby
# 启动 Metastore 服务
bin/hive --service metastore &
默认监听 localhost:9083。用 netstat -an | grep 9083 确认一下。
嗯,这里要注意:Derby 是单用户数据库,只适合本地开发。生产环境请换成 MySQL 或 PostgreSQL。
4.5 Spark + Iceberg 集成
这是最核心的一步。Spark 需要加载 Iceberg 的依赖包,并配置 Catalog。
4.5.1 下载 Iceberg Spark Runtime
我习惯把 jar 包放在 Spark 的 jars/ 目录下:
wget https://repo1.maven.org/maven2/org/apache/iceberg/iceberg-spark-runtime-3.4_2.12/1.4.3/iceberg-spark-runtime-3.4_2.12-1.4.3.jar
cp iceberg-spark-runtime-3.4_2.12-1.4.3.jar $SPARK_HOME/jars/
还需要 Hadoop S3A 的依赖:
wget https://repo1.maven.org/maven2/org/apache/hadoop/hadoop-aws/3.3.6/hadoop-aws-3.3.6.jar
cp hadoop-aws-3.3.6.jar $SPARK_HOME/jars/
4.5.2 启动 Spark Shell 验证
启动时指定 Catalog 配置:
$SPARK_HOME/bin/spark-shell \
--conf spark.sql.catalog.my_catalog=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog.type=hive \
--conf spark.sql.catalog.my_catalog.uri=thrift://localhost:9083 \
--conf spark.sql.catalog.my_catalog.warehouse=s3a://iceberg-warehouse/ \
--conf spark.sql.catalog.my_catalog.io-impl=org.apache.iceberg.aws.s3.S3FileIO \
--conf spark.hadoop.fs.s3a.access.key=你的access_key \
--conf spark.hadoop.fs.s3a.secret.key=你的secret_key \
--conf spark.hadoop.fs.s3a.endpoint=http://localhost:9000 \
--conf spark.hadoop.fs.s3a.path.style.access=true
进入 Spark Shell 后,执行:
spark.sql("CREATE DATABASE IF NOT EXISTS my_catalog.my_db")
spark.sql("USE my_catalog.my_db")
spark.sql("CREATE TABLE IF NOT EXISTS test (id INT, name STRING) USING iceberg")
spark.sql("INSERT INTO test VALUES (1, 'Alice'), (2, 'Bob')")
spark.sql("SELECT * FROM test").show()
如果能看到数据,说明环境通了。
避坑指南:我曾经因为 io-impl 没配,导致写入时报 FileNotFoundException。Iceberg 默认用 HDFS 的 FileIO,连 MinIO 必须显式指定 S3FileIO。
4.6 Catalog 配置详解
Catalog 是 Iceberg 的「入口」。它决定了表元数据存在哪里、怎么查。Iceberg 支持多种 Catalog 类型,咱们重点讲三种。
| Catalog 类型 | 元数据存储 | 适用场景 |
|---|---|---|
| hive | Hive Metastore | 生产最常用,与 Hive 生态兼容 |
| hadoop | 文件系统(HDFS/S3) | 轻量级,不需要 Hive Metastore |
| rest | REST 服务 | 多引擎共享,云原生场景 |
4.6.1 Hive Catalog 配置
刚才咱们用的就是 Hive Catalog。核心参数:
type=hive:指定 Catalog 类型uri=thrift://localhost:9083:Hive Metastore 地址warehouse=s3a://iceberg-warehouse/:数据文件存储路径io-impl=org.apache.iceberg.aws.s3.S3FileIO:文件 IO 实现
我的经验:Hive Catalog 的 uri 一定要写 thrift:// 前缀。我见过有人只写了 localhost:9083,结果一直连不上。
4.6.2 Hadoop Catalog 配置
如果你不想部署 Hive Metastore,可以用 Hadoop Catalog。元数据直接以文件形式存在 S3 上:
--conf spark.sql.catalog.my_catalog=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog.type=hadoop \
--conf spark.sql.catalog.my_catalog.warehouse=s3a://iceberg-warehouse/ \
--conf spark.sql.catalog.my_catalog.io-impl=org.apache.iceberg.aws.s3.S3FileIO
说白了,Hadoop Catalog 就是「无中心化」的方案。适合单机测试或小团队使用。但多引擎并发操作时,容易产生元数据冲突。
4.6.3 REST Catalog 配置
REST Catalog 是 Iceberg 社区主推的云原生方案。它通过 REST API 统一管理元数据,Spark、Flink、Trino 都能连同一个 Catalog 服务。
--conf spark.sql.catalog.my_catalog=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog.type=rest \
--conf spark.sql.catalog.my_catalog.uri=http://localhost:8080/iceberg/ \
--conf spark.sql.catalog.my_catalog.warehouse=s3a://iceberg-warehouse/ \
--conf spark.sql.catalog.my_catalog.io-impl=org.apache.iceberg.aws.s3.S3FileIO
注意:REST Catalog 需要额外部署 Iceberg REST Server。咱们课程后面会专门讲。本地开发阶段,用 Hive Catalog 就够了。
4.7 验证环境完整性
环境搭完,我习惯跑一套完整的「冒烟测试」:
- 创建表并写入数据
- 查询数据
- 执行一次快照查询(time travel)
- 检查 MinIO 上是否有数据文件
在 Spark Shell 里执行:
// 1. 创建表
spark.sql("CREATE TABLE my_catalog.my_db.orders (order_id INT, amount DOUBLE, ts TIMESTAMP) USING iceberg PARTITIONED BY (days(ts))")
// 2. 写入数据
spark.sql("INSERT INTO my_catalog.my_db.orders VALUES (1, 100.0, current_timestamp()), (2, 200.0, current_timestamp())")
// 3. 查询
spark.sql("SELECT * FROM my_catalog.my_db.orders").show()
// 4. 查看快照
spark.sql("SELECT * FROM my_catalog.my_db.orders.snapshots").show()
然后去 MinIO Console 看看 iceberg-warehouse bucket 下有没有生成 my_db/orders 目录。如果有 metadata 和 data 子目录,说明一切正常。
一个小技巧:如果写入后查不到数据,先检查 Spark 日志里有没有 S3FileIO 相关的报错。八成是 S3A 配置不对。
4.8 常见问题与排查
我把这些年遇到的环境问题整理了一下:
| 现象 | 原因 | 解决 |
|---|---|---|
| 连不上 Hive Metastore | 端口没开或 thrift 协议不对 | 检查 thrift:// 前缀和 9083 端口 |
| 写入报 FileNotFoundException | 没有指定 S3FileIO |
添加 io-impl 配置 |
| 查询返回空结果 | Catalog 没切换或表不存在 | 用 USE my_catalog.my_db 切换 |
| MinIO 上没数据 | warehouse 路径配置错误 | 检查 s3a:// 格式和 bucket 名称 |
嗯,环境搭建这部分确实琐碎,但它是后面所有实操的基础。你花半小时把环境跑通,后面学起来会顺畅很多。