Greptime:GreptimeDB Enterprise 现已集成 Apache Iceberg,支持从 Spark、Trino、DuckDB 和 pyiceberg 等引擎查询您的表,无需复制数据。
摘要
GreptimeDB Enterprise 与 Apache Iceberg 集成,通过发布基于现有 Parquet 文件的 Iceberg 元数据,使表可以从 Spark、Trino、DuckDB 等引擎查询,无需复制数据。
查看缓存全文
缓存时间: 2026/09/15 19:51
GreptimeDB企业版现已与Apache Iceberg集成,使您的表可通过Spark、Trino、DuckDB和pyiceberg进行查询——无需复制数据。该集成会发布引用对象存储中现有Parquet文件的Iceberg元数据,实现跨数据栈的无缝只读分析。
https://docs.greptime.com/enterprise/iceberg/…
#GreptimeDB #ApacheIceberg
Iceberg导出 | GreptimeDB文档
来源:https://docs.greptime.com/enterprise/iceberg/
GreptimeDB企业版可通过Apache Iceberg(https://iceberg.apache.org/)REST目录服务暴露其表,使外部查询引擎——pyiceberg、Spark、Trino、DuckDB及其他兼容Iceberg的客户端——能直接通过标准Iceberg API从对象存储读取GreptimeDB数据。这是只读导出,而非数据复制或双写。GreptimeDB持续以原有方式写入数据;Iceberg集成仅发布元数据,供其他引擎定位并解析这些文件。
工作原理
核心思想在于GreptimeDB已将SST(排序字符串表)数据文件以Parquet格式存储于对象存储中。Iceberg集成不会重写、复制或导出数据,而是发布指向现有Parquet文件的Iceberg元数据——清单文件、清单列表和表元数据快照。任何支持Iceberg的引擎均可通过REST目录读取这些文件。下图展示了各组件如何协同工作:
该过程分布在您已运行的GreptimeDB进程间:
- 数据节点/单机模式(写入端)。每当SST文件被写入(包括刷写、压缩、批量导入和截断操作),GreptimeDB会将当前Parquet文件集转换为Iceberg清单条目,并提交新的Iceberg快照。Iceberg元数据写入对象存储桶中
warehouse_root前缀路径下,该存储桶与数据节点现有使用的是同一个。 - 前端(目录服务器)。它实现了Iceberg REST目录API,挂载于
/v1/iceberg路径,并通过直接从对象存储读取的方式向客户端提供各表的最新元数据——详见配置部分了解前端所需的对象存储设置。
由于数据文件从未被复制,因此不会产生额外存储成本或写入路径重复——导出仅是在GreptimeDB原有数据旁添加纯元数据。
GreptimeDB概念与Iceberg的映射关系
| GreptimeDB概念 | Iceberg对应概念 |
|---|---|
Schema(数据库,如public) | 命名空间(Namespace) |
| 表(Table) | 表(Table) |
| 列(Column) | 字段(Field) |
| 时间索引列 | timestamptz字段 |
通过ALTER TABLE进行的模式变更(添加/重命名/删除列)会实时反映在Iceberg模式中,无需重启服务。
类型映射
GreptimeDB列类型与Iceberg类型的对应关系如下:
| GreptimeDB类型 | Iceberg类型 |
|---|---|
boolean | boolean |
int8、int16、int32 | int |
int64 | long |
float32 | float |
float64 | double |
string | string |
binary | binary |
date | date |
timestamp(任意精度) | timestamptz |
| Prometheus原生直方图(结构体) | struct(含list子字段) |
uint8、uint16、uint32、uint64 | long——在Spark中不可读(见下文) |
list、dictionary、json、interval、duration、time、任意struct | string(有损回退) |
配置
Iceberg集成是企业版插件。需在数据写入进程(数据节点或单机模式)和前端的[[plugins]]配置段中添加iceberg_manifest条目来启用:
- 数据节点/单机模式运行发布Iceberg元数据的写入钩子。
- 前端运行提供目录服务的REST目录。
两者必须引用相同的warehouse_root路径,确保目录读取的是写入端发布的元数据。
数据节点/单机模式。该进程已有用于数据存储的[storage]配置段——保持原样并添加插件条目:
## 数据节点已使用的对象存储(现有配置)
[storage]
type = "S3"
bucket = "greptimedb"
root = "greptimedb"
endpoint = "https://s3.us-east-1.amazonaws.com"
region = "us-east-1"
access_key_id = ""
secret_access_key = ""
## Iceberg清单导出发布Iceberg格式的元数据(快照、清单、清单列表),
## 使外部引擎(pyiceberg、Spark、Trino、DuckDB等)可通过Iceberg REST目录读取GreptimeDB表
[[plugins]]
iceberg_manifest = { warehouse_root = "iceberg_warehouse" }
前端。前端需要与数据节点相同的对象存储配置。REST目录在前端内部运行,并直接从对象存储读取Iceberg元数据——而非通过数据节点获取——因此若无[storage]配置段,目录无法解析任何表。前端通常自身没有[storage]配置段(仅代理查询);启用Iceberg集成正是其需要此配置的原因。请配置与数据节点相同的桶、root路径和凭证,并添加插件条目:
## 与数据节点相同的对象存储——前端的REST目录
## 从此处读取Iceberg元数据
[storage]
type = "S3"
bucket = "greptimedb"
root = "greptimedb"
endpoint = "https://s3.us-east-1.amazonaws.com"
region = "us-east-1"
access_key_id = ""
secret_access_key = ""
[[plugins]]
iceberg_manifest = { warehouse_root = "iceberg_warehouse" }
通过greptimedb-cluster Helm chart部署
在Kubernetes上无需手动编写前端的[storage]配置段。该chart通过objectStorage值集中配置对象存储,默认仅数据节点接收此配置。设置frontend.enableObjectStorage为true以使前端获得相同的对象存储配置,并通过frontend.configData添加插件条目:
frontend:
## 将objectStorage值(桶、root、凭证等)
## 注入前端作为其[storage]配置段
enableObjectStorage: true
configData: |
[[plugins]]
iceberg_manifest = { warehouse_root = "iceberg_warehouse" }
详见Helm chart配置(https://docs.greptime.com/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations/)了解objectStorage和configData字段。
插件选项如下:
| 选项 | 默认值 | 描述 |
|---|---|---|
warehouse_root | "iceberg_warehouse" | 路径前缀,位于数据节点对象存储桶内,用于存储Iceberg元数据 |
enable_incremental | true | 设为true(默认)时,每次刷写/压缩/截断操作都会自动发布新快照。设为false可禁用自动发布,改为通过重建接口按需生成元数据;但删除/GC清理仍会执行 |
warehouse_root是上述对象存储桶内的路径前缀,会合并到存储的root中(如s3://bucket/root/...)——这就是为什么前端和数据节点必须在[storage]配置和warehouse_root上保持一致,否则目录会找不到元数据。
支持的对象存储后端包括S3、OSS、GCS和Azure Blob。启用后,REST目录可通过以下地址访问:
http://<frontend-host>:<port>/v1/iceberg
例如,若前端监听默认HTTP端口4000,则目录基础URI为http://localhost:4000/v1/iceberg,仓库名为greptime(默认值)。
使表可读
GreptimeDB在刷写时发布Iceberg元数据,因此新写入数据的导出会在下次刷写(或压缩)后生效。若要立即暴露刚导入的行,请手动刷写表:
-- 通过MySQL或PostgreSQL协议执行
admin flush_table('your_table');
元数据异步发布;刷写返回后不久,表即可通过REST目录查询。
已有表不会自动导出
自动发布仅涵盖插件启用后发生的清单更新(刷写、压缩、截断)——没有启动时的引导过程来发布此前已刷写的SST文件。因此,在集成启用前已刷写数据的表在下次刷写或压缩前,将不会出现在目录中。要导出此类已有表,请对每个表执行一次重建接口:
curl -X POST \
"http://localhost:4000/v1/iceberg/v1/greptime/namespaces/public/tables/<table_name>/rebuild"
详见下文重建/协调部分了解重建的详细信息和注意事项。
使用pyiceberg读取
本示例使用pyiceberg和pyarrow通过REST目录读取GreptimeDB表。您需要安装pyiceberg和pyarrow,以及支撑GreptimeDB部署的对象存储凭证(此处以S3为例)。
from pyiceberg.catalog.rest import RestCatalog
# GreptimeDB前端暴露的REST目录端点
# `warehouse`是目录名称(默认目录为"greptime")
catalog = RestCatalog(
name="greptime",
uri="http://localhost:4000/v1/iceberg",
prefix="greptime",
# 对象存储凭证,使pyiceberg能读取Parquet数据文件
# 请与GreptimeDB部署使用的后端匹配
**{
"s3.endpoint": "https://s3.us-east-1.amazonaws.com",
"s3.access-key-id": "YOUR_ACCESS_KEY",
"s3.secret-access-key": "YOUR_SECRET_KEY",
"s3.region": "us-east-1",
},
)
# 列出命名空间(= GreptimeDB模式)和表
print(catalog.list_namespaces()) # 例如 [('public',)]
print(catalog.list_tables("public")) # 例如 [('public', 'my_table')]
# 加载表并使用pyarrow扫描
table = catalog.load_table(("public", "my_table"))
print(table.schema()) # Iceberg模式(GreptimeDB列 → 字段)
arrow_table = table.scan().to_arrow()
print(arrow_table.num_rows, "行")
print(arrow_table.to_pandas().head())
使用Spark读取
本示例配置Spark SQL使用GreptimeDB Iceberg REST目录,并对GreptimeDB表执行查询。您需要在Spark类路径中包含Iceberg Spark运行时和AWS bundle JAR文件(版本必须匹配您的Spark/Scala版本——此处以Spark 4.x配合Iceberg 1.11.0为例)。
1. spark-defaults.conf
spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
spark.sql.defaultCatalog=greptime
spark.sql.catalog.greptime=org.apache.iceberg.spark.SparkCatalog
spark.sql.catalog.greptime.type=rest
spark.sql.catalog.greptime.uri=http://localhost:4000/v1/iceberg
spark.sql.catalog.greptime.warehouse=greptime
# S3FileIO从GreptimeDB使用的同一对象存储读取Parquet数据文件
spark.sql.catalog.greptime.io-impl=org.apache.iceberg.aws.s3.S3FileIO
spark.sql.catalog.greptime.client.region=us-east-1
spark.sql.catalog.greptime.s3.endpoint=https://s3.us-east-1.amazonaws.com
spark.sql.catalog.greptime.s3.path-style-access=false
spark.sql.catalog.greptime.s3.access-key-id=YOUR_ACCESS_KEY
spark.sql.catalog.greptime.s3.secret-access-key=YOUR_SECRET_KEY
启动spark-sql(或spark-submit作业)时,需将两个Iceberg JAR文件加入类路径:
spark-sql \
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--jars iceberg-spark-runtime-4.1_2.13-1.11.0.jar,iceberg-aws-bundle-1.11.0.jar
对于具有自定义端点和路径风格寻址的S3兼容存储(例如MinIO、Garage或本地测试部署),请将spark.sql.catalog.greptime.s3.endpoint设为存储URL,并将spark.sql.catalog.greptime.s3.path-style-access设为true。
2. 在GreptimeDB中创建并填充表
通过MySQL或PostgreSQL协议连接GreptimeDB,创建表并刷写以发布Iceberg元数据:
CREATE TABLE demo (
ts TIMESTAMP(6) NOT NULL, -- 时间索引
host STRING,
region STRING,
cpu DOUBLE,
mem FLOAT,
status INT,
TIME INDEX (ts)
);
INSERT INTO demo VALUES
('2024-01-01 00:00:00', 'h1', 'us', 12.5, 4096.0, 200),
('2024-01-01 01:00:00', 'h1', 'us', 88.8, 7000.5, 200),
('2024-01-01 02:00:00', 'h2', 'eu', 55.0, 5500.0, 503);
-- 为刚写入的行发布Iceberg元数据
admin flush_table('demo');
3. 从Spark SQL查询
-- 目录为`greptime`,命名空间是GreptimeDB模式`public`
SHOW TABLES IN greptime.public;
SELECT count(*) FROM greptime.public.demo;
SELECT host, round(avg(cpu), 1) AS avg_cpu
FROM greptime.public.demo
WHERE ts >= '2024-01-01 00:00:00'
GROUP BY host
ORDER BY host;
该表可完全查询:时间范围过滤、聚合、连接、窗口函数和排序均可正常工作,与Spark中任何其他Iceberg表无异。
限制
只读、单一快照
- 只读。您可以通过Iceberg读取GreptimeDB表,但不能通过Iceberg目录写回GreptimeDB。GreptimeDB仍是唯一写入端。
- 仅最新快照(不支持时间旅行)。压缩操作会物理删除旧数据文件,因此历史快照不会保留。Iceberg表始终反映当前最新数据;无法查询先前快照或回滚。
- 不保存完整模式历史。当前模式始终暴露,但不会保留历史模式版本,因此无法重构表在早期时间点的样貌。
数据类型与Spark
GreptimeDB类型与Iceberg类型在常见场景(布尔值、有符号整数、浮点数、字符串、二进制、日期、时间戳)下映射清晰。需特别注意以下几点,尤其是在Spark中:
- 将时间索引声明为
TIMESTAMP(6)。GreptimeDB的默认TIMESTAMP是毫秒精度,但Iceberg模式将列声明为timestamptz(微秒)。对于毫秒列,Spark的Parquet行组统计过滤会将微秒谓词与毫秒文件统计进行比较,可能在执行>、=和范围查询时错误地过滤掉行组。将时间索引声明为TIMESTAMP(6)可使磁盘上Parquet的微秒精度与模式匹配,所有比较运算符均可正常工作。(秒/毫秒值仍正确存储;问题仅在于对文件统计的谓词下推。)现有表无需重新创建:已声明为秒或毫秒精度的时间索引可通过ALTER TABLE就地扩展。此更改无损——现有数据以新单位读取,无需重写,新写入可使用更精细的精度:
ALTER TABLE demo MODIFY COLUMN ts TIMESTAMP_US;
不支持将单位缩回(例如从微秒改回毫秒),也不支持在使用metric引擎的表上进行扩展。详见ALTER TABLE了解详情。
-
有损类型回退。
list、dictionary、json、interval、duration、time和任意用户struct类型会作为Icebergstring导出,而非结构化类型,因此其内部结构无法通过Iceberg查询。 -
无符号整数在Spark中不可读。GreptimeDB无符号整数列(
uint8、uint16、uint32、uint64)被声明为Iceberglong,但底层Parquet文件使用无符号物理类型存储,Spark无法读取。任何触及无符号整数列的扫描
相似文章
@Greptime: GreptimeDB 六月的大部分工作归结为一个想法:如果过滤器无法到达数据,那么它就没用。在分布式查询中…
GreptimeDB 通过启用远程动态过滤器在运行时下推到 datanode 扫描,并优化优化器使其在 MergeScan 包装远程计划之前运行,从而确保过滤器到达数据,提升了分布式查询性能。JSON v2 列现在支持类型提示。
@Greptime: GreptimeDB 的扁平格式查询现在可以在任何列上预过滤——标签、字段、时间戳——而不仅仅是主键。而…
GreptimeDB 的扁平格式查询现在支持在任何列(标签、字段、时间戳)上预过滤,而不仅仅是主键,性能提升高达 4.5 倍。此外,mito2 存储引擎移除了其遗留扫描路径,清理了约 1800 行代码。
@Greptime: GreptimeDB 现在与 DBeaver Community 26.1.5 连接更加便捷!@dbeaver_news 此版本添加了一个专用的 GreptimeD…
DBeaver Community 26.1.5 已发布,新增了一个专用的 GreptimeDB 驱动程序,使时序数据的连接和管理更加便捷。
@Greptime: GreptimeDB v1.1.0 发布,PromQL rate/increase 查询速度提升高达97%,整体查询时间降低20-40%,TS… 上速度提升高达4.5倍
GreptimeDB v1.1.0 已发布,提供高达97%的PromQL查询加速,整体查询时间降低20-40%,在TSBS扫描密集型查询上性能提升高达4.5倍,并支持对现有表进行在线重分区。
@EMQTech:最近的一项基准测试发现,#GreptimeDB 的数据写入吞吐量比 #InfluxDB Enterprise 高出 31%!探索这些发现……
EMQX 报道了一项基准测试,结果显示 GreptimeDB v1.2.0 的数据写入吞吐量比 InfluxDB 3.11.1 企业版高出 31%,同时还对与 EMQX Tables 上的物联网遥测数据相关的查询和存储表现进行了比较。