作者:闻乃松
创立表是引擎的必备根本能力,引擎有很多,Hive、Spark、Flink、Trino等等,咱们权且只关注这些,创立的表依照是否跟引擎绑定,分为两大类:managed table和external table。以这里举例的引擎为例,它们都能够将表元数据保护在Hive Metastore中,对引擎来讲,这些表以external table的模式存在。
在本文中,咱们将话题限度在Hive、Spark、Flink、Trino如何创立Iceberg表,并且保障各引擎都能够无障碍相互拜访。这样,咱们的话题分为3个局部:
- 不同引擎创立的Iceberg表为什么不兼容?
- 如何屏蔽不同引擎创立Iceberg表的差别?
- 创立独立引擎的Iceberg表的步骤
不同引擎创立的Iceberg表为什么不兼容
Hive、Spark、Flink、Trino创立的Iceberg表元数据都存储在HMS中,也就是复用了HMS的存储模型,次要波及的表的互相关系如下:
以Hive创立的Iceberg表为例,来看看其存储内容:
CREATE TABLE default.sample_hive_table_1( id bigint, name string ) PARTITIONED BY( dept string ) STORED BY ‘org.apache.iceberg.mr.hive.HiveIcebergStorageHandler’;
首先在TBLS中存储了一条记录:记录了以后表的ID,名称,类型,数据库ID,序列化ID,拥有者等信息。在TABLE_PARAMS中存储了相干参数:
storage_handler记录了以后表须要用Iceberg handler来解决。Iceberg表的元数据信息,通过metadata_location和previous_metadata_location指定,前者代表最新变更记录,后者代表上一次的变更记录。
在字段表COLUMNS_V2中记录了字段信息:
由图可知,其并没有存储分区字段,分区信息存储在元数据文件中。这个表只保留表最新版本的字段信息。
SERDES和SERDES_PARAMS存储序列化相干的信息,重要的字段只有一个:SERDES.SLIB=org.apache.iceberg.mr.hive.HiveIcebergSerDe
如果你用其余引擎来创立Iceberg表,会发现元数据存储上的几个差异:
首先是序列化信息变成了:
SERDES.SLIB=org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
其次是SDS的存储格局变成了其余HDFS文件格式(以下为示例格局):
最初是没有Iceberg的storage_handler属性,因为这些格局跟Hive创立的Iceberg表的差别,导致Hive引擎无奈辨认其余引擎创立的表,而其余几种引擎之间是互通的,且能拜访Hive 创立的Iceberg表,互通关系体现为:
其中红色箭头示意单项互通。
如何屏蔽不同引擎创立Iceberg表的差别
最简略的方法是间接批改元数据:
NSERT INTO TABLE_PARAMS (TBL_ID, PARAM_KEY, PARAM_VALUE)
VALUES(898, 'storage_handler', 'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler');
update SDS set INPUT_FORMAT =NULL ,OUTPUT_FORMAT =NULL where SD_ID =898;
update SERDES set slib='org.apache.iceberg.mr.hive.HiveIcebergSerDe'
where serde_ID =898
为了做到Iceberg表元数据的真正中立,也能够将SDS的INPUT_FORMAT 和 OUTPUT_FORMAT 字段都置NULL。
这是通过预先修补的方法来做到的,是否在创立表之前就批改呢?并且不批改各引擎的实现代码。实际上,引擎创立Iceberg表,是通过iceberg API来实现的,交互逻辑大略是这个样子:
那是不是有方法间接通过Iceberg API创立HMS表呢?of course!
更进一步,咱们将上述逻辑模型,形象成如下构造,引擎变成了通用了Restful API,现实状况下,应用方只须要传入创立表的相干参数等信息即可:
这样一来,不论是Hive表还是Iceberg表,都能够通过这个模型实现表的创立。接下来,咱们看如何形象这样的表模型。
创立独立引擎的Iceberg表的步骤
通过下面元数据的剖析,能够将创立Iceberg表的元数据信息分为上面几类:
表名称和类型信息,用一个复合字段来示意:
"name": {
"catalogName": "mycatalog",
"databaseName": "test_iceberg_db",
"tableName": "test_iceberg_table",
"type": "TABLE"
}
域字段列表信息,用一个复合数组示意:
"fields": [
{
"comment": "primary key",
"defaultValue": 0,
"isIndexKey": true,
"isNullable": false,
"isSortKey": true,
"name": "id",
"type": "int"
},
{
"comment": "data value",
"defaultValue": "",
"isIndexKey": false,
"isNullable": false,
"isSortKey": false,
"name": "data",
"source_type": "string",
"type": "string"
}
]
元数据信息,用一个复合构造示意:
"metadata": {
"table_type": "ICEBERG",
"location": "s3a://faas-ethan/warehouse/test_iceberg_db/test_iceberg_table"
}
序列化信息,用一个复合构造示意:
"serde": {
"inputFormat": "org.apache.iceberg.mr.hive.HiveIcebergInputFormat",
"outputFormat": "org.apache.iceberg.mr.hive.HiveIcebergOutputFormat",
"parameters":
{
"k1":"v1"
},
"serializationLib": "string",
"uri": "your_hive_table_locaton"
}
有了表的模型之后,就能够依照上面创立Hive表的创立模板来走了:
//创立Fields
List<FieldSchema> fields = new ArrayList<FieldSchema>();
fields.add(new FieldSchema("colname", serdeConstants.STRING_TYPE_NAME, "comment"));
//创立StorageDescriptor
StorageDescriptor sd = new StorageDescriptor();
sd.setCols(fields); sd.setSerdeInfo(new SerDeInfo());
//创立Table对象
Table tbl = new Table();
tbl.setDbName(DB_NAME);
tbl.setTableName(TBL_NAME);
tbl.setSd(sd);
//申请HMS长久化
Table table=hiveMetaStoreClient.createTable(tbl);
下面示例代码将创立Hive的模板流程划分为4个步骤:
- 创立Fields
- 创立StorageDescriptor
- 创立Table对象
- 申请HMS长久化Table
总结
本文讲述了不同引擎,次要是Hive、Spark、Flink和Trino,在创立Iceberg表上存在的兼容性问题及其产生的起因,而后给出了解决办法。最初,通过形象一种创立跟引擎无关的Iceberg表的示意办法及其创立步骤。该办法的重要作用是可能实现通用的元数据管理。
发表回复