Apache Iceberg
问题
什么是 Apache Iceberg?为什么它是目前最流行的数据湖表格式?
答案
Iceberg 核心特性
Apache Iceberg 是 Netflix 开源的开放表格式,在 Parquet/ORC 文件之上增加元数据层,提供数据仓库级别的能力。
| 特性 | 说明 |
|---|---|
| ACID 事务 | 快照隔离,并发读写安全 |
| 时间旅行 | 查询任意历史版本 |
| Schema 演进 | 添加/删除/重命名/重排列,不影响历史数据 |
| 分区演进 | 修改分区策略无需重写数据 |
| 隐藏分区 | 用户无需知道分区结构 |
架构
三层元数据
- Metadata File:记录所有快照、Schema 历史、分区规范
- Manifest List:每个快照对应的 Manifest 文件列表
- 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 的优势
- 厂商中立:Apache 开源,不绑定 Databricks/Cloudera
- 多引擎支持:Spark、Flink、Trino、Doris、StarRocks 都支持
- 分区演进:无需重写数据即可修改分区策略
- 隐藏分区:简化用户查询,减少错误
- 社区活跃:目前增长最快的表格式
常见面试问题
Q1: Iceberg 如何实现 ACID 事务?
答案:
- 每次写入产生新的 快照(Snapshot)
- 快照隔离:读操作读取某个快照,写操作不影响读
- 通过 乐观锁 处理并发写入冲突
- Metadata File 的更新是原子的(rename 操作)
Q2: 小文件问题如何解决?
答案:
- 流式写入(如 Flink)容易产生大量小文件
- 定期执行
rewrite_data_files合并小文件 - 设置合理的
target-file-size-bytes(默认 512MB) - Flink 写入时设置 Checkpoint 间隔控制文件大小
Q3: Iceberg 时间旅行有什么用?
答案:
- 数据回溯:误删/误改后恢复数据
- 审计:查看任意时间点的数据状态
- 增量读取:读取两个快照之间的变更数据
- 可重现分析:确保分析结果可复现
相关链接
- Delta Lake - Databricks 开源表格式
- Apache Hudi - 增量处理表格式
- 湖仓一体 - 表格式选型对比
- 存储格式 - Parquet/ORC 底层格式