Paimon 数据湖 + Gravitino 元数据中心:技术原理与实战指南

Paimon 数据湖 + Gravitino 元数据中心:技术原理与实战指南

一、概述

Apache Paimon 是一个流批一体的数据湖存储格式,支持高吞吐的数据摄入和高效的实时/批量查询。Apache Gravitino 可以作为 Paimon 的统一元数据中心,通过 lakehouse-paimon Catalog 插件直接对接 Paimon 的元数据层,实现:

  • 统一管理 Paimon + 其他数据源(Hive、MySQL、Iceberg、Kafka)的元数据
  • 通过 Gravitino 的 Spark/Flink Connector 透明访问 Paimon 表
  • 对 Paimon 表应用统一的权限控制、标签、策略治理

二、架构总览

复制代码
┌─────────────────────────────────────────────────────────┐
│                     查询引擎层                            │
│   Spark SQL          Flink SQL          Trino           │
│   (Gravitino         (Gravitino         (Gravitino      │
│    Spark Connector)   Flink Connector)   Trino Conn.)   │
└────────┬──────────────────┬──────────────────┬──────────┘
         │                  │                  │
         ▼                  ▼                  ▼
┌─────────────────────────────────────────────────────────┐
│              Gravitino Server (:8090)                    │
│                                                         │
│  ┌─────────────────────────────────────────────────┐    │
│  │           Dispatcher Chain                       │    │
│  │  Event → Normalize → Hook → Operation            │    │
│  └──────────────────────┬──────────────────────────┘    │
│                         │                               │
│  ┌──────────────────────▼──────────────────────────┐    │
│  │         CatalogManager                           │    │
│  │  loadCatalog("my_paimon") → PaimonCatalog        │    │
│  └──────────────────────┬──────────────────────────┘    │
│                         │                               │
│  ┌──────────────────────▼──────────────────────────┐    │
│  │       PaimonCatalogOperations                    │    │
│  │  → PaimonCatalogOps                              │    │
│  │  → Paimon CatalogFactory.createCatalog(...)      │    │
│  └──────────────────────┬──────────────────────────┘    │
└─────────────────────────┼───────────────────────────────┘
                          │
         ┌────────────────┼────────────────────┐
         ▼                ▼                    ▼
   ┌──────────┐    ┌──────────┐         ┌──────────┐
   │Filesystem│    │   JDBC   │         │   Hive   │
   │ (HDFS/   │    │ (MySQL/  │         │Metastore │
   │  S3/OSS) │    │  PG)     │         │(Thrift)  │
   └──────────┘    └──────────┘         └──────────┘
         │                │                    │
         ▼                ▼                    ▼
   ┌─────────────────────────────────────────────┐
   │          Paimon 数据文件 (ORC/Parquet)        │
   │          存储在 HDFS / S3 / OSS / 本地         │
   └─────────────────────────────────────────────┘

三、核心源码解析

3.1 Catalog 插件入口 --- PaimonCatalog

文件 : catalogs/catalog-lakehouse-paimon/src/main/java/.../PaimonCatalog.java

java 复制代码
public class PaimonCatalog extends BaseCatalog<PaimonCatalog> {

  @Override
  public String shortName() {
    return "lakehouse-paimon";  // 创建 Catalog 时 provider 使用此名
  }

  @Override
  protected CatalogOperations newOps(Map<String, String> config) {
    return new PaimonCatalogOperations();  // 核心操作类
  }

  @Override
  protected Capability newCapability() {
    return new PaimonCatalogCapability();  // 能力声明
  }
}

通过 SPI 注册:META-INF/services/org.apache.gravitino.CatalogProvider 中声明了 PaimonCatalog

3.2 初始化流程 --- PaimonCatalogOperations.initialize()

文件 : catalogs/catalog-lakehouse-paimon/src/main/java/.../PaimonCatalogOperations.java

java 复制代码
@Override
public void initialize(Map<String, String> conf, CatalogInfo info,
    HasPropertyMetadata propertiesMetadata) {
  // 1. 提取 gravitino.bypass.* 前缀的透传属性
  Map<String, String> prefixMap = MapUtils.getPrefixMap(conf, CATALOG_BYPASS_PREFIX);

  // 2. 将 Gravitino 属性转换为 Paimon 属性
  //    catalog-backend → metastore, warehouse → warehouse, uri → uri 等
  Map<String, String> gravitinoConfig =
      ((PaimonCatalogPropertiesMetadata) propertiesMetadata.catalogPropertiesMetadata())
          .transformProperties(conf);

  // 3. 合并配置
  Map<String, String> resultConf = Maps.newHashMap(prefixMap);
  resultConf.putAll(gravitinoConfig);

  // 4. 创建 Paimon 底层 Catalog
  this.paimonCatalogOps = new PaimonCatalogOps(new PaimonConfig(resultConf));
}

PaimonCatalogOps 内部,通过 Paimon 官方 API 创建 Catalog:

java 复制代码
// CatalogUtils.loadCatalogBackend()
Catalog catalog = CatalogFactory.createCatalog(CatalogContext.create(options));

3.3 Paimon 支持的 Catalog Backend

java 复制代码
public enum PaimonCatalogBackend {
  FILESYSTEM,   // 本地/HDFS/S3/OSS 文件系统,元数据存在文件中
  JDBC,         // MySQL/PostgreSQL 存储元数据
  HIVE,         // Hive Metastore 存储元数据
  REST          // REST Catalog(如阿里云 DLF)
}
Backend 元数据存储位置 适用场景
filesystem warehouse 目录下的文件 开发测试、简单部署
jdbc MySQL / PostgreSQL 生产环境、多节点共享
hive Hive Metastore 与 Hive 生态共存
rest REST 服务(如阿里云 DLF) 云原生部署

3.4 表操作的内部流程

createTable 为例:

复制代码
用户 REST/SDK 请求
  → Gravitino REST API (TableOperations)
    → EventDispatcher → NormalizeDispatcher → HookDispatcher
      → TableOperationDispatcher
        → CatalogManager.loadCatalog("my_paimon")
          → PaimonCatalog (IsolatedClassLoader)
            → PaimonCatalogOperations.createTable()
              → 1. 构建 GravitinoPaimonTable (Gravitino 模型)
              → 2. toPaimonTableSchema() (转为 Paimon Schema)
              → 3. paimonCatalogOps.createTable(identifier, schema)
                → 4. Paimon Catalog.createTable() (真正创建)

关键转换 : GravitinoPaimonTable.toPaimonTableSchema() 将 Gravitino 的列定义、分区、主键、分桶等信息转换为 Paimon 的 Schema 对象。

3.5 属性映射

Gravitino 属性 Paimon 属性 说明
catalog-backend metastore Catalog 后端类型
warehouse warehouse 数仓路径
uri uri 后端连接 URI
jdbc-user jdbc.user JDBC 用户名
jdbc-password jdbc.password JDBC 密码
gravitino.bypass.* * 透传给 Paimon

四、实战 Demo

4.1 前置条件

  1. Gravitino Server 已启动(默认 http://localhost:8090
  2. 已创建 Metalake(如 my_metalake)并启用
  3. 如使用 HDFS,确保 core-site.xmlhdfs-site.xml 放在 catalogs/lakehouse-paimon/conf/

4.2 场景一:Filesystem Backend(开发测试)

创建 Paimon Catalog
bash 复制代码
curl -X POST -H "Accept: application/vnd.gravitino.v1+json" \
-H "Content-Type: application/json" -d '{
  "name": "paimon_dev",
  "type": "RELATIONAL",
  "provider": "lakehouse-paimon",
  "comment": "Paimon dev catalog on local filesystem",
  "properties": {
    "catalog-backend": "filesystem",
    "warehouse": "file:///tmp/paimon-warehouse"
  }
}' http://localhost:8090/api/metalakes/my_metalake/catalogs
创建 Schema
bash 复制代码
curl -X POST -H "Accept: application/vnd.gravitino.v1+json" \
-H "Content-Type: application/json" -d '{
  "name": "ods",
  "comment": "原始数据层"
}' http://localhost:8090/api/metalakes/my_metalake/catalogs/paimon_dev/schemas
创建 Paimon 表(带主键和分区)
bash 复制代码
curl -X POST -H "Accept: application/vnd.gravitino.v1+json" \
-H "Content-Type: application/json" -d '{
  "name": "user_events",
  "comment": "用户行为事件表",
  "columns": [
    {"name": "event_id", "type": "long", "nullable": false, "comment": "事件ID"},
    {"name": "user_id", "type": "long", "nullable": false, "comment": "用户ID"},
    {"name": "event_type", "type": "string", "comment": "事件类型"},
    {"name": "event_time", "type": "timestamp", "comment": "事件时间"},
    {"name": "dt", "type": "string", "nullable": false, "comment": "日期分区"}
  ],
  "partitioning": [
    {"strategy": "identity", "fieldName": ["dt"]}
  ],
  "indexes": [
    {
      "indexType": "primary_key",
      "name": "pk_user_events",
      "fieldNames": [["event_id"], ["dt"]]
    }
  ],
  "properties": {
    "merge-engine": "deduplicate",
    "sequence.field": "event_time"
  }
}' http://localhost:8090/api/metalakes/my_metalake/catalogs/paimon_dev/schemas/ods/tables
查看表详情
bash 复制代码
curl -s http://localhost:8090/api/metalakes/my_metalake/catalogs/paimon_dev/schemas/ods/tables/user_events \
  -H "Accept: application/vnd.gravitino.v1+json" | python3 -m json.tool

4.3 场景二:JDBC Backend(生产环境)

前置:准备 MySQL 元数据库
sql 复制代码
CREATE DATABASE paimon_metastore;

将 MySQL JDBC 驱动(mysql-connector-java-8.x.jar)放到 catalogs/lakehouse-paimon/libs/ 目录下。

创建 Catalog
bash 复制代码
curl -X POST -H "Accept: application/vnd.gravitino.v1+json" \
-H "Content-Type: application/json" -d '{
  "name": "paimon_prod",
  "type": "RELATIONAL",
  "provider": "lakehouse-paimon",
  "comment": "Production Paimon catalog with JDBC backend",
  "properties": {
    "catalog-backend": "jdbc",
    "uri": "jdbc:mysql://mysql-host:3306/paimon_metastore",
    "warehouse": "hdfs://namenode:9000/data/paimon-warehouse",
    "jdbc-user": "paimon",
    "jdbc-password": "your_password",
    "jdbc-driver": "com.mysql.cj.jdbc.Driver"
  }
}' http://localhost:8090/api/metalakes/my_metalake/catalogs

4.4 场景三:Hive Backend(与 Hive 生态共存)

bash 复制代码
curl -X POST -H "Accept: application/vnd.gravitino.v1+json" \
-H "Content-Type: application/json" -d '{
  "name": "paimon_hive",
  "type": "RELATIONAL",
  "provider": "lakehouse-paimon",
  "properties": {
    "catalog-backend": "hive",
    "uri": "thrift://hive-metastore:9083",
    "warehouse": "hdfs://namenode:9000/user/hive/warehouse-paimon"
  }
}' http://localhost:8090/api/metalakes/my_metalake/catalogs

4.5 Java SDK 使用

java 复制代码
import org.apache.gravitino.client.GravitinoClient;
import org.apache.gravitino.Catalog;
import org.apache.gravitino.rel.*;

// 1. 创建客户端
GravitinoClient client = GravitinoClient.builder("http://localhost:8090")
    .withMetalake("my_metalake")
    .build();

// 2. 创建 Paimon Catalog
Map<String, String> props = ImmutableMap.of(
    "catalog-backend", "filesystem",
    "warehouse", "hdfs://namenode:9000/paimon-warehouse"
);
Catalog catalog = client.createCatalog(
    "paimon_dev", Catalog.Type.RELATIONAL,
    "lakehouse-paimon", "Dev Paimon", props);

// 3. 创建 Schema
catalog.asSchemas().createSchema("ods", "原始数据层", Collections.emptyMap());

// 4. 创建表
Column[] columns = new Column[] {
    Column.of("order_id", Types.LongType.get(), "订单ID", false, false, null),
    Column.of("user_id", Types.LongType.get(), "用户ID"),
    Column.of("amount", Types.DecimalType.of(10, 2), "金额"),
    Column.of("dt", Types.StringType.get(), "日期分区", false, false, null)
};

Transform[] partitions = new Transform[] { Transforms.identity("dt") };

Index[] indexes = new Index[] {
    Indexes.primary("pk_orders", new String[][] {{"order_id"}, {"dt"}})
};

catalog.asTableCatalog().createTable(
    NameIdentifier.of("ods", "orders"),
    columns, "订单表",
    ImmutableMap.of("merge-engine", "deduplicate"),
    partitions, Distributions.NONE, new SortOrder[0], indexes
);

// 5. 查询表
Table table = catalog.asTableCatalog().loadTable(NameIdentifier.of("ods", "orders"));
System.out.println("表名: " + table.name());
System.out.println("列数: " + table.columns().length);

4.6 Python SDK 使用

python 复制代码
from gravitino.client import GravitinoClient
from gravitino.api.catalog import Catalog

client = GravitinoClient(uri="http://localhost:8090", metalake_name="my_metalake")

# 创建 Catalog
catalog = client.create_catalog(
    name="paimon_dev",
    catalog_type=Catalog.Type.RELATIONAL,
    provider="lakehouse-paimon",
    comment="Dev Paimon",
    properties={
        "catalog-backend": "filesystem",
        "warehouse": "file:///tmp/paimon-warehouse"
    }
)

# 创建 Schema
catalog.as_schemas().create_schema("ods", "原始数据层", {})

# 列出表
tables = catalog.as_table_catalog().list_tables(Namespace.of("ods"))

五、通过 Spark 访问 Gravitino 管理的 Paimon

5.1 Spark 配置

bash 复制代码
spark-sql --master local[*] \
  --packages org.apache.gravitino:gravitino-spark-connector-runtime-3.5_2.12:1.2.0 \
  --packages org.apache.paimon:paimon-spark-3.5:1.2.0 \
  --conf spark.plugins=org.apache.gravitino.spark.connector.plugin.GravitinoSparkPlugin \
  --conf spark.sql.gravitino.uri=http://localhost:8090 \
  --conf spark.sql.gravitino.metalake=my_metalake \
  --conf spark.sql.gravitino.enablePaimonSupport=true

5.2 Spark SQL 操作

sql 复制代码
-- 切换到 Gravitino 管理的 Paimon Catalog
USE paimon_dev;

-- 创建数据库
CREATE DATABASE IF NOT EXISTS dwd;
USE dwd;

-- 创建 Paimon 表
CREATE TABLE IF NOT EXISTS user_orders (
  order_id BIGINT,
  user_id BIGINT,
  product_name STRING,
  amount DECIMAL(10,2),
  order_time TIMESTAMP,
  dt STRING
) PARTITIONED BY (dt);

-- 写入数据
INSERT INTO user_orders VALUES
  (1001, 1, '手机', 5999.00, TIMESTAMP '2025-01-15 10:30:00', '2025-01-15'),
  (1002, 2, '笔记本', 8999.00, TIMESTAMP '2025-01-15 11:00:00', '2025-01-15'),
  (1003, 1, '耳机', 299.00, TIMESTAMP '2025-01-16 09:00:00', '2025-01-16');

-- 查询
SELECT user_id, SUM(amount) as total_amount
FROM user_orders
WHERE dt = '2025-01-15'
GROUP BY user_id;

-- Schema Evolution
ALTER TABLE user_orders ADD COLUMNS (coupon_id BIGINT);

-- 查看分区
SHOW PARTITIONS user_orders;

-- 删除分区
ALTER TABLE user_orders DROP PARTITION (dt='2025-01-15');

5.3 Spark 内部原理

复制代码
Spark SQL: USE paimon_dev
  → GravitinoSparkPlugin
    → GravitinoCatalogManager 从 Gravitino 获取 Catalog 列表
    → 发现 paimon_dev (provider=lakehouse-paimon)
    → 注册为 GravitinoPaimonCatalogSpark35
    → PaimonPropertiesConverter 转换属性:
        catalog-backend → metastore
        warehouse → warehouse
    → 内部创建 Paimon SparkCatalog
    → Spark SQL 操作直接走 Paimon SparkCatalog

确保 classpath 包含:

  • gravitino-flink-connector-runtime-1.18_2.12-{version}.jar
  • paimon-flink-1.18-{version}.jar
sql 复制代码
-- 创建 Gravitino Paimon Catalog
CREATE CATALOG paimon_dev WITH (
  'type' = 'gravitino-paimon',
  'gravitino.uri' = 'http://localhost:8090',
  'gravitino.metalake' = 'my_metalake',
  'warehouse' = 'file:///tmp/paimon-warehouse',
  'metastore' = 'filesystem'
);

USE CATALOG paimon_dev;
SHOW DATABASES;

-- 创建表
CREATE TABLE ods.click_events (
  event_id BIGINT,
  user_id BIGINT,
  page_url STRING,
  click_time TIMESTAMP(3),
  PRIMARY KEY (event_id) NOT ENFORCED
);

-- 流式写入
INSERT INTO ods.click_events
SELECT * FROM kafka_source_table;

-- 批量查询
SELECT * FROM ods.click_events;

七、支持的操作和限制

7.1 Schema 操作

操作 支持 备注
创建 Schema
删除 Schema 支持 cascade
查看 Schema
列出 Schema
修改 Schema Paimon 不支持

7.2 表操作

操作 支持 备注
创建表 支持分区、主键、分桶
查看表
列出表
修改表 支持重命名、加列、改列等
dropTable 请使用 purgeTable
purgeTable 同时删除元数据和数据

7.3 支持的 Alter Table 操作

  • RenameTable(需单独执行,不能和其他变更混合)
  • AddColumn / DeleteColumn / RenameColumn
  • UpdateColumnComment / UpdateColumnNullability / UpdateColumnPosition / UpdateColumnType
  • UpdateComment(表注释)
  • SetProperty / RemoveProperty

7.4 类型映射

Gravitino 类型 Paimon 类型
Boolean Boolean
Byte / Short / Integer / Long TinyInt / SmallInt / Int / BigInt
Float / Double Float / Double
Decimal(p,s) Decimal(p,s)
String VarChar(Integer.MAX_VALUE)
VarChar(n) VarChar(n)
FixedChar(n) Char(n)
Date Date
Time§ Time§
Timestamp§ LocalZonedTimestamp§
Timestamp_tz§ Timestamp§
Binary / Fixed VarBinary / Binary
Struct / Map / List Row / Map / Array

7.5 限制事项

  1. 分区仅支持 Identity 类型(不支持 bucket/truncate/year/month 等变换分区)
  2. 索引仅支持一个主键(不支持二级索引)
  3. 分桶键必须是主键的子集
  4. 排序(Sort Orders)不支持
  5. Spark 目前仅支持 Filesystem + HDFS 后端
  6. 不支持 MERGE INTO / DELETE / UPDATE / TRUNCATE(Spark/Flink 限制)

八、生产环境建议

8.1 Backend 选择

环境 推荐 Backend 原因
本地开发 filesystem (file://) 零依赖
测试环境 filesystem (HDFS) 简单可靠
生产环境 jdbc (MySQL) 高可用、多节点共享
Hive 混合部署 hive 与 Hive 表共享 Metastore
阿里云 rest (DLF) 全托管

8.2 推荐配置

properties 复制代码
# gravitino.conf 相关
gravitino.catalog.cache.evictionIntervalMs=3600000

# Paimon Catalog 属性(通过 gravitino.bypass.* 透传)
gravitino.bypass.table.type=managed
gravitino.bypass.snapshot.num-retained-max=100
gravitino.bypass.snapshot.time-retained=7d

8.3 HDFS 集成

将以下文件放到 ${GRAVITINO_HOME}/catalogs/lakehouse-paimon/conf/

  • core-site.xml(HDFS 地址配置)
  • hdfs-site.xml(HDFS HA 配置)
  • Kerberos 相关配置(如有)
相关推荐
顧棟11 分钟前
HDFS2.X升级3.X案例与相关Issue
大数据·hadoop·hdfs
NOCSAH1 小时前
统好AI SRM模块:智能采购管理实战解析
大数据·人工智能·统好ai·数智一体化平台
黎阳之光2 小时前
数智技术如何赋能空天地一体化,领跑低空经济新赛道
大数据·人工智能·算法·安全·数字孪生
运维行者_3 小时前
使用 Applications Manager 实现 AWS 云监控:保障业务应用高效运行
大数据·运维·服务器·网络·数据库·云计算·aws
NYFEA3 小时前
NYFEA徕飞小尺寸法拉电容,高性能国产替代新选择
大数据·人工智能
星幻元宇VR3 小时前
VR环保学习机|开启沉浸式环保教育新时代
大数据·人工智能·科技·安全·vr·虚拟现实
无忧智库5 小时前
数字化转型 | 全面揭秘企业经营的数字化解决方案 —— 从挑战到突破
大数据·人工智能
Circle Studio5 小时前
AI算力发展的未来趋势
大数据·人工智能
rainy雨5 小时前
精益数据分析系统功能拆解:如何用精益数据分析解决指标虚高难题与初创期验证场景
大数据·数据库·人工智能·信息可视化·数据挖掘·数据分析·精益工程
GlobalInfo5 小时前
2026全球及中国源网荷储一体化方案市场风险评估及前景规划建议报告
大数据·人工智能