一、背景
Iceberg到底解决了什么问题?
传统Hive数仓存在的问题
一言以蔽之:Hive的表格式主要问题的关键是在文件级别跟踪表中的数据。他们不是一个指向一个目录或一组目录的表,而是将一个表定义为一个规范的文件列表。
解释如下:
Hive的Table Format的状态和两个地方有关:Hive Metastore和File System,这样很难去统一的管理。
文件级别跟踪,不能保证ACID的事务特性,如果两个人同时修改文件,可能会造成脏读的情况。
Hive的文件结构只能通过Partition和Bucket对需要扫描哪些文件进行过滤,无法精确到文件粒度,也无法使用parquet文件自带的min-max值进行过滤。
建表和查询需要显式的指定分区字段,字段必须也是表中的一部分。
Iceberg的优越点
定位:Iceberg的定位是位于计算引擎和存储层之间的位置,计算引擎不用关心数据到底以什么格式存储,只需要接入Iceberg,那么Iceberg会帮助我们统一管理存储层中的Parquet、ORC和avro等压缩的大数据文件,使这些文件更便于管理维护,同时为其构造出相应的元数据文件。
其优点有:
分层的元数据结构不需要List操作,都是直接单路径指向的,因此查询性能上没有耗时List操作,这点对于对象存储比较友好,因为对象存储在List上面是一个比较耗资源的操作。
在未完成一次commit之前,snapshot是不可以被读取的,但是commit之后的snapshot可以被读,并且可以支持并发读。
查询无需指定分区,Iceberg会自动帮我们完成,Hidden Partition。
Time Travel能力,可以回滚到任意一个版本的Snapshot。
二、Iceberg优雅的元数据分层结构
Iceberg的架构
可以看到Iceberg的架构可以分为三层:

- Catalog层
Catalog层是读写Iceberg表的一个入口,它需要指向一个Metadata File(一般是最新的那个)。
- Metadata层
- Metadata File存储有关表的元数据。这包括有关表的格式、分区信息、快照以及哪个快照是当前快照的信息。Metadata File使用Json类型文件存储这些信息。
- 在Metadata File中存有Manifest List信息,Manifest List包含有关组成该快照的每个Manifest File的信息,是一个Manifest File的集合。Manifest List使用avro格式存储。
- Manifest File是Data File的一个集合,它描述了Data File的一些信息,比如文件格式,路径,列的信息等等。Manifest File使用avro格式存储。
- Data层
Data File是真正数据存储的地方,一般是表中存储的数据,以parquet/orc/avro格式存储。
按照这种分层架构,Iceberg在读取时会按照一层一层的文件来获取最终的Data File,这样非常清晰和优雅。
在文件系统中,Metadata Layer和Data Layer分别存储在同一目录下的两个文件夹内,树状结构类似:
|- db/
|- table/
|- metadata/
|- 00000-bb018ae7-e3f2-4881-a8e8-5f1f829e2e80.metadata.json
|- 00001-e0eff477-bdc9-40a1-8c09-ed774caf4956.metadata.json
|- snap-5858671019858456068-1-4868c59a-5054-4e73-8143-992f5844238c.avro
|- 4868c59a-5054-4e73-8143-992f5844238c-m0.avro
|- data/
|- 00000-0-root_20240205130046_6572575d-2039-4de7-85d2-29291e00a128-job_1707104331969_0005-00001.parquet
文件内容具体如下:
{
"format-version" : 1,
"table-uuid" : "ec70e546-185d-4183-85e0-7e9504cbd799",
"location" : "hdfs://master-1-1.c-6678117adb2bdbd5.cn-beijing.emr.aliyuncs.com:9000/user/hive/warehouse/iceberg.db/iceberg_test",
"last-updated-ms" : 1707105252987,
"last-column-id" : 1,
"schema" : {
"type" : "struct",
"schema-id" : 0,
"fields" : [ {
"id" : 1,
"name" : "id",
"required" : false,
"type" : "int"
} ]
},
"current-schema-id" : 0,
"schemas" : [ {
"type" : "struct",
"schema-id" : 0,
"fields" : [ {
"id" : 1,
"name" : "id",
"required" : false,
"type" : "int"
} ]
} ],
"partition-spec" : [ ],
"default-spec-id" : 0,
"partition-specs" : [ {
"spec-id" : 0,
"fields" : [ ]
} ],
"last-partition-id" : 999,
"default-sort-order-id" : 0,
"sort-orders" : [ {
"order-id" : 0,
"fields" : [ ]
} ],
"properties" : {
"engine.hive.enabled" : "true",
"totalSize" : "0",
"numRows" : "0",
"rawDataSize" : "0",
"COLUMN_STATS_ACCURATE" : "{\"BASIC_STATS\":\"true\",\"COLUMN_STATS\":{\"id\":\"true\"}}",
"numFiles" : "0",
"bucketing_version" : "2",
"storage_handler" : "org.apache.iceberg.mr.hive.HiveIcebergStorageHandler"
},
"current-snapshot-id" : -1,
"refs" : { },
"snapshots" : [ ],
"statistics" : [ ],
"snapshot-log" : [ ],
"metadata-log" : [ ]
}
{
"format-version" : 1,
"table-uuid" : "ec70e546-185d-4183-85e0-7e9504cbd799",
"location" : "hdfs://master-1-1.c-6678117adb2bdbd5.cn-beijing.emr.aliyuncs.com:9000/user/hive/warehouse/iceberg.db/iceberg_test",
"last-updated-ms" : 1707109265835,
"last-column-id" : 1,
"schema" : {
"type" : "struct",
"schema-id" : 0,
"fields" : [ {
"id" : 1,
"name" : "id",
"required" : false,
"type" : "int"
} ]
},
"current-schema-id" : 0,
"schemas" : [ {
"type" : "struct",
"schema-id" : 0,
"fields" : [ {
"id" : 1,
"name" : "id",
"required" : false,
"type" : "int"
} ]
} ],
"partition-spec" : [ ],
"default-spec-id" : 0,
"partition-specs" : [ {
"spec-id" : 0,
"fields" : [ ]
} ],
"last-partition-id" : 999,
"default-sort-order-id" : 0,
"sort-orders" : [ {
"order-id" : 0,
"fields" : [ ]
} ],
"properties" : {
"engine.hive.enabled" : "true",
"totalSize" : "0",
"numRows" : "0",
"rawDataSize" : "0",
"COLUMN_STATS_ACCURATE" : "{\"BASIC_STATS\":\"true\",\"COLUMN_STATS\":{\"id\":\"true\"}}",
"numFiles" : "0",
"bucketing_version" : "2",
"storage_handler" : "org.apache.iceberg.mr.hive.HiveIcebergStorageHandler"
},
"current-snapshot-id" : 5858671019858456068,
"refs" : {
"main" : {
"snapshot-id" : 5858671019858456068,
"type" : "branch"
}
},
"snapshots" : [ {
"snapshot-id" : 5858671019858456068,
"timestamp-ms" : 1707109265835,
"summary" : {
"operation" : "append",
"added-data-files" : "1",
"added-records" : "1",
"added-files-size" : "407",
"changed-partition-count" : "1",
"total-records" : "1",
"total-files-size" : "407",
"total-data-files" : "1",
"total-delete-files" : "0",
"total-position-deletes" : "0",
"total-equality-deletes" : "0"
},
"manifest-list" : "hdfs://master-1-1.c-6678117adb2bdbd5.cn-beijing.emr.aliyuncs.com:9000/user/hive/warehouse/iceberg.db/iceberg_test/metadata/snap-5858671019858456068-1-4868c59a-5054-4e73-8143-992f5844238c.avro",
"schema-id" : 0
} ],
"statistics" : [ ],
"snapshot-log" : [ {
"timestamp-ms" : 1707109265835,
"snapshot-id" : 5858671019858456068
} ],
"metadata-log" : [ {
"timestamp-ms" : 1707105252987,
"metadata-file" : "hdfs://master-1-1.c-6678117adb2bdbd5.cn-beijing.emr.aliyuncs.com:9000/user/hive/warehouse/iceberg.db/iceberg_test/metadata/00000-bb018ae7-e3f2-4881-a8e8-5f1f829e2e80.metadata.json"
} ]
}
{
"manifest_path":"hdfs://master-1-1.c-6678117adb2bdbd5.cn-beijing.emr.aliyuncs.com:9000/user/hive/warehouse/iceberg.db/iceberg_test/metadata/4868c59a-5054-4e73-8143-992f5844238c-m0.avro",
"manifest_length":5799,
"partition_spec_id":0,
"added_snapshot_id":{
"long":5858671019858456068
},
"added_data_files_count":{
"int":1
},
"existing_data_files_count":{
"int":0
},
"deleted_data_files_count":{
"int":0
},
"partitions":{
"array":[
]
},
"added_rows_count":{
"long":1
},
"existing_rows_count":{
"long":0
},
"deleted_rows_count":{
"long":0
}
}
{
"status":1,
"snapshot_id":{
"long":5858671019858456068
},
"data_file":{
"file_path":"hdfs://master-1-1.c-6678117adb2bdbd5.cn-beijing.emr.aliyuncs.com:9000/user/hive/warehouse/iceberg.db/iceberg_test/data/00000-0-root_20240205130046_6572575d-2039-4de7-85d2-29291e00a128-job_1707104331969_0005-00001.parquet",
"file_format":"PARQUET",
"partition":{
},
"record_count":1,
"file_size_in_bytes":407,
"block_size_in_bytes":67108864,
"column_sizes":{
"array":[
{
"key":1,
"value":51
}
]
},
"value_counts":{
"array":[
{
"key":1,
"value":1
}
]
},
"null_value_counts":{
"array":[
{
"key":1,
"value":0
}
]
},
"nan_value_counts":{
"array":[
]
},
"lower_bounds":{
"array":[
{
"key":1,
"value":"\u0001\u0000\u0000\u0000"
}
]
},
"upper_bounds":{
"array":[
{
"key":1,
"value":"\u0001\u0000\u0000\u0000"
}
]
},
"key_metadata":null,
"split_offsets":{
"array":[
4
]
},
"sort_order_id":{
"int":0
}
}
}