4. Apache Iceberg Catalog
好,我们进入第四章。这一章我打算把 Iceberg 的 Catalog 彻底讲透。你想想看,一个数据湖仓里,表元数据存在哪、怎么查、怎么管,全靠 Catalog 撑着。我见过不少团队,Iceberg 用得很溜,但一换 Catalog 就翻车——说白了,就是对 Catalog 的理解还停留在“存个路径”的层面。
4.1 Iceberg 核心概念:表、快照与 Manifest
在动手操作之前,我们先理清几个关键概念。Iceberg 的表结构,跟传统 Hive 表完全不一样。
- 表(Table):逻辑上的数据集合,由元数据和数据文件组成。
- 快照(Snapshot):表在某个时间点的完整视图。每次写入、删除、合并,都会生成一个新快照。
- Manifest 文件:记录数据文件的列表。每个快照对应一组 Manifest。
- Manifest List:Manifest 文件的索引,加速快照读取。
- 元数据文件(Metadata File):存储表结构、分区信息、快照历史等。
核心理解:Iceberg 的元数据是自描述的。你不需要依赖外部 Metastore 来理解表结构——元数据文件本身就能告诉你一切。这也是 Iceberg 能实现“表格式独立”的根本原因。
我个人习惯把 Iceberg 的表想象成一个“洋葱”:最外层是元数据文件,剥开是 Manifest List,再往里是 Manifest,最里面才是真正的数据文件。每一层都有独立的版本控制。
4.2 Catalog 类型:Hive、Hadoop、REST
Iceberg 支持多种 Catalog 实现。每种都有它的适用场景。我按使用频率来介绍。
4.2.1 Hive Catalog
这是最传统的方式。元数据存储在 Hive Metastore 中。Iceberg 表在 Hive 里看起来就像一张普通表。
- 优点:与 Hive 生态无缝集成,HiveQL、Spark SQL、Presto 都能直接查。
- 缺点:依赖 Hive Metastore,扩展性受限于 Metastore 的性能。
- 适用场景:已有 Hive 数仓的团队,希望平滑迁移到 Iceberg。
我的经验:如果你公司已经有 Hive Metastore 在跑,用 Hive Catalog 是最省事的。但要注意,Metastore 的并发能力有限——我曾经遇到过一个场景,几百个并发写入直接把 Metastore 打挂了。后来我们加了读写分离才解决。
4.2.2 Hadoop Catalog
元数据直接以文件形式存储在 HDFS 或 S3 上。没有外部依赖。
- 优点:轻量、无外部依赖,适合测试和开发环境。
- 缺点:没有事务支持,多个客户端同时操作可能冲突。
- 适用场景:单机测试、临时分析、不需要高并发的场景。
避坑指南:千万不要在生产环境用 Hadoop Catalog 做多并发写入。我曾经见过一个团队,用 Hadoop Catalog 跑批处理,结果两个作业同时写同一个表,直接把元数据文件搞坏了。恢复起来非常痛苦。
4.2.3 REST Catalog
这是 Iceberg 社区推荐的现代方式。通过 REST API 与元数据服务交互。
- 优点:无状态、可水平扩展、支持多语言客户端、支持细粒度权限控制。
- 缺点:需要额外部署 REST 服务。
- 适用场景:云原生环境、多引擎共享、需要统一权限管理的团队。
我个人最推荐 REST Catalog。为什么?因为它把元数据操作抽象成了 HTTP 接口,任何语言、任何引擎都能接入。你想想看,Spark 写、Flink 读、Trino 查,全都走同一个 REST 服务,元数据一致性天然保证。
| 特性 | Hive Catalog | Hadoop Catalog | REST Catalog |
|---|---|---|---|
| 元数据存储 | Hive Metastore | 文件系统 | REST 服务 |
| 事务支持 | 有限 | 无 | 完整 |
| 扩展性 | 中等 | 低 | 高 |
| 多引擎支持 | 好 | 一般 | 优秀 |
| 部署复杂度 | 低 | 最低 | 中等 |
4.3 表管理操作:创建、查询、修改与删除
我们以 Spark 为例,演示常见的表管理操作。嗯,这里要注意,不同引擎的语法略有差异,但核心概念是一样的。
4.3.1 创建表
-- 使用 Hive Catalog
CREATE TABLE hive_catalog.db1.sales (
id BIGINT,
product STRING,
amount DOUBLE,
sale_date DATE
)
USING iceberg
PARTITIONED BY (sale_date);
-- 使用 Hadoop Catalog
CREATE TABLE hadoop_catalog.db1.sales (
id BIGINT,
product STRING,
amount DOUBLE,
sale_date DATE
)
USING iceberg
PARTITIONED BY (sale_date)
LOCATION 'hdfs://namenode:8020/warehouse/sales';
-- 使用 REST Catalog
CREATE TABLE rest_catalog.db1.sales (
id BIGINT,
product STRING,
amount DOUBLE,
sale_date DATE
)
USING iceberg
PARTITIONED BY (sale_date);
4.3.2 查询快照历史
Iceberg 最强大的特性之一就是时间旅行。你可以查看表的所有历史快照。
-- 查看快照历史
SELECT * FROM rest_catalog.db1.sales.snapshots;
-- 结果示例
+------------------------+---------------------+---------------------+
| snapshot_id | committed_at | parent_id |
+------------------------+---------------------+---------------------+
| 1234567890123456789 | 2024-01-15 10:00:00 | NULL |
| 1234567890123456790 | 2024-01-15 11:00:00 | 1234567890123456789 |
| 1234567890123456791 | 2024-01-15 12:00:00 | 1234567890123456790 |
+------------------------+---------------------+---------------------+
4.3.3 时间旅行查询
-- 按快照 ID 查询
SELECT * FROM rest_catalog.db1.sales
FOR SYSTEM_VERSION AS OF 1234567890123456789;
-- 按时间戳查询
SELECT * FROM rest_catalog.db1.sales
FOR SYSTEM_TIME AS OF '2024-01-15 10:30:00';
实用技巧:时间旅行不是无限保留的。Iceberg 默认只保留最近 7 天的快照。你可以通过 write.metadata.delete-after-commit.enabled 和 write.metadata.previous-versions-max 来控制保留策略。
4.3.4 修改表结构
-- 添加列
ALTER TABLE rest_catalog.db1.sales
ADD COLUMN category STRING;
-- 重命名列
ALTER TABLE rest_catalog.db1.sales
RENAME COLUMN product TO product_name;
-- 修改列类型
ALTER TABLE rest_catalog.db1.sales
ALTER COLUMN amount TYPE DECIMAL(10,2);
4.3.5 删除表与清理
-- 删除表(元数据 + 数据文件)
DROP TABLE rest_catalog.db1.sales;
-- 仅删除元数据,保留数据文件
DROP TABLE rest_catalog.db1.sales PURGE;
-- 清理过期快照
CALL rest_catalog.system.expire_snapshots(
table => 'db1.sales',
older_than => TIMESTAMP '2024-01-01 00:00:00'
);
注意:DROP TABLE 默认会删除数据文件。如果你只是想清理元数据,记得加上 PURGE 参数。我曾经在测试环境误删过一张生产表,还好 Iceberg 的快照机制让我们从备份中恢复了——但过程非常痛苦。
4.4 多 Catalog 整合的思考
在实际项目中,你很可能同时使用多种 Catalog。比如,历史数据在 Hive Catalog 里,实时数据在 REST Catalog 里,临时分析用 Hadoop Catalog。这时候,统一管理就成了关键。
我个人习惯的做法是:
- 统一命名规范:所有 Catalog 的数据库名、表名遵循同一套规则。
- 元数据同步:用工具(比如 Nessie 或自建服务)定期同步不同 Catalog 的元数据。
- 权限统一:REST Catalog 可以对接统一的权限服务,Hive Catalog 则依赖 Ranger。