Iceberg 导出
GreptimeDB Enterprise 可以通过 Apache Iceberg REST catalog 暴露其表,使得外部查询引擎——pyiceberg、Spark、Trino、DuckDB 以及任何兼容 Iceberg 的客户端——都能使用标准的 Iceberg API 直接从对象存储读取 GreptimeDB 数据。
这是一种只读导出,既不是数据拷贝,也不是双写。GreptimeDB 仍按原有方式写入数据;Iceberg 集成只是发布元数据,让其他引擎能够找到并解读这些相同的文件。
工作原理
关键在于:GreptimeDB 本身就已将 SST(sorted string table)数据文件以 Parquet 格式存储在对象存储中。Iceberg 集成不会重新写入、复制或导出数据,而是发布指向现有 Parquet 文件的 Iceberg 元数据——manifest、manifest-list 以及 table-metadata snapshot。任何支持 Iceberg 的引擎都能通过 REST catalog 读取这些文件。
整体流程如下图所示:
这项工作分布在 GreptimeDB 已有的进程之间:
- Datanode / standalone(写入端)。 每当写入 SST 文件时——包括 flush、compaction、批量写入和 truncate——GreptimeDB 都会将当前存活的 Parquet 文件集合转换为 Iceberg manifest 条目,并提交一个新的 Iceberg snapshot。Iceberg 元数据写入到 datanode 已使用的同一对象存储 bucket 下的
warehouse_root前缀中。 - Frontend(catalog 服务端)。 它实现了 Iceberg REST Catalog API,挂载在
/v1/iceberg,通过直接从对象存储读取元数据向客户端提供每张表当前的元数据——因此 frontend 所需的对象存储配置见配置一节。
由于数据文件从不被复制,因此没有额外的存储开销,也没有写入路径上的重复——导出纯粹是在 GreptimeDB 已写入的数据旁附加的元数据。
GreptimeDB 概念与 Iceberg 的对应关系
| GreptimeDB | Iceberg |
|---|---|
Schema(数据库,例如 public) | Namespace |
| Table(表) | Table |
| Column(列) | Field(字段) |
| 时间索引列 | 一个 timestamp 字段 |
来自 ALTER TABLE(新增 / 重命名 / 删除列)的 schema 变更会反映到 Iceberg schema 中,无需重启。
类型映射
GreptimeDB 列类型到 Iceberg 类型的映射如下:
| GreptimeDB 类型 | Iceberg 类型 |
|---|---|
boolean | boolean |
int8、int16、int32 | int |
int64 | long |
float32 | float |
float64 | double |
string | string |
binary | binary |
date | date |
timestamp(任意精度) | timestamp |
| Prometheus native histogram(struct) | struct(包含 list 子字段) |
uint8、uint16、uint32、uint64 | long — 在 Spark 中不可读(见下文) |
list、dictionary、json、interval、duration、time、任意用户 struct | string(有损降级) |
配置
Iceberg 集成是一个企业版插件。在写入进程(datanode 或 standalone)和frontend的 [[plugins]] 配置段中都添加一个 iceberg_manifest 条目即可启用:
- Datanode / standalone 运行写入 hook,负责发布 Iceberg 元数据。
- Frontend 运行 REST catalog,负责提供这些元数据。
两者必须引用相同的 warehouse_root,以便 catalog 读取到写入端发布的内容。
Datanode / standalone。 该进程本身已配置了 [storage] 数据存储段——保持不变,只需添加插件条目:
## datanode 已在使用的对象存储(现有配置)。
[storage]
type = "S3"
bucket = "greptimedb"
root = "greptimedb"
endpoint = "https://s3.us-east-1.amazonaws.com"
region = "us-east-1"
access_key_id = "<access key id>"
secret_access_key = "<secret access key>"
## Iceberg manifest 导出会发布 Iceberg 格式的元数据(snapshot、
## manifest、manifest-list),使外部引擎(pyiceberg、Spark、Trino、
## DuckDB 等)可以通过 Iceberg REST catalog 查询 GreptimeDB 表。
[[plugins]]
iceberg_manifest = { warehouse_root = "iceberg_warehouse" }
Frontend。 frontend 需要与 datanode 相同的对象存储配置。REST catalog 运行在 frontend 内部,它会直接从对象存储读取 Iceberg 元数据——而不是通过 datanode 获取——因此如果没有 [storage] 配置段,catalog 将无法解析任何表。frontend 通常没有自己的 [storage] 配置段(它只负责代理查询);启用 Iceberg 集成正是它需要该配置段的原因。请配置与 datanode 相同的 bucket、root 和凭证,并添加插件条目:
## 与 datanode 相同的对象存储——frontend 的 REST catalog
## 从这里读取 Iceberg 元数据。
[storage]
type = "S3"
bucket = "greptimedb"
root = "greptimedb"
endpoint = "https://s3.us-east-1.amazonaws.com"
region = "us-east-1"
access_key_id = "<access key id>"
secret_access_key = "<secret access key>"
[[plugins]]
iceberg_manifest = { warehouse_root = "iceberg_warehouse" }
在 Kubernetes 上无需手写 frontend 的 [storage] 配置段。chart 通过 objectStorage 统一配置对象存储,默认只有 datanode 会获得该配置。将 frontend.enableObjectStorage 设为 true,frontend 即可获得与 datanode 相同的对象存储配置;再通过 frontend.configData 添加插件条目:
frontend:
## 将 objectStorage 配置(bucket、root、凭证等)
## 注入为 frontend 的 [storage] 配置段。
enableObjectStorage: true
configData: |-
[[plugins]]
iceberg_manifest = { warehouse_root = "iceberg_warehouse" }
objectStorage 与 configData 字段的说明见常见 Helm Chart 配置。
插件的可选配置项:
| 选项 | 默认值 | 说明 |
|---|---|---|
warehouse_root | "iceberg_warehouse" | Iceberg 元数据在 datanode 对象存储 bucket 内的存放路径前缀。 |
enable_incremental | true | 为 true(默认)时,每次 flush / compaction / truncate 都会自动发布一个新 snapshot。设为 false 可关闭自动发布,改为按需通过 rebuild 接口生成元数据;drop/GC 清理仍会正常运行。 |
warehouse_root 是上述对象存储 bucket 内的一个路径前缀,会被并入 store 的 root(例如 s3://<bucket>/<root>/<warehouse_root>/)——这也正是 frontend 和 datanode 必须在 [storage] 配置和 warehouse_root 上保持一致的原因,否则 catalog 会去寻找并不存在的元数据。
支持的对象存储后端包括 S3、OSS、GCS 和 Azure Blob。
启用后,REST catalog 可通过以下地址访问:
http://<frontend-http-host>:<port>/v1/iceberg
例如,frontend 监听默认的 HTTP 端口 4000 时,catalog 基础 URI 为 http://localhost:4000/v1/iceberg,warehouse 名称为 greptime(默认值)。
让表可被读取
GreptimeDB 在 flush 时发布 Iceberg 元数据,因此新写入的数据会在下一次 flush(或 compaction)后才出现在导出中。若要立即暴露新写入的行,可手动 flush 表:
-- 通过 MySQL 或 PostgreSQL 协议执行
admin flush_table('your_table');
元数据是异步发布的;flush 返回后不久,该表即可通过 REST catalog 查询。
自动发布仅覆盖启用插件之后发生的 manifest 更新(flush、compaction、truncate)——不存在启动时的引导(bootstrap)过程去发布更早 flush 的 SST 文件。因此,在启用集成之前数据就已 flush 的表,在下一次 flush 或 compaction 之前不会出现在 catalog 中。若要导出这类存量表,请对每张表执行一次 rebuild 接口:
curl -X POST \
"http://localhost:4000/v1/iceberg/v1/greptime/namespaces/public/tables/<table>/rebuild"
rebuild 的详细说明与注意事项见下文运维说明中的「Rebuild」。
使用 pyiceberg 读取
本示例使用 pyiceberg 配合 pyarrow,通过 REST catalog 读取一张 GreptimeDB 表。你需要安装 pyiceberg 和 pyarrow