Administrator
Published on 2024-02-10 / 8 Visits
0

数据湖技术之Iceberg

一、背景

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的架构可以分为三层:

iceberg元数据架构.png

  1. Catalog层

Catalog层是读写Iceberg表的一个入口,它需要指向一个Metadata File(一般是最新的那个)。

  1. Metadata层
    1. Metadata File存储有关表的元数据。这包括有关表的格式、分区信息、快照以及哪个快照是当前快照的信息。Metadata File使用Json类型文件存储这些信息。
    2. 在Metadata File中存有Manifest List信息,Manifest List包含有关组成该快照的每个Manifest File的信息,是一个Manifest File的集合。Manifest List使用avro格式存储。
    3. Manifest File是Data File的一个集合,它描述了Data File的一些信息,比如文件格式,路径,列的信息等等。Manifest File使用avro格式存储。
  2. 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
        }
    }
}