Gravitino iceberg catalog backend 为hive 获取元数据过程
Iceberg Catalog (Hive Backend) 元数据获取流程
概述
当 Iceberg Catalog Backend 配置为 Hive 时,Gravitino 通过Hive Metastore (HMS) 和Iceberg 文件系统元数据两部分协同工作来获取完整的库、表、字段等元数据信息。
1. 元数据来源架构
| 元数据类型 | 存储位置 | 用途 |
|---|---|---|
| Hive Metastore | HMS 数据库 | 存储表的名称、位置、类型标识 (table\_type=ICEBERG) |
| Iceberg 元数据文件 | 文件系统(HDFS/S3/OSS 等) | 存储完整的 Schema、分区、排序、快照等详细信息 |
2. 获取 Schemas (Namespaces) 流程
调用链路
Plain
IcebergNamespaceOperations.listNamespaces()
↓
IcebergNamespaceOperationExecutor.listNamespaces()
↓
IcebergCatalogWrapper.listNamespace()
↓
CatalogHandlers.listNamespaces(asNamespaceCatalog, parent)
↓
GrHiveCatalog.listNamespaces(namespace) ← 实际执行
核心代码 (GrHiveCatalog.java:476-501)
Java
@Override
public List<Namespace> listNamespaces(Namespace namespace) {
if (!isValidateNamespace(namespace) && !namespace.isEmpty()) {
throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
}
if (!namespace.isEmpty()) {
return ImmutableList.of(); // Hive 不支持嵌套 namespace
}
try {
// 调用 Hive Metastore Thrift 客户端获取所有数据库
List<Namespace> namespaces =
clients.run(IMetaStoreClient::getAllDatabases).stream()
.map(Namespace::of)
.collect(Collectors.toList());
...
}
}
关键点
-
调用 Hive Metastore 的
getAllDatabases\(\)Thrift 接口 -
Hive 只支持单层 namespace(database),不支持多级
-
使用
CachedClientPool管理 HMS 客户端连接池
3. 获取 Tables 流程
调用链路
Plain
IcebergTableOperations.listTable()
↓
IcebergTableOperationExecutor.listTable()
↓
IcebergCatalogWrapper.listTable()
↓
CatalogHandlers.listTables(catalog, namespace)
↓
GrHiveCatalog.listTables(namespace) ← 实际执行
核心代码 (GrHiveCatalog.java:142-178)
Java
@Override
public List<TableIdentifier> listTables(Namespace namespace) {
Preconditions.checkArgument(
isValidateNamespace(namespace), "Missing database in namespace: %s", namespace);
String database = namespace.level(0);
try {
// 1. 调用 Hive Metastore 获取所有表名
List<String> tableNames = clients.run(client -> client.getAllTables(database));
List<TableIdentifier> tableIdentifiers;
if (listAllTables) {
// 2a. 如果配置为列出所有表,直接返回
tableIdentifiers = tableNames.stream()
.map(t -> TableIdentifier.of(namespace, t))
.collect(Collectors.toList());
} else {
// 2b. 否则只过滤出 Iceberg 表
tableIdentifiers = listIcebergTables(
tableNames, namespace, BaseMetastoreTableOperations.ICEBERG_TABLE_TYPE_VALUE);
}
...
}
}
过滤 Iceberg 表的逻辑 (GrHiveCatalog.java:342-356)
Java
private List<TableIdentifier> listIcebergTables(
List<String> tableNames, Namespace namespace, String tableTypeProp)
throws TException, InterruptedException {
// 1. 批量获取表对象(避免 OOM)
List<Table> tableObjects =
clients.run(client -> client.getTableObjectsByName(namespace.level(0), tableNames));
// 2. 过滤出 Iceberg 表(通过表参数中的 table_type 标识)
return tableObjects.stream()
.filter(table ->
table.getParameters() != null
&& (tableTypeProp.equalsIgnoreCase(
table.getParameters().get(BaseMetastoreTableOperations.TABLE_TYPE_PROP))
|| TableType.VIRTUAL_VIEW.name().equalsIgnoreCase(table.getTableType())))
.map(table -> TableIdentifier.of(namespace, table.getTableName()))
.collect(Collectors.toList());
}
关键点
-
调用 Hive Metastore 的
getAllTables\(database\)获取表名列表 -
调用
getTableObjectsByName\(\)批量获取表详情(避免逐表查询的性能问题) -
通过表参数
table\_type=ICEBERG过滤出 Iceberg 管理的表 -
配置项
list\-all\-tables=true可跳过过滤,返回所有 Hive 表
4. 加载完整表元数据 (从 Iceberg 元数据文件)
调用链路
Plain
IcebergCatalogOperations.loadTable()
↓
icebergCatalogWrapper.loadTable(tableIdentifier)
↓
CatalogHandlers.loadTable(catalog, tableIdentifier)
↓
GrHiveCatalog.loadTable(tableIdentifier)
↓
HiveTableOperations.current() → 读取文件系统 metadata.json
核心代码 (IcebergCatalogOperations.java:386-400)
Java
@Override
public Table loadTable(NameIdentifier tableIdent) throws NoSuchTableException {
try {
LoadTableResponse tableResponse =
icebergCatalogWrapper.loadTable(
IcebergCatalogWrapperHelper.buildIcebergTableIdentifier(tableIdent));
// 从 Iceberg TableMetadata 解析完整元数据
IcebergTable icebergTable =
IcebergTable.fromIcebergTable(tableResponse.tableMetadata(), tableIdent.name());
LOG.info("Loaded Iceberg table {}", tableIdent.name());
return icebergTable;
} catch (org.apache.iceberg.exceptions.NoSuchTableException e) {
throw new NoSuchTableException(e, ICEBERG_TABLE_DOES_NOT_EXIST_MSG, tableIdent.name());
}
}
从 Iceberg 元数据转换 (IcebergTable.java:157-181)
Java
public static IcebergTable fromIcebergTable(TableMetadata table, String tableName) {
// 1. 属性 - 从 Iceberg 元数据文件读取
Map<String, String> properties = new HashMap<>(table.properties());
properties.putAll(IcebergTablePropertiesUtil.buildReservedProperties(table));
// 2. Schema/字段信息 - 从 Iceberg 元数据文件读取
Schema schema = table.schema();
IcebergColumn[] icebergcolumns =
schema.columns().stream().map(ConvertUtil::fromNestedField).toArray(IcebergColumn[]::new);
// 3. 分区信息 - 从 Iceberg 元数据文件读取
Transform[] partitionSpec = FromIcebergPartitionSpec.fromPartitionSpec(table.spec(), schema);
// 4. 排序信息 - 从 Iceberg 元数据文件读取
SortOrder[] sortOrder = FromIcebergSortOrder.fromSortOrder(table.sortOrder());
// 5. 位置信息 - 从 Iceberg 元数据文件读取
String location = table.location();
// 6. 构建完整的 Gravitino Table 对象
return IcebergTable.builder()
.withComment(table.property(IcebergTablePropertiesMetadata.COMMENT, null))
.withLocation(table.location())
.withProperties(properties)
.withColumns(icebergColumns)
.withName(tableName)
.withAuditInfo(AuditInfo.EMPTY)
.withPartitioning(partitionSpec)
.withSortOrders(sortOrder)
.withDistribution(getDistribution(properties))
.withIndexes(indexes)
.build();
}
5. 数据流总结
Plain
┌─────────────────────────────────────────────────────────────────┐
│ Gravitino Iceberg Catalog │
├─────────────────────────────────────────────────────────────────┤
│ │
│ listTables(namespace) │
│ ↓ │
│ 1. Hive Metastore (HMS) │
│ - getAllTables(database) → 表名列表 │
│ - getTableObjectsByName() → 表对象(含 table_type 参数) │
│ - 过滤出 table_type=ICEBERG 的表 │
│ ↓ │
│ 2. 文件系统上的 Iceberg 元数据文件 │
│ - loadTable(tableIdentifier) │
│ - 读取 metadata.json 文件 │
│ - 解析:Schema、分区、排序、属性、位置等 │
│ ↓ │
│ 3. fromIcebergTable(TableMetadata) │
│ - 将 Iceberg 元数据转换为 Gravitino 格式 │
│ - 返回完整的 Table 对象(含字段、分区等详细信息) │
│ │
└─────────────────────────────────────────────────────────────────┘
6. 配置参数
| 参数 | 默认值 | 说明 |
|---|---|---|
hive\.metastore\.uris |
- | Hive Metastore Thrift 服务地址 |
hive\.metastore\.warehouse\.dir |
- | 数据仓库根目录 |
list\-all\-tables |
false |
是否列出所有表(包括非 Iceberg 表) |
iceberg\.catalog\.client\.pool\.size |
- | HMS 客户端连接池大小 |
7. 关键结论
Gravitino 的 Iceberg Catalog(Hive Backend)严重依赖 Iceberg 在文件系统上维护的元数据文件来提供完整的表信息:
-
HMS 只存储"表的存在性"和"类型标识" - 用于快速列出哪些表是 Iceberg 表
-
Iceberg 元数据文件存储完整 Schema - 字段名、类型、注释、nullable、分区、排序、快照历史等
-
每次
loadTable都会读取文件系统元数据 - 确保获取最新信息
这种设计的好处是:
-
Iceberg 元数据是单一事实来源(Single Source of Truth)
-
HMS 只作为"目录索引",不存储详细元数据
-
支持 Iceberg 的 ACID 快照隔离和时间旅行特性
(注:文档内容基于gravitino 0.9版本源码由 AI整理生成)