跳到主要内容

Apache Iceberg

问题

什么是 Apache Iceberg?为什么它是目前最流行的数据湖表格式?

答案

Iceberg 核心特性

Apache Iceberg 是 Netflix 开源的开放表格式,在 Parquet/ORC 文件之上增加元数据层,提供数据仓库级别的能力。

特性说明
ACID 事务快照隔离,并发读写安全
时间旅行查询任意历史版本
Schema 演进添加/删除/重命名/重排列,不影响历史数据
分区演进修改分区策略无需重写数据
隐藏分区用户无需知道分区结构

架构

三层元数据
  1. Metadata File:记录所有快照、Schema 历史、分区规范
  2. Manifest List:每个快照对应的 Manifest 文件列表
  3. Manifest File:记录具体数据文件路径及其列统计信息(min/max/null count)

核心操作示例

-- Spark SQL 操作 Iceberg 表
-- 创建表
CREATE TABLE catalog.db.events (
event_id BIGINT,
user_id BIGINT,
event_name STRING,
event_time TIMESTAMP,
amount DECIMAL(18, 2)
) USING iceberg
PARTITIONED BY (days(event_time)); -- 隐藏分区:按天

-- 时间旅行:查询历史快照
SELECT * FROM catalog.db.events VERSION AS OF 123456789;

-- 时间旅行:按时间点查询
SELECT * FROM catalog.db.events TIMESTAMP AS OF '2024-01-01 00:00:00';

-- Schema 演进:添加列
ALTER TABLE catalog.db.events ADD COLUMNS (
channel STRING AFTER event_name
);

-- 分区演进:从按天改为按月(无需重写数据)
ALTER TABLE catalog.db.events
SET PARTITION SPEC (months(event_time));

-- 快照管理:删除过期快照
CALL catalog.system.expire_snapshots('db.events', TIMESTAMP '2024-01-01');

-- 数据文件合并(小文件治理)
CALL catalog.system.rewrite_data_files('db.events');

隐藏分区

传统 Hive 分区需要用户在查询时指定分区列:

-- Hive 方式:用户必须知道分区结构
SELECT * FROM events WHERE dt = '2024-01-01';

-- Iceberg 方式:隐藏分区,用户正常写 WHERE
SELECT * FROM events WHERE event_time >= '2024-01-01';
-- 引擎自动推断分区裁剪

为什么选 Iceberg

Iceberg 的优势
  1. 厂商中立:Apache 开源,不绑定 Databricks/Cloudera
  2. 多引擎支持:Spark、Flink、Trino、Doris、StarRocks 都支持
  3. 分区演进:无需重写数据即可修改分区策略
  4. 隐藏分区:简化用户查询,减少错误
  5. 社区活跃:目前增长最快的表格式

常见面试问题

Q1: Iceberg 如何实现 ACID 事务?

答案

  • 每次写入产生新的 快照(Snapshot)
  • 快照隔离:读操作读取某个快照,写操作不影响读
  • 通过 乐观锁 处理并发写入冲突
  • Metadata File 的更新是原子的(rename 操作)

Q2: 小文件问题如何解决?

答案

  • 流式写入(如 Flink)容易产生大量小文件
  • 定期执行 rewrite_data_files 合并小文件
  • 设置合理的 target-file-size-bytes(默认 512MB)
  • Flink 写入时设置 Checkpoint 间隔控制文件大小

Q3: Iceberg 时间旅行有什么用?

答案

  • 数据回溯:误删/误改后恢复数据
  • 审计:查看任意时间点的数据状态
  • 增量读取:读取两个快照之间的变更数据
  • 可重现分析:确保分析结果可复现

相关链接