4、Apache Iceberg Catalog: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,最里面才是真正的数据文件。每一层都有独立的版本控制。

Iceberg 表元数据分层结构 元数据文件 (Metadata File) 表结构、分区、快照列表 Manifest List Manifest 文件的索引与统计信息 Manifest 文件 数据文件列表、列统计、分区信息 数据文件 (Parquet / ORC / Avro)

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。这时候,统一管理就成了关键。

我个人习惯的做法是:

  1. 统一命名规范:所有 Catalog 的数据库名、表名遵循同一套规则。
  2. 元数据同步:用工具(比如 Nessie 或自建服务)定期同步不同 Catalog 的元数据。
  3. 权限统一:REST Catalog 可以对接统一的权限服务,Hive Catalog 则依赖 Ranger。