# GreptimeDB Documentation > GreptimeDB is an open-source observability database for metrics, logs, traces, and wide events. Drop-in replacement for Prometheus, Loki & Elasticsearch, or the single backend for OpenTelemetry. This file contains all documentation content in a single document following the llmstxt.org standard. ## GreptimeDB # 简介 **GreptimeDB** 是一个开源可观测性数据库,可在单一引擎中处理指标、日志和链路追踪。将其作为单一的 OpenTelemetry 后端使用——用一个基于对象存储的数据库替代 Prometheus、Loki 和 Elasticsearch。使用 [SQL](/user-guide/query-data/sql.md) 和 [PromQL](/user-guide/query-data/promql.md) 查询,轻松扩展,成本降低高达 50 倍。 ## 为什么选择 GreptimeDB **用一个系统替代三个系统。** 大多数团队运行 Prometheus 处理指标、Loki 或 ELK 处理日志、Elasticsearch 或 Tempo 处理链路追踪——三个系统、三种查询语言、三套运维开销。GreptimeDB 在单一引擎中统一了这三者,并原生支持 OpenTelemetry。 **成本降低高达 50 倍。** 对象存储(S3、Azure Blob、GCS)作为主要数据存储,计算存储分离。计算节点独立扩展。使用 Rust 编写,配合列式存储和先进的压缩算法,实现最高效率。 **即插即用兼容。** [PromQL](/user-guide/query-data/promql.md)、[Prometheus remote write](/user-guide/ingest-data/for-observability/prometheus.md)、[Jaeger](/user-guide/query-data/jaeger.md)、[MySQL](/user-guide/protocols/mysql.md)、[PostgreSQL](/user-guide/protocols/postgresql.md) 协议——无需重写查询即可迁移。[SQL](/user-guide/query-data/sql.md) + [PromQL](/user-guide/query-data/promql.md) 双查询能力意味着一个数据库就能替代指标存储 + 数据仓库的组合。 了解更多信息请阅读[为什么选择 GreptimeDB](/user-guide/concepts/why-greptimedb.md) 和 [Observability 2.0](/user-guide/concepts/observability-2.md)。 在开始上手之前,请阅读以下文档,其包含了设置说明、基本概念、架构设计和教程: - [立即开始][1]: 为刚接触 GreptimeDB 的用户提供指引,包括如何安装与数据库操作。 - [For AI Agents][8]: 通过 MCP Server、Skills 和机器可读文档,让 AI agent 使用 GreptimeDB。 - [用户指南][2]: 应用程序开发人员可以使用 GreptimeDB 或建立自定义集成。 - [贡献者指南][3]: 有兴趣了解更多技术细节并想成为 GreptimeDB 的贡献者的开发者请阅读此文档。 - [Roadmap][7]: 最新的 GreptimeDB 发展路线图。 - [发布说明][4]: 呈现所有历史版本的发布说明。 - [FAQ][5]: 提供最常见问题的解答。 [1]: ./getting-started/overview.md [8]: ./faq-and-others/vibecoding.md [2]: ./user-guide/overview.md [3]: ./contributor-guide/overview.md [4]: /release-notes [5]: ./faq-and-others/faq.md [7]: https://greptime.cn/blogs/2026-02-11-greptimedb-roadmap-2026 --- ## GreptimeDB 分布式集群 GreptimeDB 可以运行于 [cluster](/contributor-guide/overview.md) 模式以支持水平扩展。 ## 在 Kubernetes 中部署 GreptimeDB 集群 对于生产环境,我们建议在 Kubernetes 中部署 GreptimeDB 集群。请参考 [在 Kubernetes 上部署](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md)。 ## 使用 Docker Compose :::tip 注意 虽然 Docker Compose 是运行 GreptimeDB 集群的便捷方法,但仅适用于开发和测试目的。 对于生产环境或基准测试,我们建议使用 Kubernetes。 ::: ### 前置条件 使用 Docker Compose 是运行 GreptimeDB 集群的最简单方法。开始之前,请确保已经安装了 Docker。 ### 步骤 1: 下载 Docker Compose 的 YAML 文件 ``` wget https://raw.githubusercontent.com/GreptimeTeam/greptimedb/v1.0.2/docker/docker-compose/cluster-with-etcd.yaml ``` ### 步骤 2: 启动集群 ``` GREPTIMEDB_VERSION=v1.0.2 \ GREPTIMEDB_REGISTRY=greptime-registry.cn-hangzhou.cr.aliyuncs.com \ ETCD_REGISTRY=greptime-registry.cn-hangzhou.cr.aliyuncs.com \ docker compose -f ./cluster-with-etcd.yaml up ``` 如果集群成功启动,它将监听 4000-4003 端口。你可以通过参考 [快速开始](../quick-start.md#连接-greptimedb) 访问集群。 ### 清理 你可以使用以下命令停止集群: ``` docker compose -f ./cluster-with-etcd.yaml down ``` 默认情况下,数据将被存储在 `./greptimedb-cluster-docker-compose`。如果你想清理数据,也可删除该目录。 ## 下一步 学习如何使用 GreptimeDB:[快速开始](../quick-start.md#连接-greptimedb)。 --- ## GreptimeDB 控制台 数据可视化在时间序列数据分析时发挥着关键作用。为了帮助用户充分利用 GreptimeDB 的各种功能,GreptimeDB 提供了一个简单的[控制台](https://github.com/GreptimeTeam/dashboard)。 自 GreptimeDB v0.2.0 版本以来,控制台已经默认嵌入到 GreptimeDB 的 binary 文件中。在启动 [GreptimeDB 单机版](greptimedb-standalone.md)或[分布式集群](greptimedb-cluster.md)后,可以通过 URL `http://localhost:4000/dashboard` 访问控制台。控制台支持多种查询语言,包括 [SQL 查询](/user-guide/query-data/sql.md)和 [PromQL 查询](/user-guide/query-data/promql.md)。 我们提供不同种类的图表,可以根据不同的场景进行选择。当用户有足够的数据时,图表的内容将更加丰富。 ![line](/dashboard-line.png) ![scatter](/dashboard-scatter.png) 我们将持续开发和迭代这个开源项目,并计划将时间序列数据应用于监测、分析和其他相关领域的扩展。 --- ## GreptimeDB 单机模式 ## 安装 我们先通过最简单的配置来开始。有关 GreptimeDB 中可用的所有配置选项的详细列表,请参考[配置文档](/user-guide/deployments-administration/configuration.md)。 ## 在 Kubernetes 中部署 GreptimeDB 单机版 对于生产环境,我们建议在 Kubernetes 中部署 GreptimeDB 单机版。请参考 [在 Kubernetes 上部署](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md)。 ### 二进制 你可以在[下载页面](https://greptime.cn/download)通过发布的最新稳定版本尝试使用 GreptimeDB。 ### Linux 或 macOS 如果你使用的是 Linux 或 macOS,可以通过以下命令下载 `greptime` binary 的最新版本: ```shell curl -fsSL \ https://raw.githubusercontent.com/greptimeteam/greptimedb/main/scripts/install.sh | sh -s v1.0.2 ``` 下载完成后,binary 文件 `greptime` 将存储在当前的目录中。 你可以在单机模式下运行 GreptimeDB: ```shell ./greptime standalone start ``` ### Windows 若您的 Windows 系统已开启 WSL([Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/about)),您可以直接打开一个最新的 Ubuntu 接着如上所示运行 GreptimeDB! 否则请到我们的[官网](https://greptime.com/resources)下载并解压最新的 GreptimeDB for Windows 安装包。 在单机模式下运行 GreptimeDB,您可以在 GreptimeDB 二进制所在的文件夹下打开一个终端(比如 Powershell),执行: ```shell .\greptime standalone start ``` ### Docker 请确保已经安装了 [Docker](https://www.docker.com/)。如果还没有安装,可以参考 Docker 官方的[文档](https://www.docker.com/get-started/)进行安装。 ```shell docker run -p 127.0.0.1:4000-4003:4000-4003 \ -v "$(pwd)/greptimedb_data:/greptimedb_data" \ --name greptime --rm \ greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:v1.0.2 standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` :::tip 注意事项 为了防止不小心退出 Docker 容器,你可能想以“detached”模式运行它:在 `docker run` 命令中添加 `-d` 参数即可。 ::: 数据将会存储在当前目录下的 `greptimedb_data/` 目录中。 如果你想要使用另一个版本的 GreptimeDB 镜像,可以从我们的 [GreptimeDB Dockerhub](https://hub.docker.com/r/greptime/greptimedb) 下载。 :::tip 注意事项 如果正在使用小于 [v23.0](https://docs.docker.com/engine/release-notes/23.0/) 的 Docker 版本,由于旧版本的 Docker Engine 中存在 [bug](https://github.com/moby/moby/pull/42681),所以当你尝试运行上面的命令时,可能会遇到权限不足的问题。 你可以: 1. 设置 `--security-opt seccomp=unconfined`: ```shell docker run --security-opt seccomp=unconfined -p 4000-4003:4000-4003 \ -v "$(pwd)/greptimedb_data:/greptimedb_data" \ --name greptime --rm \ greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:v1.0.2 standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` 2. 将 Docker 版本升级到 v23.0.0 或更高; ::: ## 绑定地址 GreptimeDB 默认绑定地址为 `127.0.0.1`。如果你需要能够接收来自所有地址的连接,可以通过以下参数启动。 > :::danger 危险操作 > 如果运行 GreptimeDB 的计算机直接向互联网暴露服务,那么绑定 `0.0.0.0` 会十分危险,因为这将数据库实例暴露给互联网上的所有人。 ```shell ./greptime standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` ```shell docker run -p 0.0.0.0:4000-4003:4000-4003 \ -v "$(pwd)/greptimedb_data:/greptimedb_data" \ --name greptime --rm \ greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:v1.0.2 standalone start \ --http-addr 0.0.0.0:4000 \ --rpc-bind-addr 0.0.0.0:4001 \ --mysql-addr 0.0.0.0:4002 \ --postgres-addr 0.0.0.0:4003 ``` 你也可以参考[配置 GreptimeDB](/user-guide/deployments-administration/configuration.md)文档在配置文件中修改绑定的地址。 ## 下一步 学习如何使用 GreptimeDB:[快速开始](../quick-start.md)。 --- ## GreptimeDB 安装概述 # 安装 根据以下说明安装 GreptimeDB: - [GreptimeDB 单机模式](greptimedb-standalone.md) - [GreptimeDB 分布式集群](greptimedb-cluster.md) ## 检查数据库健康状态 启动 GreptimeDB 后,你可以检查其状态以确保其正常运行。 ```shell curl http://localhost:4000/health ``` 如果 GreptimeDB 实例正常运行,你将看到下面的响应: ```json {} ``` ## 下一步 - [快速入门](/getting-started/quick-start.md):使用 MySQL 或 PostgreSQL 客户端在 GreptimeDB 中写入和查询数据。 --- ## GreptimeDB 入门概述 # 立即开始 > **AGENT ONBOARDING:** 阅读 https://docs.greptime.cn/SKILL.md 并按其中的指引在你的 AI Agent 中使用 GreptimeDB(部署、配置、写入、查询)。 立即开始使用 GreptimeDB! - [安装](./installation/overview.md):安装 GreptimeDB 单机模式或分布式集群。 - [快速开始](./quick-start.md):使用你熟悉的协议或语言快速上手 GreptimeDB。 - [For AI Agents](../faq-and-others/vibecoding.md):通过 MCP Server、Skills 和机器可读文档,让 AI agent 使用 GreptimeDB。 --- ## GreptimeDB 快速开始 # 快速开始 开始之前,请确保已[安装 GreptimeDB](./installation/overview.md)。 本指南用 SQL 带你体验 GreptimeDB 的核心能力——从数据写入到 metrics、logs、traces 跨信号关联查询。SQL 同时也是 GreptimeDB 的管理入口,用于建表、设置 TTL 策略、配置索引等。 :::tip 已经在用 Prometheus、OpenTelemetry、Loki 或 ES? 可以直接用现有工具写入数据,不需要手动建表(GreptimeDB 会[自动建表](/user-guide/ingest-data/overview.md#自动生成表结构)): - [Prometheus Remote Write](/user-guide/ingest-data/for-observability/prometheus.md) - [OpenTelemetry (OTLP)](/user-guide/ingest-data/for-observability/opentelemetry.md) - [Loki 协议](/user-guide/ingest-data/for-observability/loki.md) - [Elasticsearch](/user-guide/ingest-data/for-observability/elasticsearch/) 继续阅读本指南,了解数据进来之后能做什么。 ::: **你将学到(10–15 分钟):** - 连接 GreptimeDB,创建 metrics、logs、traces 表 - 用 SQL 查询和聚合数据 - 全文索引关键词搜索日志 - 用 Range Query 计算时间窗口内的 p95 延迟 - **一条 SQL 关联 metrics、logs 和 traces** - SQL 和 PromQL 混合查询 ## 连接 GreptimeDB GreptimeDB 支持[多种协议](/user-guide/protocols/overview.md)。本指南使用 SQL。 GreptimeDB 默认运行在 `127.0.0.1`,MySQL 协议端口 `4002`,PostgreSQL 协议端口 `4003`,连接方式: ```shell mysql -h 127.0.0.1 -P 4002 ``` 或 ```shell psql -h 127.0.0.1 -p 4003 -d public ``` 也可以用浏览器打开内置 Dashboard `http://127.0.0.1:4000/dashboard`,直接运行本指南中的所有 SQL。 默认未开启[认证](/user-guide/deployments-administration/authentication/overview.md),连接时不需要用户名和密码。 ## 建表 我们创建三张表模拟一个真实场景:gRPC 延迟指标、应用日志和请求链路。两台服务器 `host1` 和 `host2` 在采集数据,从 `2024-07-11 20:00:10` 开始,`host1` 出现异常。 ### Metrics 表 ```sql -- Metrics:gRPC 调用延迟(毫秒) CREATE TABLE grpc_latencies ( ts TIMESTAMP TIME INDEX, host STRING, method_name STRING, latency DOUBLE, PRIMARY KEY (host, method_name) ); ``` - `ts`:数据采集时间([时间索引](/user-guide/concepts/data-model.md))。 - `host` 和 `method_name`:[Tag](/user-guide/concepts/data-model.md) 列,标识时间序列。 - `latency`:[Field](/user-guide/concepts/data-model.md) 列,存放实际指标值。 ### Logs 表 ```sql -- Logs:应用错误日志 CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host STRING, api_path STRING, log_level STRING, log_msg STRING FULLTEXT INDEX WITH('case_sensitive' = 'false'), PRIMARY KEY (host, log_level) ) WITH ('append_mode'='true'); ``` - `log_msg` 启用了[全文索引](/user-guide/manage-data/data-index.md#全文索引),支持关键词搜索。 - [`append_mode`](/user-guide/deployments-administration/performance-tuning/design-table.md#何时使用-append-only-表) 针对日志场景优化(无去重开销)。 ### Traces 表 ```sql -- Traces:请求链路 Span CREATE TABLE traces ( ts TIMESTAMP TIME INDEX, trace_id STRING SKIPPING INDEX, span_id STRING, parent_span_id STRING, service_name STRING, operation STRING, duration DOUBLE, status_code INT, PRIMARY KEY (service_name) ) WITH ('append_mode'='true'); ``` 对于高基数的 `trace_id` 我们启用了[跳数索引](/user-guide/manage-data/data-index.md#跳数索引)。 :::tip 这里用 SQL 写入数据,所以需要手动建表。但 GreptimeDB 支持 [Schemaless](/user-guide/ingest-data/overview.md#自动生成表结构)——通过 OpenTelemetry、Prometheus Remote Write、InfluxDB Line Protocol 等协议写入时,表会自动创建。 ::: ## 写入数据 插入模拟数据。`20:00:10` 之前两台主机都正常,之后 `host1` 开始出现延迟飙升。 ### 正常阶段(20:00:10 之前) ```sql INSERT INTO grpc_latencies (ts, host, method_name, latency) VALUES ('2024-07-11 20:00:06', 'host1', 'GetUser', 103.0), ('2024-07-11 20:00:06', 'host2', 'GetUser', 113.0), ('2024-07-11 20:00:07', 'host1', 'GetUser', 103.5), ('2024-07-11 20:00:07', 'host2', 'GetUser', 107.0), ('2024-07-11 20:00:08', 'host1', 'GetUser', 104.0), ('2024-07-11 20:00:08', 'host2', 'GetUser', 96.0), ('2024-07-11 20:00:09', 'host1', 'GetUser', 104.5), ('2024-07-11 20:00:09', 'host2', 'GetUser', 114.0); ``` ### 异常阶段(20:00:10 之后) `host1` 延迟开始剧烈波动,偶尔飙到几千毫秒:
点击展开 INSERT 语句 ```sql INSERT INTO grpc_latencies (ts, host, method_name, latency) VALUES ('2024-07-11 20:00:10', 'host1', 'GetUser', 150.0), ('2024-07-11 20:00:10', 'host2', 'GetUser', 110.0), ('2024-07-11 20:00:11', 'host1', 'GetUser', 200.0), ('2024-07-11 20:00:11', 'host2', 'GetUser', 102.0), ('2024-07-11 20:00:12', 'host1', 'GetUser', 1000.0), ('2024-07-11 20:00:12', 'host2', 'GetUser', 108.0), ('2024-07-11 20:00:13', 'host1', 'GetUser', 80.0), ('2024-07-11 20:00:13', 'host2', 'GetUser', 111.0), ('2024-07-11 20:00:14', 'host1', 'GetUser', 4200.0), ('2024-07-11 20:00:14', 'host2', 'GetUser', 95.0), ('2024-07-11 20:00:15', 'host1', 'GetUser', 90.0), ('2024-07-11 20:00:15', 'host2', 'GetUser', 115.0), ('2024-07-11 20:00:16', 'host1', 'GetUser', 3000.0), ('2024-07-11 20:00:16', 'host2', 'GetUser', 95.0), ('2024-07-11 20:00:17', 'host1', 'GetUser', 320.0), ('2024-07-11 20:00:17', 'host2', 'GetUser', 115.0), ('2024-07-11 20:00:18', 'host1', 'GetUser', 3500.0), ('2024-07-11 20:00:18', 'host2', 'GetUser', 95.0), ('2024-07-11 20:00:19', 'host1', 'GetUser', 100.0), ('2024-07-11 20:00:19', 'host2', 'GetUser', 115.0), ('2024-07-11 20:00:20', 'host1', 'GetUser', 2500.0), ('2024-07-11 20:00:20', 'host2', 'GetUser', 95.0); ```
### 异常期间的错误日志 ```sql INSERT INTO app_logs (ts, host, api_path, log_level, log_msg) VALUES ('2024-07-11 20:00:10', 'host1', '/api/v1/resource', 'ERROR', 'Connection timeout'), ('2024-07-11 20:00:10', 'host1', '/api/v1/billings', 'ERROR', 'Connection timeout'), ('2024-07-11 20:00:11', 'host1', '/api/v1/resource', 'ERROR', 'Database unavailable'), ('2024-07-11 20:00:11', 'host1', '/api/v1/billings', 'ERROR', 'Database unavailable'), ('2024-07-11 20:00:12', 'host1', '/api/v1/resource', 'ERROR', 'Service overload'), ('2024-07-11 20:00:12', 'host1', '/api/v1/billings', 'ERROR', 'Service overload'), ('2024-07-11 20:00:13', 'host1', '/api/v1/resource', 'ERROR', 'Connection reset'), ('2024-07-11 20:00:13', 'host1', '/api/v1/billings', 'ERROR', 'Connection reset'), ('2024-07-11 20:00:14', 'host1', '/api/v1/resource', 'ERROR', 'Timeout'), ('2024-07-11 20:00:14', 'host1', '/api/v1/billings', 'ERROR', 'Timeout'), ('2024-07-11 20:00:15', 'host1', '/api/v1/resource', 'ERROR', 'Disk full'), ('2024-07-11 20:00:15', 'host1', '/api/v1/billings', 'ERROR', 'Disk full'), ('2024-07-11 20:00:16', 'host1', '/api/v1/resource', 'ERROR', 'Network issue'), ('2024-07-11 20:00:16', 'host1', '/api/v1/billings', 'ERROR', 'Network issue'); ``` ### 异常期间的 Trace Span ```sql INSERT INTO traces (ts, trace_id, span_id, parent_span_id, service_name, operation, duration, status_code) VALUES ('2024-07-11 20:00:12', 'abc123', 'span1', '', 'host1', 'POST /api/v1/resource', 1050.0, 2), ('2024-07-11 20:00:12', 'abc123', 'span2', 'span1', 'host1', 'GetUser', 1000.0, 2), ('2024-07-11 20:00:14', 'def456', 'span3', '', 'host1', 'POST /api/v1/billings', 4250.0, 2), ('2024-07-11 20:00:14', 'def456', 'span4', 'span3', 'host1', 'CreateBilling', 4200.0, 2), ('2024-07-11 20:00:16', 'ghi789', 'span5', '', 'host1', 'POST /api/v1/resource', 3100.0, 2), ('2024-07-11 20:00:16', 'ghi789', 'span6', 'span5', 'host1', 'GetUser', 3000.0, 2), ('2024-07-11 20:00:12', 'jkl012', 'span7', '', 'host2', 'POST /api/v1/resource', 115.0, 0), ('2024-07-11 20:00:12', 'jkl012', 'span8', 'span7', 'host2', 'GetUser', 108.0, 0); ``` ## 查询数据 ### 按 Tag 和时间过滤 查询 `host1` 在 `2024-07-11 20:00:15` 之后的延迟: ```sql SELECT * FROM grpc_latencies WHERE host = 'host1' AND ts > '2024-07-11 20:00:15'; ``` ```sql +---------------------+-------+-------------+---------+ | ts | host | method_name | latency | +---------------------+-------+-------------+---------+ | 2024-07-11 20:00:16 | host1 | GetUser | 3000 | | 2024-07-11 20:00:17 | host1 | GetUser | 320 | | 2024-07-11 20:00:18 | host1 | GetUser | 3500 | | 2024-07-11 20:00:19 | host1 | GetUser | 100 | | 2024-07-11 20:00:20 | host1 | GetUser | 2500 | +---------------------+-------+-------------+---------+ 5 rows in set (0.14 sec) ``` 按 host 计算 p95 延迟: ```sql SELECT host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) AS p95_latency FROM grpc_latencies WHERE ts >= '2024-07-11 20:00:10' GROUP BY host; ``` ```sql +-------+-------------------+ | host | p95_latency | +-------+-------------------+ | host1 | 4164.999999999999 | | host2 | 115 | +-------+-------------------+ 2 rows in set (0.11 sec) ``` ### 全文搜索日志 `@@` 操作符用于[全文搜索](/user-guide/logs/fulltext-search.md): ```sql SELECT * FROM app_logs WHERE lower(log_msg) @@ 'timeout' AND ts > '2024-07-11 20:00:00' ORDER BY ts; ``` ```sql +---------------------+-------+------------------+-----------+--------------------+ | ts | host | api_path | log_level | log_msg | +---------------------+-------+------------------+-----------+--------------------+ | 2024-07-11 20:00:10 | host1 | /api/v1/billings | ERROR | Connection timeout | | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection timeout | | 2024-07-11 20:00:14 | host1 | /api/v1/billings | ERROR | Timeout | | 2024-07-11 20:00:14 | host1 | /api/v1/resource | ERROR | Timeout | +---------------------+-------+------------------+-----------+--------------------+ ``` ### Range Query 用 [Range Query](/reference/sql/range.md) 计算 5 秒窗口内的 p95 延迟: ```sql SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ORDER BY host, ts; ``` ```sql +---------------------+-------+-------------+ | ts | host | p95_latency | +---------------------+-------+-------------+ | 2024-07-11 20:00:05 | host1 | 104.5 | | 2024-07-11 20:00:10 | host1 | 4200 | | 2024-07-11 20:00:15 | host1 | 3500 | | 2024-07-11 20:00:20 | host1 | 2500 | | 2024-07-11 20:00:05 | host2 | 114 | | 2024-07-11 20:00:10 | host2 | 111 | | 2024-07-11 20:00:15 | host2 | 115 | | 2024-07-11 20:00:20 | host2 | 95 | +---------------------+-------+-------------+ 8 rows in set (0.06 sec) ``` Range Query 是 GreptimeDB 做时间窗口聚合的利器,详见[文档](/reference/sql/range.md)。 ### 关联 Metrics、Logs 和 Traces 统一数据库的真正威力在这里。一条查询同时关联 p95 延迟、错误日志数和慢 Trace Span——跨三种信号类型: ```sql WITH -- Metrics:按 host 计算 5 秒窗口的 p95 延迟 metrics AS ( SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ), -- Logs:按 host 统计 5 秒窗口的 ERROR 数 logs AS ( SELECT ts, host, count(log_msg) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' ), -- Traces:按 host 统计 5 秒窗口的慢 Span slow_traces AS ( SELECT date_bin(INTERVAL '5' seconds, ts) AS ts, service_name AS host, COUNT(*) AS slow_spans, MAX(duration) AS max_span_duration FROM traces WHERE duration > 500 GROUP BY date_bin(INTERVAL '5' seconds, ts), service_name ) SELECT m.ts, m.host, m.p95_latency, COALESCE(l.num_errors, 0) AS num_errors, COALESCE(t.slow_spans, 0) AS slow_spans, t.max_span_duration FROM metrics m LEFT JOIN logs l ON m.host = l.host AND m.ts = l.ts LEFT JOIN slow_traces t ON m.host = t.host AND m.ts = t.ts ORDER BY m.ts, m.host; ``` ```sql +---------------------+-------+-------------+------------+------------+-------------------+ | ts | host | p95_latency | num_errors | slow_spans | max_span_duration | +---------------------+-------+-------------+------------+------------+-------------------+ | 2024-07-11 20:00:05 | host1 | 104.5 | 0 | 0 | NULL | | 2024-07-11 20:00:05 | host2 | 114 | 0 | 0 | NULL | | 2024-07-11 20:00:10 | host1 | 4200 | 10 | 4 | 4250 | | 2024-07-11 20:00:10 | host2 | 111 | 0 | 0 | NULL | | 2024-07-11 20:00:15 | host1 | 3500 | 4 | 2 | 3100 | | 2024-07-11 20:00:15 | host2 | 115 | 0 | 0 | NULL | | 2024-07-11 20:00:20 | host1 | 2500 | 0 | 0 | NULL | | 2024-07-11 20:00:20 | host2 | 95 | 0 | 0 | NULL | +---------------------+-------+-------------+------------+------------+-------------------+ 8 rows in set (0.02 sec) ``` 结论很清晰:**`20:00:10` – `20:00:15` 窗口内,`host1` 的 p95 延迟飙到 4200ms,出现 10 条错误日志,4 个慢 Span(最慢 4250ms)。`host2` 全程正常。** 在传统三支柱架构下,这个关联分析需要在 Prometheus、Loki、Jaeger 之间来回切换。用 GreptimeDB,一条查询搞定。 ### 用 PromQL 查询 GreptimeDB 原生支持 [PromQL](/user-guide/query-data/promql.md)。在 Dashboard 切到 PromQL tab,运行: ```promql quantile_over_time(0.95, grpc_latencies{host!=""}[5s]) ``` 也可以通过 Prometheus 兼容的 HTTP API 查询: ```bash curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ --data-urlencode 'query=quantile_over_time(0.95, grpc_latencies{host!=""}[5s])' \ --data-urlencode 'start=2024-07-11 20:00:00Z' \ --data-urlencode 'end=2024-07-11 20:00:20Z' \ --data-urlencode 'step=15s' \ 'http://localhost:4000/v1/prometheus/api/v1/query_range' ```
返回结果 ```json { "status": "success", "data": { "resultType": "matrix", "result": [ { "metric": { "__name__": "grpc_latencies", "host": "host1", "method_name": "GetUser" }, "values": [ [ 1720728015.0, "3560" ] ] }, { "metric": { "__name__": "grpc_latencies", "host": "host2", "method_name": "GetUser" }, "values": [ [ 1720728015.0, "114.2" ] ] } ] } } ```
### SQL + PromQL 混合查询 用 [TQL](/reference/sql/tql.md) 在 SQL 里嵌入 PromQL: ```sql TQL EVAL ('2024-07-11 20:00:00Z', '2024-07-11 20:00:20Z', '15s') quantile_over_time(0.95, grpc_latencies{host!=""}[5s]); ``` ```sql +---------------------+---------------------------------------------------------+-------+-------------+ | ts | prom_quantile_over_time(ts_range,latency,Float64(0.95)) | host | method_name | +---------------------+---------------------------------------------------------+-------+-------------+ | 2024-07-11 20:00:15 | 3560 | host1 | GetUser | | 2024-07-11 20:00:15 | 114.2 | host2 | GetUser | +---------------------+---------------------------------------------------------+-------+-------------+ ``` 还可以把 PromQL 作为 CTE 用在关联查询里: ```sql WITH metrics AS ( TQL EVAL ('2024-07-11 20:00:00Z', '2024-07-11 20:00:20Z', '5s') quantile_over_time(0.95, grpc_latencies{host!=""}[5s]) ), logs AS ( SELECT ts, host, COUNT(log_msg) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' ) SELECT m.*, COALESCE(l.num_errors, 0) AS num_errors FROM metrics AS m LEFT JOIN logs AS l ON m.host = l.host AND m.ts = l.ts ORDER BY m.ts, m.host; ``` ```sql +---------------------+---------------------------------------------------------+-------+-------------+------------+ | ts | prom_quantile_over_time(ts_range,latency,Float64(0.95)) | host | method_name | num_errors | +---------------------+---------------------------------------------------------+-------+-------------+------------+ | 2024-07-11 20:00:10 | 140.89999999999998 | host1 | GetUser | 10 | | 2024-07-11 20:00:10 | 113.8 | host2 | GetUser | 0 | | 2024-07-11 20:00:15 | 3560 | host1 | GetUser | 4 | | 2024-07-11 20:00:15 | 114.2 | host2 | GetUser | 0 | | 2024-07-11 20:00:20 | 3400 | host1 | GetUser | 0 | | 2024-07-11 20:00:20 | 115 | host2 | GetUser | 0 | +---------------------+---------------------------------------------------------+-------+-------------+------------+ ``` ## GreptimeDB Dashboard GreptimeDB 内置了 [Dashboard](./installation/greptimedb-dashboard.md),用于数据探索和管理。 ### 数据探索 打开 `http://localhost:4000/dashboard`,点 `+` 新建查询,输入 SQL,点 `Run All` 执行。点结果面板的 `Chart` 按钮可以可视化数据。 ```sql SELECT * FROM grpc_latencies; ``` ![查询 gRPC 延迟](/select-grpc-latencies.png) ### 用 InfluxDB Line Protocol 写入 点 Dashboard 的 `Ingest` 图标,可以用 [InfluxDB Line Protocol](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md) 格式写入数据: ```txt grpc_metrics,host=host1,method_name=GetUser latency=100,code=0 1720728021000000000 grpc_metrics,host=host2,method_name=GetUser latency=110,code=1 1720728021000000000 ``` 点 `Write` 写入。`grpc_metrics` 表不存在会自动创建——这就是 GreptimeDB 的 [Schemaless](/user-guide/ingest-data/overview.md#自动生成表结构) 能力。 ## 下一步 **接入现有栈:** - [Prometheus Remote Write](/user-guide/ingest-data/for-observability/prometheus.md) — 把 Prometheus 指向 GreptimeDB - [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md) — 配置 OTel Collector 发送 metrics、logs、traces - [Jaeger](/user-guide/query-data/jaeger.md) — 用 GreptimeDB 作为 Jaeger 的存储后端 - [Loki](/user-guide/ingest-data/for-observability/loki.md) — 用 Loki 协议发送日志 - [Elasticsearch](/user-guide/ingest-data/for-observability/elasticsearch/) — 用 Elasticsearch `_bulk` API 发送日志、traces 和事件 - 查看[所有写入方式](/user-guide/ingest-data/overview/#推荐的数据写入方法) **可视化和监控:** - [Grafana 集成](/user-guide/integrations/grafana.md) — 用 SQL 或 PromQL 数据源连接 Grafana - [内置 Dashboard](/getting-started/installation/greptimedb-dashboard.md) — `http://localhost:4000/dashboard` **深入了解:** - [为什么选择 GreptimeDB](/user-guide/concepts/why-greptimedb.md) — 架构、成本对比、竞品比较 - [Observability 2.0](/user-guide/concepts/observability-2.md) — 宽事件和统一数据模型 - [Demo 场景](https://github.com/GreptimeTeam/demo-scene/) — 更多动手示例 - [用户指南](/user-guide/overview.md) — 完整参考 --- ## 架构 GreptimeDB 采用计算存储分离架构,持久化数据保存在对象存储中,计算节点可以独立扩展。 相比以本地磁盘作为主存储的架构,这种方式更容易实现弹性扩展,也更有利于降低运维成本。 ## 高层架构 ![GreptimeDB 高层架构](/architecture-4.png) ## 组件 GreptimeDB 在分布式模式下有三个核心组件,以及一个用于流计算的可选组件: - [**Metasrv**](/contributor-guide/metasrv/overview.md):元数据与路由控制平面。负责管理 catalog、schema、table、region 等元数据,协调调度,并为其他节点提供路由信息。 - [**Frontend**](/contributor-guide/frontend/overview.md):无状态接入层。接收客户端协议请求、执行鉴权、规划和分发查询,并根据 Metasrv 的元数据完成读写路由。 - [**Datanode**](/contributor-guide/datanode/overview.md):存储与执行层。负责存储表的 region,处理读写请求,持久化 WAL,并将数据文件刷入对象存储。 - [**Flownode(可选)**](/contributor-guide/flownode/overview.md):[流计算](/user-guide/flow-computation/overview.md)的流式/持续计算运行时。在分布式部署中,如果需要将 flow workload 独立为单独服务运行,就会使用 Flownode。 在 standalone 模式下,你运行的是一个 GreptimeDB 进程,而不是分别管理这些独立服务。 ## 工作方式 ### 写入路径 1. 客户端通过支持的协议向 Frontend 发起写请求。 2. Frontend 从 Metasrv 的元数据中解析表和 region 的路由信息,并在需要时刷新本地缓存。 3. Frontend 将请求拆分并转发到目标 Datanode。 4. Datanode 先将数据写入内存和 [WAL](/user-guide/deployments-administration/wal/overview.md),随后把不可变数据文件刷入[对象存储](./storage-location.md)。 ### 查询路径 1. 客户端通过 Frontend 发起 SQL、PromQL、日志或链路追踪查询。 2. Frontend 生成分布式执行计划,并将子查询下发到相关的 Datanode。 3. Datanode 在各自负责的 region 上执行子查询并返回部分结果。 4. Frontend 汇总结果并返回给客户端。 ### Flow 路径(可选) 启用流计算后,Flownode 会持续读取源表的变化,并将计算结果写入目标表。 详细说明请参阅[流计算](/user-guide/flow-computation/overview.md)。 如果你想了解实现层细节,请参阅 [Contributor Guide](/contributor-guide/overview.md)。 --- ## 数据模型 ## 模型 GreptimeDB 使用时序表来组织、压缩和管理数据的过期。数据模型基于关系型数据库的表模型,同时针对 metrics、logs、traces 的特点做了适配。 所有数据按表组织,每个表中的列分为三种语义类型:`Tag`、`Timestamp` 和 `Field`。 - 表名通常和指标名、日志源名或 metric 名称一致。 - `Tag` 列标识时间序列的身份。相同 Tag 值的行属于同一条时间序列(有些 TSDB 也叫 label)。 - `Timestamp` 是时序数据库的根基,表示数据的生成时间。每个表只能有一个 `Timestamp` 类型的列,也叫时间索引(`Time Index`)。 - 其余列是 `Field` 列,存放实际的数据指标或日志内容,通常是数值或字符串,也可以是地理位置、时间戳等其他类型。 表按时间序列组织行,同一时间序列内按 `Timestamp` 排序。表还可以对相同 `Tag` + `Timestamp` 的行做去重,具体取决于业务需求。物理上,GreptimeDB 会把数据持久化为不可变的 Parquet SST 文件,行按照 `(primary key, timestamp)` 排序;当表没有 primary key(例如下面的 append-only 日志表)时,仅按照 timestamp 排序。要了解 SST 文件中的数据布局和裁剪方式,详见[存储引擎](/contributor-guide/datanode/storage-engine.md#sst-文件中的数据布局)文档。选择合适的表结构对查询和存储效率至关重要,详见[表设计指南](/user-guide/deployments-administration/performance-tuning/design-table.md)。 ### Metrics 假设有一个 `system_metrics` 表,监控数据中心机器的资源使用: ```sql CREATE TABLE IF NOT EXISTS system_metrics ( host STRING, idc STRING, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(host, idc), TIME INDEX(ts) ); ``` 数据模型如下: ![time-series-table-model](/time-series-data-model.svg) 和常见的关系表模型很像,区别在于 `TIME INDEX` 约束——用来指定 `ts` 列为时间索引。 - 表名 `system_metrics`。 - `PRIMARY KEY` 指定 Tag 列:`host` 是主机名,`idc` 是数据中心。 - `ts` 是 Timestamp 列,表示数据采集时间。 - `cpu_util`、`memory_util`、`disk_util` 是 Field 列,存放实际数据。 - 表按 `host`、`idc`、`ts` 排序和去重,所以 `select count(*) from system_metrics` 需要扫全表。 Prometheus metrics 如何映射到这个模型,参见[文档](/user-guide/ingest-data/for-observability/prometheus/#数据模型)。 ### Logs 创建一个存 Web Server 访问日志的表: ```sql CREATE TABLE access_logs ( access_time TIMESTAMP TIME INDEX, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request STRING, ) with ('append_mode'='true'); ``` - 时间索引列是 `access_time`。 - 没有 Tag 列。 - `http_status`、`http_method`、`remote_addr`、`http_refer`、`user_agent`、`request` 是 Field 列。 - 按 `access_time` 排序。 - 这是一个 [append-only 表](/reference/sql/create.md#创建-append-only-表),不支持去重和删除,适合日志场景。 - 查询 append-only 表通常更快,比如 `select count(*) from access_logs` 可以直接用统计信息返回结果,不需要考虑去重。 如何指定 `Tag`、`Timestamp`、`Field` 列,参见[表管理](/user-guide/deployments-administration/manage-data/basic-table-operations.md#创建表)和 [CREATE 语句](/reference/sql/create.md)。 ### Traces GreptimeDB 支持通过 OTLP/HTTP 协议直接写入 OpenTelemetry traces 数据,详见 [OTLP traces 数据模型](/user-guide/ingest-data/for-observability/opentelemetry.md#数据模型-2)。 ## 设计考虑 GreptimeDB 为什么选择表模型: - 表模型用户基础广、学习门槛低。在此基础上加一个时间索引的概念,就能统一处理 metrics、logs、traces。 - Schema 是描述数据特征的元数据,方便管理和维护。 - Schema 提供类型、长度等信息,存储和计算引擎可以做针对性优化。 - 有了表模型,自然引入 SQL,用 SQL 做跨表关联分析和聚合查询,降低用户的学习成本。 - GreptimeDB 采用多值模型,单行可以有多个 Field 列,相比需要把数据拆成多条记录的单值模型,省传输流量、查询也更简洁。详见[博客](https://greptime.cn/blogs/2024-05-09-prometheus)。 - 在 Observability 2.0 范式中,metrics、logs、traces 被视为同一组底层"宽事件"的不同投影。GreptimeDB 的统一表模型天然支持这一点——所有信号类型共享 Tag + Timestamp + Field schema,一条 SQL 就能做跨信号关联。详见 [Observability 2.0](./observability-2.md)。 GreptimeDB 用 SQL 管理表 schema,参见[表管理](/user-guide/deployments-administration/manage-data/basic-table-operations.md)。不过 schema 定义不是强制的,更偏向 **Schemaless** 的方式——写入时自动建表、自动加列。详见[自动生成表结构](../ingest-data/overview.md#自动生成表结构)。 --- ## 常见问题 ## GreptimeDB 如何处理 metrics、logs 和 traces? GreptimeDB 将所有可观测数据——metrics、logs、traces——作为带上下文的时间戳事件,统一存储在列式引擎中。用 SQL 查所有信号类型,用 PromQL 查 metrics,用 Flow 做持续聚合。 详见[日志用户指南](/user-guide/logs/overview.md)和[链路追踪用户指南](/user-guide/traces/overview.md)。 ## 支持更新数据吗? 支持,参见[更新数据](/user-guide/manage-data/overview.md#更新数据)。 ## 支持删除数据吗? 支持,参见[删除数据](/user-guide/ingest-data/overview.md#删除数据)。 ## 可以按表设置 TTL 或保留策略吗? 可以,参见[使用 TTL 策略保留数据](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据)。 ## 压缩率是多少? 取决于数据特征。 GreptimeDB 用列式存储,根据列数据的统计分布自动选择最优压缩算法。未来还会提供 Rollup 功能,以损失精度为代价进一步压缩。 实际压缩率在 2 倍到数百倍之间,取决于数据特征和是否接受精度损失。 ## 如何解决高基数问题? GreptimeDB 通过多层手段解决高基数挑战: **架构层面:** - **分片**:数据和索引分布在多个 Region Server 上,单节点不会成为瓶颈。详见 [架构](./architecture.md)。 **存储层面:** - **Flat Format(针对极端高基数)**:当 tag 是请求 ID、trace ID、用户 token 这类百万级唯一值时,传统时序数据库为每个序列分配独立 buffer,序列数一多就内存膨胀、性能下降。GreptimeDB 1.0+ 的 Flat Format 引入了 BulkMemtable 和多序列合并路径,消除 per-series 开销,高基数场景下**写入吞吐量提升 4 倍,查询快 10 倍**。详见 [Flat Format 详解](https://greptime.cn/blogs/2025-12-22-flat-format)。 **索引层面:** - **灵活索引**:支持按需手工创建索引。可以为 tag 列和 field 列创建多种索引类型(倒排、全文、跳数),而不是自动为每列建索引。按需创建索引既能优化查询性能,又能降低索引开销。详见[索引文档](/user-guide/manage-data/data-index.md)。 **查询层面:** - **MPP(大规模并行处理)**:查询引擎用向量化执行和分布式并行处理,高效处理高基数查询。 **结果:** GreptimeDB 不会遇到 Prometheus 那样的基数上限——在 Prometheus 中,高基数 label 会导致内存耗尽和查询超时。GreptimeDB 可以处理百万级序列,不需要架构层面的妥协。 ## 支持持续聚合或降采样吗? 支持。GreptimeDB 从 0.8 版本开始提供 Flow 功能,用于持续聚合和降采样等场景。详见[用户指南](/user-guide/flow-computation/overview.md)。 ## 可以把数据存到云上的对象存储吗? 可以。GreptimeDB 的数据访问层基于 [OpenDAL](https://github.com/apache/incubator-opendal),支持主流对象存储服务。数据可以存到 AWS S3、Azure Blob Storage 等,参见[存储配置](/user-guide/deployments-administration/configuration.md#存储选项)。 ## 性能对比其他方案怎么样? [GreptimeDB 在 ClickHouse JSONBench 10 亿条冷查询中拿下第一!](https://greptime.cn/blogs/2025-03-18-json-benchmark-greptimedb) 性能测试报告: * [GreptimeDB vs. InfluxDB](https://greptime.cn/blogs/2024-08-08-report) * [GreptimeDB vs. TimescaleDB](https://greptime.cn/blogs/2025-12-09-greptimedb-vs-timescaledb-benchmark) * [GreptimeDB vs. Grafana Mimir](https://greptime.cn/blogs/2024-08-01-grafana) * [GreptimeDB vs. ClickHouse vs. Elasticsearch](https://greptime.cn/blogs/2025-03-07-greptimedb-log-benchmark) * [GreptimeDB vs. SQLite](https://greptime.cn/blogs/2024-08-30-sqlite) ## 有灾难恢复方案吗? 有,参见[灾难恢复文档](/user-guide/deployments-administration/disaster-recovery/overview.md)。 ## 支持地理空间索引吗? 支持,提供 Geohash、H3 和 S2 的[内置函数](/reference/sql/functions/geo.md)。 ## 支持 JSON 数据吗? 支持,参见 [JSON 函数](/reference/sql/functions/overview.md#json-functions)。 ## 更多问题? 包括部署选项、迁移指南、性能对比、最佳实践等,请访问[常见问题页面](/faq-and-others/faq.md)。 --- ## 核心概念 为了理解 GreptimeDB 如何管理和服务其数据,你需要了解这些 GreptimeDB 的构建模块。 ## 数据库 类似于关系型数据库中的数据库,数据库是数据容器的最小单元,数据可以在这个单元中被管理和计算。 你可以利用数据库来实现数据隔离,形成类似租户的效果。 ## Time-Series Table GreptimeDB 将时序表设计为数据存储的基本单位。 其类似于传统关系型数据库中的表,但需要一个时间戳列(我们称之为 `TIME INDEX`—— **时间索引**),并且该表持有一组共享一个共同 schema 的数据。 表是行和列的集合: * 行:表中水平方向的值的集合。 * 列:表中垂直方向的值的集合,GreptimeDB 将列分为时间索引 Time Index、标签 Tag 和字段 Field。 你使用 SQL `CREATE TABLE` 创建表,或者使用[自动生成表结构](/user-guide/ingest-data/overview.md#自动生成表结构)功能通过输入的数据结构自动创建表。在分布式部署中,一个表可以被分割成多个分区,其位于不同的数据节点上。 关于时序表的数据模型的更多信息,请参考[数据模型](./data-model.md)。 ## Table Engine 表引擎(也称为存储引擎)决定了数据在数据库中的存储、管理和处理方式。每种引擎提供不同的功能特性、性能表现和权衡取舍。GreptimeDB 提供了 `mito` 和 `metric` 引擎,有关更多信息,请参阅[表引擎](/reference/about-greptimedb-engines.md)。 ## Table Region 分布式表的每个分区被称为一个区域。一个区域可能包含一个连续数据的序列,这取决于分区算法,区域信息由 Metasrv 管理。这对发送写入和查询的用户来说是完全透明的。 ## 数据类型 GreptimeDB 中的数据是强类型的,当创建表时,Auto-schema 功能提供了一些灵活性。当表被创建后,同一列的数据必须共享共同的数据类型。 在[数据类型](/reference/sql/data-types.md)中找到所有支持的数据类型。 ## 索引 索引是一种性能调优方法,可以加快数据的更快地检索速度。 GreptimeDB 提供多种类型的[索引](/user-guide/manage-data/data-index.md)来加速查询。 ## View 从 SQL 查询结果集派生的虚拟表。它像真实表一样包含行和列,但它本身不存储任何数据。 每次查询视图时,都会从底层表中动态检索视图中显示的数据。 ## Flow GreptimeDB 中的 Flow 是指[持续聚合](/user-guide/flow-computation/overview.md)过程,该过程根据传入数据持续更新和聚合数据。 --- ## Observability 2.0 Observability 2.0 是可观测性领域从"三支柱"(metrics、logs、traces)向统一数据模型的演进。核心思路是:不再为每种信号维护独立系统,而是用高基数的宽事件(wide events)作为单一数据源,支持事后分析,而非依赖预聚合。 这个术语本身有争议,但背后的问题是真实的:metrics、logs、traces 之间的壁垒,让排障和分析变得越来越痛苦。 ## 三支柱的局限 可观测性长期依赖 metrics、logs、traces 三大支柱,也催生了大量优秀工具(包括 [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md))。但随着系统复杂度增长,三支柱架构的问题越来越明显: 1. **数据孤岛**:metrics、logs、traces 分开存储,互不关联。一个错误率飙升的告警,要手动在三个系统间切换才能定位到对应的日志和链路——这个过程既慢又容易遗漏。 2. **粒度和成本两难**:传统 metrics 靠预聚合压缩数据量。但为了保留排障所需的细节,团队不得不创建百万级时间序列,各系统还有大量冗余元数据,成本反而比省下的更高。 3. **日志的结构化困境**:日志天然包含结构化信息,但从非结构化文本中提取价值需要大量的解析、索引和计算。 在 AI agent 和微服务场景下,这些问题更加突出——高维、半结构化数据已经是常态。 ## 宽事件:统一数据模型 Observability 2.0 用**宽事件(wide events)** 来解决这些问题。宽事件是一条上下文丰富、高维度、高基数的记录,在单个事件中捕获完整的应用状态。 ### 什么是宽事件? 不预计算 metrics,不预处理日志,直接保存原始的高保真事件数据。比如一个 POST 请求的宽事件可能包含: - 用户信息和订阅数据 - 带参数的数据库查询 - 缓存操作 - HTTP headers - 总计:单条记录 2KB+ 的上下文 ```json { "method": "POST", "path": "/articles", "service": "articles", "outcome": "ok", "status_code": 201, "duration": 268, "user": { "id": "fdc4ddd4-8b30-4ee9-83aa-abd2e59e9603", "subscription": { "plan": "free", "trial": true } }, "db": { "query": "INSERT INTO articles (...)", "parameters": { "$1": "f8d4d21c-..." } }, "cache": { "operation": "write", "key": "..." }, "headers": { "user-agent": "...", "cf-connecting-ip": "..." } } ``` ### Metrics、Logs、Traces 只是投影 宽事件的关键洞察:metrics、logs、traces 不是三种独立的数据类型,而是同一组底层事件的不同投影: - **Metrics**:`SELECT COUNT(*) GROUP BY status, date_bin(INTERVAL '1' minute, timestamp)` — 聚合投影 - **Logs**:`SELECT message, timestamp WHERE message @@ 'error'` — 文本投影 - **Traces**:`SELECT span_id, duration WHERE trace_id = '...'` — 关系投影 有了原始宽事件,任何 metrics、日志查询、trace 视图都可以事后从同一份数据派生出来——不需要预聚合,不需要改代码。 ## AI Agent 为什么需要宽事件 AI agent 的非确定性行为给可观测性带来了全新的挑战。传统应用有可预测的代码路径,但 agent 是动态决策的——选工具、多步推理、根据上下文调整响应。调试"agent 为什么这么做"需要保留完整的执行状态:prompt、推理链、工具调用参数、memory 状态、质量评分——全部在一条可查询的记录里。 三支柱架构在这里完全不适用:prompt 塞进日志会丢失结构,工具调用硬套进 trace 对动态行为太僵硬,token 用量做成 metrics 会丢失调试所需的上下文。AI agent 天然产生高基数(百万级独立 session)、高维度(每次执行几十个字段)、上下文丰富的事件——这恰恰是宽事件要解决的问题。 这不是"AI 时代的可观测性"这种营销话术,而是技术上的必然:非确定性系统需要细粒度、结构化、可追溯的分析能力。 ## GreptimeDB 的 Observability 2.0 支撑 GreptimeDB 的[架构](/user-guide/concepts/architecture.md)天然适配 Observability 2.0。列式引擎高效压缩宽事件(生产环境实测比 Loki 节省 50%、比 Elasticsearch 节省约 90% 存储),[原生对象存储](/user-guide/concepts/storage-location.md)(S3、Azure Blob、GCS)让存储成本随数据量线性增长而非指数增长。以下是和宽事件最相关的核心能力。 ### 统一的 Tag + Timestamp + Field 模型 所有可观测数据——metrics、logs、traces——在 GreptimeDB 中共享同一套 [schema 模型](/user-guide/concepts/data-model.md): - **Tag**:实体标识(pod_name、service、region、trace_id、session_id) - **Timestamp**:时间戳 - **Field**:多维度值(message、duration、status_code、prompt、response) 一个模型统一三种信号,在单条 SQL 里就能做跨信号关联。 ### SQL + PromQL 跨信号关联 用一条 [SQL](/user-guide/query-data/sql.md) 同时查 metrics 异常、日志模式和 trace 延迟: ```sql SELECT date_bin(INTERVAL '1' minute, timestamp) AS minute, COUNT(CASE WHEN status >= 500 THEN 1 END) AS errors, AVG(duration) AS avg_latency FROM access_logs WHERE timestamp >= NOW() - INTERVAL '1' hour AND message @@ 'timeout' GROUP BY date_bin(INTERVAL '1' minute, timestamp); ``` 不用在系统间切换,所有信号在同一个数据库里。同时支持 [PromQL](/user-guide/query-data/promql.md),现有 Grafana 仪表板可以直接复用。 ### Flow 引擎:从宽事件实时派生 Metrics GreptimeDB 的 [Flow 引擎](/user-guide/flow-computation/overview.md)直接从原始事件实时计算 metrics,不需要额外的预处理管道: ```sql CREATE FLOW http_status_count SINK TO status_metrics AS SELECT status, COUNT(*) AS count, date_bin('1 minute'::INTERVAL, timestamp) AS time_window FROM access_logs GROUP BY status, time_window; ``` 同一份宽事件数据,既能驱动预聚合仪表板,也能支持 ad-hoc 的探索式查询。 ## 生产验证 宽事件不是概念,已经在大规模生产环境中得到验证: - **得物(Poizon)**:宽事件的早期生产级落地。Flow 引擎 + 多级持续聚合,P99 延迟从秒级降到毫秒级。[详情 →](https://greptime.cn/blogs/2025-05-06-poizon-greptimedb-observability) - **OceanBase Cloud**:从 Loki 迁移到 GreptimeDB 一年后,已部署 80+ 集群、300TB 多云日志和 SQL 审计数据,整体存储成本下降 60%+。[详情 →](https://greptime.cn/blogs/2025-07-22-user-case-obcloud-log-storage-greptimedb) - **Traces 存储**:某出海物流电商企业用 GreptimeDB 替换 [Elasticsearch](/user-guide/protocols/elasticsearch.md) 存储 [Jaeger](/user-guide/query-data/jaeger.md) Trace 数据。存储成本降低 45 倍,冷数据查询快 3 倍。[详情 →](https://greptime.cn/blogs/2026-01-27-logistics-trace-case) ## 开始使用 迁移到 Observability 2.0 不需要一步到位。从任意一个支柱切入——[Logs](/user-guide/logs/overview.md)、[Metrics](/user-guide/ingest-data/for-observability/prometheus.md)、[Traces](/user-guide/traces/overview.md)——然后逐步扩展。GreptimeDB 开箱支持 [PromQL](/user-guide/query-data/promql.md)、[Jaeger](/user-guide/query-data/jaeger.md)、[OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md)、[Grafana](/user-guide/integrations/grafana.md),现有仪表板和告警直接可用。详细迁移路径参见[为什么选择 GreptimeDB](./why-greptimedb.md)。 ## 延伸阅读 - [什么是可观测性 2.0?什么是可观测性 2.0 原生数据库?](https://greptime.cn/blogs/2025-04-24-observability2.0-greptimedb.html) — 完整愿景和技术深入 - [让 Observability 更简单 —— GreptimeDB 统一存储架构](https://greptime.cn/blogs/2024-12-24-observability) — GreptimeDB 统一模型的设计哲学 - [Agent 可观测性:旧瓶装新酒,还是需要新瓶?](https://greptime.cn/blogs/2025-12-11-agent-observability) — AI agent 为什么需要宽事件 - [得物可观测平台架构升级:基于 GreptimeDB 的全新监控体系实践](https://greptime.cn/blogs/2025-05-06-poizon-greptimedb-observability) — 生产级验证 - [替换 Loki!GreptimeDB 在 OB Cloud 的大规模日志存储实践](https://greptime.cn/blogs/2025-07-22-user-case-obcloud-log-storage-greptimedb) — Logs 迁移 - [存储成本降低 45 倍!某出海物流电商企业用 GreptimeDB 替换 ES 存储 Trace 数据](https://greptime.cn/blogs/2026-01-27-logistics-trace-case) — Traces 迁移 --- ## GreptimeDB 概念概述 # 概念 GreptimeDB 是一个可观测性数据库,在单一引擎中统一处理 metrics、logs 和 traces。这里介绍理解 GreptimeDB 所需的核心概念。 **从这里开始:** - [为什么选择 GreptimeDB](./why-greptimedb.md) — 三支柱架构的问题,GreptimeDB 怎么解决 - [数据模型](./data-model.md) — Metrics、logs、traces 如何用 Tag + Timestamp + Field 统一表示 - [架构](./architecture.md) — 计算存储分离、无状态 Frontend、GreptimeDB 如何扩展 **深入了解:** - [Observability 2.0](./observability-2.md) — 宽事件、统一数据模型,超越三支柱的演进 - [存储位置](./storage-location.md) — 对象存储、本地盘、多引擎存储 - [核心概念](./key-concepts.md) — 表、Region、时间索引、数据类型、视图、Flow - [常见问题](./features-that-you-concern.md) — 更新、删除、TTL、压缩、高基数等 FAQ ## 延伸阅读 - [什么是可观测性 2.0?什么是可观测性 2.0 原生数据库?](https://greptime.cn/blogs/2025-04-24-observability2.0-greptimedb.html) — 下一代可观测性的愿景 - [事件管理革命:监控系统中统一日志和指标](https://greptime.cn/blogs/2024-06-25-logs-and-metrics) - [GreptimeDB 存储引擎设计内幕](https://greptime.cn/blogs/2022-12-21-storage-engine-design) --- ## 存储位置 GreptimeDB 支持将数据存储在本地文件系统、AWS S3 及其兼容服务(包括 minio、digitalocean space、腾讯云对象存储 (COS)、百度云对象存储 (BOS) 等)、Azure Blob Storage 和阿里云 OSS 中。 ## 本地文件结构 GreptimeDB 的存储文件结构包括以下内容: ```cmd ├── metadata ├── raftlog ├── rewrite └── LOCK ├── data │   ├── greptime │   └── public ├── cache ├── logs ├── index_intermediate │   └── staging └── wal ├── raftlog ├── rewrite └── LOCK ``` - `metadata`: 内部元数据目录,保存 catalog、数据库以及表的元信息、procedure 状态等内部状态。在集群模式下,此目录不存在,因为所有这些状态(包括区域路由信息)都保存在 `Metasrv` 中。 - `data`: 存储 GreptimeDB 的实际的时间序列数据和索引文件。如果要自定义此路径,请参阅 [存储选项](/user-guide/deployments-administration/configuration.md#storage-options)。该目录按照 catalog 和 schema 的两级结构组织。 - `cache`: 内部的数据缓存目录,比如对象存储的本地缓存等。 - `logs`: GreptimeDB 日志文件目录。 - `wal`: 预写日志文件目录。 - `index_intermediate`: 索引构建和查询相关的临时中间数据目录。 ## 云存储 文件结构中的 `data` 目录可以存储在云存储中。请参考[存储选项](/user-guide/deployments-administration/configuration.md#storage-options)了解更多细节。 请注意,仅将 `data` 目录存储在对象存储中不足以确保数据可靠性和灾难恢复,`wal` 和 `metadata` 也需要考虑灾难恢复,更详细地请参阅[灾难恢复文档](/user-guide/deployments-administration/disaster-recovery/overview.md)。 ## 多存储引擎支持 GreptimeDB 的另一个强大功能是可以为每张表单独选择存储引擎。例如,您可以将一些表存储在本地磁盘上,将另一些表存储在 Amazon S3 或 Google Cloud Storage 中,请参考 [create table](/reference/sql/create.md#create-table)。 --- ## 为什么选择 GreptimeDB ## 问题:三种信号,三套系统 大多数团队的可观测性栈长这样:[Prometheus](/user-guide/ingest-data/for-observability/prometheus.md)(或 Thanos/Mimir)跑 metrics,[Grafana Loki](/user-guide/ingest-data/for-observability/loki.md)(或 ELK)跑日志,[Elasticsearch](/user-guide/protocols/elasticsearch.md)(或 Tempo)跑 traces。每套系统各有一套查询语言、存储方案、扩展方式,运维各管各的。 "三支柱"架构在这些关注点各自独立时是合理的。但实际跑起来就是: - **3 倍运维量** — 三套系统要分别部署、监控、升级、排障 - **数据孤岛** — 错误率飙升和日志里的异常模式要手动在系统间切换才能关联 - **成本失控** — 每套系统存一份冗余元数据,各自独立扩展导致资源浪费 GreptimeDB 的思路不同:一个引擎处理三种信号,数据放对象存储,计算存储分离。 ## 统一处理可观测数据 GreptimeDB 通过以下方式统一处理 metrics、logs 和 traces: - 一致的[数据模型](./data-model.md),将所有可观测数据视为带上下文的时间戳宽事件 - 原生支持 [SQL](/user-guide/query-data/sql.md) 和 [PromQL](/user-guide/query-data/promql.md) 双查询 - 内置流计算能力([Flow](/user-guide/flow-computation/overview.md))做实时聚合和分析 - 跨信号无缝关联分析(参见 [SQL 示例](/getting-started/quick-start.md#关联-metricslogs-和-traces)) 一套系统替代原来的多组件栈。 具体来说:用一个数据库替代 [Prometheus](/user-guide/ingest-data/for-observability/prometheus.md) + [Loki](/user-guide/ingest-data/for-observability/loki.md) + [Elasticsearch](/user-guide/protocols/elasticsearch.md),用 SQL 在一条查询里关联 metrics 异常、日志模式和 trace 延迟——不用在系统间来回切换。 ## 对象存储,成本低一个数量级 GreptimeDB 以[云对象存储](/user-guide/concepts/storage-location.md)(S3、Azure Blob Storage 等)为主存储层,配合列式压缩,存储成本最高可降低 50 倍。支持灵活扩展到各类云存储,管理简单,**无厂商锁定**。 生产环境实测: - **Logs**:OceanBase Cloud 生产环境存储成本下降 60%+(从 [Loki](/user-guide/ingest-data/for-observability/loki.md) 迁移到 GreptimeDB,80+ 集群、300TB 多云日志和 SQL 审计数据) - **Traces**:存储成本降低 45 倍,查询快 3 倍(替换 [Elasticsearch](/user-guide/protocols/elasticsearch.md) 作为 [Jaeger](/user-guide/query-data/jaeger.md) 后端,一周完成迁移) - **Metrics**:用原生计算存储分离替代 Thanos,运维复杂度大幅下降 ## 高性能 写入端,GreptimeDB 用 LSM Tree、数据分片、灵活的 WAL 配置(本地盘或 Kafka)等手段处理大规模可观测数据的写入负载。 查询端,GreptimeDB 用纯 Rust 编写,查询引擎基于 [Apache DataFusion](https://datafusion.apache.org/) 做向量化执行和分布式并行处理,结合[多种索引](/user-guide/manage-data/data-index.md)(倒排索引、跳数索引、全文索引)做智能裁剪和过滤。 [GreptimeDB 在 JSONBench 10 亿条记录冷查询中拿下第一!](https://greptime.cn/blogs/2025-03-18-json-benchmark-greptimedb) 更多[性能测试报告](https://greptime.cn/blogs/2024-09-09-report-summary)。 ## 基于 Kubernetes 的弹性扩展 GreptimeDB 从底层就为 [Kubernetes](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md) 设计,采用计算存储分离[架构](/user-guide/concepts/architecture.md),实现真正的弹性扩展: - 存储和计算资源独立伸缩 - 通过 Kubernetes 水平扩展,无上限 - 写入、查询、压缩等不同负载之间做资源隔离 - 自动故障转移和高可用 Thanos 和 Mimir 要靠多个有状态组件(ingester 需要持久盘、store-gateway、compactor)才能扩展。GreptimeDB 从架构层面就是计算存储分离——数据持久化在对象存储,计算节点独立扩展,本地盘只做缓冲和缓存。扩容加节点,缩容不丢数据。 ![存储/计算分离,计算/计算分离](/storage-compute-disaggregation-compute-compute-separation.png) ## 灵活部署:从边缘到云 ![GreptimeDB 架构](/architecture-2.png) GreptimeDB 的模块化[架构](/user-guide/concepts/architecture.md)让各组件既能独立运行,也能协同部署。从边缘设备到云环境,都用同一套 API。比如: - Frontend、Datanode 和 Metasrv 可以合并成单一二进制(standalone 模式) - WAL、索引等组件可以按表级别启用或关闭 这种灵活性让 GreptimeDB 能覆盖从边缘到云的完整场景,比如[边云一体化解决方案](https://greptime.cn/carcloud)。 从嵌入式单机部署到云原生集群,GreptimeDB 都能适配。 ## 易于集成 GreptimeDB 支持 [PromQL](/user-guide/query-data/promql.md)、[Prometheus remote write](/user-guide/ingest-data/for-observability/prometheus.md)、[OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md)、[Jaeger](/user-guide/query-data/jaeger.md)、[Loki](/user-guide/ingest-data/for-observability/loki.md)、[Elasticsearch](/user-guide/protocols/elasticsearch.md)、[MySQL](/user-guide/protocols/mysql.md)、[PostgreSQL](/user-guide/protocols/postgresql.md) 协议——从现有栈迁移不用改查询、不用改 pipeline。查询用 [SQL](/user-guide/query-data/sql.md) 或 PromQL,可视化接 [Grafana](/user-guide/integrations/grafana.md)。 SQL + PromQL 双引擎意味着 GreptimeDB 可以替代"Prometheus + 数据仓库"的经典组合——PromQL 做实时监控告警,SQL 做深度分析、JOIN、聚合,全在一个系统里。GreptimeDB 还支持[多值模型](/user-guide/concepts/data-model.md),单行可以有多个字段列,比单值模型省流量、查询也更简洁。 SQL 不只是查询语言,也是 GreptimeDB 的管理入口——[建表](/user-guide/deployments-administration/manage-data/basic-table-operations.md)、[管理 schema](/reference/sql/alter.md)、设置 [TTL 策略](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据)、配置[索引](/user-guide/manage-data/data-index.md),全部用标准 SQL 完成。不需要专有配置文件,不需要自定义 API,不需要 YAML 驱动的控制面。这是和 Prometheus(YAML 配置 + relabeling rules)、Loki(YAML 配置 + LogQL)、Elasticsearch(REST API + JSON mappings)在运维层面的关键区别。团队只要会 SQL,就能管理 GreptimeDB,不用学新工具。 ## GreptimeDB 对比 | | GreptimeDB | Prometheus / Thanos / Mimir | Grafana Loki | Elasticsearch | |---|---|---|---|---| | 数据类型 | Metrics、Logs、Traces | 仅 Metrics | 仅 Logs | Logs、Traces | | 查询语言 | SQL + PromQL | PromQL | LogQL | Query DSL | | 存储 | 原生对象存储(S3 等) | 本地盘 + 对象存储(Thanos/Mimir),ingester 需要持久盘 | 对象存储(chunks) | 本地盘 | | 扩展 | 计算存储分离,计算节点独立扩展 | Federation / Thanos / Mimir — 多组件,运维重 | 无状态 + 对象存储 | 基于分片,运维重 | | 成本 | 存储成本最高降低 50 倍 | 大规模下成本高 | 中等 | 高(倒排索引开销) | | OpenTelemetry | 原生支持(Metrics + Logs + Traces) | 部分(仅 Metrics) | 部分(仅 Logs) | 通过 instrumentation | | 管理方式 | 标准 SQL(DDL、TTL、索引) | YAML 配置 + relabeling rules | YAML 配置 + LogQL | REST API + JSON mappings | 了解更多: - [Observability 2.0](./observability-2.md) — 宽事件、统一数据模型,GreptimeDB 面向下一代可观测性的架构 - [可观测性统一存储](https://greptime.cn/blogs/2024-12-24-observability) — GreptimeDB 的统一存储设计 - [替换 Loki!GreptimeDB 在 OB Cloud 的大规模日志存储实践](https://greptime.cn/blogs/2025-07-22-user-case-obcloud-log-storage-greptimedb) --- ## 鉴权 当客户端尝试连接到数据库时,将会进行身份验证。GreptimeDB 通过“user provider”进行身份验证。GreptimeDB 中有多种 user provider 实现: - [Static User Provider](./static.md):一个简单的内置 user provider 实现,从静态文件中查找用户。 - [LDAP User Provider](/enterprise/deployments-administration/authentication.md):**企业版功能**,使用外部 LDAP 服务进行用户身份验证。 --- ## Static User Provider GreptimeDB 提供了简单的内置身份验证机制,允许你配置一个固定的帐户以方便使用,或者配置一个帐户文件以支持多个用户帐户。通过传入文件,GreptimeDB 会加载其中的所有用户。 ## 单机模式 GreptimeDB 从配置文件中读取用户配置,每行定义一个用户及其密码和可选的权限模式。 ### 基本配置 基本格式使用 `=` 作为用户名和密码之间的分隔符: ``` greptime_user=greptime_pwd alice=aaa bob=bbb ``` 以这种方式配置的用户默认拥有完整的读写权限。 ### 权限模式 你可以选择性地指定权限模式来控制用户的访问级别。格式为: ``` username:permission_mode=password ``` 可用的权限模式: - `rw` 或 `readwrite` - 完整的读写权限(未指定时的默认值) - `ro` 或 `readonly` - 只读权限 - `wo` 或 `writeonly` - 只写权限 混合权限模式的配置示例: ``` admin=admin_pwd alice:readonly=aaa bob:writeonly=bbb viewer:ro=viewer_pwd editor:rw=editor_pwd ``` 在此配置中: - `admin` 拥有完整的读写权限(默认) - `alice` 拥有只读权限 - `bob` 拥有只写权限 - `viewer` 拥有只读权限 - `editor` 明确设置了读写权限 ### 启动服务器 在启动服务端时,需添加 `--user-provider` 参数,并将其设置为 `static_user_provider:file:`(请将 `` 替换为你的用户配置文件路径): ```shell ./greptime standalone start --user-provider=static_user_provider:file: ``` 用户及其权限将被载入 GreptimeDB 的内存。使用这些用户账户连接至 GreptimeDB 时,系统会严格执行相应的访问权限控制。 :::tip 注意 `static_user_provider:file` 模式下,文件的内容只会在启动时被加载到数据库中,在数据库运行时修改或追加的内容不会生效。 ::: ### 动态文件重载 如果你需要在不重启服务器的情况下更新用户凭证,可以使用 `watch_file_user_provider` 替代 `static_user_provider:file`。该 provider 会监控凭证文件的变化并自动重新加载: ```shell ./greptime standalone start --user-provider=watch_file_user_provider: ``` `watch_file_user_provider`的特点: - 使用与 `static_user_provider:file` 相同的文件格式 - 自动检测文件修改并重新加载凭证 - 允许在不重启服务器的情况下添加、删除或修改用户 - 如果文件临时不可用或无效,会保持上次有效的配置 这在需要动态管理用户访问的生产环境中特别有用。 ## Kubernetes 集群 你可以在 `values.yaml` 文件中配置鉴权用户。 更多详情,请参考 [Helm Chart 配置](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#鉴权配置)。 --- ## 容量规划 本指南提供了关于 GreptimeDB 的 CPU、内存和存储需求的一般建议。 GreptimeDB 具备超轻量级的启动基准, 这使数据库能以最少的服务器资源启动。 然而当为生产环境配置服务器容量时, 以下关键因素需要被考虑: - 每秒处理的数据点数 - 每秒查询请求 - 数据量 - 数据保留策略 - 硬件成本 要监控 GreptimeDB 的各种指标,请参阅[监控](/user-guide/deployments-administration/monitoring/overview.md)。 ## CPU 一般来说,大量并发查询、处理大量数据或执行其他计算密集型操作的应用需要更多的 CPU 核数。 以下是一些关于 CPU 资源使用的建议, 但实际使用的 CPU 核数取决于你实际的工作负载。 你可以考虑将 30% 的 CPU 资源用于数据写入, 剩余 70% 用于查询和分析。 一般推荐 CPU 到内存的比例为 1:4(例如,8 核 32 GB), 如果你的主要工作负载是数据写入且查询请求较少, 1:2 的比例(8 核 16 GB)也是可以接受的。 ## 内存 一般来说,内存越大,查询速度越快。 对于基本工作负载,建议至少有 8 GB 的内存,对于更高级的工作负载,建议至少有 32 GB 的内存。 ## 存储空间 GreptimeDB 具有高效的数据压缩机制,可将原始数据大小减少到其初始大小的约 1/8 到 1/10。 这使得 GreptimeDB 以更小的空间存储大量数据。 数据可以存储在本地文件系统或云存储中,例如 AWS S3。 有关存储选项的更多信息, 请参阅[存储配置](/user-guide/deployments-administration/configuration.md#存储选项)文档。 由于云存储在存储管理方面的简单性,强烈推荐使用云存储进行数据存储。 使用云存储时,本地存储空间只需要大约 200GB 用于查询相关的缓存和 Write-Ahead Log (WAL)。 无论你选择云存储还是本地存储, 建议设置[保留策略](/user-guide/concepts/features-that-you-concern.md#可以按表设置-ttl-或保留策略吗)以有效管理存储成本。 ## 举例 假设你的数据库每秒处理约 200 个简单查询请求(QPS),每秒处理约 300k 数据点的写入请求,使用云存储存储数据。 在这种写入和查询速率下, 以下是你可能分配资源的示例: - CPU:8 核 - 内存:32 GB - 存储空间:200 GB 这样的分配旨在优化性能, 确保数据写入和查询处理的平稳进行,而不会导致系统过载。 然而,请记住这些只是建议, 实际需求可能会根据特定的工作负载特征和性能期望而有所不同。 --- ## GreptimeDB 部署配置 # 配置 GreptimeDB GreptimeDB 提供了层次化的配置能力,按照下列优先顺序来生效配置(每个项目都会覆盖下面的项目): - Greptime 命令行选项 - 配置文件选项 - 环境变量 - 默认值 你只需要设置所需的配置项。 GreptimeDB 将为未配置的任何设置分配默认值。 ## 如何设置配置项 ### Greptime 命令行选项 你可以使用命令行参数指定多个配置项。 例如,以配置的 HTTP 地址启动 GreptimeDB 的独立模式: ```shell greptime standalone start --http-addr 127.0.0.1:4000 ``` 有关 Greptime 命令行支持的所有选项,请参阅 [GreptimeDB 命令行界面](/reference/command-lines/overview.md)。 ### 配置文件选项 你可以在 TOML 文件中指定配置项。 例如,创建一个名为 `standalone.example.toml` 的配置文件,如下所示: ```toml [storage] type = "File" data_home = "./greptimedb_data/" ``` 然后使用命令行参数 `-c [file_path]` 指定配置文件。 ```sh greptime [standalone | frontend | datanode | metasrv] start -c config/standalone.example.toml ``` 例如以 standalone 模式启动 GreptimeDB: ```bash greptime standalone start -c standalone.example.toml ``` #### 示例文件 以下是每个 GreptimeDB 组件的示例配置文件,包括所有可用配置项。 在实际场景中,你只需要配置所需的选项,不需要像示例文件中那样配置所有选项。 - [独立模式](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/standalone.example.toml) - [前端](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/frontend.example.toml) - [数据节点](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/datanode.example.toml) - [流节点](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/flownode.example.toml) - [元服务](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/metasrv.example.toml) ### Helm 配置 当使用 Helm 在 Kubernetes 上部署 GreptimeDB 时,你可以直接在 Helm `values.yaml` 文件中做相应的设置。 请参阅 [Helm 配置项文档](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md)了解所有 Helm 支持的配置项。 对于仅在本篇文档中[可用的配置项](#配置项),你可以通过[注入 TOML 配置文件](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#注入配置文件)来设置配置。 ### 环境变量 配置文件中的每个项目都可以映射到环境变量。 例如,使用环境变量设置数据节点的 `data_home` 配置项: ```toml # ... [storage] data_home = "/data/greptimedb" # ... ``` 使用以下 shell 命令以以下格式设置环境变量: ``` export GREPTIMEDB_DATANODE__STORAGE__DATA_HOME=/data/greptimedb ``` #### 环境变量规则 - 每个环境变量应具有组件前缀,例如: - `GREPTIMEDB_FRONTEND` - `GREPTIMEDB_METASRV` - `GREPTIMEDB_DATANODE` - `GREPTIMEDB_STANDALONE` - 使用**双下划线 `__`**作为分隔符。例如,数据结构 `storage.data_home` 转换为 `STORAGE__DATA_HOME`。 环境变量还接受以逗号 `,` 分隔的列表,例如: ``` GREPTIMEDB_METASRV__META_CLIENT__METASRV_ADDRS=127.0.0.1:3001,127.0.0.1:3002,127.0.0.1:3003 ``` ## 配置项 本节将介绍主要的配置项,请前往 GitHub 查看[所有配置项](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/config.md)。 ### 写入内存限制选项 内存限制选项控制所有协议(HTTP、gRPC 和 Arrow Flight)并发写入请求使用的总内存。 这些选项适用于 `frontend` 和 `standalone` 子命令。 ```toml # 所有并发写入请求体和消息的最大总内存 # 设置为 0 表示禁用限制(默认为无限制) max_in_flight_write_bytes = "1GB" # 写入字节配额耗尽时的策略 # 可选值:`"wait"`(默认,10 秒超时)、`"wait()"`(例如 `"wait(30s)"`)、`"fail"` write_bytes_exhausted_policy = "wait" ``` | 配置项 | 类型 | 默认值 | 描述 | | ------------------------------- | ------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `max_in_flight_write_bytes` | 字符串 | `"0"` | 所有并发写入请求体和消息(HTTP、gRPC、Flight)的最大总内存。设置为 `"0"` 表示禁用限制(无限制)。支持的单位:`B`、`KB`、`MB`、`GB` 等。示例:`"1GB"` 将并发写入总量限制为 1GB。 | | `write_bytes_exhausted_policy` | 字符串 | `"wait"` | 写入字节配额耗尽时的策略。可选值:`"wait"`(默认,等待最多 10 秒)、`"wait()"`(自定义超时时间,例如 `"wait(30s)"`)、`"fail"`(立即拒绝请求)。 | ### 协议选项 协议选项适用于 `frontend` 和 `standalone` 子命令,它指定了协议服务器地址和其他协议相关的选项。 :::tip 提示 HTTP 协议配置适用于所有 GreptimeDB 组件:`frontend`、`datanode`、`flownode` 和 `metasrv`。 ::: 下面的示例配置包含了所有协议选项的默认值。 你可以在配置文件中更改这些值或禁用某些协议。 例如禁用 OpenTSDB 协议支持,可以将 `enable` 参数设置为 `false`。 请注意,为了保障数据库的正常工作,无法禁用 HTTP 和 gRPC 协议。 ```toml [http] addr = "127.0.0.1:4000" timeout = "0s" body_limit = "64MB" [grpc] bind_addr = "127.0.0.1:4001" runtime_size = 8 [mysql] enable = true addr = "127.0.0.1:4002" runtime_size = 2 [mysql.tls] mode = "disable" cert_path = "" key_path = "" [postgres] enable = true addr = "127.0.0.1:4003" runtime_size = 2 [postgres.tls] mode = "disable" cert_path = "" key_path = "" [opentsdb] enable = true [influxdb] enable = true [prom_store] enable = true ``` 下表描述了每个选项的详细信息: | 选项 | 键 | 类型 | 描述 | | ---------- | ------------------ | ------ | ------------------------------------------------------------ | | http | | | HTTP 服务器选项 | | | addr | 字符串 | 服务器地址,默认为 "127.0.0.1:4000" | | | timeout | 字符串 | HTTP 请求超时时间。设为 "0s" 可禁用超时(默认值为 "0s")。 | | | body_limit | 字符串 | HTTP 最大体积大小,默认为 "64MB" | | | prom_validation_mode | 字符串 | 在 Prometheus Remote Write 协议中是否检查字符串是否为有效的 UTF-8 字符串。可用选项:`strict`(拒绝任何包含无效 UTF-8 字符串的请求),`lossy`(用 [UTF-8 REPLACEMENT CHARACTER](https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-23/#G24272)(即 `�` ) 替换无效字符),`unchecked`(不验证字符串有效性)。 | | grpc | | | gRPC 服务器选项 | | | bind_addr | 字符串 | gRPC 服务绑定地址,默认为 "127.0.0.1:4001" | | | runtime_size | 整数 | 服务器工作线程数量,默认为 8 | | | max_connection_age | 字符串 | gRPC 连接在服务端保持的最长时间。参见 ["MAX_CONNECTION_AGE"](https://grpc.io/docs/guides/keepalive/)。默认不设置。示例:"1h" 表示 1 小时,"30m" 表示 30 分钟 | | | flight_compression | 字符串 | Frontend 的 Arrow IPC 服务的压缩模式。可用选项:`none`:禁用所有压缩,`transport`:仅启用 gRPC 传输压缩(zstd),`arrow_ipc`:仅启用 Arrow IPC 压缩(lz4),`all`:启用所有压缩。默认值为 `none`。| | mysql | | | MySQL 服务器选项 | | | enable | 布尔值 | 是否启用 MySQL 协议,默认为 true | | | addr | 字符串 | 服务器地址,默认为 "127.0.0.1:4002" | | | runtime_size | 整数 | 服务器工作线程数量,默认为 2 | | influxdb | | | InfluxDB 协议选项 | | | enable | 布尔值 | 是否在 HTTP API 中启用 InfluxDB 协议,默认为 true | | opentsdb | | | OpenTSDB 协议选项 | | | enable | 布尔值 | 是否启用 OpenTSDB 协议,默认为 true | | prom_store | | | Prometheus 远程存储选项 | | | enable | 布尔值 | 是否在 HTTP API 中启用 Prometheus 远程读写,默认为 true | | | with_metric_engine | 布尔值 | 是否在 Prometheus 远程写入中使用 Metric Engine,默认为 true | | postgres | | | PostgresSQL 服务器选项 | | | enable | 布尔值 | 是否启用 PostgresSQL 协议,默认为 true | | | addr | 字符串 | 服务器地址,默认为 "127.0.0.1:4003" | | | runtime_size | 整数 | 服务器工作线程数量,默认为 2 | 对 MySQL,Postgres 和 gRPC 接口,我们支持 TLS 配置 | Option | Key | Type | Description | |------------------------------------------|-------------|---------|--------------------------------------------------| | `mysql.tls`,`postgres.tls` 或 `grpc.tls` | | | MySQL 或 Postgres 的 TLS 配置 | | | `mode` | String | TLS 模式,支持 `disable`, `prefer` and `require` | | | `cert_path` | String | TLS 证书文件路径 | | | `key_path` | String | TLS 私钥文件路径 | | | `watch` | Boolean | 监控文件变化,自动重新加载证书或私钥 | ### 查询选项 `查询`选项在 standalone、datanode 和 frontend 模式下有效,用于控制查询引擎的行为。 下表详细描述了这些选项: | 选项 | 键 | 类型 | 描述 | | ----------- | ------------------ | ------ | -------------------------------------------------------------------- | | parallelism | 整数 | `0` | 查询引擎的并行度。默认为 0,表示 CPU 核心数。 | 示例配置: ```toml [query] parallelism = 0 ``` ### 存储选项 `存储`选项在 `datanode` 和 `standalone` 模式下有效,它指定了数据库数据目录和其他存储相关的选项。 GreptimeDB 支持将数据保存在本地文件系统,AWS S3 以及其兼容服务(比如 MinIO、digitalocean space、腾讯 COS、百度对象存储(BOS)等),Azure Blob Storage 和阿里云 OSS。 | 选项 | 键 | 类型 | 描述 | | ------- | ----------------- | ------ | --------------------------------------------------- | | storage | | | 存储选项 | | | type | 字符串 | 存储类型,支持 "File","S3" 和 "Oss" 等。 | | File | | | 本地文件存储选项,当 type="File" 时有效 | | | data_home | 字符串 | 数据库存储根目录,默认为 "./greptimedb_data" | | S3 | | | AWS S3 存储选项,当 type="S3" 时有效 | | | name | 字符串 | 存储提供商名字,默认为 `S3` | | | bucket | 字符串 | S3 桶名称 | | | root | 字符串 | S3 桶中的根路径 | | | endpoint | 字符串 | S3 的 API 端点 | | | region | 字符串 | S3 区域 | | | access_key_id | 字符串 | S3 访问密钥 id | | | secret_access_key | 字符串 | S3 秘密访问密钥 | | | enable_virtual_host_style | 布尔值 | 使用 virtual-host-style 域名而不是 path-style 域名调用 API,默认为 false | | Oss | | | 阿里云 OSS 存储选项,当 type="Oss" 时有效 | | | name | 字符串 | 存储提供商名字,默认为 `Oss` | | | bucket | 字符串 | OSS 桶名称 | | | root | 字符串 | OSS 桶中的根路径 | | | endpoint | 字符串 | OSS 的 API 端点 | | | access_key_id | 字符串 | OSS 访问密钥 id | | | access_key_secret | 字符串 | OSS 秘密访问密钥 | | Azblob | | | Azure Blob 存储选项,当 type="Azblob" 时有效 | | | name | 字符串 | 存储提供商名字,默认为 `Azblob` | | | container | 字符串 | 容器名称 | | | root | 字符串 | 容器中的根路径 | | | endpoint | 字符串 | Azure Blob 存储的 API 端点 | | | account_name | 字符串 | Azure Blob 存储的账户名 | | | account_key | 字符串 | 访问密钥 | | | sas_token | 字符串 | 共享访问签名 | | Gsc | | | Google Cloud Storage 存储选项,当 type="Gsc" 时有效 | | | name | 字符串 | 存储提供商名字,默认为 `Gsc` | | | root | 字符串 | Gsc 桶中的根路径 | | | bucket | 字符串 | Gsc 桶名称 | | | scope | 字符串 | Gsc 权限 | | | credential_path | 字符串 | Gsc 访问证书 | | | endpoint | 字符串 | GSC 的 API 端点 | 文件存储配置范例: ```toml [storage] type = "File" data_home = "./greptimedb_data/" ``` s3 配置范例: ```toml [storage] type = "S3" bucket = "test_greptimedb" root = "/greptimedb" access_key_id = "" secret_access_key = "" ``` ### 存储服务的 http 客户端 `[storage.http_client]` 设置了向存储服务发送请求的 http 客户端的各种配置。 仅当存储服务类型是“S3”,“Oss”,“Azblob”或“Gcs”时生效。 | Key | 类型 | 默认值 | 含义 | |--------------------------|-----|------------|-------------------------------------------------------------| | `pool_max_idle_per_host` | 数字 | 1024 | http 连接池中对每个 host 的最大空闲连接数。 | | `connect_timeout` | 字符串 | “30s”(30 秒) | http 客户端在进行连接时的超时 | | `timeout` | 字符串 | “30s”(30 秒) | 总的 http 请求超时,包括了从建立连接到接收完返回值为止的时间。也可视为一个请求从开始到结束的一个完整的截止时间。 | | `pool_idle_timeout` | 字符串 | “90s”(90 秒) | 对空闲连接进行保活( "keep-alive" )的超时。 | ### 存储引擎提供商 `[[storage.providers]]` 用来设置存储引擎的提供商列表。基于这个配置,你可以为每张表指定不同的存储引擎,具体请参考 [create table](/reference/sql/create.md#create-table): ```toml # Allows using multiple storages [[storage.providers]] name = "S3" type = "S3" bucket = "test_greptimedb" root = "/greptimedb" access_key_id = "" secret_access_key = "" [[storage.providers]] name = "Gcs" type = "Gcs" bucket = "test_greptimedb" root = "/greptimedb" credential_path = "" ``` 所有配置的这些存储引擎提供商的 `name` 都可以在创建表时用作 `storage` 选项。 对于同样提供商的存储,比如你希望使用不同 S3 bucket 来作为不同表的存储引擎,你就可以设置不同的 `name`,并在创建表的时候指定 `storage` 选项。 ### 对象存储缓存 在使用 AWS S3、阿里云 OSS 或 Azure Blob Storage 等远程存储服务时,查询过程中获取数据通常会很耗时,尤其在公有云环境。为了解决这个问题,GreptimeDB 提供了写入缓存机制来加速重复数据的访问。 你可以通过修改 mito 的配置调整缓存的大小和行为。 ```toml [[region_engine]] [region_engine.mito] write_cache_size = "10GiB" # 在写入缓存未命中时从对象存储下载文件填充缓存 enable_refill_cache_on_read = true ``` 默认情况下,当查询时发生缓存未命中,GreptimeDB 会自动从对象存储下载文件填充写入缓存(`enable_refill_cache_on_read = true`)。这可以提高后续查询性能,使频繁访问的数据保留在写入缓存中。如果你想减少网络流量或存储成本,可以通过设置 `enable_refill_cache_on_read = false` 来禁用此行为。 更详细的信息请参阅[性能调优技巧](/user-guide/deployments-administration/performance-tuning/performance-tuning-tips.md)。 ### WAL 选项 GreptimeDB 支持三种 WAL 存储方式:本地 WAL、Remote WAL 和 Noop WAL。关于它们的对比,请参见 [WAL 概述](/user-guide/deployments-administration/wal/overview.md)。具体配置可参考 [本地 WAL](/user-guide/deployments-administration/wal/local-wal.md)、[Remote WAL](/user-guide/deployments-administration/wal/remote-wal/configuration.md) 和 [Noop WAL](/user-guide/deployments-administration/wal/noop-wal.md) 文档。 ### Logging 选项 `frontend`、`metasrv`、`datanode` 和 `standalone` 都可以在 `[logging]` 部分配置 log、tracing 相关参数: ```toml [logging] dir = "./greptimedb_data/logs" level = "info" enable_otlp_tracing = false otlp_endpoint = "localhost:4317" append_stdout = true [logging.tracing_sample_ratio] default_ratio = 1.0 ``` - `dir`: log 输出目录。 - `level`: log 输出的日志等级,日志等级有 `info`, `debug`, `error`, `warn`,默认等级为 `info`。 - `enable_otlp_tracing`:是否打开分布式追踪,默认不开启。 - `otlp_endpoint`:使用基于 gRPC 的 OTLP 协议导出 tracing 的目标端点,默认值为 `localhost:4317`。 - `append_stdout`:是否将日志打印到 stdout。默认是`true`。 - `tracing_sample_ratio`:该字段可以配置 tracing 的采样率,如何使用 `tracing_sample_ratio`,请参考 [如何配置 tracing 采样率](/user-guide/deployments-administration/monitoring/tracing.md#指南如何配置-tracing-采样率)。 如何使用分布式追踪,请参考 [Tracing](/user-guide/deployments-administration/monitoring/tracing.md#教程使用-jaeger-追踪-greptimedb-调用链路) ### Region 引擎选项 datanode 和 standalone 在 `[region_engine]` 部分可以配置不同存储引擎的对应参数。目前可以配置 `mito` 和 `metric` 存储引擎的选项。 部分常用的选项如下 ```toml [[region_engine]] [region_engine.mito] num_workers = 8 manifest_checkpoint_distance = 10 max_background_flushes = 4 max_background_compactions = 2 max_background_purges = 4 auto_flush_interval = "1h" global_write_buffer_size = "1GB" global_write_buffer_reject_size = "2GB" sst_meta_cache_size = "128MB" vector_cache_size = "512MB" page_cache_size = "512MB" write_cache_size = "5GB" write_cache_ttl = "8h" scan_memory_limit = "unlimited" scan_memory_on_exhausted = "fail" min_compaction_interval = "0m" default_flat_format = true sst_write_buffer_size = "8MB" max_concurrent_scan_files = 384 [region_engine.mito.index] aux_path = "" staging_size = "2GB" staging_ttl = "7d" metadata_cache_size = "64MiB" content_cache_size = "128MiB" content_cache_page_size = "64KiB" result_cache_size = "128MiB" [region_engine.mito.inverted_index] create_on_flush = "auto" create_on_compaction = "auto" apply_on_query = "auto" mem_threshold_on_create = "64M" intermediate_path = "" [region_engine.mito.memtable] type = "time_series" ``` 此外,`mito` 也提供了一个实验性质的 memtable。该 memtable 主要优化大量时间序列下的写入性能和内存占用。其查询性能可能会不如默认的 `time_series` memtable。 ```toml [region_engine.mito.memtable] type = "partition_tree" index_max_keys_per_shard = 8192 data_freeze_threshold = 32768 fork_dictionary_bytes = "1GiB" ``` 以下是可供使用的选项 | 键 | 类型 | 默认值 | 描述 | | ---------------------------------------- | ------ | ------------- | ---------------------------------------------------------------------------------------------------------------------- | | `num_workers` | 整数 | `8` | 写入线程数量 | | `manifest_checkpoint_distance` | 整数 | `10` | 每写入 `manifest_checkpoint_distance` 个 manifest 文件创建一次 checkpoint | | `compress_manifest` | 布尔值 | `false` | 是否使用 gzip 压缩 manifest 和 checkpoint 文件。 | | `max_background_flushes` | 整数 | 自动 | 后台 flush 任务数(默认:1/2 CPU 核心数)。 | | `max_background_compactions` | 整数 | 自动 | 后台 compaction 任务数(默认:1/4 CPU 核心数)。 | | `max_background_purges` | 整数 | 自动 | 后台 purge 任务数(默认:CPU 核心数)。 | | `auto_flush_interval` | 字符串 | `1h` | 自动 flush 超过 `auto_flush_interval` 没 flush 的 region | | `global_write_buffer_size` | 字符串 | `1GB` | 写入缓冲区大小,默认值为内存总量的 1/8,但不会超过 1GB | | `global_write_buffer_reject_size` | 字符串 | `2GB` | 写入缓冲区内数据的大小超过 `global_write_buffer_reject_size` 后拒绝写入请求,默认为 `global_write_buffer_size` 的 2 倍 | | `sst_meta_cache_size` | 字符串 | `128MB` | SST 元数据缓存大小。设为 0 可关闭该缓存默认为内存的 1/32,不超过 128MB | | `vector_cache_size` | 字符串 | `512MB` | 内存向量和 arrow array 的缓存大小。设为 0 可关闭该缓存默认为内存的 1/16,不超过 512MB | | `page_cache_size` | 字符串 | `512MB` | SST 数据页的缓存。设为 0 可关闭该缓存默认为内存的 1/8 | | `write_cache_size` | 字符串 | `5GiB` | 写入缓存容量。如果磁盘空间充足,建议设置更大的值。 | | `write_cache_ttl` | 字符串 | `8h` | 写入缓存的 TTL。默认为 8 小时。 | | `preload_index_cache` | 布尔值 | `true` | 在 region 打开时预加载索引(puffin)文件到缓存(默认:true)。启用时,索引文件会在 region 初始化期间加载到写入缓存中,这可以提高查询性能,但会延长启动时间。 | | `index_cache_percent` | 整数 | `20` | 为索引(puffin)文件分配的写入缓存容量百分比(默认:20)。剩余容量用于数据(parquet)文件。必须在 0 到 100 之间(不包括边界)。例如,对于 5GiB 的写入缓存和 20% 的分配,1GiB 保留给索引文件,4GiB 用于数据文件。 | | `enable_refill_cache_on_read` | 布尔值 | `true` | 启用读取操作时的缓存回填(默认:true)。禁用时,不会在读取时回填缓存。 | | `manifest_cache_size` | 字符串 | `256MB` | Manifest 缓存容量(默认:256MB)。 | | `selector_result_cache_size` | 字符串 | `512MB` | `last_value()` 等时间线检索结果的缓存。设为 0 可关闭该缓存默认为内存的 1/16,不超过 512MB | | `sst_write_buffer_size` | 字符串 | `8MB` | SST 的写缓存大小 | | `max_concurrent_scan_files` | 整数 | `384` | 最大并发扫描的 SST 文件数量。 | | `allow_stale_entries` | 布尔值 | `false` | 是否允许 replay 时读取陈旧的 WAL 条目。 | | `scan_memory_limit` | 字符串 | `unlimited` | 所有查询的表扫描内存限制。支持绝对大小(如 "2GB")或系统内存百分比(如 "20%")。设为 0 或 "unlimited" 可禁用限制。 | | `scan_memory_on_exhausted` | 字符串 | `fail` | 扫描内存耗尽时的行为。选项:`fail`(快速失败),`wait` 或 `wait()`(等待内存)。 | | `min_compaction_interval` | 字符串 | `0m` | 两次 compaction 之间的最小时间间隔。设为 "0m"(默认)允许 compactions 立即运行,无限制。 | | `default_flat_format` | 布尔值 | `true` | 是否启用 Flat 格式作为默认 SST 格式。 | | `scan_parallelism` | 整数 | `0` | (已弃用,请使用 `max_concurrent_scan_files`)旧版扫描并发度选项。 | | `index` | -- | -- | Mito 引擎中索引的选项。 | | `index.aux_path` | 字符串 | `""` | 文件系统中索引的辅助目录路径,用于存储创建索引的中间文件和搜索索引的暂存文件,默认为 `{data_home}/index_intermediate`。为了向后兼容,该目录的默认名称为 `index_intermediate`。此路径包含两个子目录:- `__intm`: 用于存储创建索引时使用的中间文件。- `staging`: 用于存储搜索索引时使用的暂存文件。 | | `index.staging_size` | 字符串 | `2GB` | 暂存目录的最大容量。 | | `index.staging_ttl` | 字符串 | `7d` | 暂存目录的 TTL。默认为 7 天。设为 "0s" 可禁用 TTL。 | | `index.metadata_cache_size` | 字符串 | `64MiB` | 索引元数据的缓存大小。 | | `index.content_cache_size` | 字符串 | `128MiB` | 索引内容的缓存大小。 | | `index.content_cache_page_size` | 字符串 | `64KiB` | 倒排索引内容缓存的页大小。 | | `index.result_cache_size` | 字符串 | `128MiB` | 索引查询结果的缓存大小。 | | `inverted_index.create_on_flush` | 字符串 | `auto` | 是否在 flush 时构建索引- `auto`: 自动- `disable`: 从不 | | `inverted_index.create_on_compaction` | 字符串 | `auto` | 是否在 compaction 时构建索引- `auto`: 自动- `disable`: 从不 | | `inverted_index.apply_on_query` | 字符串 | `auto` | 是否在查询时使用索引- `auto`: 自动- `disable`: 从不 | | `inverted_index.mem_threshold_on_create` | 字符串 | `64M` | 创建索引时如果超过该内存阈值则改为使用外部排序设置为空会关闭外排,在内存中完成所有排序 | | `inverted_index.intermediate_path` | 字符串 | `""` | 存放外排临时文件的路径 (默认 `{data_home}/index_intermediate`). | | `memtable.type` | 字符串 | `time_series` | Memtable type.- `time_series`: time-series memtable- `partition_tree`: partition tree memtable (实验性功能) | | `memtable.index_max_keys_per_shard` | 整数 | `8192` | 一个 shard 内的主键数只对 `partition_tree` memtable 生效 | | `memtable.data_freeze_threshold` | 整数 | `32768` | 一个 shard 内写缓存可容纳的最大行数只对 `partition_tree` memtable 生效 | | `memtable.fork_dictionary_bytes` | 字符串 | `1GiB` | 主键字典的大小只对 `partition_tree` memtable 生效 | `metric` 引擎针对包含大量小表的 metrics 数据进行了优化: ```toml [[region_engine]] [region_engine.metric] sparse_primary_key_encoding = true ``` 可用选项: | 键 | 类型 | 默认值 | 描述 | | --------------------------------- | ------ | ------- | ----------------------------------------------------------------------------------------------------------------- | | `sparse_primary_key_encoding` | 布尔值 | `true` | 是否使用稀疏主键编码。此优化通过仅编码非空主键列来提高写入和查询性能。 | ### 设定 meta client `meta_client` 选项适用于 `datanode` 和 `frontend` 模块,用于指定 Metasrv 的相关信息。 ```toml [meta_client] metasrv_addrs = ["127.0.0.1:3002"] timeout = "3s" connect_timeout = "1s" ddl_timeout = "10s" tcp_nodelay = true ``` 通过 `meta_client` 配置 metasrv 客户端,包括: - `metasrv_addrs`,Metasrv 地址列表,对应 Metasrv 启动配置的 server address。 - `timeout`,操作超时时长,默认为 3 秒。 - `connect_timeout`,连接服务器超时时长,默认为 1 秒。 - `ddl_timeout`,DDL 执行的超时时间,默认 10 秒。 - `tcp_nodelay`,接受连接时的 `TCP_NODELAY` 选项,默认为 true。 ### 心跳配置 在分布式模式下,心跳间隔由 Metasrv 的 `heartbeat_interval` 选项统一控制。 ```toml heartbeat_interval = "3s" ``` | 键 | 类型 | 默认值 | 描述 | |----------------------|--------|--------|------| | `heartbeat_interval` | 字符串 | `3s` | Metasrv 的基础心跳间隔。Frontend 的心跳间隔为该值的 6 倍,Datanode/Flownode 的心跳间隔与该值相同。心跳间隔会在握手阶段由 Metasrv 协商下发。 | ### 默认时区配置 `default_timezone` 选项适用于 `frontend` 模块和 `standalone` 模式,默认值为 `UTC`。 它指定了与 GreptimeDB 交互时的客户端默认时区。 如果在客户端中[指定了时区](/user-guide/timezone.md#在客户端中指定时区),此选项将在该客户端会话中被覆盖。 ```toml default_timezone = "UTC" ``` `default_timezone` 的值可以是任何时区名称,例如 `Europe/Berlin` 或 `Asia/Shanghai`。 有关客户端时区如何影响数据的写入和查询,请参阅[时区](/user-guide/timezone.md#时区对-sql-语句的影响)文档。 ### 仅限于 Metasrv 的配置 ```toml # 工作主目录。 data_home = "./greptimedb_data" # metasrv 存储后端服务器地址,默认为 etcd 实现。 # 对于 postgres 存储后端,格式为: # "password=password dbname=postgres user=postgres host=localhost port=5432" # 对于 mysql 存储后端,格式为: # "mysql://user:password@ip:port/dbname" # 对于 etcd 存储后端,格式为: # "127.0.0.1:2379" store_addrs = ["127.0.0.1:2379"] # 如果不为空,metasrv 将使用此键前缀存储所有数据。 store_key_prefix = "" # metasrv 的存储后端类型。 # 可选项: # - `etcd_store`(默认值) # - `memory_store` # - `postgres_store` # - `mysql_store` backend = "etcd_store" # 在 RDS 中存储元数据的表名。仅在使用 RDS kvbackend 时生效。 # **仅当后端为 RDS kvbackend 时使用。** meta_table_name = "greptime_metakv" ## PostgreSQL 选举的咨询锁 ID。仅在使用 PostgreSQL 作为 kvbackend 时生效。 ## 仅当后端为 `postgres_store` 时使用。 meta_election_lock_id = 1 # Datanode 选择器类型。 # - "lease_based" (默认值) # - `lease_based` # - "load_based" # 详情请参阅 "https://docs.greptime.com/contributor-guide/meta/selector" selector = "lease_based" # 将数据存储在内存中,默认值为 false。 use_memory_store = false # 是否启用 region failover。 # 该功能仅适用于以集群模式运行并使用共享存储(例如 s3)的 GreptimeDB,并且 WAL 需要满足以下条件之一: # - Remote WAL # - Local WAL 且设置 `allow_region_failover_on_local_wal = true`(故障转移期间可能导致数据丢失) enable_region_failover = false ## 设置启动 region 故障检测的延迟时间。 ## 该延迟有助于避免在所有 Datanode 尚未完全启动时,Metasrv 过早启动 region 故障检测,从而导致不必要的 region failover。 ## 尤其适用于未通过 GreptimeDB Operator 部署的集群,此时可能未正确启用集群维护模式,提前检测可能会引发误判。 region_failure_detector_initialization_delay = "10m" # 是否允许在本地 WAL 上进行 region failover。 # **此选项不建议设置为 true, # 因为这可能会在故障转移期间导致数据丢失。** allow_region_failover_on_local_wal = false ## 从 metasrv 内存中删除节点信息前允许的最大空闲时间。 node_max_idle_time = "24hours" ## 后端客户端选项。 ## 目前仅适用于使用 etcd 作为元数据存储时。 [backend_client] ## 后端客户端的保持连接超时时间。 keep_alive_timeout = "3s" ## 后端客户端的保持连接间隔。 keep_alive_interval = "10s" ## 后端客户端的连接超时时间。 connect_timeout = "3s" ## gRPC 服务器选项。 [grpc] bind_addr = "127.0.0.1:3002" server_addr = "127.0.0.1:3002" runtime_size = 8 ## 服务器端 HTTP/2 保持连接间隔 http2_keep_alive_interval = "10s" ## 服务器端 HTTP/2 保持连接超时时间。 http2_keep_alive_timeout = "3s" ## Procedure 选项 [procedure] ## 最大重试次数 max_retry_times = 12 ## 程序的初始重试延迟 retry_delay = "500ms" ## 最大运行程序数。 ## 同一时间可以运行的程序最大数量。 ## 如果运行的程序数量超过此限制,程序将被拒绝。 max_running_procedures = 128 # Failure detector 选项 # GreptimeDB 使用 Phi 累积故障检测器算法来检测数据节点故障。 [failure_detector] ## 判定节点故障前可接受的最大 φ 值。 ## 较低的值反应更快但会产生更多误报。 threshold = 8.0 ## 心跳间隔的最小标准差。 ## 防止微小变化导致 φ 值激增。在心跳间隔变化很小时防止过度敏感。 min_std_deviation = "100ms" ## 心跳之间可接受的暂停时长。 ## 在 φ 值上升前为学习到的平均间隔提供额外的宽限期,吸收临时网络故障或GC暂停。 acceptable_heartbeat_pause = "10000ms" ## Datanode 选项。 [datanode] ## Datanode 客户端配置。 [datanode.client] ## 操作超时时间 timeout = "10s" ## 连接服务器超时时间。 connect_timeout = "10s" ## 接受连接时的 `TCP_NODELAY` 选项,默认为 true。 tcp_nodelay = true [wal] # 可用的 WAL 提供者: # - `raft_engine`(默认):由于 metasrv 目前仅涉及远程 WAL,因此没有 raft-engine WAL 配置。 # - `kafka`:在 datanode 中使用 kafka WAL 提供者时,metasrv **必须** 配置 kafka WAL 配置。 provider = "raft_engine" # Kafka WAL 配置。 ## Kafka 集群的代理端点。 broker_endpoints = ["127.0.0.1:9092"] ## 自动为 WAL 创建 topics ## 设置为 `true` 则自动为 WAL 创建 topics ## 否则,使用名为 `topic_name_prefix_[0..num_topics)` 的 topics auto_create_topics = true ## Topic 数量。 num_topics = 64 ## Topic selector 类型。 ## 可用的 selector 类型: ## - `round_robin`(默认) selector_type = "round_robin" ## Kafka topic 通过连接 `topic_name_prefix` 和 `topic_id` 构建。 topic_name_prefix = "greptimedb_wal_topic" ## 每个分区的预期副本数。 replication_factor = 1 ## 超过此时间创建 topic 的操作将被取消。 create_topic_timeout = "30s" ## kafka 客户端的连接超时时间。 ## **仅在 provider 为 `kafka` 时使用。** connect_timeout = "3s" ## kafka 客户端的超时时间。 ## **仅在 provider 为 `kafka` 时使用。** timeout = "3s" ``` | 键 | 类型 | 默认值 | 描述 | | --------------------------------------------- | ------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `data_home` | String | `./greptimedb_data/metasrv/` | 工作目录。 | | `bind_addr` | String | `127.0.0.1:3002` | Metasrv 的绑定地址。 | | `server_addr` | String | `127.0.0.1:3002` | frontend 和 datanode 连接到 Metasrv 的通信服务器地址,默认为本地主机的 `127.0.0.1:3002`。 | | `store_addrs` | Array | `["127.0.0.1:2379"]` | 元数据服务地址,默认值为 `["127.0.0.1:2379"]`。支持配置多个服务地址,格式为 `["ip1:port1","ip2:port2",...]`。默认使用 Etcd 作为元数据后端。根据你的存储服务器类型配置地址,例如:- 使用 `"127.0.0.1:2379"` 连接到 etcd- 使用 `"password=password dbname=postgres user=postgres host=localhost port=5432"` 连接到 postgres- 使用 `"mysql://user:password@ip:port/dbname"` 连接到 mysql | | `selector` | String | `lease_based` | 创建新表时选择 datanode 的负载均衡策略,详见 [选择器](/contributor-guide/metasrv/selector.md)。 | | `use_memory_store` | Boolean | `false` | 仅用于在没有 etcd 集群时的测试,将数据存储在内存中,默认值为 `false`。 | | `enable_region_failover` | Bool | `false` | 是否启用 region failover。该功能仅适用于以集群模式运行并使用共享存储(如 s3)的 GreptimeDB,并且 WAL 需要满足以下条件之一:- Remote WAL- Local WAL 且设置 `allow_region_failover_on_local_wal = true`(故障转移期间可能导致数据丢失)。 | | `region_failure_detector_initialization_delay` | String | `10m` | 设置启动 region 故障检测的延迟时间。该延迟有助于避免在所有 Datanode 尚未完全启动时,Metasrv 过早启动 region 故障检测,从而导致不必要的 region failover。尤其适用于未通过 GreptimeDB Operator 部署的集群,此时可能未正确启用集群维护模式,提前检测可能会引发误判。 | | `allow_region_failover_on_local_wal` | Bool | false | 是否允许在本地 WAL 上进行 region failover。**此选项不建议设置为 true,因为这可能会在故障转移期间导致数据丢失。** | | `node_max_idle_time` | String | `24hours` | 从 metasrv 内存中删除节点信息前允许的最大空闲时间。超过该时间未发送心跳的节点将被视为不活跃并被删除。 | | `backend_client` | -- | -- | 后端客户端选项。目前仅适用于使用 etcd 作为元数据存储时。 | | `backend_client.keep_alive_timeout` | String | `3s` | 后端客户端的保持连接超时时间。 | | `backend_client.keep_alive_interval` | String | `10s` | 后端客户端的保持连接间隔。 | | `backend_client.connect_timeout` | String | `3s` | 后端客户端的连接超时时间。 | | `grpc` | -- | -- | gRPC 服务器选项。 | | `grpc.bind_addr` | String | `127.0.0.1:3002` | gRPC 服务器的绑定地址。 | | `grpc.server_addr` | String | `127.0.0.1:3002` | frontend 和 datanode 连接到 metasrv 的通信服务器地址。 | | `grpc.runtime_size` | Integer | `8` | 服务器工作线程数。 | | `grpc.http2_keep_alive_interval` | String | `10s` | 服务器端 HTTP/2 保持连接间隔。 | | `grpc.http2_keep_alive_timeout` | String | `3s` | 服务器端 HTTP/2 保持连接超时时间。 | | `backend` | String | `etcd_store` | 元数据存储类型。- `etcd_store` (默认)- `memory_store` (纯内存存储 - 仅用于测试)- `postgres_store`- `mysql_store` | | `meta_table_name` | String | `greptime_metakv` | 使用 RDS 存储元数据时的表名。**仅在 backend 为 postgre_store 和 mysql_store 时有效。** | | `meta_schema_name` | String | -- | 可选的 PostgreSQL schema,用于元数据表和选举表名称限定。当 PostgreSQL public schema 不可写入时(例如 PostgreSQL 15+ 限制 public schema),可设置此参数为可写入的 schema。GreptimeDB 将使用 `meta_schema_name.meta_table_name`。**仅在 backend 为 postgres_store 时有效。** | | `auto_create_schema` | Bool | `true` | 如果 PostgreSQL schema 不存在则自动创建。启用后,系统会在创建元数据表之前执行 `CREATE SCHEMA IF NOT EXISTS `。这在生产环境中可能受限于手动创建 schema 的情况下非常有用。注意:PostgreSQL 用户必须具有 CREATE SCHEMA 权限才能使此功能生效。**仅在 backend 为 postgres_store 时有效。** | | `meta_election_lock_id` | Integer | `1` | 用于领导选举的 PostgreSQL 咨询锁 id。**仅在 backend 为 postgre_store 时有效。** | | `procedure` | -- | -- | | | `procedure.max_retry_times` | 整数 | `12` | Procedure 的最大重试次数。 | | `procedure.retry_delay` | 字符串 | `500ms` | Procedure 初始重试延迟,延迟会指数增长。 | | `procedure.max_running_procedures` | Integer | `128` | 同一时间可以运行的程序最大数量。如果运行的程序数量超过此限制,程序将被拒绝。 | | `failure_detector` | -- | -- | 故障检测选项。 | | `failure_detector.threshold` | 浮点数 | `8.0` | 判定节点故障前可接受的最大 φ 值。较低的值反应更快但会产生更多误报。 | | `failure_detector.min_std_deviation` | 字符串 | `100ms` | 心跳间隔的最小标准差。防止微小变化导致 φ 值激增。在心跳间隔变化很小时防止过度敏感。 | | `failure_detector.acceptable_heartbeat_pause` | 字符串 | `10000ms` | 心跳之间可接受的暂停时长。在 φ 值上升前为学习到的平均间隔提供额外的宽限期,吸收临时网络故障或GC暂停。 | | `datanode` | -- | -- | | | `datanode.client` | -- | -- | Datanode 客户端选项。 | | `datanode.client.timeout` | 字符串 | `10s` | 操作超时。 | | `datanode.client.connect_timeout` | 字符串 | `10s` | 连接服务器超时。 | | `datanode.client.tcp_nodelay` | 布尔值 | `true` | 接受连接的 `TCP_NODELAY` 选项。 | | wal | -- | -- | -- | | wal.provider | String | raft_engine | -- | | wal.broker_endpoints | Array | -- | Kafka 集群的端点 | | `wal.auto_create_topics` | Bool | `true` | 自动为 WAL 创建 topics 设置为 `true` 则自动为 WAL 创建 topics 否则,使用名为 `topic_name_prefix_[0..num_topics)` 的 topics | | `wal.auto_prune_interval` | String | `0s` | 定期自动裁剪远程 WAL 的时间间隔 设置为 `0s` 表示禁止自动裁剪 | | `wal.trigger_flush_threshold` | Integer | `0` | 自动 WAL 裁剪中触发 region flush 操作的阈值 当满足以下条件时,metasrv 会对 region 发送 flush 请求:`trigger_flush_threshold` + `prunable_entry_id` < `max_prunable_entry_id`其中:- `prunable_entry_id` 是该 region 可裁剪的最大日志条目 ID,在该 ID 之前的日志都不被该 region 使用- `max_prunable_entry_id` 是使用与该 region 同一 kafka topic 的所有 region 可裁剪的最大日志条目 ID,在该 ID 之前的日志都不再被任一 region 使用 设置为 `0` 以禁止在自动 WAL 裁剪中触发 region flush 操作 | | `wal.auto_prune_parallelism` | Integer | `10` | 自动 WAL 裁剪的最大并行任务限制,其中每个任务负责一个 kafka topic 的 WAL 裁剪 | | `wal.num_topics` | Integer | `64` | Topic 数量 | | wal.selector_type | String | round_robin | topic selector 类型 可用 selector 类型:- round_robin(默认) | | wal.topic_name_prefix | String | greptimedb_wal_topic | 一个 Kafka topic 是通过连接 topic_name_prefix 和 topic_id 构建的 | | wal.replication_factor | Integer | 1 | 每个分区的副本数 | | wal.create_topic_timeout | String | 30s | 超过该时间后,topic 创建操作将被取消 | | `wal.connect_timeout` | String | `3s` | kafka 客户端的连接超时时间。**仅在 provider 为 `kafka` 时使用。** | | `wal.timeout` | String | `3s` | kafka 客户端的超时时间。**仅在 provider 为 `kafka` 时使用。** | | `wal.sasl` | String | -- | Kafka 客户端 SASL 配置 | | `wal.sasl.type` | String | -- | SASL 机制,可选值:`PLAIN`, `SCRAM-SHA-256`, `SCRAM-SHA-512` | | `wal.sasl.username` | String | -- | SASL 鉴权用户名 | | `wal.sasl.password` | String | -- | SASL 鉴权密码 | | `wal.tls` | String | -- | Kafka 客户端 TLS 配置 | | `wal.tls.server_ca_cert_path` | String | -- | 服务器 CA 证书地址 | | `wal.tls.client_cert_path` | String | -- | 客户端证书地址(用于启用 mTLS) | | `wal.tls.client_key_path` | String | -- | 客户端密钥地址(用于启用 mTLS) | ### 仅限于 `Datanode` 的配置 ```toml node_id = 42 [grpc] bind_addr = "127.0.0.1:3001" server_addr = "127.0.0.1:3001" runtime_size = 8 ``` | Key | Type | Description | | ---------------- | ------ | ------------------------------------------- | | node_id | 整数 | 该 `datanode` 的唯一标识符。 | | grpc.bind_addr | 字符串 | gRPC 服务绑定地址,默认为`"127.0.0.1:3001"`。 | | grpc.server_addr | 字符串 | 该地址用于来自主机外部的连接和通信。如果留空或未设置,服务器将自动使用主机上第一个网络接口的 IP 地址,其端口号与 `grpc.bind_addr` 中指定的相同。 | | grpc.rpc_runtime_size | 整数 | gRPC 服务器工作线程数,默认为 8。 | ### 仅限于 `Frontend` 的配置 ```toml [datanode] [datanode.client] connect_timeout = "1s" tcp_nodelay = true ``` | Key | Type | Default | Description | |-----------------------------------|------|---------|-------------------------| | `datanode` | -- | -- | | | `datanode.client` | -- | -- | Datanode 客户端选项。 | | `datanode.client.connect_timeout` | 字符串 | `1s` | 连接服务器超时。 | | `datanode.client.tcp_nodelay` | 布尔值 | `true` | 接受连接的 `TCP_NODELAY` 选项。 | --- ## 常见 Helm Chart 配置项 对于每一个 Helm Chart,你都可以通过创建 `values.yaml` 来进行配置。当你需要应用配置时,你可以通过 `helm upgrade` 命令来应用配置: ``` helm upgrade --install ${release-name} ${chart-name} --namespace ${namespace} -f values.yaml ``` ## GreptimeDB Cluster Chart 完整的配置项可参考 [GreptimeDB Cluster Chart](https://github.com/GreptimeTeam/helm-charts/tree/main/charts/greptimedb-cluster/README.md)。 ### GreptimeDB 运行镜像配置 顶层变量 `image` 用于配置集群全局的运行镜像,如下所示: ```yaml image: # -- The image registry registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com # -- The image repository repository: greptime/greptimedb # -- The image tag tag: "v1.0.2" # -- The image pull secrets pullSecrets: [] ``` 如果你想为集群中的每个 Role 配置不同的镜像,可以使用 `${role}.podTemplate.main.image` 字段(其中 `role` 可以是 `meta`、`frontend`、`datanode` 和 `flownode`),该字段会**覆盖顶层**变量 `image` 的配置,如下所示: ```yaml image: # -- The image registry registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com # -- The image repository repository: greptime/greptimedb # -- The image tag tag: "v1.0.2" # -- The image pull secrets pullSecrets: [] frontend: podTemplate: main: image: "greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:latest" ``` 此时 `frontend` 的镜像将会被设置为 `greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:latest`,而其他组件的镜像将会使用顶层变量 `image` 的配置。 ### 服务端口配置 你可以使用如下字段来配置服务端口,如下所示: - `httpServicePort`:用于配置 HTTP 服务的端口,默认 4000; - `grpcServicePort`:用于配置 gRPC 服务的端口,默认 4001; - `mysqlServicePort`:用于配置 MySQL 服务的端口,默认 4002; - `postgresServicePort`:用于配置 PostgreSQL 服务的端口,默认 4003; - `frontend.internalPort`:用于配置内部服务的端口,默认 4010,此端口用于 GreptimeDB 组件之间的内部通信。 ### Datanode 存储配置 你可以通过 `datanode.storage` 字段来配置 Datanode 的存储,如下所示: ```yaml datanode: storage: # -- Storage class for datanode persistent volume storageClassName: null # -- Storage size for datanode persistent volume storageSize: 20Gi # -- Storage retain policy for datanode persistent volume storageRetainPolicy: Retain # -- The dataHome directory, default is "/data/greptimedb/" dataHome: "/data/greptimedb" ``` - `storageClassName`:用于配置 StorageClass,默认使用 Kubernetes 当前默认的 StorageClass; - `storageSize`:用于配置 Storage 的大小,默认 20Gi。你可以使用常用的容量单位,如 `50Gi` 等; - `storageRetainPolicy`:用于配置 Storage 的保留策略,默认 `Retain`,如果设置为 `Delete`,则当集群被删除时,相应的 Storage 也会被删除; - `dataHome`:用于配置数据目录,默认 `/data/greptimedb/`; ### 运行资源配置 顶层变量 `base.podTemplate.main.resources` 用于全局配置每个 Role 的资源,如下所示: ```yaml base: podTemplate: main: resources: requests: memory: "1Gi" cpu: "1" limits: memory: "2Gi" cpu: "2" ``` 如果你想为集群中的每个 Role 配置不同的资源,可以使用 `${role}.podTemplate.main.resources` 字段(其中 `role` 可以是 `meta`、`frontend`、`datanode`、`flownode` 等),该字段会**覆盖顶层**变量 `base.podTemplate.main.resources` 的配置,如下所示: ```yaml base: podTemplate: main: resources: requests: memory: "1Gi" cpu: "1" limits: memory: "2Gi" cpu: "2" frontend: podTemplate: main: resources: requests: cpu: "2" memory: "4Gi" limits: cpu: "4" memory: "8Gi" ``` ### 服务运行副本数配置 对于不同 Role 的副本数,可以通过 `${role}.replicas` 字段进行配置对应的副本数,如下所示: ```yaml frontend: replicas: 3 datanode: replicas: 3 ``` 你可以通过配置其副本数来实现水平扩缩。 ### 环境变量配置 你既可以通过 `base.podTemplate.main.env` 字段配置全局的环境变量,也可以通过 `${role}.podTemplate.main.env` 字段为每个 Role 配置不同的环境变量,如下所示: ```yaml base: podTemplate: main: env: - name: GLOBAL_ENV value: "global_value" frontend: podTemplate: main: env: - name: FRONTEND_ENV value: "frontend_value" ``` ### 注入配置文件 对于不同 Role 的服务,你可以通过 `${role}.configData` 字段注入自定义的 TOML 配置文件,如下所示: ```yaml datanode: configData: | [[region_engine]] [region_engine.mito] # Number of region workers num_workers = 8 ``` 你可以通过 [config.md](https://github.com/GreptimeTeam/greptimedb/blob/main/config/config.md) 了解 GreptimeDB 的配置项。 除了使用 `${role}.configData` 字段注入配置文件,你还可以通过 `${role}.configFile` 来指定相应的文件,如下所示: ```yaml frontend: configFile: "configs/frontend.toml" ``` 此时需要确保对应的配置文件路径与执行 `helm upgrade` 命令时所处的目录一致。 :::note 用户注入的配置文件默认优先级低于由 GreptimeDB Operator 所接管的配置项,某些配置项仅能通过 GreptimeDB Operator 进行配置,而这些配置项默认会暴露在 `values.yaml` 中。 如下默认配置将由 GreptimeDB Operator 管理: - Logging 配置; - Datanode 的 Node ID; ::: ### 鉴权配置 Helm Chart 默认不启用 User Provider 模式的鉴权,你可以通过 `auth.enabled` 字段启用 User Provider 模式的鉴权并配置相应的用户信息,如下所示: ```yaml auth: enabled: true users: - username: "admin" password: "admin" permission: "readwrite" - username: "grafana" password: "grafana_pwd" permission: "readonly" - username: "telegraf" password: "telegraf_pwd" permission: "writeonly" ``` GreptimeDB 支持三种权限模式: | 模式 | 缩写 | 允许的操作 | 典型场景 | |------|------|-----------|---------| | `readwrite` | `rw` | 读取 + 写入 | 管理员、开发环境 | | `readonly` | `ro` | 仅读取 | 仪表盘、报表系统、只读副本 | | `writeonly` | `wo` | 仅写入 | 数据采集器、IoT 设备、日志收集 | :::note 未指定权限模式的用户默认拥有 `readwrite` 权限,与此前版本行为一致。 ### 日志配置 顶层变量 `logging` 用于配置全局日志级别,如下所示: ```yaml # -- Global logging configuration logging: # -- The log level for greptimedb, only support "debug", "info", "warn", "debug" level: "info" # -- The log format for greptimedb, only support "json" and "text" format: "text" # -- The logs directory for greptimedb logsDir: "/data/greptimedb/logs" # -- Whether to log to stdout only onlyLogToStdout: false # -- indicates whether to persist the log with the datanode data storage. It **ONLY** works for the datanode component. persistentWithData: false # -- The log filters, use the syntax of `target[span\{field=value\}]=level` to filter the logs. filters: [] ``` 其中: - `logging.level`:用于配置全局日志级别,支持 `debug`、`info`、`warn`、`error` 四个级别; - `logging.format`:用于配置全局日志格式,支持 `json` 和 `text` 两种格式; - `logging.logsDir`:用于配置全局日志目录,默认位于 `/data/greptimedb/logs`; - `logging.onlyLogToStdout`:用于配置是否仅输出到标准输出,默认不启用; - `logging.persistentWithData`:用于配置是否将日志持久化到数据存储,仅适用于 `datanode` 组件,默认不启用; - `logging.filters`:用于配置全局日志过滤器,支持 `target[span\{field=value\}]=level` 的语法,特步地,如果你希望对某些组件启动 `debug` 级别的日志,可以配置如下: ```yaml logging: level: "info" format: "json" filters: - mito2=debug ``` 每一个 Role 的日志配置都可以通过 `${role}.logging` 字段进行配置,其字段与顶层 `logging` 一致,并会**覆盖**顶层变量 `logging` 的配置,比如: ```yaml frontend: logging: level: "debug" ``` ### 启用 Flownode Helm Chart 默认不启用 Flownode,你可以通过 `flownode.enabled` 字段启用 Flownode,如下所示: ```yaml flownode: enabled: true ``` `flownode` 的其他字段的配置与其他 Role 的配置一致,比如: ```yaml flownode: enabled: true replicas: 1 podTemplate: main: resources: requests: memory: "1Gi" cpu: "1" limits: memory: "2Gi" cpu: "2" ``` ### 对象存储配置 `objectStorage` 字段用于配置云对象存储(例如 AWS S3 和 Azure Blob Storage 等)作为 GreptimeDB 存储层。 #### AWS S3 ```yaml objectStorage: credentials: # AWS access key ID accessKeyId: "" # AWS secret access key secretAccessKey: "" s3: # AWS S3 bucket name bucket: "" # AWS S3 region region: "" # The root path in bucket is 's3:////data/...' root: "" # The AWS S3 endpoint, see more detail: https://docs.aws.amazon.com/general/latest/gr/s3.html endpoint: "" ``` #### 使用 AWS EKS Pod Identity 访问 S3 除了提供静态访问密钥外,你还可以使用 [AWS EKS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html)(IAM Roles for Service Accounts)来授予 GreptimeDB 访问 S3 的权限。这种方式更加安全,因为无需管理长期有效的凭证。 首先,为 datanode 的 Service Account 配置 IAM 角色注解。只有 datanode 会读写 S3: ```yaml datanode: podTemplate: serviceAccount: create: true annotations: eks.amazonaws.com/role-arn: ${YOUR_IAM_ROLE_ARN} ``` 请确保 IAM 角色具有对目标 S3 存储桶的读写权限: - `s3:PutObject` - `s3:ListBucket` - `s3:GetObject` - `s3:DeleteObject` 然后,配置对象存储时无需填写凭证: ```yaml objectStorage: s3: bucket: "${YOUR_S3_BUCKET}" region: "${YOUR_S3_REGION}" root: "greptimedb" ``` :::note 使用 EKS Pod Identity 时,请完全省略 `objectStorage.credentials` 部分。datanode Pod 将通过与 Service Account 关联的 IAM 角色自动获取临时凭证。 ::: #### Google Cloud Storage ```yaml objectStorage: credentials: # GCP serviceAccountKey JSON-formatted base64 value serviceAccountKey: "" gcs: # Google Cloud Storage bucket name bucket: "" # Google Cloud OAuth 2.0 Scopes, example: "https://www.googleapis.com/auth/devstorage.read_write" scope: "" # The root path in bucket is 'gcs:////data/...' root: "" # Google Cloud Storage endpoint, example: "https://storage.googleapis.com" endpoint: "" ``` #### Azure Blob ```yaml objectStorage: credentials: # Azure account name accountName: "" # Azure account key accountKey: "" azblob: # Azure Blob container name container: "" # The root path in container is 'blob:////data/...' root: "" # Azure Blob endpoint, see: "https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-query-endpoint-srp?tabs=dotnet#query-for-the-blob-storage-endpoint" endpoint: "" ``` #### AliCloud OSS ```yaml objectStorage: credentials: # AliCloud access key ID accessKeyId: "" # AliCloud access key secret accessKeySecret: "" oss: # AliCloud OSS bucket name bucket: "" # AliCloud OSS region region: "" # The root path in bucket is 'oss:////data/...' root: "" # The AliCloud OSS endpoint endpoint: "" ``` #### Volcengine TOS TOS ([Torch Object Storage](https://www.volcengine.com/docs/6349)) 是[火山引擎](https://www.volcengine.com)提供的海量、安全、低成本、易用、高可靠、高可用的对象存储服务。 ```yaml objectStorage: credentials: # Volcengine access key ID accessKeyId: "" # Volcengine secret access key secretAccessKey: "" s3: # Volcengine TOS bucket name bucket: "" # Volcengine TOS region region: "" # The root path in bucket is 'tos:////data/...' root: "" # The Volcengine TOS endpoint, see more detail: https://www.volcengine.com/docs/6349/107356 endpoint: "" # Enable virtual host style so that OpenDAL will send API requests in virtual host style instead of path style. enableVirtualHostStyle: true ``` ### Prometheus 监控配置 如果你已经安装了 [prometheus-operator](https://github.com/prometheus-operator/prometheus-operator),你可以通过 `prometheusMonitor.enabled` 字段创建 Prometheus PodMonitor 来监控 GreptimeDB,如下所示: ```yaml prometheusMonitor: # -- Create PodMonitor resource for scraping metrics using PrometheusOperator enabled: false # -- Interval at which metrics should be scraped interval: "30s" # -- Add labels to the PodMonitor labels: release: prometheus ``` ### Debug Pod 配置 debug pod 中安装了各种工具(例如 mysql-client、psql-client 等)。你可以 exec 进入调试 debug pod 进行调试。使用 `debugPod.enabled` 字段创建它,如下所示: ```yaml debugPod: # -- Enable debug pod enabled: false # -- The debug pod image image: registry: docker.io repository: greptime/greptime-tool tag: "20250606-04e3c7d" # -- The debug pod resource resources: requests: memory: 64Mi cpu: 50m limits: memory: 256Mi cpu: 200m ``` ### 配置 Metasrv 后端存储 #### 使用 MySQL 和 PostgreSQL 作为后端存储 你可以通过 `meta.backendStorage` 字段配置 Metasrv 的后端存储。 以 MySQL 为例。 ```yaml meta: backendStorage: mysql: # -- MySQL host host: "mysql.default.svc.cluster.local" # -- MySQL port port: 3306 # -- MySQL database database: "metasrv" # -- MySQL table table: "greptime_metakv" # -- MySQL credentials credentials: # -- MySQL credentials secret name secretName: "meta-mysql-credentials" # -- MySQL credentials existing secret name existingSecretName: "" # -- MySQL credentials username username: "root" # -- MySQL credentials password password: "test" ``` - `mysql.host`: MySQL 主机。 - `mysql.port`: MySQL 端口。 - `mysql.database`: MySQL 数据库。 - `mysql.table`: MySQL 表。 - `mysql.credentials.secretName`: MySQL 凭证 secret 名称。 - `mysql.credentials.existingSecretName`: MySQL 凭证 secret 名称。如果你希望使用已有的 secret,你需要确保该 secret 包含 `username` 和 `password` 两个 key。 - `mysql.credentials.username`: MySQL 凭证用户名。如果 `mysql.credentials.existingSecretName` 被设置,该字段将被忽略。`username` 将会被存储在 `username` key 中,该 key 的值为 `mysql.credentials.secretName`。 - `mysql.credentials.password`: MySQL 凭证密码。如果 `mysql.credentials.existingSecretName` 被设置,该字段将被忽略。`password` 将会被存储在 `password` key 中,该 key 的值为 `mysql.credentials.secretName`。 `meta.backendStorage.postgresql` 的大部分字段与 `meta.backendStorage.mysql` 的相同。例如: ```yaml meta: backendStorage: postgresql: # -- PostgreSQL host host: "postgres.default.svc.cluster.local" # -- PostgreSQL port port: 5432 # -- PostgreSQL database database: "metasrv" # -- PostgreSQL table table: "greptime_metakv" # -- PostgreSQL Advisory lock id used for election, shouldn't be used in other clusters or applications. electionLockID: 1 # -- PostgreSQL credentials credentials: # -- PostgreSQL credentials secret name secretName: "meta-postgresql-credentials" # -- PostgreSQL credentials existing secret name existingSecretName: "" # -- PostgreSQL credentials username username: "root" # -- PostgreSQL credentials password password: "root" ``` - `postgresql.host`: PostgreSQL 主机。 - `postgresql.port`: PostgreSQL 端口。 - `postgresql.database`: PostgreSQL 数据库。 - `postgresql.table`: PostgreSQL 表。 - `postgresql.electionLockID`: PostgreSQL 中用于选举的锁 ID。 - `postgresql.credentials.secretName`: PostgreSQL 凭证 secret 名称。 - `postgresql.credentials.existingSecretName`: PostgreSQL 凭证 secret 名称。如果你希望使用已有的 secret,你需要确保该 secret 包含 `username` 和 `password` 两个 key。 - `postgresql.credentials.username`: PostgreSQL 凭证用户名。如果 `mysql.credentials.existingSecretName` 被设置,该字段将被忽略。`username` 将会被存储在 `username` key 中,该 key 的值为 `mysql.credentials.secretName`。 - `postgresql.credentials.password`: PostgreSQL 凭证密码。如果 `mysql.credentials.existingSecretName` 被设置,该字段将被忽略。`password` 将会被存储在 `password` key 中,该 key 的值为 `mysql.credentials.secretName`。 #### 使用 etcd 作为后端存储 :::tip NOTE chart 版本之间的配置结构已发生变化: - 旧版本: `meta.etcdEndpoints` - 新版本: `meta.backendStorage.etcd.endpoints` 请参考 chart 仓库中配置 [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) 以获取最新的结构。 ::: 你可以通过 `meta.backendStorage.etcd` 字段配置 etcd 作为后端存储。 ```yaml meta: backendStorage: etcd: # -- Etcd endpoints endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] # -- Etcd store key prefix storeKeyPrefix: "" ``` - `etcd.endpoints`: etcd 服务地址。 - `etcd.storeKeyPrefix`: etcd 存储 key 前缀。所有 key 都会被存储在这个前缀下。如果你希望使用一个 etcd 集群为多个 GreptimeDB 集群提供服务,你可以为每个 GreptimeDB 集群配置不同的存储 key 前缀。这仅用于测试和调试目的。 ### 启用 Region Failover 你可以通过 `meta.enableRegionFailover` 字段启用 Region Failover。在启用 Region Failover 之前,请确保你的部署满足 [Region Failover](/user-guide/deployments-administration/manage-data/region-failover.md) 文档中的先决条件。如果你的配置不满足条件,**Operator 将无法部署集群组件**。 ```yaml meta: enableRegionFailover: true ``` ### 启用 IPv6 通过 `enableIPv6` 字段可开启 IPv6 网络协议支持。设置为 true 时,系统将启用 IPv6 地址分配与通信功能,默认为 false(不启用)。启用前请确保底层基础环境已配置支持 IPv6 网络。 ```yaml enableIPv6: true ``` ### 启用 GC 重分区依赖共享对象存储和 GC。你可以通过下面的示例同时开启 metasrv 和 datanode 的 GC: ```yaml meta: configData: | [gc] enable = true gc_cooldown_period = "5m" datanode: configData: | [[region_engine]] [region_engine.mito] [region_engine.mito.gc] enable = true lingering_time = "10m" unknown_file_lingering_time = "1h" ``` 请确保 `datanode` 的 `lingering_time` 大于 `meta` 的 `gc_cooldown_period`,以避免正在使用的文件过早被删除。 #### 启用 Region Failover 在本地 WAL 在本地 WAL 上启用 Region Failover,你需要设置 `meta.enableRegionFailover: true` 和在 `meta.configData` 字段中添加 `allow_region_failover_on_local_wal = true`。 :::warning WARNING 在本地 WAL 启用 Region Failover 可能会导致数据丢失。另外,确保你的 Operator 版本大于或等于 v0.2.2。 ::: ```yaml meta: enableRegionFailover: true configData: | allow_region_failover_on_local_wal = true ``` ### 专用 WAL 卷 配置专用 WAL 卷时,可以为 GreptimeDB Datanode 的 WAL(预写日志)目录使用单独的磁盘,并指定自定义的 `StorageClass`。 ```yaml dedicatedWAL: enabled: true raftEngine: fs: storageClassName: io2 # 使用 AWS ebs io2 存储以获得更好的性能 name: wal storageSize: 20Gi mountPath: /wal ``` ### 启用 Remote WAL 在启用前,请务必查阅 [Remote WAL 配置](/user-guide/deployments-administration/wal/remote-wal/configuration.md)文档,以了解完整的配置项说明及相关注意事项。 ```yaml remoteWal: enabled: true kafka: brokerEndpoints: ["kafka.kafka-cluster.svc:9092"] meta: configData: | [wal] provider = "kafka" replication_factor = 1 auto_prune_interval = "30m" datanode: configData: | [wal] provider = "kafka" overwrite_entry_start_id = true ``` --- ## 部署多个具有 frontend 组的 GreptimeDB 集群 在本指南中,你将学习如何在 Kubernetes 上部署具有多个 frontend 组的 GreptimeDB 集群。 ## 先决条件 - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [GreptimeDB Operator](https://github.com/GrepTimeTeam/greptimedb-operator) >= v0.3.0 - [ETCD](https://github.com/bitnami/charts/tree/main/bitnami/etcd) ## 升级 operator 安装 GreptimeDB Operator,将镜像版本设置为大于或等于 `v0.3.0`。 请参考 GreptimeDB Operator 文档查看[如何升级 Operator](/user-guide/deployments-administration/deploy-on-kubernetes/greptimedb-operator-management.md#升级)。 ## Frontend 组配置 :::tip NOTE chart 版本之间的配置结构已发生变化: - 旧版本: `meta.etcdEndpoints` - 新版本: `meta.backendStorage.etcd.endpoints` 请参考 chart 仓库中配置 [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) 以获取最新的结构。 ::: 在配置 frontend 组时,确保每个组都包含 `name` 字段。以下 `values.yaml` 示例展示了如何为读写操作分别定义不同的 frontend 组: ```yaml frontend: enabled: false # 禁用默认 frontend 组 frontendGroups: - name: read replicas: 1 config: | default_timezone = "UTC" [http] timeout = "60s" template: main: resources: limits: cpu: 2000m memory: 2048Mi - name: write replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: - "etcd.etcd-cluster.svc.cluster.local:2379" datanode: replicas: 1 ``` 你可以使用以下命令应用上述配置: ``` helm upgrade --install greptimedb greptime/greptimedb-cluster --namespace default -f values.yaml ``` ## 合规配置 设置 frontend 组时,必须设置名称。 ```yaml # 非法配置 !!! frontendGroups: # - name: read #<=========必须指定该字段=============> - replicas: 1 ``` ## 校验安装 检查 Pod 的状态: ```bash kubectl get pods -n default NAME READY STATUS RESTARTS AGE greptimedb-datanode-0 1/1 Running 0 32s greptimedb-flownode-0 1/1 Running 0 17s greptimedb-frontend-read-6d45bc9b89-hftqz 1/1 Running 0 23s greptimedb-frontend-write-557b6585c6-jq874 1/1 Running 0 23s greptimedb-meta-58cd4cff6c-zp7s9 1/1 Running 0 37s ``` 检查 services 状态: ```bash kubectl get service -n default NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE greptimedb-datanode ClusterIP None 4001/TCP,4000/TCP 102s greptimedb-flownode ClusterIP None 4001/TCP 2m5s greptimedb-frontend-read ClusterIP 10.96.174.200 4001/TCP,4000/TCP,4002/TCP,4003/TCP 42s greptimedb-frontend-write ClusterIP 10.96.223.1 4001/TCP,4000/TCP,4002/TCP,4003/TCP 42s greptimedb-meta ClusterIP 10.96.195.163 3002/TCP,4000/TCP 3m4s ``` ## Conclusion 您已成功部署 GreptimeDB 集群,其 frontend 组由读写实例组成。您现在可以继续探索 GreptimeDB 集群的功能,或根据需要将其与其他工具集成。 --- ## 部署启用 Remote WAL 的 GreptimeDB 集群 本指南将介绍如何在 Kubernetes 集群中部署启用了 Remote WAL(远程写前日志)的 GreptimeDB。在开始之前,建议先阅读 [部署 GreptimeDB 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md) 文档。 ## 前置条件 - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## 所需依赖 在部署启用了 Remote WAL 的 GreptimeDB 之前,请确保元数据存储和 Kafka 集群已经部署完成,或者已准备好可用的实例: - 元数据存储:请参考 [管理元数据概述](/user-guide/deployments-administration/manage-metadata/overview.md) 了解更多详情。在本示例中,我们使用 etcd 作为元数据存储。 - Kafka 集群:请参考 [管理 Kafka](/user-guide/deployments-administration/wal/remote-wal/manage-kafka.md) 了解更多详情。 ## Remote WAL 配置 :::tip NOTE chart 版本之间的配置结构已发生变化: - 旧版本: `meta.etcdEndpoints` - 新版本: `meta.backendStorage.etcd.endpoints` 请参考 chart 仓库中配置 [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) 以获取最新的结构。 ::: 本示例假设你已经部署了一个 Kafka 集群,运行在 `kafka-cluster` 命名空间中,并且一个 etcd 集群运行在 `etcd-cluster` 命名空间中。`values.yaml` 文件如下: ```yaml meta: backendStorage: etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] configData: | [wal] provider = "kafka" replication_factor = 1 topic_name_prefix = "gtp_greptimedb_wal_topic" auto_prune_interval = "30m" datanode: configData: | [wal] provider = "kafka" overwrite_entry_start_id = true remoteWal: enabled: true kafka: brokerEndpoints: ["kafka.kafka-cluster.svc.cluster.local:9092"] ``` ## 部署 GreptimeDB 集群 你可以使用以下命令部署 GreptimeDB 集群: ```bash helm upgrade --install mycluster \ --values values.yaml \ greptime/greptimedb-cluster \ -n default ``` ## 最佳实践 - **不要在已部署的集群中切换 WAL 存储类型**. 如果需要将 WAL 存储从本地更换为远程,必须 删除整个集群并重新部署,包括: - 删除集群使用的所有 PersistentVolumeClaims(PVCs) - 清空对象存储中的集群目录 - 删除或清理使用的元数据存储 - 建议先使用一个**最小可行部署**来验证集群是否运行正常,例如执行建表和插入数据等基本操作,确保数据库正常工作。 ## 后续步骤 - 请参考 [部署 GreptimeDB 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md) 指南访问你的 GreptimeDB 集群。 - 请参考 [快速开始](/getting-started/quick-start.md) 指南创建表并写入数据。 - 请参考 [Remote WAL 配置](/user-guide/deployments-administration/wal/remote-wal/configuration.md) 了解更多关于 Remote WAL 配置的信息。 --- ## 部署 GreptimeDB 集群 在该指南中,你将学会如何使用 GreptimeDB Operator 在 Kubernetes 上部署 GreptimeDB 集群。 :::note 以下输出可能会因 Helm chart 版本和具体环境的不同而有细微差别。 ::: ## 前置条件 - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) >= v0.20.0 ## 创建一个测试 Kubernetes 集群 :::warning 不建议在生产环境或性能测试中使用 `kind`。如有这类需求建议使用公有云托管的 Kubernetes 服务,如 [Amazon EKS](https://aws.amazon.com/eks/)、[Google GKE](https://cloud.google.com/kubernetes-engine/) 或 [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/),或者自行搭建生产级 Kubernetes 集群。 ::: 目前有很多方法可以创建一个用于测试的 Kubernetes 集群。在本指南中,我们将使用 [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) 来创建一个本地 Kubernetes 集群。如果你想使用已有的 Kubernetes 集群,可以跳过这一步。 这里是一个使用 `kind` v0.20.0 的示例: ```bash kind create cluster ```
预期输出 ```bash Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Thanks for using kind! 😊 ```
使用以下命令检查集群的状态: ```bash kubectl cluster-info ```
预期输出 ```bash Kubernetes control plane is running at https://127.0.0.1:60495 CoreDNS is running at https://127.0.0.1:60495/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ```
:::note 中国大陆用户如有网络访问问题,可使用 Greptime 提供的位于阿里云镜像仓库的 `kindest/node:v1.27.3` 镜像: ```bash kind create cluster --image greptime-registry.cn-hangzhou.cr.aliyuncs.com/kindest/node:v1.27.3 ``` ::: ## 添加 Greptime Helm 仓库 :::note 中国大陆用户如有网络访问问题,可跳过这一步骤并直接参考下一步中使用阿里云 OCI 镜像仓库的方式。采用这一方式将无需手动添加 Helm 仓库。 ::: 我们提供了 GreptimeDB Operator 和 GreptimeDB 集群的[官方 Helm 仓库](https://github.com/GreptimeTeam/helm-charts)。你可以通过运行以下命令来添加仓库: ```bash helm repo add greptime https://greptimeteam.github.io/helm-charts/ helm repo update ``` 检查 Greptime Helm 仓库中的 charts: ```bash helm search repo greptime ```
预期输出 ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-cluster 0.8.3 1.0.1 A Helm chart for deploying GreptimeDB cluster i... greptime/greptimedb-enterprise-dashboard 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB Enterpr... greptime/greptimedb-infra-test 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB infra t... greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. greptime/greptimedb-remote-compaction 0.1.1 0.1.0 Remote compaction components (scheduler, compac... greptime/greptimedb-standalone 0.4.2 1.0.1 A Helm chart for deploying standalone greptimedb ```
## 安装和验证 GreptimeDB Operator 现在我们准备使用 Helm 在 Kubernetes 集群上安装 GreptimeDB Operator。 ### 安装 GreptimeDB Operator [GreptimeDB Operator](https://github.com/GrepTimeTeam/greptimedb-operator) 是一个用于管理 GreptimeDB 集群生命周期的 Kubernetes operator。 让我们在 `greptimedb-admin` 命名空间中安装最新版本的 GreptimeDB Operator: ```bash helm install greptimedb-operator greptime/greptimedb-operator -n greptimedb-admin --create-namespace ```
预期输出 ```bash NAME: greptimedb-operator LAST DEPLOYED: Sun Apr 26 20:43:58 2026 NAMESPACE: greptimedb-admin STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-operator Chart version: 0.5.9 GreptimeDB Operator version: 0.5.5 *********************************************************************** Installed components: * greptimedb-operator The greptimedb-operator is starting, use `kubectl get deployment greptimedb-operator -n greptimedb-admin` to check its status. ```
:::note 中国大陆用户如有网络访问问题,可直接使用阿里云 OCI 镜像仓库的方式安装 GreptimeDB Operator: ```bash helm install greptimedb-operator \ oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/greptimedb-operator \ --set image.registry=greptime-registry.cn-hangzhou.cr.aliyuncs.com \ -n greptimedb-admin \ --create-namespace ``` 此时我们也将镜像仓库设置为 Greptime 官方的阿里云镜像仓库。 ::: :::note 我们还可以直接使用 `kubectl` 和 `bundle.yaml` 来安装最新版本的 GreptimeDB Operator: ```bash kubectl apply -f \ https://github.com/GreptimeTeam/greptimedb-operator/releases/latest/download/bundle.yaml \ --server-side ``` 这种方式仅适用于在测试环境快速部署 GreptimeDB Operator,不建议在生产环境中使用。 ::: ### 验证 GreptimeDB Operator 安装 检查 GreptimeDB Operator 的状态: ```bash kubectl get pods -n greptimedb-admin -l app.kubernetes.io/instance=greptimedb-operator ```
预期输出 ```bash NAME READY STATUS RESTARTS AGE greptimedb-operator-68d684c6cf-qr4q4 1/1 Running 0 4m8s ```
你也可以检查 CRD 的安装: ```bash kubectl get crds | grep greptimedb ```
预期输出 ```bash greptimedbclusters.greptime.io 2026-04-26T12:43:58Z greptimedbstandalones.greptime.io 2026-04-26T12:43:58Z ```
GreptimeDB Operator 将会使用 `greptimedbclusters.greptime.io` and `greptimedbstandalones.greptime.io` 这两个 CRD 来管理 GreptimeDB 集群和单机实例。 ## 安装 etcd 集群 GreptimeDB 集群需要一个 etcd 集群来存储元数据。让我们使用 Bitnami 的 etcd Helm [chart](https://github.com/bitnami/charts/tree/main/bitnami/etcd) 来安装一个 etcd 集群。 ```bash helm install etcd \ oci://registry-1.docker.io/bitnamicharts/etcd \ --version 12.0.8 \ --set replicaCount=3 \ --set auth.rbac.create=false \ --set auth.rbac.token.enabled=false \ --create-namespace \ --set global.security.allowInsecureImages=true \ --set image.registry=docker.io \ --set image.repository=greptime/etcd \ --set image.tag=3.6.1-debian-12-r3 \ -n etcd-cluster ```
预期输出 ```bash NAME: etcd LAST DEPLOYED: Sun Apr 26 20:49:03 2026 NAMESPACE: etcd-cluster STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: etcd CHART VERSION: 12.0.8 APP VERSION: 3.6.1 ** Please be patient while the chart is being deployed ** etcd can be accessed via port 2379 on the following DNS name from within your cluster: etcd.etcd-cluster.svc.cluster.local To create a pod that you can use as a etcd client run the following command: kubectl run etcd-client --restart='Never' --image docker.io/greptime/etcd:3.6.1-debian-12-r3 --env ETCDCTL_ENDPOINTS="etcd.etcd-cluster.svc.cluster.local:2379" --namespace etcd-cluster --command -- sleep infinity Then, you can set/get a key using the commands below: kubectl exec --namespace etcd-cluster -it etcd-client -- bash etcdctl put /message Hello etcdctl get /message To connect to your etcd server from outside the cluster execute the following commands: kubectl port-forward --namespace etcd-cluster svc/etcd 2379:2379 & echo "etcd URL: http://127.0.0.1:2379" WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs: - resources - preUpgradeJob.resources - disasterRecovery.cronjob.resources +info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ Substituted images detected: - docker.io/greptime/etcd:3.6.1-debian-12-r3 ```
当 etcd 集群准备好后,你可以使用以下命令检查 Pod 的状态: ```bash kubectl get pods -n etcd-cluster -l app.kubernetes.io/instance=etcd ```
预期输出 ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 2m8s etcd-1 1/1 Running 0 2m8s etcd-2 1/1 Running 0 2m8s ```
:::note 中国大陆用户如有网络访问问题,可直接使用阿里云 OCI 镜像仓库的方式安装 etcd 集群: ```bash helm install etcd \ oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/etcd \ --set image.registry=greptime-registry.cn-hangzhou.cr.aliyuncs.com \ --set global.security.allowInsecureImages=true \ --set image.repository=bitnami/etcd \ --set image.tag=3.6.1-debian-12-r3 \ --set replicaCount=3 \ --set auth.rbac.create=false \ --set auth.rbac.token.enabled=false \ --create-namespace \ -n etcd-cluster ``` ::: 你可以通过运行以下命令来测试 etcd 集群: ```bash kubectl -n etcd-cluster \ exec etcd-0 -- etcdctl endpoint health \ --endpoints=http://etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379,http://etcd-1.etcd-headless.etcd-cluster.svc.cluster.local:2379,http://etcd-2.etcd-headless.etcd-cluster.svc.cluster.local:2379 ```
预期输出 ```bash http://etcd-1.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 3.008575ms http://etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 3.136576ms http://etcd-2.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 3.147702ms ```
## 配置 `values.yaml` `values.yaml` 文件设置了 GreptimeDB 的一些参数和配置,是定义 helm chart 的关键。 例如一个最小规模 GreptimeDB 集群定义如下: ```yaml image: # 镜像仓库地址: # OSS GreptimeDB 使用 `greptime-registry.cn-hangzhou.cr.aliyuncs.com`, # Enterprise GreptimeDB 请咨询工作人员 registry: # 镜像仓库: # OSS GreptimeDB 使用 `greptime/greptimedb`, # Enterprise GreptimeDB 请咨询工作人员 repository: # 镜像标签: # OSS GreptimeDB 使用数据库版本,例如 `v1.0.2` # Enterprise GreptimeDB 请咨询工作人员 tag: pullSecrets: [] initializer: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: greptime/greptimedb-initializer tag: "v0.6.0" frontend: replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] datanode: replicas: 1 flownode: replicas: 1 ``` 上述配置不适用于严肃的生产环境,请根据自己的需求调整配置。 可参考[配置文档](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md)获取完整的 `values.yaml` 的配置项。 ## 安装 GreptimeDB 集群 在上述步骤中我们已经准备好了 GreptimeDB Operator,etcd 集群以及 GreptimeDB 集群相应的配置, 现在部署一个最小 GreptimeDB 集群: ```bash helm upgrade --install mycluster \ greptime/greptimedb-cluster \ --values /path/to/values.yaml \ -n default ``` 如果你使用了不同的集群名称和命名空间,请将 `mycluster` 和 `default` 替换为你的配置。
预期输出 ```bash Release "mycluster" does not exist. Installing it now. NAME: mycluster LAST DEPLOYED: Sun Apr 26 21:00:40 2026 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-cluster Chart version: 0.8.3 GreptimeDB Cluster version: 1.0.1 *********************************************************************** Installed components: * greptimedb-meta * greptimedb-datanode * greptimedb-frontend * greptimedb-flownode The greptimedb-cluster is starting, use `kubectl get pods -n default` to check its status. ```
当启动集群安装之后,我们可以用如下命令检查 GreptimeDB 集群的状态。若你使用了不同的集群名和命名空间,可将 `default` 和 `mycluster` 替换为你的配置: ```bash kubectl -n default get greptimedbclusters.greptime.io mycluster ```
预期输出 ```bash NAME FRONTEND DATANODE META FLOWNODE PHASE VERSION AGE mycluster 1 1 1 1 Running v1.0.1 111s ```
上面的命令将会显示 GreptimeDB 集群的状态。当 `PHASE` 为 `Running` 时,表示 GreptimeDB 集群已经成功启动。 你还可以检查 GreptimeDB 集群的 Pod 状态: ```bash kubectl -n default get pods ```
预期输出 ```bash NAME READY STATUS RESTARTS AGE mycluster-datanode-0 1/1 Running 0 2m51s mycluster-flownode-0 1/1 Running 0 2m26s mycluster-frontend-5894994974-w2cls 1/1 Running 0 2m32s mycluster-meta-58cd4cff6c-ddbxq 1/1 Running 0 2m58s ```
正如你所看到的,我们默认创建了一个最小的 GreptimeDB 集群,包括 1 个 frontend、1 个 datanode、1 个 flownode 和 1 个 metasrv。关于一个完整的 GreptimeDB 集群的组成,你可以参考 [architecture](/user-guide/concepts/architecture.md)。 ## 探索 GreptimeDB 集群 ### 访问 GreptimeDB 集群 你可以通过使用 `kubectl port-forward` 命令转发 frontend 服务来访问 GreptimeDB 集群: ```bash kubectl -n default port-forward svc/mycluster-frontend 4000:4000 4001:4001 4002:4002 4003:4003 ```
预期输出 ```bash Forwarding from 127.0.0.1:4000 -> 4000 Forwarding from [::1]:4000 -> 4000 Forwarding from 127.0.0.1:4001 -> 4001 Forwarding from [::1]:4001 -> 4001 Forwarding from 127.0.0.1:4002 -> 4002 Forwarding from [::1]:4002 -> 4002 Forwarding from 127.0.0.1:4003 -> 4003 Forwarding from [::1]:4003 -> 4003 ```
请注意,当你使用了其他集群名和命名空间时,你可以使用如下命令,并将 `${cluster}` 和 `${namespace}` 替换为你的配置: ```bash kubectl -n ${namespace} port-forward svc/${cluster}-frontend 4000:4000 4001:4001 4002:4002 4003:4003 ``` :::warning 如果你想将服务暴露给公网访问,可以使用带有 `--address` 选项的 `kubectl port-forward` 命令: ```bash kubectl -n default port-forward --address 0.0.0.0 svc/mycluster-frontend 4000:4000 4001:4001 4002:4002 4003:4003 ``` 在将服务暴露给公网访问之前,请确保你已经配置了适当的安全设置。 ::: 打开浏览器并访问 `http://localhost:4000/dashboard` 来访问 [GreptimeDB Dashboard](https://github.com/GrepTimeTeam/dashboard)。 如果你想使用其他工具如 `mysql` 或 `psql` 来连接 GreptimeDB 集群,你可以参考 [快速入门](/getting-started/quick-start.md)。 ## 删除集群 :::danger 清理操作将会删除 GreptimeDB 集群的元数据和数据。请确保在继续操作之前已经备份了数据。 ::: ### 停止端口转发 可以使用以下命令停止 GreptimeDB 集群的端口转发: ```bash pkill -f kubectl port-forward ``` ### 卸载 GreptimeDB 集群 可以使用以下命令卸载 GreptimeDB 集群: ```bash helm -n default uninstall mycluster ``` ### 删除 PVCs 为了安全起见,PVCs 默认不会被删除。如果你想删除 PV 数据,你可以使用以下命令: ```bash kubectl -n default delete pvc -l app.greptime.io/component=mycluster-datanode ``` ### 清理 etcd 数据 你可以使用以下命令清理 etcd 集群: ```bash kubectl -n etcd-cluster exec etcd-0 -- etcdctl del "" --from-key=true ``` ### 删除 Kubernetes 集群 如果你使用 `kind` 创建 Kubernetes 集群,你可以使用以下命令销毁集群: ```bash kind delete cluster ``` --- ## 部署 GreptimeDB 环境测试 在该指南中,你将学会如何在 Kubernetes 上部署 GreptimeDB 基础环境测试工具。 ## 前置条件 - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) >= v0.20.0 ## 创建一个测试 Kubernetes 集群 :::warning 不建议在生产环境或性能测试中使用 `kind`。如有这类需求建议使用公有云托管的 Kubernetes 服务,如 [Amazon EKS](https://aws.amazon.com/eks/)、[Google GKE](https://cloud.google.com/kubernetes-engine/) 或 [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/),或者自行搭建生产级 Kubernetes 集群。 ::: 目前有很多方法可以创建一个用于测试的 Kubernetes 集群。在本指南中,我们将使用 [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) 来创建一个本地 Kubernetes 集群。如果你想使用已有的 Kubernetes 集群,可以跳过这一步。 这里是一个使用 `kind` v0.20.0 的示例: ```bash kind create cluster ```
预期输出 ```bash Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Thanks for using kind! 😊 ```
使用以下命令检查集群的状态: ```bash kubectl cluster-info ```
预期输出 ```bash Kubernetes control plane is running at https://127.0.0.1:60495 CoreDNS is running at https://127.0.0.1:60495/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ```
:::note 中国大陆用户如有网络访问问题,可使用 Greptime 提供的位于阿里云镜像仓库的 `kindest/node:v1.27.3` 镜像: ```bash kind create cluster --image greptime-registry.cn-hangzhou.cr.aliyuncs.com/kindest/node:v1.27.3 ``` ::: ## 添加 Greptime Helm 仓库 :::note 中国大陆用户如有网络访问问题,可跳过这一步骤并直接参考下一步中使用阿里云 OCI 镜像仓库的方式。采用这一方式将无需手动添加 Helm 仓库。 ::: 我们提供了 GreptimeDB Operator 和 GreptimeDB 集群的[官方 Helm 仓库](https://github.com/GreptimeTeam/helm-charts)。你可以通过运行以下命令来添加仓库: ```bash helm repo add greptime https://greptimeteam.github.io/helm-charts/ helm repo update ``` 检查 Greptime Helm 仓库中的 charts: ```bash helm search repo greptime ```
预期输出 ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-cluster 0.8.3 1.0.1 A Helm chart for deploying GreptimeDB cluster i... greptime/greptimedb-enterprise-dashboard 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB Enterpr... greptime/greptimedb-infra-test 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB infra t... greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. greptime/greptimedb-remote-compaction 0.1.1 0.1.0 Remote compaction components (scheduler, compac... greptime/greptimedb-standalone 0.4.2 1.0.1 A Helm chart for deploying standalone greptimedb ```
## 配置 创建自定义配置文件 `infra-test-values.yaml`: ```yaml image: # -- The image registry registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com # -- The image repository repository: greptime/greptime-tool # -- The image tag tag: "20260521-c19a702" # -- The image pull secrets pullSecrets: [] # -- Configure to the tests case: disk: enabled: true storageClass: null size: 20Gi cpu: enabled: true rds: enabled: true host: "your-rds-host" port: 3306 database: "test" username: "your-rds-username" password: "your-rds-password" s3: enabled: true bucket: "bucket-name" region: "s3-region" accessKeyID: "your-access-key-id" secretAccessKey: "your-secret-access-key" kafka: enabled: true endpoint: "your-kafka-endpoint" ``` ## 安装 使用自定义配置安装: ```bash helm upgrade --install greptimedb-infra-test greptime/greptimedb-infra-test \ --values infra-test-values.yaml \ -n default ``` ## 查看测试结果 测试工具以 kubernetes job 方式运行,结果输出在 pod 日志中: ```bash kubectl get pod -n default ```
期望输出 ```bash NAMESPACE NAME READY STATUS RESTARTS AGE default greptimedb-infra-test-n7z74 0/1 Completed 0 10m ```
```bash kubectl logs greptimedb-infra-test-n7z74 -n default ```
期望输出 ```bash ================== Starting testing... ================== ================== Fetching UUID for kube-system namespace ================== Successfully got UUID: 419a9914-5f9c-4d47-af69-3d09789db7a3 ================== Disk tests ================== ================== Running full I/O test ================== seq-read: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64 seq-write: (g=0): rw=write, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64 rand-iops: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=256 ... fio-3.28 Starting 6 processes seq-read: Laying out IO file (1 file / 1024MiB) seq-read: (groupid=0, jobs=6): err= 0: pid=14: Thu May 21 19:01:15 2026 read: IOPS=48.2k, BW=188MiB/s (198MB/s)(11.1GiB/60436msec) slat (nsec): min=625, max=615290k, avg=53392.68, stdev=2634423.19 clat (nsec): min=875, max=636646k, avg=7912987.95, stdev=30341131.85 lat (usec): min=52, max=636649, avg=7966.49, stdev=30463.52 clat percentiles (usec): | 1.00th=[ 223], 5.00th=[ 375], 10.00th=[ 562], 20.00th=[ 979], | 30.00th=[ 1303], 40.00th=[ 1680], 50.00th=[ 2311], 60.00th=[ 3490], | 70.00th=[ 4752], 80.00th=[ 6128], 90.00th=[ 13042], 95.00th=[ 23725], | 99.00th=[103285], 99.50th=[270533], 99.90th=[421528], 99.95th=[438305], | 99.99th=[488637] bw ( KiB/s): min= 9969, max=450583, per=99.87%, avg=192706.79, stdev=24021.38, samples=596 iops : min= 2490, max=112644, avg=48175.32, stdev=6005.33, samples=596 write: IOPS=34.0k, BW=133MiB/s (139MB/s)(8021MiB/60436msec); 0 zone resets slat (nsec): min=708, max=615509k, avg=77566.35, stdev=3387406.46 clat (usec): min=241, max=640859, avg=22321.94, stdev=54921.92 lat (usec): min=281, max=640862, avg=22399.63, stdev=55019.71 clat percentiles (msec): | 1.00th=[ 3], 5.00th=[ 5], 10.00th=[ 7], 20.00th=[ 8], | 30.00th=[ 9], 40.00th=[ 10], 50.00th=[ 11], 60.00th=[ 12], | 70.00th=[ 14], 80.00th=[ 16], 90.00th=[ 26], 95.00th=[ 54], | 99.00th=[ 359], 99.50th=[ 414], 99.90th=[ 485], 99.95th=[ 502], | 99.99th=[ 634] bw ( KiB/s): min=15032, max=284142, per=99.98%, avg=135879.94, stdev=12430.31, samples=596 iops : min= 3757, max=71033, avg=33968.77, stdev=3107.56, samples=596 lat (nsec) : 1000=0.01% lat (usec) : 20=0.01%, 50=0.01%, 100=0.01%, 250=0.95%, 500=3.99% lat (usec) : 750=3.41%, 1000=3.77% lat (msec) : 2=15.07%, 4=11.77%, 10=31.21%, 20=20.84%, 50=5.71% lat (msec) : 100=1.14%, 250=0.99%, 500=1.12%, 750=0.02% cpu : usr=1.88%, sys=8.37%, ctx=786665, majf=0, minf=263 IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0% submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.1% issued rwts: total=2915521,2053386,0,0 short=0,0,0,0 dropped=0,0,0,0 latency : target=0, window=0, percentile=100.00%, depth=256 Run status group 0 (all jobs): READ: bw=188MiB/s (198MB/s), 188MiB/s-188MiB/s (198MB/s-198MB/s), io=11.1GiB (11.9GB), run=60436-60436msec WRITE: bw=133MiB/s (139MB/s), 133MiB/s-133MiB/s (139MB/s-139MB/s), io=8021MiB (8411MB), run=60436-60436msec Disk stats (read/write): vda: ios=2915375/2054793, merge=4/1130, ticks=8259465/6477837, in_queue=14772291, util=82.28% ================== Running mixed read/write test ================== fiotest: (g=0): rw=rw, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=16 ... fio-3.28 Starting 8 processes fiotest: Laying out IO file (1 file / 1024MiB) fiotest: (groupid=0, jobs=8): err= 0: pid=22: Thu May 21 19:02:19 2026 read: IOPS=42.5k, BW=2657MiB/s (2786MB/s)(4092MiB/1540msec) slat (nsec): min=1541, max=3755.0k, avg=6912.45, stdev=28881.60 clat (usec): min=30, max=52156, avg=1045.12, stdev=2441.43 lat (usec): min=45, max=52191, avg=1052.13, stdev=2441.68 clat percentiles (usec): | 1.00th=[ 118], 5.00th=[ 188], 10.00th=[ 265], 20.00th=[ 392], | 30.00th=[ 506], 40.00th=[ 635], 50.00th=[ 783], 60.00th=[ 922], | 70.00th=[ 1074], 80.00th=[ 1254], 90.00th=[ 1680], 95.00th=[ 2311], | 99.00th=[ 3949], 99.50th=[ 4948], 99.90th=[47973], 99.95th=[49546], | 99.99th=[50070] bw ( MiB/s): min= 2578, max= 2871, per=100.00%, avg=2697.33, stdev=16.88, samples=24 iops : min=41246, max=45946, avg=43154.67, stdev=270.28, samples=24 write: IOPS=42.6k, BW=2662MiB/s (2792MB/s)(4100MiB/1540msec); 0 zone resets slat (usec): min=2, max=3271, avg= 8.33, stdev=25.30 clat (usec): min=95, max=52303, avg=1920.68, stdev=2554.97 lat (usec): min=138, max=52312, avg=1929.12, stdev=2555.52 clat percentiles (usec): | 1.00th=[ 310], 5.00th=[ 498], 10.00th=[ 693], 20.00th=[ 988], | 30.00th=[ 1254], 40.00th=[ 1516], 50.00th=[ 1762], 60.00th=[ 1975], | 70.00th=[ 2212], 80.00th=[ 2474], 90.00th=[ 2835], 95.00th=[ 3294], | 99.00th=[ 4817], 99.50th=[ 5800], 99.90th=[50594], 99.95th=[50594], | 99.99th=[50594] bw ( MiB/s): min= 2560, max= 2861, per=100.00%, avg=2701.42, stdev=15.97, samples=24 iops : min=40960, max=45780, avg=43219.67, stdev=255.59, samples=24 lat (usec) : 50=0.01%, 100=0.26%, 250=4.39%, 500=12.56%, 750=12.72% lat (usec) : 1000=12.92% lat (msec) : 2=34.10%, 4=21.45%, 10=1.28%, 20=0.01%, 50=0.23% lat (msec) : 100=0.06% cpu : usr=2.91%, sys=9.45%, ctx=35300, majf=0, minf=295 IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=99.9%, 32=0.0%, >=64=0.0% submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0% issued rwts: total=65475,65597,0,0 short=0,0,0,0 dropped=0,0,0,0 latency : target=0, window=0, percentile=100.00%, depth=16 Run status group 0 (all jobs): READ: bw=2657MiB/s (2786MB/s), 2657MiB/s-2657MiB/s (2786MB/s-2786MB/s), io=4092MiB (4291MB), run=1540-1540msec WRITE: bw=2662MiB/s (2792MB/s), 2662MiB/s-2662MiB/s (2792MB/s-2792MB/s), io=4100MiB (4299MB), run=1540-1540msec Disk stats (read/write): vda: ios=58387/58501, merge=35/82, ticks=56442/57649, in_queue=114196, util=49.76% ================== CPU tests ================== Architecture: aarch64 CPU op-mode(s): 64-bit Byte Order: Little Endian CPU(s): 6 On-line CPU(s) list: 0-5 Vendor ID: Apple Model: 0 Thread(s) per core: 1 Core(s) per cluster: 6 Socket(s): - Cluster(s): 1 Stepping: 0x0 BogoMIPS: 48.00 Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp flagm2 frint Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Not affected Vulnerability Meltdown: Not affected Vulnerability Mmio stale data: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Not affected Vulnerability Spec store bypass: Vulnerable Vulnerability Spectre v1: Mitigation; __user pointer sanitization Vulnerability Spectre v2: Not affected Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected ================== PostgreSQL Tests ================== ================== Running connection test ================== ✓ Connection successful PostgreSQL version: 17.5 ================== Running latency test ================== Query 1: 62.14ms Query 2: 32.75ms Query 3: 26.37ms Query 4: 27.06ms Query 5: 27.67ms ================== Running write performance test ================== DROP TABLE CREATE TABLE Testing single row INSERT performance (1000 rows)... Inserted 1000 rows in 50.45ms Average: .05ms per insert Testing bulk INSERT performance (10000 rows)... k Bulk inserted 10000 rows in 292.07ms Throughput: 34238 rows/sec ================== Running read performance test ================== Total rows: 10001 Count query took: 29.80ms SELECT with condition (id < 1000): 30.32ms Aggregate query (GROUP BY): 32.23ms ================== Running concurrent connection test ================== Spawned 20 concurrent connections (all completed) ================== Running database info query ================== Database size: 8531091 bytes Active connections: 6 PostgreSQL uptime: 2026-05-21 17:37:54.672924+00 ================== Running cleanup ================== DROP TABLE ================== PostgreSQL tests completed ================== ================== Generating 10MB test file... ================== 1+0 records in 1+0 records out 10485760 bytes (10 MB, 10 MiB) copied, 0.0255081 s, 411 MB/s ================== Running S3 transfer test... ================== ================== Upload s3 testfile... ================== 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (491.69 kB/s) 22s (1/1) Script started on 2026-05-21 19:02:22+00:00 [] 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (491.69 kB/s) 22s (1/1) Script done on 2026-05-21 19:02:44+00:00 [COMMAND_EXIT_CODE="0"] ================== Upload time: 22 seconds ================== ================== Download s3 testfile... ================== 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (7.48 MB/s) 1.6s (1/1) Script started on 2026-05-21 19:02:44+00:00 [] 100.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.49 MB / 10.49 MB (7.48 MB/s) 1.6s (1/1) Script done on 2026-05-21 19:02:45+00:00 [COMMAND_EXIT_CODE="0"] ================== Download time: 1 seconds ================== ================== Verifying file integrity... ================== ================== S3 test passed ================== File size: 10485760 bytes MD5 checksum: 29022c552b0f81a9c89f6ff676a5c102 ================== Kafka test ================== ================== Creating Kafka Topic ================== ================== Starting Consumer ================== ================== Producing Messages ================== Produce time: 1 seconds ================== Consumed Messages ================== Successfully consumed 23 messages ================== All tests completed! ================== ```
--- ## 部署 GreptimeDB 单机版 在该指南中,你将学会如何在 Kubernetes 上部署 GreptimeDB 单机版。 :::note 以下输出可能会因 Helm chart 版本和具体环境的不同而有细微差别。 ::: ## 前置条件 - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) >= v0.20.0 ## 创建一个测试 Kubernetes 集群 :::warning 不建议在生产环境或性能测试中使用 `kind`。如有这类需求建议使用公有云托管的 Kubernetes 服务,如 [Amazon EKS](https://aws.amazon.com/eks/)、[Google GKE](https://cloud.google.com/kubernetes-engine/) 或 [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/),或者自行搭建生产级 Kubernetes 集群。 ::: 目前有很多方法可以创建一个用于测试的 Kubernetes 集群。在本指南中,我们将使用 [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) 来创建一个本地 Kubernetes 集群。如果你想使用已有的 Kubernetes 集群,可以跳过这一步。 这里是一个使用 `kind` v0.20.0 的示例: ```bash kind create cluster ```
预期输出 ```bash Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Thanks for using kind! 😊 ```
使用以下命令检查集群的状态: ```bash kubectl cluster-info ```
预期输出 ```bash Kubernetes control plane is running at https://127.0.0.1:60495 CoreDNS is running at https://127.0.0.1:60495/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ```
:::note 中国大陆用户如有网络访问问题,可使用 Greptime 提供的位于阿里云镜像仓库的 `kindest/node:v1.27.3` 镜像: ```bash kind create cluster --image greptime-registry.cn-hangzhou.cr.aliyuncs.com/kindest/node:v1.27.3 ``` ::: ## 添加 Greptime Helm 仓库 :::note 中国大陆用户如有网络访问问题,可跳过这一步骤并直接参考下一步中使用阿里云 OCI 镜像仓库的方式。采用这一方式将无需手动添加 Helm 仓库。 ::: 我们提供了 GreptimeDB Operator 和 GreptimeDB 集群的[官方 Helm 仓库](https://github.com/GreptimeTeam/helm-charts)。你可以通过运行以下命令来添加仓库: ```bash helm repo add greptime https://greptimeteam.github.io/helm-charts/ helm repo update ``` 检查 Greptime Helm 仓库中的 charts: ```bash helm search repo greptime ```
预期输出 ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-cluster 0.8.3 1.0.1 A Helm chart for deploying GreptimeDB cluster i... greptime/greptimedb-enterprise-dashboard 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB Enterpr... greptime/greptimedb-infra-test 0.1.0 0.1.0 The Helm chart for deploying GreptimeDB infra t... greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. greptime/greptimedb-remote-compaction 0.1.1 0.1.0 Remote compaction components (scheduler, compac... greptime/greptimedb-standalone 0.4.2 1.0.1 A Helm chart for deploying standalone greptimedb ```
## 安装 GreptimeDB 单机版 ### 基础安装 使用默认配置快速安装: ```bash helm upgrade --install greptimedb-standalone greptime/greptimedb-standalone -n default ```
期望输出 ```bash Release "greptimedb-standalone" does not exist. Installing it now. NAME: greptimedb-standalone LAST DEPLOYED: Sun Apr 26 20:30:51 2026 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-standalone Chart version: 0.4.2 GreptimeDB Standalone version: 1.0.1 *********************************************************************** Installed components: * greptimedb-standalone The greptimedb-standalone is starting, use `kubectl get statefulset greptimedb-standalone -n default` to check its status. ```
```bash kubectl get pod -n default ```
期望输出 ```bash NAME READY STATUS RESTARTS AGE greptimedb-standalone-0 1/1 Running 0 40s ```
### 自定义安装 创建自定义配置文件 `values.yaml`: ```yaml resources: requests: cpu: "2" memory: "4Gi" limits: cpu: "4" memory: "8Gi" ``` 更多配置选项请参考 [文档](https://github.com/GreptimeTeam/helm-charts/tree/main/charts/greptimedb-standalone). 使用自定义配置安装: ```bash helm upgrade --install greptimedb-standalone greptime/greptimedb-standalone \ --values values.yaml \ --namespace default ```
期望输出 ```bash Release "greptimedb-standalone" has been upgraded. Happy Helming! NAME: greptimedb-standalone LAST DEPLOYED: Sun Apr 26 20:35:11 2026 NAMESPACE: default STATUS: deployed REVISION: 2 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-standalone Chart version: 0.4.2 GreptimeDB Standalone version: 1.0.1 *********************************************************************** Installed components: * greptimedb-standalone The greptimedb-standalone is starting, use `kubectl get statefulset greptimedb-standalone -n default` to check its status. ```
```bash kubectl get pod -n default ```
期望输出 ```bash NAME READY STATUS RESTARTS AGE greptimedb-standalone-0 1/1 Running 0 3s ```
## 访问 GreptimeDB 安装完成后,您可以通过以下方式访问 GreptimeDB: ### MySQL 协议 ```bash kubectl port-forward svc/greptimedb-standalone 4002:4002 -n default > connections.out & ``` ```bash mysql -h 127.0.0.1 -P 4002 ```
期望输出 ```bash Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.4.2 Greptime Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> ```
### PostgreSQL 协议 ```bash kubectl port-forward svc/greptimedb-standalone 4003:4003 -n default > connections.out & ``` ```bash psql -h 127.0.0.1 -p 4003 -d public ```
期望输出 ```bash psql (16.2, server 16.3-GreptimeDB-1.0.1) Type "help" for help. public=> ```
### HTTP 协议 ```bash kubectl port-forward svc/greptimedb-standalone 4000:4000 -n default > connections.out & ``` ```bash curl -X POST \ -d 'sql=show databases' \ http://localhost:4000/v1/sql | jq . ```
期望输出 ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "Database", "data_type": "String" } ] }, "rows": [ [ "greptime_private" ], [ "information_schema" ], [ "public" ] ], "total_rows": 3 } } ], "execution_time_ms": 2 } ```
## 卸载 删除 GreptimeDB 单机版: ```bash helm uninstall greptimedb-standalone -n default ``` ```bash kubectl delete pvc -l app.kubernetes.io/instance=greptimedb-standalone -n default ``` --- ## 部署 Kafka 集群 在该指南中,你将学会如何使用 Helm Chart 在 Kubernetes 上部署 Kafka 集群。 ## 前置依赖 - Kubernetes >= v1.18.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## 配置管理 在安装之前,你需要创建一个文件来配置 Kafka 集群。请根据你的 Kubernetes 环境调整,以下是 `kafka-values.yaml` 的参考配置: ```yaml image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: greptime/kafka tag: 3.9.0-debian-12-r1 listeners: client: containerPort: 9092 protocol: PLAINTEXT name: CLIENT controller: protocol: PLAINTEXT heapOpts: "-Xmx512m -Xms512m -XX:MetaspaceSize=96m -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16M -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80 -XX:+ExplicitGCInvokesConcurrent" controller: replicaCount: 3 resources: limits: cpu: '1' memory: 1Gi requests: cpu: 500m memory: 512Mi persistence: enabled: true storageClass: "" size: 50Gi broker: replicaCount: 3 resources: limits: cpu: '1' memory: 1Gi requests: cpu: 500m memory: 512Mi persistence: enabled: true storageClass: "" size: 50Gi extraConfig: | num.network.threads=3 num.io.threads=8 min.insync.replicas=1 socket.send.buffer.bytes=102400 socket.receive.buffer.bytes=102400 socket.request.max.bytes=104857600 num.recovery.threads.per.data.dir=1 offsets.topic.replication.factor=1 transaction.state.log.replication.factor=1 transaction.state.log.min.isr=1 allow.everyone.if.no.acl.found=true auto.create.topics.enable=true default.replication.factor=1 max.partition.fetch.bytes=1048576 max.request.size=1048576 message.max.bytes=20000000 log.dirs=/bitnami/kafka/data log.flush.interval.messages=10000 log.flush.interval.ms=1000 log.retention.hours=4 log.roll.hours=3 log.retention.bytes=250000000 log.segment.bytes=1073741824 ``` ## 安装 Kafka 集群 在 kafka 命名空间中安装 Kafka 集群: ```bash helm upgrade --install kafka \ --create-namespace \ oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/kafka \ --version 31.0.0 \ -n kafka --values kafka-values.yaml ```
预期输出 ```bash Release "kafka" does not exist. Installing it now. Pulled: greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/kafka:31.0.0 Digest: sha256:85b135981fd5d951ceef8b51cdcbc6917ebface50d0eb3367eb7ddc4a5db482b NAME: kafka LAST DEPLOYED: Tue May 12 00:57:32 2026 NAMESPACE: kafka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: kafka CHART VERSION: 31.0.0 APP VERSION: 3.9.0 ** Please be patient while the chart is being deployed ** Kafka can be accessed by consumers via port 9092 on the following DNS name from within your cluster: kafka.kafka.svc.cluster.local Each Kafka broker can be accessed by producers via port 9092 on the following DNS name(s) from within your cluster: kafka-controller-0.kafka-controller-headless.kafka.svc.cluster.local:9092 kafka-broker-0.kafka-broker-headless.kafka.svc.cluster.local:9092 To create a pod that you can use as a Kafka client run the following commands: kubectl run kafka-client --restart='Never' --image greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/kafka:3.9.0-debian-12-r1 --namespace kafka --command -- sleep infinity kubectl exec --tty -i kafka-client --namespace kafka -- bash PRODUCER: kafka-console-producer.sh \ --bootstrap-server kafka.kafka.svc.cluster.local:9092 \ --topic test CONSUMER: kafka-console-consumer.sh \ --bootstrap-server kafka.kafka.svc.cluster.local:9092 \ --topic test \ --from-beginning Substituted images detected: - greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/kafka:3.9.0-debian-12-r1 ```
## 验证 Kafka 集群安装 检查 Kafka 组件(Broker 和 Controller)的状态: ```bash kubectl get pod -n kafka ```
预期输出 ```bash NAME READY STATUS RESTARTS AGE kafka-broker-0 1/1 Running 0 8m3s kafka-broker-1 1/1 Running 0 8m2s kafka-broker-2 1/1 Running 0 8m1s kafka-controller-0 1/1 Running 0 8m3s kafka-controller-1 1/1 Running 0 8m2s kafka-controller-0 1/1 Running 0 8m1s ```
# 配置 Kafka 端点 在 Kafka 集群部署完成后,GreptimeDB 可以通过配置 Kafka 端点启用 Remote WAL(远程写前日志),更多参考[此篇文档](/user-guide/deployments-administration/deploy-on-kubernetes/configure-remote-wal.md)。 ```yaml remoteWal: enabled: true kafka: brokerEndpoints: - "kafka-broker-0.kafka-broker-headless.kafka.svc.cluster.local:9092" - "kafka-broker-1.kafka-broker-headless.kafka.svc.cluster.local:9092" - "kafka-broker-2.kafka-broker-headless.kafka.svc.cluster.local:9092" ``` # 监控 - 安装 Prometheus Operator (例如: [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack))。 - 安装 podmonitor CRD。 要监控 Kafka 集群,你需要提前部署好监控系统(如 Prometheus 和 Grafana)。然后在 `kafka-values.yaml` 中增加以下内容,并重新执行更新 Kafka 配置: ```yaml metrics: jmx: enabled: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: greptime/jmx-exporter tag: 1.0.1-debian-12-r9 serviceMonitor: enabled: true namespace: "kafka" interval: "10s" labels: release: kube-prometheus-stack ``` ## Grafana dashboard 使用 [Kubernetes Kafka](https://grafana.com/grafana/dashboards/12483-kubernetes-kafka/) (ID: 12483) 来监控 kafka 的指标。 1. 登录你的 Grafana。 2. 导航至 Dashboards -> New -> Import。 3. 输入 Dashboard ID: 12483, 选择数据源并加载图表。 ![Kubernetes Kafka](/kubernetes-kafka-monitoring-dashboard.png) # 卸载 Kafka 集群 可以使用以下命令卸载 Kafka 集群: ```bash helm -n kafka uninstall kafka ``` ## 删除 PVCs 删除 PVCs 操作将会删除 Kafka 集群的持久化数据。请确保在继续操作之前已经备份了数据。 ```bash kubectl -n kafka delete pvc -l app.kubernetes.io/instance=kafka ``` --- ## 部署 MinIO 集群 在该指南中,你将学会如何使用 Helm Chart 在 Kubernetes 上部署 MinIO 集群。 ## 前置依赖 - Kubernetes >= v1.18.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## 配置管理 在安装之前,你需要创建一个 `minio-values.yaml` 配置文件。请根据你的 Kubernetes 环境调整以下配置: ```yaml global: security: allowInsecureImages: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: greptime/minio tag: 2025.4.22-debian-12-r1 auth: rootUser: greptimedbadmin rootPassword: "greptimedbadmin" resources: requests: cpu: 500m memory: 500Mi limits: cpu: '2' memory: 2Gi extraEnvVars: - name: MINIO_REGION value: "ap-southeast-1" statefulset: replicaCount: 4 mode: distributed persistence: storageClass: null size: 100Gi ``` ## 安装 MinIO 集群 在 minio 命名空间中安装 MinIO 集群: ```bash helm upgrade \ --install minio oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/minio \ --create-namespace \ --version 16.0.10 \ -n minio --values minio-values.yaml ```
预期输出 ```bash Release "minio" does not exist. Installing it now. Pulled: greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/minio:16.0.10 Digest: sha256:96e220fd7cf1596879a243453b39c96a95d34f0005fdd452da3d094a7b386eb4 NAME: minio LAST DEPLOYED: Tue May 12 17:21:30 2026 NAMESPACE: minio STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: minio CHART VERSION: 16.0.10 APP VERSION: 2025.4.22 Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or application customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami for more information. ** Please be patient while the chart is being deployed ** MinIO® can be accessed via port on the following DNS name from within your cluster: minio.minio.svc.cluster.local To get your credentials run: export ROOT_USER=$(kubectl get secret --namespace minio minio -o jsonpath="{.data.root-user}" | base64 -d) export ROOT_PASSWORD=$(kubectl get secret --namespace minio minio -o jsonpath="{.data.root-password}" | base64 -d) To connect to your MinIO® server using a client: - Run a MinIO® Client pod and append the desired command (e.g. 'admin info'): kubectl run --namespace minio minio-client \ --rm --tty -i --restart='Never' \ --env MINIO_SERVER_ROOT_USER=$ROOT_USER \ --env MINIO_SERVER_ROOT_PASSWORD=$ROOT_PASSWORD \ --env MINIO_SERVER_HOST=minio \ --image docker.io/bitnami/minio-client:2025.4.16-debian-12-r1 -- admin info minio To access the MinIO® web UI: - Get the MinIO® URL: echo "MinIO® web URL: http://127.0.0.1:9001/minio" kubectl port-forward --namespace minio svc/minio 9001:9001 Substituted images detected: - greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/minio:2025.4.22-debian-12-r1 ```
## 验证 MinIO 集群安装 检查 MinIO Pod 的状态: ```bash kubectl get pod -n minio ```
预期输出 ```bash NAME READY STATUS RESTARTS AGE minio-0 1/1 Running 0 30s minio-1 1/1 Running 0 30s minio-2 1/1 Running 0 30s minio-3 1/1 Running 0 30s ```
# 创建 Bucket 和 Access Key ## 访问 MinIO 控制台 1. 首先需要将 MinIO 控制台服务暴露出来,你可以使用 `kubectl port-forward` 命令: ```bash kubectl port-forward -n minio svc/minio 9001:9001 ``` 2. 打开浏览器访问 http://localhost:9001/login 3. 使用配置文件中设置的账号密码登录: - username: `greptimedbadmin` - password: `greptimedbadmin` ![MinIO login](/minio-login-page.png) ## 创建 Bucket 登录 MinIO 控制台后,按照以下步骤创建 Bucket: 1. 点击左侧菜单栏的 "Buckets" 2. 点击 "Create Bucket" 按钮 3. 输入 Bucket 名称,例如:`greptimedb-bucket` 4. 点击 "Create Bucket" 确认创建 ![MinIO create bucket step 1](/minio-create-bucket-1.png) ![MinIO create bucket step 2](/minio-create-bucket-2.png) ## 生成 Access Key 1. 点击左侧菜单栏的 "Access Keys" 2. 点击 "Create Access Key" 按钮 3. 可选:设置权限策略 4. 点击 "Create" 生成 Access Key 和 Secret Key ![MinIO create access key step 1](/minio-create-access-key-1.png) ![MinIO create access key step 2](/minio-create-access-key-2.png) :::warning ⚠️ 重要:请妥善保存以下信息,在部署 GreptimeDB 时会用到。 - Bucket 名称:greptimedb-bucket - Region:ap-southeast-1 - MinIO Endpoint:`http://minio.minio:9000` - Access Key:创建时生成的 Access Key - Secret Key:创建时生成的 Secret Key ::: # 配置 GreptimeDB 使用 MinIO 在部署 GreptimeDB 集群时,可以通过以下配置使用 MinIO 作为后端存储: ```yaml objectStorage: credentials: accessKeyId: "" secretAccessKey: "" s3: bucket: "greptimedb-bucket" region: "ap-southeast-1" root: "greptimedb-data" endpoint: "http://minio.minio:9000" ``` # 监控 - 安装 Prometheus Operator (例如: [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack))。 - 安装 podmonitor CRD。 要监控 MinIO 集群,你需要提前部署好监控系统(如 Prometheus 和 Grafana)。然后在 `minio-values.yaml` 中增加以下内容,并重新执行更新 MinIO 配置: ```yaml metrics: enabled: true serviceMonitor: enabled: true namespace: minio labels: release: kube-prometheus-stack interval: 30s ``` ## Grafana dashboard 使用 [MinIO Dashboard](https://grafana.com/grafana/dashboards/13502-minio-dashboard/) (ID: 13502) 来监控 MinIO 的指标。 1. 登录你的 Grafana。 2. 导航至 Dashboards -> New -> Import。 3. 输入 Dashboard ID: 13502, 选择数据源并加载图表。 ![MinIO Dashboard](/kubernetes-minio-monitoring-dashboard.png) # 卸载 MinIO 集群 使用以下命令卸载 MinIO 集群: ```bash helm -n minio uninstall minio ``` ## 删除 PVCs 删除 PVCs 操作将会删除 MinIO 集群的持久化数据。请确保在继续操作之前已经备份了数据。 ```bash kubectl -n minio delete pvc -l app.kubernetes.io/instance=minio ``` --- ## GreptimeDB Operator 的管理 GreptimeDB Operator 使用 [Operator 模式](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) 在 [Kubernetes](https://kubernetes.io/) 上管理 [GreptimeDB](https://github.com/GrepTimeTeam/greptimedb) 资源。 就像自动驾驶一样,GreptimeDB Operator 自动化了 GreptimeDB 集群和单机实例的部署、配置和管理。 GreptimeDB Operator 包括但不限于以下功能: - **自动化部署**: 通过提供 `GreptimeDBCluster` 和 `GreptimeDBStandalone` CRD 来自动化在 Kubernetes 上部署 GreptimeDB 集群和单机实例。 - **多云支持**: 用户可以在任何 Kubernetes 集群上部署 GreptimeDB,包括私有环境和公有云环境(如 AWS、GCP、阿里云等)。 - **扩缩容**: 通过修改 `GreptimeDBCluster` CR 中的 `replicas` 字段即可轻松实现 GreptimeDB 集群的扩缩容。 - **监控**: 通过在 `GreptimeDBCluster` CR 中提供 `monitoring` 字段来自动化部署基于 GreptimeDB 的监控组件。 本指南将展示如何在 Kubernetes 上安装、升级、配置和卸载 GreptimeDB Operator。 :::note 以下输出可能会因 Helm chart 版本和具体环境的不同而有细微差别。 ::: ## 前置依赖 - Kubernetes >= v1.18.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## 生产环境部署 对于生产环境部署,推荐使用 Helm 来安装 GreptimeDB Operator。 ### 安装 你可以参考 [安装和验证 GreptimeDB Operator](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md#安装和验证-greptimedb-operator) 获取详细的指导。 :::note 如果你使用 [Argo CD](https://argo-cd.readthedocs.io/en/stable/) 来部署应用,请确保 `Application` 已设置 [`ServerSideApply=true`](https://argo-cd.readthedocs.io/en/latest/user-guide/sync-options/#server-side-apply) 以启用 server-side apply(其他 GitOps 工具可能也有类似的设置)。 ::: ### 升级 我们总是将最新版本的 GreptimeDB Operator 作为 Helm chart 发布在我们的[官方 Helm 仓库](https://github.com/GreptimeTeam/helm-charts/tree/main)。 当最新版本的 GreptimeDB Operator 发布时,您可以通过运行以下命令来升级 GreptimeDB Operator。 #### 更新 Helm 仓库 ```bash helm repo update greptime ```
期望输出 ```bash Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "greptime" chart repository Update Complete. ⎈Happy Helming!⎈ ```
你可以使用以下命令来搜索 GreptimeDB Operator 的最新版本: ```bash helm search repo greptime/greptimedb-operator ```
预期输出 ```bash NAME CHART VERSION APP VERSION DESCRIPTION greptime/greptimedb-operator 0.5.9 0.5.5 The greptimedb-operator Helm chart for Kubernetes. ```
如果你想列出所有可用的版本,你可以使用以下命令: ``` helm search repo greptime/greptimedb-operator --versions ``` #### 升级 GreptimeDB Operator 你可以通过运行以下命令升级到最新发布的 GreptimeDB Operator 版本: ```bash helm -n greptimedb-admin upgrade --install greptimedb-operator greptime/greptimedb-operator ```
期望输出 ```bash NAME: greptimedb-operator LAST DEPLOYED: Sun Apr 26 20:43:58 2026 NAMESPACE: greptimedb-admin STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: *********************************************************************** Welcome to use greptimedb-operator Chart version: 0.5.9 GreptimeDB Operator version: 0.5.5 *********************************************************************** Installed components: * greptimedb-operator The greptimedb-operator is starting, use `kubectl get deployment greptimedb-operator -n greptimedb-admin` to check its status. ```
如果你想升级到特定版本,你可以使用以下命令: ```bash helm -n greptimedb-admin upgrade --install greptimedb-operator greptime/greptimedb-operator --version ``` 升级完成后,你可以使用以下命令来验证安装: ```bash helm list -n greptimedb-admin ```
期望输出 ```bash NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION greptimedb-operator greptimedb-admin 1 2026-04-26 20:43:58.003167 +0800 CST deployed greptimedb-operator-0.5.9 0.5.5 ```
### CRDs 这里将有两种类型的 CRD 与 GreptimeDB Operator 一起安装:`GreptimeDBCluster` 和 `GreptimeDBStandalone`。 你可以使用以下命令来验证安装: ```bash kubectl get crd | grep greptime ```
期望输出 ```bash greptimedbclusters.greptime.io 2026-04-26T12:43:58Z greptimedbstandalones.greptime.io 2026-04-26T12:43:58Z ```
默认情况下,GreptimeDB Operator chart 将管理 CRDs 的安装和升级,用户不需要手动管理它们。如果你想了解这两类 CRD 的具体定义,可参考 GreptimeDB Operator 的 [API 文档](https://github.com/GreptimeTeam/greptimedb-operator/blob/main/docs/api-references/docs.md)。 ### 配置 GreptimeDB Operator chart 提供了一组配置选项,允许您自行配置,您可以参考 [GreptimeDB Operator Helm Chart](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-operator/README.md) 来获取更多详细信息。 你可以创建一个 `values.yaml` 来配置 GreptimeDB Operator chart (完整的 `values.yaml` 配置可以参考 [chart](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-operator/values.yaml)),例如: ```yaml image: # -- The image registry registry: docker.io # -- The image repository repository: greptime/greptimedb-operator # -- The image pull policy for the controller imagePullPolicy: IfNotPresent # -- The image tag tag: "v0.6.0" # -- The image pull secrets pullSecrets: [] replicas: 1 resources: limits: cpu: 500m memory: 512Mi requests: cpu: 250m memory: 256Mi ``` :::note 中国大陆用户如有网络访问问题,可将上文中的 `image.registry` 配置为阿里云镜像仓库地址 `greptime-registry.cn-hangzhou.cr.aliyuncs.com`。 ::: 你可以使用以下的命令来安装或升级带有自定义配置的 GreptimeDB Operator: ```bash helm -n greptimedb-admin upgrade --install greptimedb-operator greptime/greptimedb-operator -f values.yaml ``` ### 卸载 你可以使用 `helm` 命令来卸载 GreptimeDB Operator: ```bash helm -n greptimedb-admin uninstall greptimedb-operator ``` 默认情况下,卸载 GreptimeDB Operator 时不会删除 CRDs。 :::danger 如果你确实想要删除 CRDs,你可以使用以下命令: ```bash kubectl delete crd greptimedbclusters.greptime.io greptimedbstandalones.greptime.io ``` 删除 CRDs 后,相关资源将被删除。 ::: --- ## 在 Kubernetes 上部署 GreptimeDB GreptimeDB 专为云原生环境而构建,从第一天起就可以在 Kubernetes 上部署。 你可以在任何云服务提供商上部署 GreptimeDB,包括 AWS、阿里云或谷歌云等。 ## 部署 GreptimeDB 单机版 对于开发、测试或小规模生产用例,你可以在 Kubernetes 上[部署 GreptimeDB 单机实例](deploy-greptimedb-standalone.md)。 这种方式较为简单,无需管理完整集群的复杂性。 ## 部署 GreptimeDB 集群 对于需要高可用性和可扩展性的生产环境, 你可以使用 GreptimeDB Operator 在 Kubernetes 上[部署 GreptimeDB 集群](deploy-greptimedb-cluster.md)以建立分布式 GreptimeDB 集群, 水平扩展并高效处理大量数据。 ## 配置 在部署 GreptimeDB 集群或单机实例时,你可以通过创建 `values.yaml` 文件 来对 GreptimeDB 应用自定义配置。 有关可用配置选项的完整列表,请参阅[通用 Helm Chart 配置](./common-helm-chart-configurations.md)。 ## 管理 GreptimeDB Operator 基于 GreptimeDB Operator,你可以很轻松地部署、升级和管理 GreptimeDB 集群和单机实例。 无论是私有还是公有云部署,GreptimeDB Operator 都将快速部署和扩容 GreptimeDB 变得简单易行。 了解如何[管理 GreptimeDB Operator](./greptimedb-operator-management.md), 包括安装和升级。 ## 进阶部署 在熟悉了 [GreptimeDB 的架构和组件](/user-guide/concepts/architecture.md)之后,你可以进一步探索高级部署场景: - [部署 GreptimeDB 基础设施测试](deploy-greptimedb-infra-test.md): 安装 GreptimeDB 的前置基础设施测试检查。 - [部署 MinIO 集群](deploy-minio.md):学习如何部署,配置和监控 MinIO 集群。 - [部署 Kafka 集群](deploy-kafka.md):学习如何部署,配置和监控 Kafka 集群。 - [部署带有 Remote WAL 的 GreptimeDB 集群](configure-remote-wal.md):将 Kafka 配置为 GreptimeDB 集群的远程预写日志 (WAL),以持久记录每个数据修改并确保不丢失内存缓存的数据。 - [使用 MySQL/PostgreSQL 作为元数据存储](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#配置-metasrv-后端存储):集成 MySQL/PostgreSQL 数据库以提供强大的元数据存储功能,增强可靠性和性能。 - [部署多 Frontend 的 GreptimeDB 集群](configure-frontend-groups.md):GreptimeDB 集群的 Frontend 组由多个 Frontend 实例组成,以改善负载分配和可用性。 --- ## GreptimeDB 导出和导入工具 本指南描述了如何使用 GreptimeDB 的导出和导入工具进行数据库备份和恢复。 有关详细的命令行选项和高级配置,请参阅 [数据导出和导入](/reference/command-lines/utilities/data.md)。 ## 概述 ## 导出操作 ### 完整数据库备份 导出所有数据库备份。此操作将每个数据库导出到单个目录中,包括所有表及其数据。 ```bash # 导出所有数据库备份 greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/greptimedb ``` 输出目录结构: ``` / └── greptime/ └── / ├── create_database.sql ├── create_tables.sql ├── copy_from.sql └── <数据文件> ``` #### 导出到 S3 导出所有数据库备份到 S3: ```bash greptime cli data export \ --addr localhost:4000 \ --s3 \ --s3-bucket \ --s3-access-key-id \ --s3-secret-access-key \ --s3-region \ --s3-root \ --s3-endpoint ``` ### 使用 Basic Authentication 导出 如果 GreptimeDB 实例启用了身份认证,请使用 `--auth-basic` 传入凭据: ```bash greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/greptimedb \ --auth-basic : ``` ### 仅导出表结构 仅导出表结构而不包含数据。此操作将 `CREATE TABLE` 语句导出到 SQL 文件中,允许您备份表结构而不包含实际数据。 ```bash # 仅导出表结构 greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/schemas \ --target schema ``` ### 基于时间范围备份 ```bash # 导出指定时间范围内的数据 greptime cli data export --addr localhost:4000 \ --output-dir /tmp/backup/timerange \ --start-time "2024-01-01 00:00:00" \ --end-time "2024-01-31 23:59:59" ``` ### 指定数据库备份 ```bash # 导出指定数据库 greptime cli data export \ --addr localhost:4000 \ --output-dir /tmp/backup/greptimedb \ --database '{my_database_name}' ``` ## 导入操作 ### 完整数据库备份 导入所有数据库备份。 ```bash # 导入所有数据库 greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/greptimedb ``` ### 使用 Basic Authentication 导入 如果 GreptimeDB 实例启用了身份认证,请使用 `--auth-basic` 传入凭据: ```bash greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/greptimedb \ --auth-basic : ``` ### 仅导入表结构 仅导入表结构而不包含数据。此操作将 `CREATE TABLE` 语句从 SQL 文件中导入,允许您恢复表结构而不包含实际数据。 ```bash # 仅导入表结构 greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/schemas \ --target schema ``` ### 指定数据库备份 ```bash # 导入指定数据库 greptime cli data import \ --addr localhost:4000 \ --input-dir /tmp/backup/greptimedb \ --database '{my_database_name}' ``` ## 最佳实践 1. **并行度配置** - 根据可用系统资源调整 `--export-jobs`/`--import-jobs` - 从较低的值开始,逐步增加 - 在操作期间监控系统性能 2. **备份策略** - 使用时间范围进行增量数据备份 - 定期备份用于灾难恢复 3. **错误处理** - 使用 `--max-retry` 处理临时异常 - 保留日志以便故障排除 ## 性能提示 1. **导出性能** - 对大型数据集使用时间范围 - 根据 CPU/内存调整并行任务数量 - 考虑网络带宽限制 2. **导入性能** - 注意监控数据库资源 1. **导出性能** - 对大型数据集使用时间范围 - 根据 CPU/内存调整并行任务 - 考虑网络带宽限制 2. **导入性能** - 监控数据库资源 ## 故障排除 ### 常见问题 1. **连接错误** - 验证服务器地址和端口 - 检查网络连接 - 确保身份验证凭据正确 2. **权限问题** - 验证输出/输入目录的读写权限 3. **资源限制** - 减少并行任务数 - 确保足够的磁盘空间 - 在操作期间监控系统资源 --- ## GreptimeDB 元信息导出和导入工具 本指南描述了如何使用 GreptimeDB 的元信息导出和导入工具进行元数据库备份和恢复。 有关详细的命令行选项和高级配置,请参阅 [元数据导出和导入](/reference/command-lines/utilities/metadata.md)。 ## 概述 ## 导出操作 ### 导出到 S3 云存储 将元数据从 PostgreSQL 导出到 S3 云存储,用于云备份存储: ```bash greptime cli meta snapshot save \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store \ --s3 \ --s3-bucket your-bucket-name \ --s3-region ap-southeast-1 \ --s3-access-key-id \ --s3-secret-access-key ``` **输出**: 在指定的 S3 桶中创建 `metadata_snapshot.metadata.fb` 文件。 ### 导出到本地目录 #### 从 PostgreSQL 后端导出 将元数据从 PostgreSQL 导出到本地目录: ```bash greptime cli meta snapshot save \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store ``` #### 从 MySQL 后端导出 将元数据从 MySQL 导出到本地目录: ```bash greptime cli meta snapshot save \ --store-addrs 'mysql://user:password@127.0.0.1:3306/database' \ --backend mysql-store ``` #### 从 etcd 后端导出 将元数据从 etcd 导出到本地目录: ```bash greptime cli meta snapshot save \ --store-addrs 127.0.0.1:2379 \ --backend etcd-store ``` **输出**: 在当前工作目录中创建 `metadata_snapshot.metadata.fb` 文件。 #### 从 RaftEngine 后端导出 :::note RaftEngine 在 standalone 实例运行期间会锁定元数据目录,请在导出前停止 standalone 实例。 ::: 将元数据从 RaftEngine 导出到本地目录: ```bash greptime cli meta snapshot save \ --store-addrs "raftengine:///path/to/metadata" \ --backend raft-engine-store ``` **输出**: 在当前工作目录中创建 `metadata_snapshot.metadata.fb` 文件。 ## 导入操作 :::warning **重要**: 在导入元数据之前,请确保目标存储后端的对应表中没有**任何数据**,否则可能会导致元数据损坏。 如果你需要导入到具有现有数据的后端,请使用 `--force` 标志绕过此安全检查。但是,请谨慎操作,因为这可能导致数据损坏。 ::: ### 从 S3 云存储导入 从 S3 备份恢复元数据到 PostgreSQL 存储后端: ```bash greptime cli meta snapshot restore \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store \ --s3 \ --s3-bucket your-bucket-name \ --s3-region ap-southeast-1 \ --s3-access-key-id \ --s3-secret-access-key ``` ### 从本地文件导入 #### 导入到 PostgreSQL 后端 从本地备份文件恢复元数据到 PostgreSQL: ```bash greptime cli meta snapshot restore \ --store-addrs 'password=password dbname=postgres user=postgres host=localhost port=5432' \ --backend postgres-store ``` #### 导入到 MySQL 后端 从本地备份文件恢复元数据到 MySQL: ```bash greptime cli meta snapshot restore \ --store-addrs 'mysql://user:password@127.0.0.1:3306/database' \ --backend mysql-store ``` #### 导入到 etcd 后端 从本地备份文件恢复元数据到 etcd: ```bash greptime cli meta snapshot restore \ --store-addrs 127.0.0.1:2379 \ --backend etcd-store ``` #### 导入到 RaftEngine 后端 从本地备份文件恢复元数据到 RaftEngine: ```bash greptime cli meta snapshot restore \ --store-addrs "raftengine:///path/to/metadata" \ --backend raft-engine-store ``` --- ## 基于单集群跨区域部署的 DR 解决方案 ## GreptimeDB DR 的工作原理 GreptimeDB 非常适合跨区域灾难恢复。GreptimeDB 提供了量身定制的解决方案,以满足不同区域特征和业务需求的多样化要求。 GreptimeDB 资源管理涉及 Availability Zones(AZ)的概念。一个 AZ 是一个逻辑上的灾难恢复单元。 它可以是数据中心(DC),也可以是 DC 的一个分区,这取决于你具体的 DC 条件和部署设计。 在跨区域灾难恢复解决方案中,一个 GreptimeDB 区域是一个城市。当两个 DC 在同一区域且其中一个 DC 不可用时,另一个 DC 可以接管不可用 DC 的服务。这是一种本地化策略。 在了解每个 DR 解决方案的细节之前,有必要先了解以下知识: 1. Remote wal 组件的 DR 解决方案也非常重要。本质上,它构成了整个 DR 解决方案的基础。因此,对于每个 GreptimeDB 的 DR 解决方案,我们将在图中展示 remote wal 组件。目前,GreptimeDB 默认使用基于 Kafka 实现的 remote wal 组件,将来会提供其他实现;然而,在部署上不会有显著差异。 2. GreptimeDB 表:每张表可以根据一定范围划分为多个分区,每个分区可能分布在不同的数据节点上。在写入或查询时,会根据相应的路由规则调用到指定的数据节点。一张表的分区可能如下所示: ``` Table name: T1 Table partition count: 4 T1-1 T1-2 T1-3 T1-4 Table name: T2 Table partition count: 3 T2-1 T2-2 T2-3 ``` ### 元数据跨两个区域,数据在同一区域 ![DR-across-2dc-1region](/DR-across-2dc-1region.png) 在此解决方案中,数据位于一个区域(2 个 DC),而元数据跨越两个区域。 DC1 和 DC2 一起用于处理读写服务,而位于第二区域的 DC3 是用来满足多数派协议的副本。这种架构也被称为“2-2-1”解决方案。 在极端情况下,DC1 和 DC2 都必须能够处理所有请求,因此请确保分配足够的资源。 网络延迟: - 同一区域内延迟为 2ms - 两个区域间延迟为 30ms 支持高可用性级别: - 单个 AZ 不可用时性能相同 - 单个 DC 不可用时性能几乎相同 如果您想要一个区域级别的灾难恢复解决方案,可以更进一步,在 DC3 上提供读写服务。因此,下一个解决方案是: ### 数据跨两个区域 ![DR-across-3dc-2region](/DR-across-3dc-2region.png) 在此解决方案中,数据跨越两个区域。 每个数据中心必须能够在极端情况下处理所有请求,因此请确保分配足够的资源。 网络延迟: - 同一区域内延迟为 2 毫秒 - 两个区域间延迟为 30 毫秒 支持高可用性级别: - 单个可用区不可用时性能不变 - 单个数据中心不可用时性能下降 如果无法容忍单个数据中心故障导致的性能下降,请考虑升级到五个数据中心和三个区域的解决方案。 ### 元数据跨三个区域,数据跨两个区域 ![DR-across-5dc-2region](/DR-across-5dc-2region.png) 在此解决方案中,数据跨越两个区域,而元数据跨越三个区域。 Region1 和 Region2 一起用于处理读写服务,而 Region3 是一个副本,用于满足多数派协议。这种架构也被称为“2-2-1”解决方案。 两个相邻的区域中的每一个都必须能够在极端情况下处理所有请求,因此请确保分配足够的资源。 网络延迟: - 同一区域内延迟为 2ms - 两个相邻区域之间延迟为 7ms - 两个远距离区域之间延迟为 30ms 支持高可用性级别: - 单一 AZ 不可用时性能不变 - 单一 DC 不可用时性能不变 - 单一区域(城市)不可用时性能略有下降 您可以更进一步,在三个区域上提供读写服务。因此,下一个解决方案是: (此解决方案可能具有更高的延迟,如果无法接受,则不推荐。) ## 数据跨三个区域 ![DR-across-5dc-3region](/DR-across-5dc-3region.png) 在此解决方案中,数据跨越三个区域。 如果一个区域发生故障,其他两个区域必须能够处理所有请求,因此请确保分配足够的资源。 网络延迟: - 同一区域内延迟为 2 毫秒 - 相邻两个区域之间的延迟为 7 毫秒 - 两个远距离区域之间的延迟为 30 毫秒 支持高可用性级别: - 单个 AZ 不可用时性能不变 - 单个 DC 不可用时性能不变 - 单个区域(城市)不可用时性能下降 ## 解决方案比较 上述解决方案的目标是在中大型场景中满足高可用性和可靠性的要求。然而,在具体实施过程中,每种解决方案的成本和效果可能会有所不同。下表对每种解决方案进行了比较,以帮助你根据具体场景、需求和成本进行最终选择。 以下是内容格式化为表格: | 解决方案 | 延迟 | 高可用性 | | --- | --- | --- | | 元数据跨两个区域,数据在同一区域 | - 同一区域内延迟 2 毫秒- 两个区域间延迟 30 毫秒 | - 单个 AZ 不可用时性能不变- 单个 DC 不可用时性能几乎不变 | | 数据跨两个区域 | - 同一区域内延迟 2 毫秒- 两个区域间延迟 30 毫秒 | - 单个 AZ 不可用时性能不变- 单个 DC 不可用时性能下降 | | 元数据跨三个区域,数据跨两个区域 | - 同一区域内延迟 2 毫秒- 相邻两个区域间延迟 7 毫秒- 两个远距离的区域间延迟 30 毫秒 | - 单个 AZ 不可用时性能不变- 单个 DC 不可用时性能不变- 单一区域(城市)不可用时,性能略有下降 | | 数据跨三个区域 | - 同一区域内延迟 2 毫秒- 相邻两个区域间延迟 7 毫秒- 两个远距离的区域间延迟 30 毫秒 | - 单个 AZ 不可用时性能不变- 单个 DC 不可用时性能不变 - 单一区域(城市)不可用时,性能下降 | --- ## GreptimeDB Standalone 的 DR 方案 --- ## 灾难恢复 作为分布式数据库,GreptimeDB 提供了不同的灾难恢复(DR)解决方案。 本文档包括以下内容: * DR 中的基本概念 * GreptimeDB 中备份与恢复(BR)的部署架构。 * GreptimeDB 的 DR 解决方案。 * DR 解决方案的比较。 ## 基本概念 * **恢复时间目标(RTO)**:指灾难发生后业务流程可以停止的最长时间,而不会对业务产生负面影响。 * **恢复点目标(RPO)**:指自上一个数据恢复点以来可接受的最大时间量,决定了上一个恢复点和服务中断之间可接受的数据丢失量。 下图说明了这两个概念: ![RTO-RPO-explain](/RTO-RPO-explain.png) * **预写式日志(WAL)**:持久记录每个数据修改,以确保数据的完整性和一致性。 GreptimeDB 存储引擎是一个典型的 [LSM 树](https://en.wikipedia.org/wiki/Log-structured_merge-tree): ![LSM-tree-explain](/LSM-tree-explain.png) 写入的数据首先持久化到 WAL,然后应用到内存中的 Memtable。 在特定条件下(例如超过内存阈值时), Memtable 将被刷新并持久化为 SSTable。 因此,WAL 和 SSTable 的备份恢复是 GreptimeDB 灾难恢复的关键。 * **Region**:表的连续段,也可以被视为某些关系数据库中的分区。请阅读[表分片](/contributor-guide/frontend/table-sharding.md#region)以获取更多详细信息。 ## 组件架构 ### GreptimeDB 在深入了解具体的解决方案之前,让我们从灾难恢复的角度看一下 GreptimeDB 组件的架构: ![Component-architecture](/Component-architecture.png) GreptimeDB 基于存储计算分离的云原生架构设计: * **Frontend**:数据插入和查询的服务层,将请求转发到 Datanode 并处理和合并 Datanode 的响应。 * **Datanode**:GreptimeDB 的存储层,是一个 LSM 存储引擎。Region 是在 Datanode 中存储和调度数据的基本单元。Region 是一个表分区,是一组数据行的集合。Region 中的数据保存在对象存储中(例如 AWS S3)。未刷新的 Memtable 数据被写入 WAL,并可以在灾难发生时恢复。 * **WAL**:持久化内存中未刷新的 Memtable 数据。当 Memtable 被刷新到 SSTable 文件时,WAL 将被截断。它可以是基于本地磁盘的(本地 WAL)或基于 Kafka 集群的(远程 WAL)。 * **对象存储**:持久化 SSTable 数据和索引。 GreptimeDB 将数据存储在对象存储(如 [AWS S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/DataDurability.html))或兼容的服务中,这些服务在年度范围内提供了 99.999999999% 的持久性和 99.99% 的可用性。像 S3 这样的服务提供了[单区域或跨区域的复制](https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html),天然具备灾难恢复能力。 同时,WAL 组件是可插拔的,例如使用 Kafka 作为 WAL 服务以提供成熟的[灾难恢复解决方案](https://www.confluent.io/blog/disaster-recovery-multi-datacenter-apache-kafka-deployments/)。 ### 备份与恢复 ![BR-explain](/BR-explain.png) 备份与恢复(BR)工具可以在特定时间对数据库或表进行完整快照备份,并支持增量备份。 当集群遇到灾难时,你可以使用备份数据恢复集群。 一般来说,BR 是灾难恢复的最后手段。 ## 解决方案介绍 ### GreptimeDB Standalone 的 DR 方案 如果 GreptimeDB Standalone 在本地磁盘上运行 WAL 和数据,那么: * RPO:取决于备份频率。 * RTO:在 Standalone 没有意义,主要取决于要恢复的数据大小、故障响应时间和操作基础设施。 选择将 GreptimeDB Standalone 部署到具有备份和恢复解决方案的 IaaS 平台中是一个很好的开始,例如亚马逊 EC2(结合 EBS 卷)提供了全面的[备份和恢复解决方案](https://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/backup-recovery/backup-recovery-ec2-ebs.html)。 但是如果使用远程 WAL 和对象存储运行 Standalone,有一个更好的 DR 解决方案: ![DR-Standalone](/DR-Standalone.png) 将 WAL 写入 Kafka 集群,并将数据存储在对象存储中,因此数据库本身是无状态的。 在影响独立数据库的灾难事件发生时,你可以使用远程 WAL 和对象存储来恢复它。 此方案能实现 RPO=0 和分钟级 RTO。 ### 基于双活互备的 DR 解决方案 ![Active-active failover](/active-active-failover.png) 在某些边缘或中小型场景中,或者如果你没有资源部署远程 WAL 或对象存储,双活互备相对于 Standalone 的灾难恢复提供了更好的解决方案。 通过在两个独立节点之间同步复制请求,确保了高可用性。 即使使用基于本地磁盘的 WAL 和数据存储,任何单个节点的故障也不会导致数据丢失或服务可用性降低。 在不同区域部署节点也可以满足区域级灾难恢复要求,但可扩展性有限。 :::tip 注意 **双活互备功能仅在 GreptimeDB 企业版中提供。** ::: 有关此解决方案的更多信息,请参阅[基于双活 - 备份的 DR 解决方案](/enterprise/deployments-administration/disaster-recovery/dr-solution-based-on-active-active-failover.md)。 ### 基于单集群跨区域部署的 DR 解决方案 ![Cross-region-single-cluster](/Cross-region-single-cluster.png) 对于需要零 RPO 的中大型场景,强烈推荐此解决方案。 在此部署架构中,整个集群跨越三个 Region,每个 Region 都能处理读写请求。 两者都必须启用跨 Region DR 并使用远程 WAL 和对象存储实现数据复制。 如果 Region 1 因灾难而完全不可用,其中的表 Region 将在其他 Region 中打开和恢复。 Region 3 作为副本遵循 Metasrv 的多种协议。 此解决方案提供 Region 级别的容错、可扩展的写入能力、零 RPO 和分钟级或更低的 RTO。 有关此解决方案的更多信息,请参阅[基于单集群跨区域部署的 DR 解决方案](./dr-solution-based-on-cross-region-deployment-in-single-cluster.md)。 ### 基于备份恢复的 DR 解决方案 ![/BR-DR](/BR-DR.png) 在此架构中,GreptimeDB Cluster 1 部署在 Region 1。 BR 进程持续定期将数据从 Cluster 1 备份到 Region 2。 如果 Region 1 遭遇灾难导致 Cluster 1 无法恢复, 你可以使用备份数据恢复 Region 2 中的新集群(Cluster 2)以恢复服务。 基于 BR 的 DR 解决方案提供的 RPO 取决于备份频率,RTO 随要恢复的数据大小而变化。 阅读[备份与恢复数据](./back-up-&-restore-data.md)获取详细信息。 ### 解决方案比较 通过比较这些 DR 解决方案,你可以根据其特定场景、需求和成本选择最终的选项。 | DR 解决方案 | 容错目标 | RPO | RTO | TCO | 场景 | 远程 WAL 和对象存储 | 备注 | | ------------- | ------------------------- | ----- | ----- | ----- | ---------------- | --------- | --------| | 独立模式的 DR 解决方案 | 单区域 | 备份间隔 | 分钟或小时级 | 低 | 小型场景中对可用性和可靠性要求较低 | 可选 | | | 基于双活互备的 DR 解决方案 | 跨区域 | 可配置 | 分钟级 | 低 | 中小型场景中对可用性和可靠性要求较高 | 可选 | 商业功能 | | 基于单集群跨区域部署的 DR 解决方案 | 多区域 | 0 | 分钟级 | 高 | 中大型场景中对可用性和可靠性要求较高 | 必需 | | | 基于 BR 的 DR 解决方案 | 单区域 | 备份间隔 | 分钟或小时级 | 低 | 可接受的可用性和可靠性要求 | 可选 | | ## 参考资料 * [备份与恢复数据](./back-up-&-restore-data.md) * [基于双活 - 备份的 DR 解决方案](/enterprise/deployments-administration/disaster-recovery/dr-solution-based-on-active-active-failover.md) * [基于单集群跨区域部署的 DR 解决方案](./dr-solution-based-on-cross-region-deployment-in-single-cluster.md) * [S3 对象副本概述](https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html) --- ## 集群维护模式 集群维护模式是 GreptimeDB 中的一个安全特性,用于临时禁止集群的自动调度操作。 该模式在以下情况下特别有用: - 集群部署 - 集群升级 - 计划停机 - 任何可能暂时影响集群稳定性的操作 ## 何时使用维护模式 ### 使用 GreptimeDB Operator 如果你使用 GreptimeDB Operator 升级集群,你不需要手动启用维护模式。Operator 会自动处理。 ### 不使用 GreptimeDB Operator 当不使用 GreptimeDB Operator 升级集群时,**在以下情况下必须手动启用 Metasrv 的维护模式**: 1. 部署新集群(在 metasrv 节点就绪后启用维护模式) 2. Datanode 节点滚动升级 3. Metasrv 节点升级 4. Frontend 节点升级 5. 任何可能暂时影响节点可用性的操作 在集群部署/升级完成后,你可以停用维护模式。 ## 维护模式的影响 当维护模式启用时: - Region Balancer(如果启用)将暂停 - Region Failover(如果启用)将暂停 - 手动操作/迁移 Region 仍然可行 - 集群读、写服务正常工作 - 监控和指标收集继续运行 ## 管理维护模式 维护模式可以通过 Metasrv 的 HTTP 接口启用和禁用:`http://{METASRV}:{HTTP_PORT}/admin/maintenance/enable` 和 `http://{METASRV}:{HTTP_PORT}/admin/maintenance/disable`。请注意,此接口监听 Metasrv 的 `HTTP_PORT`,默认为 `4000`。 ### 启用维护模式 :::danger 调用运维模式接口后,请务必检查接口返回的 HTTP 状态码为 200,并确认响应内容符合预期。如果出现异常或接口行为不符合预期,请谨慎操作,并避免继续执行集群升级等高风险操作。 ::: 通过发送 POST 请求到 `/admin/maintenance/enable` 端点启用维护模式。 ```bash curl -X POST 'http://localhost:4000/admin/maintenance/enable' ``` 预期输出: ```bash {"enabled":true} ``` 如果遇到任何问题或意外行为,请不要继续进行维护操作。 ### 停用维护模式 :::danger 在关闭运维模式之前,必须确认**所有组件均已恢复至正常状态**。 ::: 通过发送 POST 请求到 `/admin/maintenance/disable` 端点停用维护模式。 在停用维护模式之前: 1. 确保所有组件健康且正常运行 2. 验证所有节点是否正确加入集群 ```bash curl -X POST 'http://localhost:4000/admin/maintenance/disable' ``` 预期输出: ```bash {"enabled":false} ``` ### 检查维护模式状态 通过发送 GET 请求到 `/admin/maintenance/status` 端点检查维护模式状态。 ```bash curl -X GET http://localhost:4000/admin/maintenance/status ``` 预期输出: ```bash {"enabled":false} ``` ## 故障排除 ### 常见问题 1. **无法启用维护模式** - 验证 Metasrv 是否正在运行且可访问 - 检查你是否具有正确的权限 - 确保 HTTP 端口正确 ### 最佳实践 1. 在操作前后始终验证维护模式状态 2. 准备好回滚计划 3. 监控集群健康状况 4. 记录所有维护期间进行的更改 --- ## 防止元数据变更 要防止元数据变更,你可以暂停 Procedure Manager。此机制拒绝所有新 procedure(即新的元数据变更操作),同时允许现有 procedure 继续运行。 一旦启用,Metasrv 将拒绝以下 procedure 操作(包括不限于): **DDL 操作:** - 创建表 - 删除表 - 修改表 - 创建数据库 - 删除数据库 - 创建视图 - 创建 Flow - 删除 Flow **Region 调度操作:** - Region Migration - Region Failover (如果启用) - Region Balancer (如果启用) 你在启用暂停元数据变更功能后尝试执行这些操作时,可能会看到错误消息。对于 Region 调度操作,你可以启用 [集群维护模式](/user-guide/deployments-administration/maintenance/maintenance-mode.md) 来临时暂时它们。 ## 管理 Procedure Manager Procedure Manager 可以通过 Metasrv 的 HTTP 接口暂停和恢复:`http://{METASRV}:{HTTP_PORT}/admin/procedure-manager/pause` 和 `http://{METASRV}:{HTTP_PORT}/admin/procedure-manager/resume`。请注意,此接口监听 Metasrv 的 `HTTP_PORT`,默认为 `4000`。 ### 暂停 Procedure Manager 通过向 `/admin/procedure-manager/pause` 端点发送 POST 请求来暂停 Procedure Manager。 ```bash curl -X POST 'http://localhost:4000/admin/procedure-manager/pause' ``` 预期输出: ```bash {"status":"paused"} ``` ### 恢复 Procedure Manager 通过向 `/admin/procedure-manager/resume` 端点发送 POST 请求来恢复 Procedure Manager。 ```bash curl -X POST 'http://localhost:4000/admin/procedure-manager/resume' ``` 预期输出: ```bash {"status":"running"} ``` ### 检查 Procedure Manager 状态 通过向 `/admin/procedure-manager/status` 端点发送 GET 请求来检查 Procedure Manager 状态。 ```bash curl -X GET 'http://localhost:4000/admin/procedure-manager/status' ``` 预期输出: ```bash {"status":"running"} ``` --- ## 集群恢复模式 恢复模式是 GreptimeDB 提供的一项安全机制,使开发者能够在集群出现故障时,手动将其恢复至正常状态。 ## 何时使用恢复模式 恢复模式在 Datanode 启动失败时特别有用,通常是由于 "Empty region directory" 错误,这可能是由于: - Datanode 数据损坏(缺少 Region 数据目录) - 从元数据快照恢复集群 ## 恢复模式管理 恢复模式可以通过 Metasrv 的 HTTP 接口启用和禁用:`http://{METASRV}:{HTTP_PORT}/admin/recovery/enable` 和 `http://{METASRV}:{HTTP_PORT}/admin/recovery/disable`。请注意,此接口监听 Metasrv 的 `HTTP_PORT`,默认为 `4000`。 ### 启用恢复模式 通过发送 POST 请求到 `/admin/recovery/enable` 端点启用恢复模式。 ```bash curl -X POST 'http://localhost:4000/admin/recovery/enable' ``` 预期输出: ```bash {"enabled":true} ``` ### 禁用恢复模式 通过发送 POST 请求到 `/admin/recovery/disable` 端点禁用恢复模式。 ```bash curl -X POST 'http://localhost:4000/admin/recovery/disable' ``` 预期输出: ```bash {"enabled":false} ``` ### 检查恢复模式状态 通过发送 GET 请求到 `/admin/recovery/status` 端点检查恢复模式状态。 ```bash curl -X GET 'http://localhost:4000/admin/recovery/status' ``` 预期输出: ```bash {"enabled":false} ``` --- ## 资源标识(ID)管理 资源标识(ID)管理主要用于在从[元数据备份](/user-guide/deployments-administration/manage-metadata/restore-backup.md)恢复集群时,手动设置资源标识(如表 ID)。这是因为备份文件可能未包含最新的`待分配表 ID`值,如果不及时重置,可能会导致资源冲突或数据不一致。 ### 理解表 ID 及 待分配表 ID 的关系 在 GreptimeDB 中: - **表 ID**:每个表都有一个唯一的数字标识符,用于数据库内部识别和管理表 - **待分配表 ID(Next Table ID)**:系统预留的下一个可用的表 ID 值。当创建新表时,系统会自动分配这个 ID 给新表,然后将`待分配表 ID`递增 **举例说明:** - 假设当前集群中已有表 ID 为 1001、1002、1003 的表 - 此时`待分配表 ID`应该是 1004 - 当创建新表时,系统分配 ID 1004 给新表,并将`待分配表 ID`更新为 1005 - 如果从备份恢复时,`待分配表 ID`仍然是 1002,就会与现有表 ID 1002、1003 产生冲突(通常你会在 Datanode 启动时遇到 `Region 1024 is corrupted, reason: ` 的错误) 通常情况下,资源标识(ID)由数据库自动维护,无需人工干预。但在某些特殊场景下(如从元数据备份恢复集群,且备份后集群又创建了新表),备份中的`待分配表 ID`可能已经落后于实际集群状态,此时需要手动调整。 **如何判断是否需要手动设置`待分配表 ID`:** 1. 查询当前集群中所有表的 ID:`SELECT TABLE_ID FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_ID DESC LIMIT 1;` 2. 通过 API 获取当前的`待分配表 ID`(见下方接口说明) 3. 如果现有表 ID 的最大值大于等于当前的`待分配表 ID`,则需要手动设置`待分配表 ID`为一个更大的值。通常为现有表 ID 的最大值加 1。 你可以通过 Metasrv 的 HTTP 接口获取或设置`待分配的表 ID`:`http://{METASRV}:{HTTP_PORT}/admin/sequence/table/next-id`(获取)和 `http://{METASRV}:{HTTP_PORT}/admin/sequence/table/set-next-id`(设置)。请注意,此接口监听 Metasrv 的 `HTTP_PORT`,默认为 `4000`。 ### 设置待分配的表 ID 要安全地更新`待分配的表 ID`,请按照以下步骤操作: 1. **启用集群恢复模式** - 这可以防止在更新过程中创建新表。详情请参阅[集群恢复模式](/user-guide/deployments-administration/maintenance/recovery-mode.md)。 2. **设置待分配的表 ID** - 通过 HTTP 接口设置`待分配的表 ID`。 3. **重启 metasrv 节点** - 这确保新的`待分配的表 ID`被正确设置。 4. **禁用集群恢复模式** - 恢复正常的集群操作。 通过发送 POST 请求到 `/admin/sequence/table/set-next-id` 端点设置`待分配的表 ID`: ```bash curl -X POST 'http://localhost:4000/admin/sequence/table/set-next-id' \ -H 'Content-Type: application/json' \ -d '{"next_table_id": 2048}' ``` 预期输出(`next_table_id` 可能不同): ```bash {"next_table_id":2048} ``` ### 获取待分配的表 ID ```bash curl -X GET 'http://localhost:4000/admin/sequence/table/next-id' ``` 预期输出(`next_table_id` 可能不同): ```bash {"next_table_id":1254} ``` --- ## 表元数据修复 ## 概述 在 GreptimeDB 分布式环境中,系统采用了分层的元数据管理架构: - **Metasrv**:作为元数据管理层,负责维护集群中所有表的元信息 - **Datanode**:负责实际的数据存储和查询执行,同时会持久化部分表元信息 在理想情况下,Metasrv 和 Datanode 的表元信息应该保持完全一致。但在实际生产环境中,从[元数据备份](/user-guide/deployments-administration/manage-metadata/restore-backup.md)恢复集群的操作可能会导致元数据不一致。 **Table Reconciliation** 是 GreptimeDB 提供的表元数据修复机制,用于: - 检测 Metasrv 与 Datanode 之间的元信息差异 - 根据预定义的策略修复不一致问题 - 确保系统能够从异常状态恢复到一致、可用的状态 ## 在开始之前 在开始表元数据修复之前,你需要: 1. 从[元数据备份](/user-guide/deployments-administration/manage-metadata/restore-backup.md)中恢复集群 2. 将[待分配表 ID](/user-guide/deployments-administration/maintenance/sequence-management.md) 设置为原集群的待分配表 ID ## 修复场景 ### `Table not found` 错误 当集群从特定元数据恢复后,写入和查询可能出现 `Table not found` 错误。 - **场景一**:原集群在备份元数据后新增了表,导致新增表的元数据没有包含在备份中,从而查询这些新增表时出现 `Table not found` 错误。这种情况下,新建表将丢失,同时你必须手动设置 [待分配表 ID](/user-guide/deployments-administration/maintenance/sequence-management.md),确保恢复后的集群在新创建表时不会因为表 ID 冲突导致创建失败。 - **场景二**:原集群在备份元数据后将原有表重命名,这种情况下新表名将丢失。 ### `Empty region directory` 错误 当集群从特定元数据恢复后,启动 Datanode 时出现 `Empty region directory` 错误。这通常是因为原集群在备份元数据后删除了表(即执行 `DROP TABLE`),导致删除表的元数据没有包含在备份中,从而启动 Datanode 时出现该错误。针对这种情况,你需要在启动集群时,在 Metasrv 启动后开启 [Recovery Mode](/user-guide/deployments-administration/maintenance/recovery-mode.md),确保 Datanode 可以正常启动。 - **Mito Engine 表**:表元信息不可修复,需要手动执行 `DROP TABLE` 命令删除不存在的表。 - **Metric Engine 表**:表元信息可以修复,需要手动执行 `ADMIN reconcile_table('table_name')` 命令修复表元信息。 ### `No field named` 错误 当集群从特定元数据恢复后,写入和查询可能出现 `No field named` 错误。这通常是因为原集群在备份元数据后删除了列(即执行 `DROP COLUMN`),导致删除列的元数据没有包含在备份中,从而查询这些已删除列时出现该错误。针对这种情况,你需要手动执行 `ADMIN reconcile_table('table_name')` 命令修复表元信息。 ### `schema has a different type` 错误 当集群从特定元数据恢复后,写入和查询可能出现 `schema has a different type` 错误。这通常是因为原集群在备份元数据后修改了列类型(即执行 `MODIFY COLUMN [column_name] [type]`),导致修改列类型的元数据没有包含在备份中,从而查询这些修改后的列时出现该错误。针对这种情况,你需要手动执行 `ADMIN reconcile_table('table_name')` 命令修复表元信息。 ### 缺少特定列 当集群从特定元数据恢复后,写入和查询可能正常运行,但是未包含一些列。这是因为原集群在备份元数据后新增了列(即执行 `ADD COLUMN`),导致新增列的元数据未包含在备份中,从而查询时无法列出这些列。针对这种情况,你需要手动执行 `ADMIN reconcile_table('table_name')` 命令修复表元信息。 ### 列缺少索引 当集群从特定元数据恢复后,写入和查询可能正常运行,但是 `SHOW CREATE TABLE`/`SHOW INDEX FROM [table_name]` 显示某些列未包含预期索引。这是因为原集群在备份元数据后修改了索引(即执行 `MODIFY INDEX [column_name] SET [index_type] INDEX`),导致索引变更后的元数据未包含在备份中。针对这种情况,你需要手动执行 `ADMIN reconcile_table('table_name')` 命令修复表元信息。 ## 修复操作 GreptimeDB 提供了以下 Admin 函数用于触发表元数据修复: ### 修复所有表 修复整个集群中所有表的元数据不一致问题: ```sql ADMIN reconcile_catalog() ``` ### 修复指定数据库 修复指定数据库中所有表的元数据不一致问题: ```sql ADMIN reconcile_database('database_name') ``` ### 修复指定表 修复单个表的元数据不一致问题: ```sql ADMIN reconcile_table('table_name') ``` ### 查看修复进度 上述 Admin 函数执行后会返回一个 `ProcedureID`,你可以通过以下命令查看修复任务的执行进度: ```sql ADMIN procedure_state('procedure_id') ``` 当 `procedure_state` 返回 Done 时,标识修复任务完成。 ## 注意事项 在执行表元数据修复操作时,请注意以下几点: - 修复操作是异步执行的,可以通过 `procedure_id` 查看执行进度 - 建议在业务低峰期执行修复操作,以减少对系统性能的影响 - 对于大规模的修复操作(如 `reconcile_catalog()`),建议先在测试环境验证 --- ## 表的基本操作 在阅读本文档之前请先阅读 [数据模型](/user-guide/concepts/data-model.md). GreptimeDB 通过 SQL 提供了表管理的功能,下面通过 [MySQL Command-Line Client](https://dev.mysql.com/doc/refman/8.0/en/mysql.html) 来演示它。 以下部分更详细的关于 SQL 语法的解释,请参考 [SQL reference](/reference/sql/overview.md)。 ## 创建数据库 默认的数据库是 `public`,可以手动创建一个数据库。 ```sql CREATE DATABASE test; ``` ```sql Query OK, 1 row affected (0.05 sec) ``` 创建一个具有 7 天 `TTL`(数据存活时间)的数据库,也就是该数据库中的所有表如果没有单独设置 TTL 选项,都将继承此选项值。 ```sql CREATE DATABASE test WITH (ttl='7d'); ``` 列出所有现有的数据库。 ```sql SHOW DATABASES; ``` ```sql +--------------------+ | Database | +--------------------+ | greptime_private | | information_schema | | public | | test | +--------------------+ 4 rows in set (0.00 sec) ``` 使用 `like` 语法: ```sql SHOW DATABASES LIKE 'p%'; ``` ```sql +----------+ | Database | +----------+ | public | +----------+ 1 row in set (0.00 sec) ``` 然后更改数据库: ```sql USE test; ``` ## 创建表 :::tip NOTE 注意:GreptimeDB 提供了一种 schemaless 方法来写入数据,不需要使用额外的协议手动创建表。参见 [自动生成表结构](/user-guide/ingest-data/overview.md#自动生成表结构)\*\*。 ::: 如果您有特殊需要,仍然可以通过 SQL 手动创建表。假设我们想要创建一个名为 `monitor` 的表,其数据模型如下: - `host` 是独立机器的主机名,是 `Tag` 列,用于在查询时过滤数据。 - `ts` 是收集数据的时间,是 `Timestamp` 列。它也可以在查询数据时用作时间范围的过滤器。 - `cpu` 和 `memory` 是机器的 CPU 利用率和内存利用率,是包含实际数据且未索引的 `Field` 列。 创建表的 SQL 代码如下。在 SQL 中,我们使用 PRIMARY KEY 来指定 `Tag`,使用 `TIME INDEX` 来指定 `Timestamp` 列,其余列是 `Field`。 ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host)); ``` ```sql Query OK, 0 row affected (0.03 sec) ``` 创建一个具有 7 天 `TTL`(数据存活时间)的表: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host) ) WITH (ttl='7d'); ``` :::warning NOTE GreptimeDB 目前不支持在创建表后更改 TIME INDEX 约束, 因此,在创建表之前,仔细选择适当的 TIME INDEX 列。 ::: ### `CREATE TABLE` 语法 - 时间戳列:GreptimeDB 是一个时序数据库系统,在创建表时,必须用 `TIME INDEX` 关键字明确指定时间序列的列。 时间序列的列的数据类型必须是 `TIMESTAMP`。 - 主键:`Primary key`指定的主键列类似于其他时序系统中的 Tag,比如 [InfluxDB][1]。主键和时间戳列用于唯一地定义一条时间线,这类似于其他时间序列系统中的时间线的概念,如 [InfluxDB][2]。 - 表选项:当创建一个表时,可以指定一组表选项,点击[这里](/reference/sql/create.md#table-options)了解更多细节。 ### 表名约束 GreptimeDB 支持在表名中使用有限的特殊字符,但必须遵守以下约束: - 有效的 GreptimeDB 表名必须以字母(小写或大写)或 `-` / `_` / `:` 开头。 - 表名的其余部分可以是字母数字或以下特殊字符:`-` / `_` / `:` / `@` / `#`。 - 任何包含特殊字符的表名都必须用反引号括起来。 - 任何包含大写字母的表名都必须用反引号括起来。 以下是有效和无效表名的例子: ```sql -- ✅ Ok create table a (ts timestamp time index); -- ✅ Ok create table a0 (ts timestamp time index); -- 🚫 Invalid table name create table 0a (ts timestamp time index); -- 🚫 Invalid table name create table -a (ts timestamp time index); -- ✅ Ok create table `-a` (ts timestamp time index); -- ✅ Ok create table `a@b` (ts timestamp time index); -- 🚫 Invalid table name create table memory_HugePages (ts timestamp time index); -- ✅ Ok create table `memory_HugePages` (ts timestamp time index); ``` [1]: https://docs.influxdata.com/influxdb/v1.8/concepts/glossary/#tag-key [2]: https://docs.influxdata.com/influxdb/v1/concepts/glossary/#series ## 描述表 显示表的详细信息: ```sql DESC TABLE monitor; ``` ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | | cpu | Float64 | | YES | 0 | FIELD | | memory | Float64 | | YES | | FIELD | +--------+----------------------+------+------+---------------------+---------------+ 4 rows in set (0.01 sec) ``` Semantic Type 列描述了表的数据模型。`host` 是 `Tag` 列,`ts` 是 `Timestamp` 列,`cpu` 和 `memory` 是 `Field` 列。 ## 显示表定义和索引 使用 `SHOW CREATE TABLE table_name` 来获取创建表时的语句: ```sql SHOW CREATE TABLE monitor; ``` ``` +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | monitor | CREATE TABLE IF NOT EXISTS `monitor` ( `host` STRING NULL, `ts` TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(), `cpu` DOUBLE NULL DEFAULT 0, `memory` DOUBLE NULL, TIME INDEX (`ts`), PRIMARY KEY (`host`) ) ENGINE=mito | +---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` 列出表中的所有索引: ```sql SHOW INDEXES FROM monitor; ``` ```sql +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+-------------------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+-------------------------+---------+---------------+---------+------------+ | monitor | 1 | PRIMARY | 1 | host | A | NULL | NULL | NULL | YES | greptime-primary-key-v1 | | | YES | NULL | | monitor | 1 | TIME INDEX | 1 | ts | A | NULL | NULL | NULL | NO | | | | YES | NULL | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+-------------------------+---------+---------------+---------+------------+ ``` 有关 `SHOW` 语句的更多信息,请阅读 [SHOW 参考](/reference/sql/show.md#show)。 ## 列出现有的表 可以使用 `show tables` 语句来列出现有的表 ```sql SHOW TABLES; ``` ```sql +----------------+ | Tables_in_test | +----------------+ | monitor | +----------------+ 1 row in set (0.00 sec) ``` 其目前只支持表名的过滤,可以通过表名字对其进行过滤。 ```sql SHOW TABLES LIKE monitor; ``` ```sql +----------------+ | Tables_in_test | +----------------+ | monitor | +----------------+ 1 row in set (0.00 sec) ``` 列出指定数据库中的表: ```sql SHOW TABLES FROM test; ``` ```sql +----------------+ | Tables_in_test | +----------------+ | monitor | +----------------+ 1 row in set (0.01 sec) ``` ## 改动表 可以像在 MySQL 数据库中一样,改变现有表的模式 ```sql ALTER TABLE monitor ADD COLUMN label VARCHAR; ``` ```sql Query OK, 0 rows affected (0.03 sec) ``` ```sql ALTER TABLE monitor DROP COLUMN label; ``` ```sql Query OK, 0 rows affected (0.03 sec) ``` `ALTER TABLE` 语句还支持添加、删除、重命名列以及修改列的数据类型等更改。有关更多信息,请参阅[ALTER 参考指南](/reference/sql/alter.md)。 ## 删除表 :::danger 危险操作 表删除后不可撤销!请谨慎操作! ::: `DROP TABLE [db.]table` 用于删除 `db` 或当前正在使用的数据库中的表。 删除当前数据库中的表 `monitor`: ```sql DROP TABLE monitor; ``` ```sql Query OK, 1 row affected (0.01 sec) ``` ## 删除数据库 :::danger 危险操作 数据库删除后不可撤销!请谨慎操作! ::: 可以使用 `DROP DATABASE` 删除数据库。 例如,切换回 `public` 数据库并删除 `test` 数据库: ```sql USE public; DROP DATABASE test; ``` 请前往 [DROP](/reference/sql/drop.md#drop-database) 文档了解更多内容。 ## HTTP API 使用以下代码,通过 POST 方法创建一个表: ```shell curl -X POST \ -H 'authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=CREATE TABLE monitor (host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), cpu FLOAT64 DEFAULT 0, memory FLOAT64, TIME INDEX (ts), PRIMARY KEY(host))' \ http://localhost:4000/v1/sql?db=public ``` ```json { "output": [{ "affectedrows": 0 }], "execution_time_ms": 10 } ``` 关于 SQL HTTP 请求的更多信息,请参考 [API 文档](/user-guide/protocols/http.md#post-sql-语句)。 ## 时区 SQL 客户端会话中指定的时区将影响创建或更改表时的默认时间戳值。 如果将时间戳列的默认值设置为不带时区的字符串,则该默认值会被自动添加客户端的时区信息。 有关客户端时区的影响,请参考 [写入数据](/user-guide/ingest-data/for-iot/sql.md#时区) 文档中的时区部分。 --- ## Compaction 对于基于 LSM 树的数据库,压缩是极其关键的。它将重叠的碎片化 SST 文件合并成一个有序的文件,丢弃已删除的数据,同时显著提高查询性能。 从 v0.9.1 版本开始,GreptimeDB 提供了控制 SST 文件如何压缩的策略:时间窗口压缩策略(TWCS)和严格窗口压缩策略(SWCS)。 ## 概念 让我们从 GreptimeDB 中压缩的核心概念开始介绍。 ### SST 文件 当内存表刷新到持久存储(如磁盘和对象存储)时,会生成排序的 SST 文件。 在 GreptimeDB 中,SST 文件中的数据行按[tag 列](/user-guide/concepts/data-model.md)和时间戳组织,如下所示。每个 SST 文件覆盖特定的时间范围。当查询指定一个时间范围时,GreptimeDB 只检索可能包含该范围内数据的相关 SST 文件,而不是加载所有已持久化的文件。 ![SST layout](/compaction-sst-file-layout.jpg) 通常,在实时写入工作负载中,SST 文件的时间范围不会重叠。然而,由于数据删除和乱序写入等因素,SST 文件可能会有重叠的时间范围,这会影响查询性能。 ### 时间窗口 时间序列工作负载呈现出显著的“窗口”特征,即最近插入的行更有可能被读取。因此,GreptimeDB 将时间轴逻辑上划分为不同的时间窗口,我们更关注压缩那些落在同一时间窗口内的 SST 文件。 特定表的时间窗口参数通常是从最新 flush 到存储的 SST 文件推断出来的,或者如果选择了 TWCS,您可以在建表时手动指定时间窗口。 GreptimeDB 预设了一组窗口大小,它们是: - 1 小时 - 2 小时 - 12 小时 - 1 天 - 1 周 如果未指定时间窗口大小,GreptimeDB 将使用 1 小时作为初始时间窗口并在第一次压缩时通过文件的时间分布推断窗口,通过从上述集合中选择**能够覆盖所有要压缩文件的整个时间跨度的**,**最小的**时间窗口作为时间窗口大小。 例如,在第一次压缩期间,所有输入 SST 文件的时间跨度为 4 小时,那么 GreptimeDB 将选择 12 小时作为该表的时间窗口,并将此参数持久化以便后续的压缩中使用。 ### 有序组 有序组(sorted runs)是一个包含已排序且时间范围不重叠的 SST 文件的集合。 例如,一个表包含 5 个 SST,时间范围如下(全部包括在内):`[0, 10]`, `[12, 23]`, `[22, 25]`,`[24, 30]`,`[26,33]`,我们可以找到 2 个有序组: ![num-of-sorted-runs](/compaction-num-sorted-runs.jpg) 有序组的数量往往能够反映 SST 文件的有序性。更多的有序组通常会导致查询性能变差,因为特定时间范围的查询往往会命中多个重叠的文件。压缩的主要目标是减少有序组的数量。 ### 层级 基于 LSM 树的数据库常常有多个层级,数据的键(key)会逐层进行合并。GreptimeDB 只有两个层级,分别是 0(未压缩)和 1(已压缩)。 ## 压缩策略 GreptimeDB 提供了上述两种压缩策略,但在创建表时只能选择时间窗口压缩策略(TWCS)。严格窗口(SWCS)仅在执行手动压缩时可用。 ## 时间窗口压缩策略(TWCS) TWCS 主要旨在减少压缩过程中的读 / 写放大。 TWCS 将要压缩的文件分配到不同的时间窗口。对于每个窗口,TWCS 会识别有序组。如当前出现了多于一个有序组,TWCS 会基于合并开销来计算一个文件合并策略,从而将有序组的数量减少到 1。如果有序组的数量没有超过 1(也就是任意两个文件的时间范围都不重叠),TWCS 会检查是否存在过多的文件碎片,并在必要时合并这些碎片文件,因为 SST 文件数量也会影响查询性能。 对于窗口分配,SST 文件可能跨越多个时间窗口。为了确保不受陈旧数据影响,TWCS 根据 SST 的最大时间戳来进行分配。在时间序列工作负载中,无序写入很少发生,即使发生了,最近数据的查询性能也比陈旧数据更为重要。 常用的 TWCS 表级参数包括: - `trigger_file_num`: 单一时间窗口中触发 compaction 的文件数量(默认为 4) - `time_window`: TWCS compaction 的时间窗口大小 - `max_output_file_size`: compaction 产生文件的最大大小(默认 512MB) 以下图表显示了当 `trigger_file_num`为 3 时,窗口中的文件如何被压缩: - 在 A 中,有两个 SST 文件 `[0, 3]` 和 `[5, 6, 9]`,但只有一个有序组,因为这两个文件的时间范围不重叠。 - 在 B 中,一个新的 SST 文件 `[1, 4]` 被写入,因此形成了两个有序组。然后将 `[0, 3]` 和 `[1, 4]` 合并为 `[0, 1, 3, 4]`。 - 在 C 中,一个新的 SST 文件 `[9, 10]` 被写入,它将与 `[5, 6, 10]` 合并以创建 `[5, 6, 9, 10]`,经过压缩后文件将变成 D 中的样子。 - 在 E 中,一个新文件 `[11, 12]` 被写入。尽管仍然只有一个有序组,但文件数量达到了 `trigger_file_num`(3),因此将会把 `[5, 6, 9,10]` 与 `[11,12]` 合并形成 `[5,6,9,10,11,12 ]`. ![compaction-trigger-file-num.png](/compaction-trigger-file-num.png) ### 指定 TWCS 参数 TWCS 参数可以在两个级别指定: 1. **表级别**:在创建或修改表时明确设置 2. **数据库级别**:为数据库中的所有表设置默认值 有效的压缩设置在压缩调度时动态解析,优先级如下: - 表级别设置(如果指定) - 数据库级别设置(如果指定且没有表级别覆盖) - 内置默认值 #### 表级别压缩设置 用户可以在创建表时指定 TWCS 参数: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host)) WITH ( 'compaction.type'='twcs', 'compaction.twcs.trigger_file_num'='8', 'compaction.twcs.time_window'='1h', 'compaction.twcs.max_output_file_size'='500MB' ); ``` #### 数据库级别压缩设置 您也可以为数据库中的所有表设置默认压缩参数。这些设置将被没有明确设置压缩选项的表继承。参见 [ALTER DATABASE](/reference/sql/alter.md#修改数据库的压缩选项) 获取示例。 :::note 与存储在表元数据中的表级别设置不同,数据库级别的压缩设置在运行时动态解析。更改数据库级别的压缩选项会立即影响数据库中所有没有明确设置压缩选项的表。此行为类似于[数据库级别的 TTL](/reference/sql/create.md#create-database) 的工作方式。 ::: ## 严格窗口压缩策略(SWCS)和手动压缩 与 TWCS 根据 SST 文件的最大时间戳为每个窗口分配一个 SST 文件不同的是,严格窗口策略(SWCS)将 SST 文件分配给**所有与此文件的时间范围重叠**的窗口,正如其名称所示。因此,一个 SST 文件可能会包含在多个压缩输出中。由于其在压缩期间的高读取放大率,SWCS 并不是默认的压缩策略。然而,当用户需要手动触发压缩以重新组织 SST 文件布局时,它是有用的,特别是当单个 SST 文件跨越较大的时间范围而显著减慢查询速度时。GreptimeDB 提供了一个简单的 SQL 函数来触发手动压缩: ```sql ADMIN COMPACT_TABLE( , , [] ); ``` `` 参数可以是 `regular`(或 `twcs`)来指定常规 TWCS compaction,也可以是 `swcs`(或 `strict_window`)来指定严格窗口压缩策略。该值大小写不敏感。 对于 `swcs` 策略, `` 可以指定: - 用于拆分 SST 文件的窗口大小(以秒为单位) - `parallelism` 参数用于控制压缩的并行度(默认为 1) 例如,触发使用 1 小时窗口的压缩: ```sql ADMIN COMPACT_TABLE( "monitor", "swcs", "3600" ); +------------------------------------------------+ | ADMIN COMPACT_TABLE("monitor", "swcs", "3600") | +------------------------------------------------+ | 0 | +------------------------------------------------+ 1 row in set (0.01 sec) ``` 执行此语句时,GreptimeDB 会将每个 SST 文件按 1 小时(3600 秒)的时间跨度拆分成多个分块,并将这些分块合并为一个输出文件,确保没有重叠的文件。 你还可以指定 `parallelism` 参数来通过并发处理多个文件以加速压缩: ```sql -- 使用默认时间窗口和并行度为 2 的 SWCS 压缩 ADMIN COMPACT_TABLE("monitor", "swcs", "parallelism=2"); -- 使用自定义时间窗口和并行度的 SWCS 压缩 ADMIN COMPACT_TABLE("monitor", "swcs", "window=1800,parallelism=2"); ``` `parallelism` 参数同样适用于常规压缩: ```sql -- 并行度为 2 的常规压缩 ADMIN COMPACT_TABLE("monitor", "regular", "parallelism=2"); ``` 下图展示了一次 SWCS 压缩的过程: 在图 A 中,有 3 个重叠的 SST 文件,分别是 `[0, 3]`(也就是包含 0、1、2、3 的时间戳)、`[3, 8]` 和 `[8, 10]`。 严格窗口压缩策略会将覆盖了窗口 0、4、8 的文件 `[3, 8]` 分别分配给 3 个窗口,从而分别和 `[0, 3]` 以及 `[8, 10]` 合并。 图 B 给出了最终的压缩结果,分别有 3 个文件: `[0, 3]`、`[4, 7]` 和 `[8, 10]`,它们彼此互相不重叠。 ![compaction-strict-window.jpg](/compaction-strict-window.jpg) --- ## 垃圾回收(GC) GreptimeDB GC 会延迟删除 SST/索引文件,直到所有引用(运行中的查询、[repartition](./repartition.md) 的跨 region 文件引用)释放。配置包含两部分: - Metasrv 配置 - Datanode 配置 ## 工作原理 - **角色**:Meta 决定何时/何处清理;Datanode 负责实际删除,同时保护正在使用的文件。 - **安全窗口**:`lingering_time` 会额外保留已移除文件;`unknown_file_lingering_time` 用于极少见的保护场景。 - **列举模式**:快速模式删除系统已标记的文件;全量列举遍历对象存储以发现滞留/孤儿文件。 ![GC 工作流程图](/gc-flow.zh.svg) ## Metasrv 配置 在 Metasrv 侧,GC 负责为各个 region 安排清理任务,并协调 GC 的运行时机。 ```toml [gc] enable = true # 开启 meta GC 调度器,默认值为 false;必须与 datanode 一致。 gc_cooldown_period = "5m" # 同一 region 再次 GC 的最小间隔。 ``` ### 配置 | 配置项 | 说明 | | --- | --- | | `enable` | 启用 meta GC 调度器,必须与 datanode 的 GC 开关一致。 | | `gc_cooldown_period` | 同一 region 再次被调度 GC 的最小间隔;请保证 datanode 的 `lingering_time` 大于该值。 | ## Datanode 配置 Datanode 负责实际删除,同时保护仍在使用中的文件。 ```toml [[region_engine]] [region_engine.mito] [region_engine.mito.gc] enable = true # 开启 datanode GC worker;必须与 meta 一致。 lingering_time = "10m" # 已移除文件在活跃查询期间保留时长。 unknown_file_lingering_time = "1h" # 未记录 expel time 的文件保留时长;罕见保护。 ``` ### 配置 | 配置项 | 说明 | | --- | --- | | `enable` | 启用 datanode GC worker,必须与 meta GC 的 `enable` 一致。 | | `lingering_time` | manifest 中已移除文件在删除前的保留时长,用于保护长时间 follower-region 查询/跨 region 引用;请设置为大于 `gc_cooldown_period`。设为 `"0s"` 表示立即删除。 | | `unknown_file_lingering_time` | 对缺少 expel time 的文件的安全保留时间(未在 manifest 中追踪)。建议设置为较长值;此类情况较少。 | :::warning `gc.enable` 必须在 metasrv 与所有 datanode 上保持一致。开关不一致会导致 GC 被跳过或卡住。 ::: ## 何时启用 - GC 仅在表使用对象存储时生效;本地文件系统上的表会忽略 GC 设置。 - 如果需要重分区,请开启 GC,以便跨 region 引用在删除前安全释放。 - 对于有长时间 follower-region 查询的集群,开启 GC 并将 `lingering_time` 设为大于 `gc_cooldown_period`,确保 GC 周期内创建或引用的文件保持存活(在用或 lingering)直到至少下个周期。 - 如果不进行重分区且不需要延迟删除,可保持 GC 关闭。 ## 运维注意事项 - GC 面向对象存储后端(需支持 list/delete);确保存储凭据与权限允许列举和删除。 - 删除的文件会在对象存储中保留直到 GC 清理;确保具备列举/删除权限。 - 启用后重启 Metasrv 与 Datanode 以使配置生效。 --- ## 管理数据 * [存储位置说明](/user-guide/concepts/storage-location.md) * [表的基本操作](basic-table-operations.md): 如何创建、修改和删除表 * [更新或删除数据](/user-guide/manage-data/overview.md) * [通过设置 TTL 过期数据](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据) * [表分片](table-sharding.md): 按 Region 对表进行分区 * [重分区](repartition.md): 调整已创建表的分区边界 * [Region Migration](region-migration.md): 为负载均衡迁移 Region * [Region Failover](/user-guide/deployments-administration/manage-data/region-failover.md) * [Compaction](compaction.md) --- ## Region Failover Region Failover 提供了从 Region 故障中恢复的能力。使用 Kafka WAL (Remote WAL) 和共享存储时,Region Failover 可以在不丢失数据的情况下恢复 Region。这是通过 [Region 迁移](/user-guide/deployments-administration/manage-data/region-migration.md) 实现的。 ## 开启 Region Failover 该功能仅在 GreptimeDB 集群模式下可用,并且需要满足以下条件 - 使用 Kafka WAL (Remote WAL),或者使用 Local WAL 并设置 `allow_region_failover_on_local_wal=true`(在 Local WAL 上启用 Region Failover,Failover 过程中可能会导致数据丢失) - 使用[共享存储](/user-guide/deployments-administration/configuration.md#storage-options) (例如:AWS S3) 如果想要在本地 WAL 上启用 Region Failover,需要设置 `allow_region_failover_on_local_wal=true` 在 [metasrv](/user-guide/deployments-administration/configuration.md#metasrv-only-configuration) 配置文件中。不建议启用此选项,因为它可能会导致数据丢失。 ### 通过配置文件 在 [metasrv](/user-guide/deployments-administration/configuration.md#metasrv-only-configuration) 配置文件中设置 `enable_region_failover=true`. 另外,你还需要将 `region_failure_detector_initialization_delay` 设置为较大的值,并在 `region_failure_detector_initialization_delay` 期间内,启动[集群维护模式](/user-guide/deployments-administration/maintenance/maintenance-mode.md),以避免在 Datanode 启动或升级期间触发不必要的 Region Failover。 ### 通过 GreptimeDB Operator 要通过 GreptimeDB Operator 启用 Region Failover,可以参考 [常见 Helm Chart 配置项](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#enable-region-failover) 了解更多详细信息。 ## Region Failover 的恢复用时 使用 Kafka WAL (Remote WAL) 时,Region Failover 的恢复时间取决于: - 每个 Topic 的 region 数量 - Kafka 集群的读取吞吐性能 ### 读放大 在最佳实践中,[Kafka 集群所支持的 topics/partitions 数量是有限的](https://docs.aws.amazon.com/msk/latest/developerguide/bestpractices.html)(超过这个数量可能会导致 Kafka 集群性能下降)。 因此,GreptimeDB 允许多个 regions 共享一个 topic 作为 WAL,然而这可能会带来读放大的问题。 属于特定 Region 的数据由数据文件和 WAL 中的数据(通常为 WAL[LastCheckpoint...Latest])组成。特定 Region 的 failover 只需要读取该 Region 的 WAL 数据以重建内存状态,这被称为 Region 重放(region replaying)。然而,如果多个 Region 共享一个 Topic,则从 Topic 重放特定 Region 的数据需要过滤掉不相关的数据(即其他 Region 的数据)。这意味着从 Topic 重放特定 Region 的数据需要读取比该 Region 实际 WAL 数据大小更多的数据,这种现象被称为读取放大(read amplification)。 尽管多个 Region 共享同一个 Topic,可以让 Datanode 支持更多的 Region,但这种方法的代价是在 Region 重放过程中产生读取放大。 例如,为 [metasrv](/user-guide/deployments-administration/configuration.md#metasrv-only-configuration) 配置 128 个 Topic,如果整个集群包含 1024 个 Region(物理 Region),那么每 8 个 Region 将共享一个 Topic。 ![Read Amplification](/remote-wal-read-amplification.png) (图 1:恢复 Region 3 需要读取比实际大小大 7 倍的冗余数据) 估算冗余读取放大倍数(冗余重放数据大小/实际数据大小)的简单模型: - 对于单个 Topic,如果我们尝试重放属于该 Topic 的所有 Region,那么放大倍数将是 7+6+...+1 = 28 倍。(图 1 显示了 Region WAL 数据分布。重放 Region 3 将读取约为实际大小 7 倍的数据;重放 Region 6 将读取约为实际大小 6 倍的数据,以此类推) - 在恢复 100 个 Region 时(需要大约 13 个 Topic),放大倍数大约为 28 \* 13 = 364 倍。 假设要恢复 100 个 Region,所有 Region 的实际数据大小是 0.5 GB,下表根据每个 Topic 的 Region 数量展示了数据重放的总量。 | 每个 Topic 的 Region 数量 | 100 个 Region 所需 Topic 数量 | 单个 Topic 冗余读取系数 | 总冗余读取系数 | 重放数据大小(GB) | | ------------------------- | ----------------------------- | --------------------- | ------------ | ------------------ | | 1 | 100 | 0 | 0 | 0.5 | | 2 | 50 | 1 | 50 | 25.5 | | 4 | 25 | 6 | 150 | 75.5 | | 8 | 13 | 28 | 364 | 182.5 | | 16 | 7 | 120 | 840 | 420.5 | 下表展示了在 Kafka 集群在不同读取吞吐量情况下,100 个 region 的恢复时间。例如在提供 300MB/s 的读取吞吐量的情况下,恢复 100 个 Region 大约需要 10 分钟(182.5GB/0.3GB = 10 分钟)。 | 每个主题的区域数 | 重放数据大小(GB) | Kafka 吞吐量 300MB/s- 恢复时间(秒) | Kafka 吞吐量 1000MB/s- 恢复时间(秒) | | ---------------- | ------------------ | ------------------------------------ | ------------------------------------- | | 1 | 0.5 | 2 | 1 | | 2 | 25.5 | 85 | 26 | | 4 | 75.5 | 252 | 76 | | 8 | 182.5 | 608 | 183 | | 16 | 420.5 | 1402 | 421 | ### 改进恢复时间的建议 在上文中我们根据不同的每个 Topic 包含的 Region 数量计算了恢复时间以供参考。 在实际场景中,读取放大的现象可能会比这个模型更为严重。 如果使用 Kafka WAL 且对恢复时间非常敏感,我们建议每个 Region 都有自己的 Topic(即,每个 Topic 包含的 Region 数量为 1)。 --- ## Region Migration Region 迁移允许用户在 Datanode 间移动 Region 数据。 :::warning 注意 该功能仅在 GreptimeDB 集群模式下可用,并且需要满足以下条件 - 使用共享存储 (例如:AWS S3) 无法在任何上述以外的情况下使用 Region 迁移。 ::: ## 查询 Region 分布 首先需要查询该数据表分区(Region)分布情况,即查询数据表中的 Region 分别在哪一些 Datanode 节点上。 ```sql select b.peer_id as datanode_id, a.greptime_partition_id as region_id from information_schema.partitions a left join information_schema.region_peers b on a.greptime_partition_id = b.region_id where a.table_name='migration_target' order by datanode_id asc; ``` 例如:有以下的 Region 分布 ```sql +-------------+---------------+ | datanode_id | region_id | +-------------+---------------+ | 1 | 4398046511104 | +-------------+---------------+ 1 row in set (0.01 sec) ``` 更多关于 `region_peers` 表的信息,请阅读 [REGION-PEERS](/reference/sql/information-schema/region-peers.md)。 ## 选择 Region 迁移的目标节点 :::warning Warning 当起始节点等于目标节点时,Region 迁移不会被执行 ::: 如果你通过 GreptimeDB operator 部署 DB 集群,Datanode 的 `peer_id` 总是从 0 开始递增。例如,DB 集群有 3 个 Datanode,则 `peer_id` 应为 0,1,2。 最后,你可以通过以下 SQL 请求发起 Region 迁移请求: ```sql ADMIN migrate_region(4398046511104, 1, 2, 60); ``` `migrate_region` 参数说明: ```sql ADMIN migrate_region(region_id, from_peer_id, to_peer_id); ADMIN migrate_region(region_id, from_peer_id, to_peer_id, replay_timeout); ``` | Option | Description | Required | | | ---------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------ | --- | | `region_id` | Region Id | **Required** | | | `from_peer_id` | 迁移起始节点 (Datanode) 的 peer id。 | **Required** | | | `to_peer_id` | 迁移目标节点 (Datanode) 的 peer id。 | **Required** | | | `replay_timeout` | 迁移时回放数据的超时时间(单位:秒)。省略时默认 300 秒。如果新 Region 未能在指定时间内回放数据,迁移将失败,旧 Region 中的数据不会丢失。 | Optional | | ## 查询迁移状态 `migrate_region` 函数将返回执行迁移的 Procedure Id,可以通过它查询过程状态: ```sql ADMIN procedure_state('538b7476-9f79-4e50-aa9c-b1de90710839') ``` 如果顺利完成,将输出 JSON 格式的状态: ```json {"status":"Done"} ``` 当然,最终可以通过从 `information_schema` 中查询 `region_peers` 和 `partitions` 来确认 Region 分布是否符合预期。 --- ## 重分区 重分区可以在表创建后调整分区规则。GreptimeDB 通过 `ALTER TABLE` 的分区拆分与合并能力来完成重分区,详细语法请参考 [ALTER TABLE](/reference/sql/alter.md#分区拆分与合并)。 重分区仅支持分布式集群。 ## 原理 重分区的核心是在线调整分区规则和 Region 路由,而不是把数据手工迁移到新的表。 GreptimeDB 会通过更新每个 Region 的 manifest 文件引用切换到新的分区布局,从而让分区规则重新贴合当前的数据分布。 当业务流量模式发生变化时,这种方式可以帮助你继续保持分区规则与负载匹配,而不需要重建整张表。 重分区期间,写入可能会出现短暂波动,建议客户端开启重试机制。 ## 什么时候需要重分区 如果出现下面这些情况,就可以考虑重分区: - 某些 Region 的写入或查询明显更热,负载长期不均衡; - 业务分布发生变化,原有分区边界已经不再合适; - 部分 Region 变得很小且很冷,希望通过合并减少资源占用; - 需要把某个分区进一步细分,以改善写入并发或查询性能。 通常来说,当分区规则已经不能很好地反映当前数据分布时,就值得考虑重分区。 ## 如何发现热点分区 在做重分区之前,建议先确认哪些 Region 已经出现热点。 你可以先把 Region 级别的统计信息和分区规则关联起来,找出最热的规则: ```sql SELECT t.table_name, r.region_id, r.region_number, p.partition_name, p.partition_description, r.region_role, r.written_bytes_since_open, r.region_rows FROM information_schema.region_statistics r JOIN information_schema.tables t ON r.table_id = t.table_id JOIN information_schema.partitions p ON p.table_schema = t.table_schema AND p.table_name = t.table_name AND p.greptime_partition_id = r.region_id WHERE t.table_schema = 'public' AND t.table_name = 'your_table' ORDER BY r.written_bytes_since_open DESC LIMIT 10; ``` 如果某些 Region 的 `written_bytes_since_open` 长期明显更高,通常就说明这条分区规则比较热,适合优先考虑拆分。 同时也建议检查 Region 对应的节点是否正常,避免把节点抖动误判为热点: ```sql SELECT p.region_id, p.peer_addr, p.status, p.down_seconds FROM information_schema.region_peers p WHERE p.table_schema = 'public' AND p.table_name = 'your_table' ORDER BY p.region_id, p.peer_addr; ``` 如果节点状态正常,而热点信号持续存在,就可以继续设计重分区方案。 ## 前置条件 :::warning 警告 该功能仅在 GreptimeDB 的分布式集群中可用,并且 - 使用[共享对象存储](/user-guide/deployments-administration/configuration.md#storage-options)(例如 AWS S3) - 在 metasrv 和所有 datanode 上启用 [GC](/user-guide/deployments-administration/manage-data/gc.md) 否则你无法执行重分区。 ::: 当前开源版支持通过多次 `SPLIT PARTITION` / `MERGE PARTITION` 组合完成分区调整,最常见的场景是 1 拆 2 或 2 合 1。对于更复杂的分区变更,也可以通过逐步拆分和合并来完成。 对象存储用于保存 region 文件,GC 则负责在引用释放后再回收旧文件,避免重分区过程中误删仍在使用的数据。 如需了解详细配置,请参考: - [GC](/user-guide/deployments-administration/manage-data/gc.md) - [对象存储配置](/user-guide/deployments-administration/configuration.md#storage-options) ### 通过 GreptimeDB Operator 如果你使用 GreptimeDB Operator 部署,可以参考 [常见 Helm Chart 配置项](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) 快速完成 GC 和对象存储配置。 ## 重分区示例 你可以通过先合并现有分区,然后用新规则拆分它们来修改分区规则。下面的示例展示了如何将 `device_id < 100` 的设备的分区键 `area` 从 `South` 更改为 `North`: ```sql ALTER TABLE sensor_readings MERGE PARTITION ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ); ALTER TABLE sensor_readings SPLIT PARTITION ( device_id < 100 ) INTO ( device_id < 100 AND area < 'North', device_id < 100 AND area >= 'North' ); ``` ## 延伸阅读 如果你希望查看包含更多背景说明和完整示例的教程,请参考博客文章:[如何在 GreptimeDB 中在线拆分与合并分区](https://greptime.cn/blogs/2026-03-19-greptimedb-repartition-guide)。 :::caution 注意 重分区仅支持在分布式集群中执行。请确认 GC 与对象存储已正确配置后,再运行相关操作。 ::: --- ## 表分片 表分片是一种将大表分成多个小表的技术。 这种做法通常用于提高数据库系统的性能。 在 GreptimeDB 中,数据从逻辑上被分片成多个分区。 由于 GreptimeDB 使用“表”来分组数据并使用 SQL 来查询数据, 因此采用了 OLTP 数据库中常用的术语“分区”。 ## 表分片的时机 在 GreptimeDB 中,数据管理和调度都是基于 region 级别的, 每个 region 对应一个表分区。 因此,当你的表太大而无法放入单个节点, 或者表太热而无法由单个节点提供服务时, 应该考虑进行分片。 GreptimeDB 中的一个 region 具有相对固定的吞吐量, 表中的 region 数量决定了表的总吞吐量容量。 如果你想增加表的吞吐量容量, 可以增加表中的 region 数量。 理想情况下,表的整体吞吐量应与 region 的数量成正比。 至于使用哪个特定的分区列或创建多少个 region, 这取决于数据分布和查询模式。 一个常见的目标是使数据在 region 之间的分布尽可能均匀。 在设计分区规则集时应考虑查询模式, 因为一个查询可以在 region 之间并行处理。 换句话说,查询延迟取决于“最慢”的 region 延迟。 请注意,region 数量的增加会带来一些基本的消耗并增加系统的复杂性。 你需要考虑数据写入速率的要求、查询性能、存储系统上的数据分布。 只有在必要时才应进行表分片。 有关分区和 region 之间关系的更多信息,请参阅贡献者指南中的[表分片](/contributor-guide/frontend/table-sharding.md)部分。 ## 分区 在 GreptimeDB 中,表可以按列值范围进行水平分区。 目前,GreptimeDB 支持使用 `PARTITION ON COLUMNS` 语法进行范围分区。 每个分区仅包含表中的一部分数据, 并按某些列的值范围进行分组。 例如,我们可以在 GreptimeDB 中这样分区一个表: ```sql CREATE TABLE (...) PARTITION ON COLUMNS () ( ); ``` 该语法主要由两部分组成: 1. `PARTITION ON COLUMNS` 后跟一个用逗号分隔的列名列表,指定了将用于分区的列。这里指定的列必须是 Tag 类型(由 PRIMARY KEY 指定)。请注意,所有分区的范围必须**不能**重叠。 2. `RULE LIST` 是多个分区规则的列表。每个规则是一个分区条件,GreptimeDB 会为这些规则生成 `p0`、`p1` 等分区名称。这里的表达式可以使用 `=`, `!=`, `>`, `>=`, `<`, `<=`, `AND`, `OR`, 列名和字面量。 :::tip 提示 `PARTITION ON COLUMNS` 括号里只能写列名(如 `device_id`、`area`),不支持表达式。GreptimeDB 不支持 MySQL 的 `PARTITION BY RANGE` 语法。 ::: ### 示例 ## 创建分布式表 你可以使用 MySQL CLI [连接到 GreptimeDB](/user-guide/protocols/mysql.md) 并创建一个分布式表。 下方的示例创建了一个表并基于 `device_id` 列进行分区。 ```SQL CREATE TABLE sensor_readings ( device_id INT16, reading_value FLOAT64, ts TIMESTAMP DEFAULT current_timestamp(), PRIMARY KEY (device_id), TIME INDEX (ts) ) PARTITION ON COLUMNS (device_id) ( device_id < 100, device_id >= 100 AND device_id < 200, device_id >= 200 ); ``` 你可以使用更多的分区列来创建更复杂的分区规则: ```sql CREATE TABLE sensor_readings ( device_id INT, area STRING, reading_value FLOAT64, ts TIMESTAMP DEFAULT current_timestamp(), PRIMARY KEY (device_id, area), TIME INDEX (ts) ) PARTITION ON COLUMNS (device_id, area) ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South', device_id >= 100 AND area <= 'East', device_id >= 100 AND area > 'East' ); ``` 以下内容以具有两个分区列的 `sensor_readings` 表为例。 ## 重分区 如果你需要修改已创建表的分区规则,请参考单独的 [重分区](/user-guide/deployments-administration/manage-data/repartition.md) 页面。 ## 向表中插入数据 以下代码向 `sensor_readings` 表的每个分区插入 3 行数据。 ```sql INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (1, 'North', 22.5, '2023-09-19 08:30:00'), (10, 'North', 21.8, '2023-09-19 09:45:00'), (50, 'North', 23.4, '2023-09-19 10:00:00'); INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (20, 'South', 20.1, '2023-09-19 11:15:00'), (40, 'South', 19.7, '2023-09-19 12:30:00'), (90, 'South', 18.9, '2023-09-19 13:45:00'); INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (110, 'East', 25.3, '2023-09-19 14:00:00'), (120, 'East', 26.5, '2023-09-19 15:30:00'), (130, 'East', 27.8, '2023-09-19 16:45:00'); INSERT INTO sensor_readings (device_id, area, reading_value, ts) VALUES (150, 'West', 24.1, '2023-09-19 17:00:00'), (170, 'West', 22.9, '2023-09-19 18:15:00'), (180, 'West', 23.7, '2023-09-19 19:30:00'); ``` :::tip NOTE 注意,当写入数据不满足分区规则中的任何规则时,数据将被分配到默认分区(即表的第一个分区 0)。 ::: ## 分布式查询 只需使用 `SELECT` 语法查询数据: ```sql SELECT * FROM sensor_readings order by reading_value desc LIMIT 5; ``` ```sql +-----------+------+---------------+---------------------+ | device_id | area | reading_value | ts | +-----------+------+---------------+---------------------+ | 130 | East | 27.8 | 2023-09-19 16:45:00 | | 120 | East | 26.5 | 2023-09-19 15:30:00 | | 110 | East | 25.3 | 2023-09-19 14:00:00 | | 150 | West | 24.1 | 2023-09-19 17:00:00 | | 180 | West | 23.7 | 2023-09-19 19:30:00 | +-----------+------+---------------+---------------------+ 5 rows in set (0.02 sec) ``` ```sql SELECT MAX(reading_value) AS max_reading FROM sensor_readings; ``` ```sql +-------------+ | max_reading | +-------------+ | 27.8 | +-------------+ 1 row in set (0.03 sec) ``` ```sql SELECT * FROM sensor_readings WHERE area = 'North' AND device_id < 50 ORDER BY device_id; ``` ```sql +-----------+-------+---------------+---------------------+ | device_id | area | reading_value | ts | +-----------+-------+---------------+---------------------+ | 1 | North | 22.5 | 2023-09-19 08:30:00 | | 10 | North | 21.8 | 2023-09-19 09:45:00 | +-----------+-------+---------------+---------------------+ 2 rows in set (0.03 sec) ``` ## 检查分片表 GreptimeDB 提供了几个系统表来检查数据库的状态。 对于表分片信息,你可以查询 [`information_schema.partitions`](/reference/sql/information-schema/partitions.md), 它提供了一个表内分区的详细信息, 以及 [`information_schema.region_peers`](/reference/sql/information-schema/region-peers.md) 提供了 region 的运行时分布信息。 --- ## 元数据存储配置 本节介绍如何为 GreptimeDB Metasrv 组件配置不同的元数据存储后端。元数据存储用于存储关键的系统信息,包括 catalog、schema、table、region 以及其他对 GreptimeDB 运行至关重要的元数据。 ## 可用存储后端 GreptimeDB 支持以下元数据存储后端: - **etcd**:开发和测试环境的默认推荐后端,提供简单性和易用性 - **MySQL/PostgreSQL**:适合生产环境的后端选择,能够无缝对接现有的数据库基础设施和云服务商提供的 RDS 服务 本文档描述的每种后端的 TOML 配置,适用于没有使用 Helm Chart 部署 GreptimeDB 的情况下。 如果你使用 Helm Chart 部署 GreptimeDB,可以参考 [Common Helm Chart Configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md#configuring-metasrv-backend-storage) 了解更多详情。 ## 使用 etcd 作为元数据存储 虽然 etcd 适合开发和测试环境,但对于需要高可用性和可扩展性的生产环境来说可能并不是最佳选择。 配置 metasrv 组件使用 etcd 作为元数据存储: ```toml # metasrv 组件的元数据存储后端 backend = "etcd_store" # 存储服务器地址 # 可以指定多个 etcd 端点以实现高可用性 store_addrs = ["127.0.0.1:2379"] # etcd 后端客户端选项 [backend_client] # 后端客户端的保持连接超时时间 keep_alive_timeout = "3s" # 后端客户端的保持连接间隔 keep_alive_interval = "10s" # 后端客户端的连接超时时间 connect_timeout = "3s" [backend_tls] # - "disable" - 不使用 TLS # - "require" - 要求 TLS mode = "prefer" # 客户端证书文件路径(用于客户端身份验证) # 例如 "/path/to/client.crt" cert_path = "" # 客户端私钥文件路径(用于客户端身份验证) # 例如 "/path/to/client.key" key_path = "" # CA 证书文件路径(用于服务器证书验证) # 使用自定义 CA 或自签名证书时必需 # 留空则仅使用系统根证书 # 例如 "/path/to/ca.crt" ca_cert_path = "" ``` ### 最佳实践 虽然 etcd 可以用作元数据存储,但我们不建议在生产环境中使用它,除非你对 etcd 的操作和维护有丰富的经验。有关 etcd 管理的详细指南,包括安装、备份和维护程序,请参阅[管理 etcd](/user-guide/deployments-administration/manage-metadata/manage-etcd.md)。 使用 etcd 作为元数据存储时: - 在不同可用区部署多个端点以实现高可用性 - 配置适当的自动压缩设置以管理存储增长 - 实施定期维护程序: - 定期运行 `Defrag` 命令以回收磁盘空间 - 监控 etcd 集群健康指标 - 根据使用模式审查和调整资源限制 ## 使用 MySQL 作为元数据存储 MySQL 可作为一种可行的元数据存储后端选项。特别是在需要与现有 MySQL 基础设施集成,或存在特定 MySQL 相关需求的场景下,这一选择尤为适用。对于生产环境部署,我们强烈建议使用各大云服务商提供的关系型数据库服务(RDS),以获得更高的可靠性和托管服务带来的便利。 配置 metasrv 组件以使用 MySQL 作为元数据存储: ```toml # metasrv 组件的元数据存储后端 backend = "mysql_store" # 存储服务器地址 # 格式:mysql://user:password@ip:port/dbname store_addrs = ["mysql://user:password@ip:port/dbname"] # 可选:自定义元数据存储表名 # 默认值: greptime_metakv meta_table_name = "greptime_metakv" [backend_tls] # - "disable" - 不使用 TLS # - "prefer" (默认) - 尝试 TLS,失败时回退到明文连接 # - "require" - 要求 TLS # - "verify_ca" - 要求 TLS 并验证 CA # - "verify_full" - 要求 TLS 并验证主机名 mode = "prefer" # 客户端证书文件路径(用于客户端身份验证) # 例如 "/path/to/client.crt" cert_path = "" # 客户端私钥文件路径(用于客户端身份验证) # 例如 "/path/to/client.key" key_path = "" # CA 证书文件路径(用于服务器证书验证) # 使用自定义 CA 或自签名证书时必需 # 留空则仅使用系统根证书 # 例如 "/path/to/ca.crt" ca_cert_path = "" ``` 当多个 GreptimeDB 集群共享同一个 MySQL 实例时,必须为每个 GreptimeDB 集群设置一个唯一的 `meta_table_name` 以避免元数据冲突。 ## 使用 PostgreSQL 作为元数据存储 PostgreSQL 可作为一种可行的元数据存储后端选项。特别是在需要与现有 PostgreSQL 基础设施集成,或存在特定 PostgreSQL 相关需求的场景下,这一选择尤为适用。对于生产环境部署,我们强烈建议使用各大云服务商提供的关系型数据库服务(RDS),以获得更高的可靠性和托管服务带来的便利。 配置 metasrv 组件以使用 PostgreSQL 作为元数据存储: ```toml # metasrv 组件的元数据存储后端 backend = "postgres_store" # 存储服务器地址 # 格式: password=password dbname=postgres user=postgres host=localhost port=5432 store_addrs = ["password=password dbname=postgres user=postgres host=localhost port=5432"] # 可选:自定义元数据存储表名 # 默认值: greptime_metakv meta_table_name = "greptime_metakv" # 可选:PostgreSQL schema,用于元数据表和选举表名称限定。 # 在 PostgreSQL 15 及更高版本中,默认的 public schema 通常被限制写入权限, # 非超级用户无法在 public schema 中创建表。 # 当遇到权限限制时,可通过此参数指定一个具有写入权限的 schema。 meta_schema_name = "greptime_schema" # 可选:如果 PostgreSQL schema 不存在则自动创建。 # 启用后,系统会在创建元数据表之前执行 `CREATE SCHEMA IF NOT EXISTS `。 # 这在生产环境中可能受限于手动创建 schema 的情况下非常有用。 # 默认值:true # 注意:PostgreSQL 用户必须具有 CREATE SCHEMA 权限才能使此功能生效。 auto_create_schema = true # 可选: 用于选举的 Advisory lock ID # 默认值: 1 meta_election_lock_id = 1 [backend_tls] # - "disable" - 不使用 TLS # - "prefer" (默认) - 尝试 TLS,失败时回退到明文连接 # - "require" - 要求 TLS # - "verify_ca" - 要求 TLS 并验证 CA # - "verify_full" - 要求 TLS 并验证主机名 mode = "prefer" # 客户端证书文件路径(用于客户端身份验证) # 例如 "/path/to/client.crt" cert_path = "" # 客户端私钥文件路径(用于客户端身份验证) # 例如 "/path/to/client.key" key_path = "" # CA 证书文件路径(用于服务器证书验证) # 使用自定义 CA 或自签名证书时必需 # 留空则仅使用系统根证书 # 例如 "/path/to/ca.crt" ca_cert_path = "" ``` 当多个 GreptimeDB 集群共享同一个 PostgreSQL 实例或与其他应用程序共享时,必须配置两个唯一标识符以防止冲突: 1. 为每个 GreptimeDB 集群设置唯一的 `meta_table_name` 以避免元数据冲突 2. 为每个 GreptimeDB 集群分配唯一的 `meta_election_lock_id` 以防止与使用同一 PostgreSQL 实例的其他应用程序发生 advisory lock 冲突 --- ## 管理 etcd GreptimeDB 集群默认需要一个 etcd 集群用于[元数据存储](https://docs.greptime.com/nightly/contributor-guide/metasrv/overview)。让我们使用 Bitnami 的 etcd Helm [chart](https://github.com/bitnami/charts/tree/main/bitnami/etcd) 安装一个 etcd 集群。 ## 先决条件 - [Kubernetes](https://kubernetes.io/docs/setup/) >= v1.23 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## 安装 将以下配置保存为文件 `etcd.yaml`: ```yaml global: security: allowInsecureImages: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: bitnami/etcd tag: 3.6.1-debian-12-r3 replicaCount: 3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" ``` 安装 etcd 集群: ```bash helm upgrade \ --install etcd oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd.yaml ``` 等待 etcd 集群运行: ```bash kubectl get pod -n etcd-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 64s etcd-1 1/1 Running 0 65s etcd-2 1/1 Running 0 72s ```
等待 etcd 集群运行完毕,使用以下命令检查 etcd 集群的健康状态: ```bash kubectl -n etcd-cluster \ exec etcd-0 -- etcdctl \ --endpoints etcd-0.etcd-headless.etcd-cluster:2379,etcd-1.etcd-headless.etcd-cluster:2379,etcd-2.etcd-headless.etcd-cluster:2379 \ endpoint status -w table ```
Expected Output ```bash +----------------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +----------------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | etcd-0.etcd-headless.etcd-cluster:2379 | 680910587385ae31 | 3.5.15 | 20 kB | false | false | 4 | 73991 | 73991 | | | etcd-1.etcd-headless.etcd-cluster:2379 | d6980d56f5e3d817 | 3.5.15 | 20 kB | false | false | 4 | 73991 | 73991 | | | etcd-2.etcd-headless.etcd-cluster:2379 | 12664fc67659db0a | 3.5.15 | 20 kB | true | false | 4 | 73991 | 73991 | | +----------------------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ ```
## 备份 在 bitnami etcd chart 中,使用共享存储卷 Network File System (NFS) 存储 etcd 备份数据。通过 Kubernetes 中的 CronJob 进行 etcd 快照备份,并挂载 NFS PersistentVolumeClaim (PVC),可以将快照传输到 NFS 中。 添加以下配置,并将其命名为 `etcd-backup.yaml` 文件,注意需要将 **existingClaim** 修改为你的 NFS PVC 名称: ```yaml global: security: allowInsecureImages: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: bitnami/etcd tag: 3.6.1-debian-12-r3 replicaCount: 3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Backup settings disasterRecovery: enabled: true cronjob: schedule: "*/30 * * * *" historyLimit: 2 snapshotHistoryLimit: 2 pvc: existingClaim: "${YOUR_NFS_PVC_NAME_HERE}" ``` 重新部署 etcd 集群: ```bash helm upgrade \ --install etcd oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-backup.yaml ``` 你可以看到 etcd 备份计划任务: ```bash kubectl get cronjob -n etcd-cluster ```
Expected Output ```bash NAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE etcd-snapshotter */30 * * * * False 0 36s ```
```bash kubectl get pod -n etcd-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 35m etcd-1 1/1 Running 0 36m etcd-2 0/1 Running 0 6m28s etcd-snapshotter-28936038-tsck8 0/1 Completed 0 4m49s ```
```bash kubectl logs etcd-snapshotter-28936038-tsck8 -n etcd-cluster ```
Expected Output ```log etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379 is healthy: successfully committed proposal: took = 2.698457ms etcd 11:18:07.47 INFO ==> Snapshotting the keyspace {"level":"info","ts":"2025-01-06T11:18:07.579095Z","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"/snapshots/db-2025-01-06_11-18.part"} {"level":"info","ts":"2025-01-06T11:18:07.580335Z","logger":"client","caller":"v3@v3.5.15/maintenance.go:212","msg":"opened snapshot stream; downloading"} {"level":"info","ts":"2025-01-06T11:18:07.580359Z","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379"} {"level":"info","ts":"2025-01-06T11:18:07.582124Z","logger":"client","caller":"v3@v3.5.15/maintenance.go:220","msg":"completed snapshot read; closing"} {"level":"info","ts":"2025-01-06T11:18:07.582688Z","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379","size":"20 kB","took":"now"} {"level":"info","ts":"2025-01-06T11:18:07.583008Z","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"/snapshots/db-2025-01-06_11-18"} Snapshot saved at /snapshots/db-2025-01-06_11-18 ```
接下来,可以在 NFS 服务器中看到 etcd 备份快照: ```bash ls ${NFS_SERVER_DIRECTORY} ```
Expected Output ```bash db-2025-01-06_11-18 db-2025-01-06_11-20 db-2025-01-06_11-22 ```
## 恢复 当您遇到 etcd 数据丢失或损坏(例如,存储在 etcd 中的关键信息被意外删除,或者发生无法恢复的灾难性集群故障)时,您需要执行 etcd 恢复。此外,恢复 etcd 还可用于开发和测试目的。 恢复前需要停止向 etcd 集群写入数据(停止 GreptimeDB Metasrv 对 etcd 的写入),并创建最新的快照文件用于恢复。 添加以下配置文件,命名为 `etcd-restore.yaml`。注意,**existingClaim** 是你的 NFS PVC 的名字,**snapshotFilename** 为 etcd 快照文件名: ```yaml global: security: allowInsecureImages: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: bitnami/etcd tag: 3.6.1-debian-12-r3 replicaCount: 3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Restore settings startFromSnapshot: enabled: true existingClaim: "${YOUR_NFS_PVC_NAME_HERE}" snapshotFilename: "${YOUR_ETCD_SNAPSHOT_FILE_NAME}" ``` 部署 etcd 恢复集群: ```bash helm upgrade \ --install etcd-recover oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-restore.yaml ``` 等待 etcd 恢复集群运行: ```bash kubectl get pod -n etcd-cluster -l app.kubernetes.io/instance=etcd-recover ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-recover-0 1/1 Running 0 91s etcd-recover-1 1/1 Running 0 91s etcd-recover-2 1/1 Running 0 91s ```
:::tip NOTE chart 版本之间的配置结构已发生变化: - 旧版本: `meta.etcdEndpoints` - 新版本: `meta.backendStorage.etcd.endpoints` 请参考 chart 仓库中配置 [values.yaml](https://github.com/GreptimeTeam/helm-charts/blob/main/charts/greptimedb-cluster/values.yaml) 以获取最新的结构。 ::: 接着,将 Metasrv 的 [backendStorage.etcd.endpoints](https://github.com/GreptimeTeam/helm-charts/tree/main/charts/greptimedb-cluster) 改成新的 etcd recover 集群,本例中为 `"etcd-recover.etcd-cluster.svc.cluster.local:2379"`: ```yaml apiVersion: greptime.io/v1alpha1 kind: GreptimeDBCluster metadata: name: greptimedb spec: # 其他配置 meta: backendStorage: etcd: endpoints: - "etcd-recover.etcd-cluster.svc.cluster.local:2379" ``` 然后重启 GreptimeDB Metasrv 完成 etcd 恢复。 ## Monitoring - 安装 Prometheus Operator (例如: [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack))。 - 安装 podmonitor CRD。 将以下配置保存为文件 `etcd-monitoring.yaml`: ```yaml global: security: allowInsecureImages: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: bitnami/etcd tag: 3.6.1-debian-12-r3 replicaCount: 3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Monitoring settings metrics: enabled: true podMonitor: enabled: true namespace: etcd-cluster interval: 10s scrapeTimeout: 10s additionalLabels: release: prometheus ``` 部署并监控 etcd: ```bash helm upgrade \ --install etcd oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-monitoring.yaml ``` ### Grafana dashboard 使用 [ETCD Cluster Overview dashboard](https://grafana.com/grafana/dashboards/15308-etcd-cluster-overview/) (ID: 15308) 来监控 etcd 的指标。 1. 登录你的 Grafana。 2. 导航至 Dashboards -> New -> Import。 3. 输入 Dashboard ID: 15308, 选择数据源并加载图表。 ![ETCD Cluster Overview dashboard](/etcd-cluster-overview-dashboard.png) ## ⚠️ Defrag - Critical Warning Defrag 是一项高风险操作,可能会严重影响您的 ETCD 集群及其依赖系统(例如 GreptimeDB): 1. 执行期间会阻止所有读/写操作(集群将不可用)。 2. 高 I/O 使用率可能导致客户端应用程序超时。 3. 如果碎片整理耗时过长,可能会触发领导者选举。 4. 如果资源分配不当,可能会导致 OOM 终止。 5. 如果在过程中中断,可能会损坏数据。 ETCD 使用多版本并发控制 (MVCC) 机制,用于存储多个版本的 KV。随着时间的推移,随着数据的更新和删除,后端数据库可能会变得碎片化,从而增加存储空间并降低性能。Defrag 是指压缩这些存储空间以回收空间并提高性能的过程。 在 `etcd-defrag.yaml` 文件中添加以下与 defrag 相关的配置: ```yaml global: security: allowInsecureImages: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: bitnami/etcd tag: 3.6.1-debian-12-r3 replicaCount: 3 auth: rbac: create: false token: enabled: false persistence: storageClass: null size: 8Gi resources: limits: cpu: '2' memory: 8Gi requests: cpu: '2' memory: 8Gi autoCompactionMode: "periodic" autoCompactionRetention: "1h" extraEnvVars: - name: ETCD_QUOTA_BACKEND_BYTES value: "8589934592" - name: ETCD_ELECTION_TIMEOUT value: "2000" - name: ETCD_SNAPSHOT_COUNT value: "10000" # Defragmentation settings defrag: enabled: true cronjob: schedule: "0 3 * * *" # Daily at 3:00 AM suspend: false successfulJobsHistoryLimit: 1 failedJobsHistoryLimit: 1 ``` 部署 etcd 集群并开启 defrag 功能: ```bash helm upgrade \ --install etcd oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/etcd \ --create-namespace \ --version 12.0.8 \ -n etcd-cluster \ --values etcd-defrag.yaml ``` 你可以看到 etcd defrag 定时任务: ```bash kubectl get cronjob -n etcd-cluster ```
Expected Output ```bash NAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE etcd-defrag 0 3 * * * False 0 34s ```
```bash kubectl get pod -n etcd-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE etcd-0 1/1 Running 0 4m30s etcd-1 1/1 Running 0 4m29s etcd-2 1/1 Running 0 4m29s etcd-defrag-29128518-sstbf 0/1 Completed 0 90s ```
```bash kubectl logs etcd-defrag-29128518-sstbf -n etcd-cluster ```
Expected Output ```log Finished defragmenting etcd member[http://etcd-0.etcd-headless.etcd-cluster.svc.cluster.local:2379] Finished defragmenting etcd member[http://etcd-1.etcd-headless.etcd-cluster.svc.cluster.local:2379] Finished defragmenting etcd member[http://etcd-2.etcd-headless.etcd-cluster.svc.cluster.local:2379] ```
--- ## GreptimeDB Metasrv 元数据管理概述 # 概述 GreptimeDB 集群 Metasrv 组件需要一个元数据存储来保存元数据。GreptimeDB 提供了灵活的元数据存储选项,包括 [etcd](https://etcd.io/)、[MySQL](https://www.mysql.com/) 和 [PostgreSQL](https://www.postgresql.org/)。每种选项都针对不同的部署场景设计,在可扩展性、可靠性和运维开销之间取得平衡。 - [etcd](https://etcd.io/):一个轻量级的分布式键值存储,非常适合元数据管理。其简单性和易于设置的特点使其成为开发和测试环境的绝佳选择。 - [MySQL](https://www.mysql.com/) 和 [PostgreSQL](https://www.postgresql.org/):企业级关系型数据库,提供强大的元数据存储能力。它们提供包括 ACID 事务、复制和全面的备份解决方案在内的基本功能,使其成为生产环境的理想选择。这两种数据库在各大云平台上都广泛提供托管数据库服务(RDS)。 ## 推荐方案 对于测试和开发环境,[etcd](https://etcd.io/) 提供了一个轻量级且简单的元数据存储解决方案。 **对于生产环境部署,我们强烈建议使用云服务商提供的关系型数据库服务(RDS)作为元数据存储。** 这种方式具有以下优势: - 托管服务内置高可用性和灾难恢复能力 - 自动化的备份和维护 - 专业的监控和支持 - 相比自托管解决方案,降低了运维复杂度 - 与其他云服务无缝集成 ## 最佳实践 - 为元数据存储实施定期备份计划 - 建立全面的存储健康状态和性能指标监控 - 制定清晰的灾难恢复流程 - 记录元数据存储配置和维护程序 ## 后续步骤 - 要配置元数据存储后端,请参阅[配置](/user-guide/deployments-administration/manage-metadata/configuration.md)。 - 要为测试和开发环境设置 etcd,请参阅[管理 etcd](/user-guide/deployments-administration/manage-metadata/manage-etcd.md)。 --- ## 备份、恢复和迁移 GreptimeDB 通过其 CLI 工具提供元数据备份和恢复功能。该功能支持所有主要的元数据存储后端,包括 etcd、MySQL 和 PostgreSQL。有关使用这些功能的详细说明,请参阅[备份和恢复](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data.md)指南。 ## 备份 为了获得最佳的备份可靠性,建议在 DDL(数据定义语言)操作(即建表、删表、修改表结构等)较少的时段进行元数据备份。这有助于确保数据一致性,并降低部分或不完整备份的风险。 执行备份的步骤: 1. 确认 GreptimeDB 集群处于正常运行状态 2. 使用 CLI 工具执行备份,按照[备份和恢复](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-meta-data.md)指南中的导出元数据步骤操作 3. 确保备份输出文件已创建,且文件大小大于 0 ## 恢复 从备份恢复的步骤: 1. 使用 CLI 工具恢复元数据,按照[备份和恢复](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-meta-data.md)指南中的导入元数据步骤操作 2. 重启 GreptimeDB 集群以应用恢复的元数据 3. 将[待分配表 ID](/user-guide/deployments-administration/maintenance/sequence-management.md) 设置为原集群的待分配表 ID 4. 调用[表元数据修复](/user-guide/deployments-administration/maintenance/table-reconciliation.md)函数,修复表元数据不一致问题 ## 迁移 我们建议在 DDL(数据定义语言)操作(即建表、删表、修改表结构等)较少的时段进行元数据迁移,以确保数据一致性并降低部分或不完整迁移的风险。 将元数据从一个存储后端迁移到另一个存储后端的步骤: 1. 从源存储备份元数据 2. 将元数据恢复到目标存储 3. 重启整个 GreptimeDB 集群(所有组件)以应用恢复的元数据 --- ## 检查 GreptimeDB 状态 GreptimeDB 包含了一系列的 HTTP 接口可供查询 GreptimeDB 的运行情况。 以下发起的 HTTP 请求均假定 GreptimeDB 运行在节点 `127.0.0.1` 上,其 HTTP 服务监听默认的 `4000` 端口。 ## 查看 GreptimeDB 是否正常运行: 你可以使用 `/health` 接口检查 GreptimeDB 是否正常运行。 HTTP 状态码 `200 OK` 表示 GreptimeDB 运行正常。 例子: ```bash curl -i -X GET http://127.0.0.1:4000/health ``` 输出: ```text HTTP/1.1 200 OK content-type: application/json vary: origin, access-control-request-method, access-control-request-headers access-control-allow-origin: * content-length: 2 date: Sun, 26 Apr 2026 13:46:41 GMT {} ``` 有关健康检查接口的更多信息,请参考[健康检查接口](/reference/http-endpoints.md#健康检查)。 ## 查看 GreptimeDB 的部署状态 你可以使用 `/status` 接口检查 GreptimeDB 的部署状态。 ```bash curl -X GET http://127.0.0.1:4000/status | jq ``` 输出: ```json { "commit": "8d2f92c01ae762287a3cac587156519a536ae134", "branch": "", "rustc_version": "rustc 1.96.0-nightly (ac7f9ec7d 2026-03-20)", "hostname": "127.0.0.1", "version": "1.0.1" } ``` 有关状态接口的更多信息,请参考[状态接口](/reference/http-endpoints.md#状态)。 --- ## 自监控 GreptimeDB 集群 在阅读本文档前,请确保你已经了解如何[在 Kubernetes 上部署 GreptimeDB 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md)。 本文将介绍在部署 GreptimeDB 集群时如何配置监控。 ## 快速开始 你可以在使用 Helm Chart 部署 GreptimeDB 集群时,通过对 `values.yaml` 文件进行配置来启用监控和 Grafana。下面是一个完整的 `values.yaml` 示例,用于部署一个最小化的带有监控和 Grafana 的 GreptimeDB 集群: ```yaml image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com # 镜像仓库: # OSS GreptimeDB 使用 `greptime/greptimedb`, # GreptimeDB 企业版配置请咨询工作人员 repository: # 镜像标签: # OSS GreptimeDB 使用数据库版本,例如 `v1.0.2` # GreptimeDB 企业版配置请咨询工作人员 tag: pullSecrets: [] initializer: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: greptime/greptimedb-initializer tag: "v0.6.0" monitoring: # 启用监控 enabled: true # 监控数据的默认保留时间 ttl: 30d vector: # 监控需要使用 Vector registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com grafana: # 用于监控面板 # 需要先启用监控 `monitoring.enabled: true` 选项 enabled: true image: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com frontend: replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] datanode: replicas: 1 flownode: replicas: 1 ``` 当启用 `monitoring` 后,GreptimeDB Operator 会额外启动一个 GreptimeDB Standalone 实例用于收集 GreptimeDB 集群的指标和日志数据。 为了收集日志数据,GreptimeDB Operator 会在每一个 Pod 中启动一个 [Vector](https://vector.dev/) 的 Sidecar 容器。 当启用 `grafana` 后,会部署一个 Grafana 实例,并将用于集群监控的 GreptimeDB Standalone 实例作为其数据源。 这样就可以开箱即用地通过 Prometheus 和 MySQL 协议来可视化 GreptimeDB 集群的监控数据。 接下来使用上述配置的 `values.yaml` 文件来部署 GreptimeDB 集群: ```bash helm upgrade --install mycluster \ greptime/greptimedb-cluster \ --values /path/to/values.yaml \ -n default ``` 部署完成后,你可以用如下命令来查看 GreptimeDB 集群的 Pod 状态: ```bash kubectl -n default get pods ```
期望输出 ```bash NAME READY STATUS RESTARTS AGE mycluster-datanode-0 2/2 Running 0 77s mycluster-flownode-0 2/2 Running 0 2m26s mycluster-frontend-6ffdd549b-9s7gx 2/2 Running 0 66s mycluster-grafana-675b64786-ktqps 1/1 Running 0 6m35s mycluster-meta-58bc88b597-ppzvj 2/2 Running 0 86s mycluster-monitor-standalone-0 1/1 Running 0 6m35s ```
你可以转发 Grafana 的端口到本地来访问 Grafana 仪表盘: ```bash kubectl -n default port-forward svc/mycluster-grafana 18080:80 ``` 请参考[访问 Grafana 仪表盘](#访问-grafana仪表盘)章节来查看相应的数据面板。 ## 配置监控数据的收集 本节将介绍监控配置的细节。 ### 启用监控 在使用 Helm Chart 部署 GreptimeDB 集群时,在 [`values.yaml`](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md#setup-valuesyaml) 中添加以下配置来启用监控: ```yaml monitoring: enabled: true ``` 这将部署一个名为 `${cluster-name}-monitoring` 的 GreptimeDB Standalone 实例来收集指标和日志。你可以使用以下命令验证部署: ```bash kubectl get greptimedbstandalones.greptime.io ${cluster-name}-monitoring -n ${namespace} ``` GreptimeDB Standalone 实例使用 `${cluster-name}-monitoring-standalone` 作为 Kubernetes Service 名称来暴露服务。你可以使用以下地址访问监控数据: - **Prometheus 指标**:`http://${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4000/v1/prometheus` - **SQL 日志**:`${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4002`。默认情况下,集群日志存储在 `public._gt_logs` 表中。 ### 自定义监控数据存储 默认情况下,GreptimeDB Standalone 实例使用 Kubernetes 默认的 StorageClass 将监控数据存储在本地存储中。 你可以通过 `values.yaml` 中的 `monitoring.standalone` 字段来配置 GreptimeDB Standalone 实例。例如,以下配置使用 S3 对象存储来存储监控数据: ```yaml monitoring: enabled: true ttl: 30d standalone: base: main: # 用于配置 GreptimeDB Standalone 实例的镜像 image: "greptime-registry.cn-hangzhou.cr.aliyuncs.com/greptime/greptimedb:v1.0.2" # 用于配置 GreptimeDB Standalone 实例的资源配置 resources: requests: cpu: "2" memory: "4Gi" limits: cpu: "2" memory: "4Gi" # 用于配置 GreptimeDB Standalone 实例的对象存储 objectStorage: s3: # 用于配置 GreptimeDB Standalone 实例的对象存储的 bucket bucket: "monitoring" # 用于配置 GreptimeDB Standalone 实例的对象存储的 region region: "ap-southeast-1" # 用于配置 GreptimeDB Standalone 实例的对象存储的 secretName secretName: "s3-credentials" # 用于配置 GreptimeDB Standalone 实例的对象存储的 root root: "standalone-with-s3-data" ``` ### 自定义 Vector Sidecar 用于日志收集的 Vector Sidecar 配置可以通过 `monitoring.vector` 字段进行自定义。 例如,你可以按如下方式调整 Vector 的镜像和资源: ```yaml monitoring: enabled: true ttl: 30d vector: # 用于配置 Vector 的镜像仓库 registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com # 用于配置 Vector 的镜像仓库 repository: timberio/vector # 用于配置 Vector 的镜像标签 tag: "0.49.0-debian" # 用于配置 Vector 的资源配置 resources: requests: cpu: "50m" memory: "64Mi" limits: cpu: "250m" memory: "256Mi" ``` ### 使用 `kubectl` 部署的 YAML 配置 如果你没有使用 Helm Chart 部署 GreptimeDB 集群, 可以在 `GreptimeDBCluster` 的 YAML 中使用 `monitoring` 字段来手动配置自监控模式: ```yaml monitoring: enabled: true ``` 详细的配置选项请参考 [`GreptimeDBCluster` API 文档](https://github.com/GreptimeTeam/greptimedb-operator/blob/main/docs/api-references/docs.md#monitoringspec)。 ## Grafana 配置 ### 启用 Grafana 在 `values.yaml` 中添加以下配置启用 Grafana 部署, 注意该功能必须先启用[监控(`monitoring.enabled: true`)配置](#启用监控): ```yaml monitoring: enabled: true grafana: enabled: true ``` ### 自定义 Grafana 数据源 默认情况下,Grafana 使用 `mycluster` 和 `default` 作为集群名称和命名空间来创建数据源。 要监控其他名称或命名空间的集群,请根据实际的集群名称和命名空间自定义配置。 以下是 `values.yaml` 配置示例: ```yaml monitoring: enabled: true grafana: enabled: true datasources: datasources.yaml: datasources: # Query the cluster metrics. - name: greptimedb-metrics type: prometheus url: http://${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4000/v1/prometheus access: proxy # Query the cluster traces. - name: greptimedb-traces type: jaeger url: http://${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4000/v1/jaeger access: proxy # Query the cluster logs and slow queries. - name: greptimedb-logs type: mysql url: ${cluster-name}-monitor-standalone.${namespace}.svc.cluster.local:4002 access: proxy database: public # Query the information schema from the cluster. - name: information_schema type: mysql url: ${cluster-name}-frontend.${namespace}.svc.cluster.local:4002 access: proxy database: information_schema ``` 此配置会在 Grafana 中为 GreptimeDB 集群的监控创建以下数据源: - **`greptimedb-metrics`**:用于存储监控数据的单机数据库中的集群指标,通过 Prometheus 协议提供服务(`type: prometheus`)。 - **`greptimedb-logs`**:用于存储监控数据的单机数据库中的集群日志,通过 MySQL 协议提供服务(`type: mysql`),默认使用 `public` 数据库。 - **`greptimedb-traces`**: 用于存储监控数据的单机数据库中的集群 traces,通过 Jaeger 协议提供服务 (`type: jaeger`)。 - **`information_schema`**: 用于存储数据库中的集群信息,通过 MySQL 协议提供服务 (`type: mysql`)。 ### 访问 Grafana 仪表盘 你可以通过将 Grafana 服务端口转发到本地来访问 Grafana 仪表盘: ```bash kubectl -n ${namespace} port-forward svc/${cluster-name}-grafana 18080:80 ``` 然后打开 `http://localhost:18080` 来访问 Grafana 仪表盘。 默认登录凭据为: - **用户名**:`admin` - **密码**:`gt-operator` 接着进入到 `Dashboards` 部分来查看用于监控 GreptimeDB 集群而预配置的仪表盘。 ![Grafana Dashboard](/kubernetes-cluster-grafana-dashboard.jpg) ## 清理 PVC :::danger 清理操作将移除 GreptimeDB 集群的元数据和数据,请确保在操作前已备份数据。 ::: 请参考[清理 GreptimeDB 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md#cleanup)文档 查看如何卸载 GreptimeDB 集群, 要清理 GreptimeDB 用于监控的单机数据库的 PVC,请使用以下命令: ```bash kubectl -n default delete pvc -l app.greptime.io/component=${cluster-name}-monitor-standalone ``` --- ## 运维关键日志 GreptimeDB 在运行过程中,会将一些关键的操作以及预期外的错误信息输出到日志中。 你可以通过这些日志了解 GreptimeDB 的运行情况,以及排查错误出现的原因。 ## 日志位置 GreptimeDB 的组件默认都会输出 INFO 级别的日志到以下位置: - 标准输出 - GreptimeDB 当前工作目录下的 `greptimedb_data/logs` 目录 日志文件的输出目录也可以通过配置文件的 `[logging]` 小节或者启动参数 `--log_dir` 修改: ```toml [logging] dir = "/path/to/logs" ``` 日志文件格式为: - `greptimedb.YYYY-MM-DD-HH` 包含 INFO 以上等级的日志 - `greptimedb-err.YYYY-MM-DD-HH` 包含错误日志 例如: ```bash greptimedb.2025-04-11-06 greptimedb-err.2025-04-11-06 ``` 目前 GreptimeDB 的组件包括 - frontend - datanode - metasrv - flownode 如果需要调整日志级别,如查看某组件 DEBUG 级别的日志,可以参考[这篇文档](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-change-log-level-on-the-fly.md)在运行时进行修改。 ## 重要日志 以下将列举建议关注的日志 ### 错误日志 数据库在正常平稳运行时,不会输出错误日志。如果数据库的一些操作出现异常,或者出现了 panic,都会打印错误日志。建议用户检查所有组件的错误日志。 #### Panic 如果数据库出现了 panic ,则建议收集 panic 的日志反馈给官方。通常 panic 日志如下,关键字为 `panicked at`: ```bash 2025-04-02T14:44:24.485935Z ERROR common_telemetry::panic_hook: panicked at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/expr/src/logical_plan/plan.rs:1035:25: with_new_exprs for Distinct does not support sort expressions backtrace= 0: backtrace::backtrace::libunwind::trace at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/backtrace/libunwind.rs:116:5 backtrace::backtrace::trace_unsynchronized at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/backtrace/mod.rs:66:5 1: backtrace::backtrace::trace at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/backtrace/mod.rs:53:14 2: backtrace::capture::Backtrace::create at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/capture.rs:292:9 3: backtrace::capture::Backtrace::new at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/backtrace-0.3.74/src/capture.rs:257:22 4: common_telemetry::panic_hook::set_panic_hook::{{closure}} at /greptime/codes/greptime/procedure-traits/src/common/telemetry/src/panic_hook.rs:37:25 5: as core::ops::function::Fn>::call at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/alloc/src/boxed.rs:1984:9 std::panicking::rust_panic_with_hook at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/panicking.rs:820:13 6: std::panicking::begin_panic_handler::{{closure}} at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/panicking.rs:678:13 7: std::sys::backtrace::__rust_end_short_backtrace at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/sys/backtrace.rs:168:18 8: rust_begin_unwind at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/std/src/panicking.rs:676:5 9: core::panicking::panic_fmt at /rustc/409998c4e8cae45344fd434b358b697cc93870d0/library/core/src/panicking.rs:75:14 10: datafusion_expr::logical_plan::plan::LogicalPlan::with_new_exprs at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/expr/src/logical_plan/plan.rs:1035:25 11: ::analyze::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/optimizer/type_conversion.rs:105:17 12: core::ops::function::impls::::call_mut at /greptime/.rustup/toolchains/nightly-2024-12-25-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:272:13 13: core::ops::function::impls::::call_once at /greptime/.rustup/toolchains/nightly-2024-12-25-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:305:13 14: datafusion_common::tree_node::Transformed::transform_parent at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:764:44 15: datafusion_common::tree_node::TreeNode::transform_up::transform_up_impl::{{closure}} at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:265:13 16: stacker::maybe_grow at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/stacker-0.1.17/src/lib.rs:55:9 datafusion_common::tree_node::TreeNode::transform_up::transform_up_impl at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:260:9 17: datafusion_common::tree_node::TreeNode::transform_up at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:269:9 18: datafusion_common::tree_node::TreeNode::transform at /greptime/.cargo/git/checkouts/datafusion-11a8b534adb6bd68-shallow/2464703/datafusion/common/src/tree_node.rs:220:9 19: ::analyze at /greptime/codes/greptime/procedure-traits/src/query/src/optimizer/type_conversion.rs:46:9 20: query::query_engine::state::QueryEngineState::optimize_by_extension_rules::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/query_engine/state.rs:195:17 21: core::iter::traits::iterator::Iterator::try_fold at /greptime/.rustup/toolchains/nightly-2024-12-25-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2370:21 22: query::query_engine::state::QueryEngineState::optimize_by_extension_rules at /greptime/codes/greptime/procedure-traits/src/query/src/query_engine/state.rs:192:9 23: query::planner::DfLogicalPlanner::plan_sql::{{closure}}::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:119:20 24: as core::future::future::Future>::poll at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tracing-0.1.40/src/instrument.rs:321:9 25: query::planner::DfLogicalPlanner::plan_sql::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:71:5 26: ::plan::{{closure}}::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:198:73 27: as core::future::future::Future>::poll at /greptime/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tracing-0.1.40/src/instrument.rs:321:9 28: ::plan::{{closure}} at /greptime/codes/greptime/procedure-traits/src/query/src/planner.rs:195:5 ... ``` ### Metasrv 当 GreptimeDB 集群出现节点上线,节点下线,region 迁移,schema 变更等情况时, metasrv 都会记录相应的日志。因此,除了各个组件的错误日志外,也建议关注 metasrv 的以下日志关键字 #### Metasrv 切主/发起选举 ```bash // error 级别,标识当前 leader step down, 接下来会发生新的选举,注意 {:?} 这部分是 leader 标识 "Leader :{:?} step down" ``` #### Region 续租失败 ```bash // Warn 级别,表示一个 region 被拒绝续租,region 在某个 DN 上未被正常关闭/调度时,该 region 续租请求会被拒绝。 Denied to renew region lease for datanode: {datanode_id}, region_id: {region_id} ``` ```bash // Info 级别,DN 收到续租失败信息,并尝试关闭目标 region Closing staled region: ``` #### Region Failover ```bash // Warn 级别,发现部分 region 未通过 Phi 健康检测,需要执行 failover 操作,冒号后面好打印出相关的 region ids Detects region failures: // 某一个 region 迁移失败 Failed to wait region migration procedure // Info 级别,当维护模式打开时,failover procedure 会被跳过。 Maintenance mode is enabled, skip failover ``` #### Region 迁移 ```bash // info 级别,表明某一个 region 开始迁移,日志后面会打印出 region 相关信息 Starting region migration procedure // error 级别,某一个 region 迁移失败 Failed to wait region migration procedure ``` #### Procedure Metasrv 内部通过一个叫做 procedure 的组件执行一些分布式操作。可以关注该组件的错误日志 ```bash Failed to execute procedure ``` #### Flow 创建失败 在创建 flow 失败时,通常在 procedure 的错误日志中可以看到失败的原因。日志可能包含以下关键字 ```bash Failed to execute procedure metasrv-procedure:: CreateFlow ``` ### Datanode #### Compaction 在 compaction 开始和结束时,datanode 上会有如下日志: ```bash 2025-05-16T06:01:08.794415Z INFO mito2::compaction::task: Compacted SST files, region_id: 4612794875904(1074, 0), input: [FileMeta { region_id: 4612794875904(1074, 0), file_id: FileId(a29500fb-cae0-4f3f-8376-cb3f14653378), time_range: (1686455010000000000::Nanosecond, 1686468410000000000::Nanosecond), level: 0, file_size: 45893329, available_indexes: [], index_file_size: 0, num_rows: 5364000, num_row_groups: 53, sequence: Some(114408000) }, FileMeta { region_id: 4612794875904(1074, 0), file_id: FileId(a31dcb1b-19ae-432f-8482-9e1b7db7b53b), time_range: (1686468420000000000::Nanosecond, 1686481820000000000::Nanosecond), level: 0, file_size: 45900506, available_indexes: [], index_file_size: 0, num_rows: 5364000, num_row_groups: 53, sequence: Some(119772000) }], output: [FileMeta { region_id: 4612794875904(1074, 0), file_id: FileId(5d105ca7-9e3c-4298-afb3-e85baae3b2e8), time_range: (1686455010000000000::Nanosecond, 1686481820000000000::Nanosecond), level: 1, file_size: 91549797, available_indexes: [], index_file_size: 0, num_rows: 10728000, num_row_groups: 105, sequence: Some(119772000) }], window: Some(86400), waiter_num: 0, merge_time: 3.034328293s ``` ```bash 2025-05-16T06:01:08.805366Z INFO mito2::request: Successfully compacted region: 4612794875904(1074, 0) ``` --- ## 使用 Prometheus 监控 GreptimeDB Cluster 在阅读本文档之前,请确保你已经了解如何[在 Kubernetes 上部署 GreptimeDB 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md)。 我们推荐使用[自监控方法](cluster-monitoring-deployment.md)来监控 GreptimeDB 集群, 这种模式配置简单且提供了开箱即用的 Grafana 仪表板。 但如果你已经在 Kubernetes 集群中部署了 Prometheus 实例,并希望写入 GreptimeDB 集群的监控指标,请按照本文档中的步骤操作。 ## 检查 Prometheus 实例配置 请先确保你已经部署 Prometheus Operator 并创建了 Prometheus 实例。例如,你可以使用 [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) 来部署 Prometheus 技术栈。请参考其[官方文档](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack)了解更多详情。 在部署 Prometheus 实例时,确保你设置了用于抓取 GreptimeDB 集群指标的标签。 例如,你现有的 Prometheus 实例包含下面的配置: ```yaml apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: greptime-podmonitor namespace: default spec: selector: matchLabels: release: prometheus # 其他配置... ``` 当 `PodMonitor` 被部署后, Prometheus Operator 会持续监视 `default` 命名空间中匹配 `spec.selector.matchLabels` 中定义的所有标签(在此示例中为 `release: prometheus`)的 Pod。 ## 为 GreptimeDB 集群启用 `prometheusMonitor` 使用 Helm Chart 部署 GreptimeDB 集群时, 在你的 `values.yaml` 文件中启用 `prometheusMonitor` 字段。例如: ```yaml prometheusMonitor: # 启用 Prometheus 监控 - 这将创建 PodMonitor 资源 enabled: true # 配置抓取间隔 interval: "30s" # 配置标签 labels: release: prometheus ``` **重要:** `labels` 字段的值(`release: prometheus`) 必须与创建 Prometheus 实例时使用的 `matchLabels` 的值匹配, 否则指标收集将无法正常工作。 配置 `prometheusMonitor` 后, GreptimeDB Operator 将自动创建 `PodMonitor` 资源并按指定的时间间隔 `interval` 将指标导入到 Prometheus。 你可以使用以下命令检查 `PodMonitor` 资源: ``` kubectl get podmonitors.monitoring.coreos.com -n ${namespace} ``` :::note 如果你没有使用 Helm Chart 部署 GreptimeDB 集群, 可以在 `GreptimeDBCluster` YAML 中手动配置 Prometheus 监控: ```yaml apiVersion: greptime.io/v1alpha1 kind: GreptimeDBCluster metadata: name: basic spec: base: main: image: greptime/greptimedb:v1.0.2 frontend: replicas: 1 meta: replicas: 1 backendStorage: etcd: endpoints: - "etcd.etcd-cluster.svc.cluster.local:2379" datanode: replicas: 1 prometheusMonitor: enabled: true interval: "30s" labels: release: prometheus ``` ::: ## Grafana 仪表板 你需要自己部署 Grafana, 然后导入仪表板。 ### 添加数据源 部署 Grafana 后, 参考 Grafana 的[数据源](https://grafana.com/docs/grafana/latest/datasources/)文档添加以下两种类型的数据源: - **Prometheus**:将其命名为 `metrics`。此数据源连接到你的收集 GreptimeDB 集群监控指标的 Prometheus 实例,因此请使用你的 Prometheus 实例 URL 作为连接 URL。 - **MySQL**:将其命名为 `information-schema`。此数据源连接到你的 GreptimeDB 集群,通过 SQL 协议访问集群元数据。如果你已经按照[在 Kubernetes 上部署 GreptimeDB 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md)指南部署了 GreptimeDB,服务器地址为 `${cluster-name}-frontend.${namespace}.svc.cluster.local:4002`,数据库为 `information_schema`。 ### 导入仪表板 [GreptimeDB 集群指标仪表板](https://github.com/GreptimeTeam/greptimedb/tree/v1.0.2/grafana/dashboards/metrics/cluster)使用 `metrics` 和 `information-schema` 数据源来显示 GreptimeDB 集群指标。 请参考 Grafana 的[导入仪表板](https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/import-dashboards/)文档了解如何导入仪表板。 --- ## 监控 数据库的有效管理在很大程度上依赖于监控。 你可以使用以下方法监控 GreptimeDB: --- ## 运行时信息 `INFORMATION_SCHEMA` 数据库提供了对系统元数据的访问,如数据库或表的名称、列的数据类型等。 * 通过 [CLUSTER_INFO](/reference/sql/information-schema/cluster-info.md) 表查找集群的拓扑信息。 * 通过 [PARTITIONS](/reference/sql/information-schema/partitions.md) 表和[REGION_PEERS](/reference/sql/information-schema/region-peers.md) 表查找表的 Region 分布。 例如查询一张表的所有 Region Id: ```sql SELECT greptime_partition_id FROM PARTITIONS WHERE table_name = 'monitor' ``` 查询一张表的 region 分布在哪些 datanode 上: ```sql SELECT b.peer_id as datanode_id, a.greptime_partition_id as region_id FROM information_schema.partitions a LEFT JOIN information_schema.region_peers b ON a.greptime_partition_id = b.region_id WHERE a.table_name='monitor' ORDER BY datanode_id ASC ``` 请阅读[参考文档](/reference/sql/information-schema/overview.md)获取更多关于 `INFORMATION_SCHEMA` 数据库的信息。 --- ## 慢查询(实验性功能) GreptimeDB 提供了慢查询日志功能,帮助您发现和修复慢查询。默认情况下,慢查询会输出到系统表 `greptime_private.slow_queries` 中,阈值为 `30s`,采样率为 `1.0`,TTL 为 `30d`。 `greptime_private.slow_queries` 表的架构如下: ```sql +--------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------+----------------------+------+------+---------+---------------+ | cost | UInt64 | | NO | | FIELD | | threshold | UInt64 | | NO | | FIELD | | query | String | | NO | | FIELD | | is_promql | Boolean | | NO | | FIELD | | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | promql_range | UInt64 | | NO | | FIELD | | promql_step | UInt64 | | NO | | FIELD | | promql_start | TimestampMillisecond | | NO | | FIELD | | promql_end | TimestampMillisecond | | NO | | FIELD | +--------------+----------------------+------+------+---------+---------------+ ``` - `cost`: 查询的执行时间,单位为毫秒。 - `threshold`: 慢查询的阈值,单位为毫秒。 - `query`: 查询语句。 - `is_promql`: 是否为 PromQL 查询。 - `timestamp`: 查询的时间戳。 - `promql_range`: 查询的时间范围。仅当 `is_promql` 为 `true` 时使用。 - `promql_step`: 查询的时间步长。仅当 `is_promql` 为 `true` 时使用。 - `promql_start`: 查询的开始时间。仅当 `is_promql` 为 `true` 时使用。 - `promql_end`: 查询的结束时间。仅当 `is_promql` 为 `true` 时使用。 在集群模式下,你可以在 frontend 配置中配置慢查询(与单机模式相同),例如: ```toml [slow_query] ## 是否启用慢查询日志。 enable = true ## 慢查询的记录类型。可以是 `system_table` 或 `log`。 ## 如果选择 `system_table`,慢查询将记录在系统表 `greptime_private.slow_queries` 中。 ## 如果选择 `log`,慢查询将记录在日志文件 `greptimedb-slow-queries.*` 中。 record_type = "system_table" ## 慢查询的阈值。可以是可读的时间字符串,例如:`10s`,`100ms`,`1s`。 threshold = "30s" ## 慢查询日志的采样率。值应在 (0, 1] 范围内。例如,`0.1` 表示 10% 的慢查询将被记录,`1.0` 表示所有慢查询将被记录。 sample_ratio = 1.0 ## `slow_queries` 系统表的 TTL。当 `record_type` 为 `system_table` 时,默认值为 `30d`。 ttl = "30d" ``` 如果你使用 Helm 部署 GreptimeDB,可以在 `values.yaml` 文件中配置慢查询,例如: ```yaml slowQuery: enable: true recordType: "system_table" threshold: "30s" sampleRatio: "1.0" ttl: "30d" ``` 如果使用 `log` 作为记录类型,慢查询将记录在日志文件 `greptimedb-slow-queries.*` 中。默认情况下,日志文件位于 `${data_home}/logs` 目录。 --- ## 单机监控 GreptimeDB 单机版在 HTTP 端口(默认 `4000`)上提供 `/metrics` 端点,暴露 [Prometheus 指标](/reference/http-endpoints.md#指标)。 你可以使用 Prometheus 抓取这些指标,并使用 Grafana 进行可视化展示。 ## Grafana 仪表板集成 GreptimeDB 为监控单机部署提供预构建的 Grafana 仪表板。你可以从 [GreptimeDB 代码库](https://github.com/GreptimeTeam/greptimedb/tree/v1.0.2/grafana/dashboards/metrics/standalone) 访问仪表板 JSON 文件。 --- ## 链路追踪 GreptimeDB 支持分布式链路追踪。GreptimeDB 使用基于 gRPC 的 OTLP 协议导出所有采集到的 Span。您可以使用 [Jaeger](https://www.jaegertracing.io/)、[Tempo](https://grafana.com/oss/tempo/) 等支持基于 gRPC 的 OTLP 协议后端接收 GreptimeDB 采集到的 Span。 在配置中的 [logging 部分](/user-guide/deployments-administration/configuration.md#logging-选项) 有对 tracing 的相关配置项说明,[standalone.example.toml](https://github.com/GreptimeTeam/greptimedb/blob/v1.0.2/config/standalone.example.toml) 的 logging 部分提供了参考配置项。 ## 动态链路追踪控制 GreptimeDB 提供了通过 HTTP API 在运行时动态启用或禁用链路追踪的功能,无需重启服务器。这对于排查生产环境问题或临时启用追踪进行调试非常有用。 启用链路追踪: ```bash curl --data "true" http://127.0.0.1:4000/debug/enable_trace # 输出: trace enabled ``` 禁用链路追踪: ```bash curl --data "false" http://127.0.0.1:4000/debug/enable_trace # 输出: trace disabled ``` ## 教程:使用 Jaeger 追踪 GreptimeDB 调用链路 [Jaeger](https://www.jaegertracing.io/) 是一个开源的、端到端的分布式链路追踪系统,最初由 Uber 开发并开源。它的目标是帮助开发人员监测和调试复杂的微服务架构中的请求流程。 Jaeger 支持基于 gRPC 的 OTLP 协议,所以 GreptimeDB 可以将跟踪数据导出到 Jaeger。以下教程向您展示如何部署和使用 Jaeger 来跟踪 GreptimeDB。 ### 步骤一:部署 Jaeger 使用 jaeger 官方提供的 `all-in-one` docker 镜像启动一个 Jaeger 实例: ```bash docker run --rm -d --name jaeger \ -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ -p 6831:6831/udp \ -p 6832:6832/udp \ -p 5778:5778 \ -p 16686:16686 \ -p 4317:4317 \ -p 4318:4318 \ -p 14250:14250 \ -p 14268:14268 \ -p 14269:14269 \ -p 9411:9411 \ jaegertracing/all-in-one:latest ``` ### 步骤二:部署 GreptimeDB 编写配置文件,允许 GreptimeDB 进行链路追踪。将下面的配置项保存为文件 `config.toml` ```Toml [logging] enable_otlp_tracing = true ``` 之后使用 standalone 模式启动 GreptimeDB ```bash greptime standalone start -c config.toml ``` 参考章节 [Mysql](/user-guide/protocols/mysql.md) 如何连接到 GreptimeDB。在 Mysql Client 中运行下面的 SQL 语句: ```sql CREATE TABLE host ( ts timestamp(3) time index, host STRING PRIMARY KEY, val BIGINT, ); INSERT INTO TABLE host VALUES (0, 'host1', 0), (20000, 'host2', 5); SELECT * FROM host ORDER BY ts; DROP TABLE host; ``` ### 步骤三:在 Jaeger 中获取 trace 信息 1. 转到 http://127.0.0.1:16686/ 并选择“Search”选项卡。 2. 在服务下拉列表中选择 `greptime-standalone` 服务。 3. 单击 **Find Traces** 以显示追踪到的链路信息。 ![JaegerUI](/jaegerui.png) ![Select-tracing](/select-tracing.png) ## 指南:如何配置 tracing 采样率 GreptimeDB 提供了许多协议与接口,用于数据的插入、查询等功能。您可以通过 tracing 采集到每种操作的调用链路。但是对于某些高频操作,将所有该操作的 tracing 都采集下来,可能没有必要而且浪费存储空间。这个时候,您可以使用 `tracing_sample_ratio` 来对各种操作 tracing 的采样率进行设置,这样能够很大程度上减少导出 tracing 的数量并有利于系统观测。 GreptimeDB 根据接入的协议,还有该协议对应的操作,对所有 tracing 进行了分类: | **protocol** | **request_type** | |--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | grpc | inserts / query.sql / query.logical_plan / query.prom_range / query.empty / ddl.create_database / ddl.create_table / ddl.alter / ddl.drop_table / ddl.truncate_table / ddl.empty / deletes / row_inserts / row_deletes | | mysql | | | postgres | | | otlp | metrics / traces | | opentsdb | | | influxdb | write_v1 / write_v2 | | prometheus | remote_read / remote_write / format_query / instant_query / range_query / labels_query / series_query / label_values_query | | http | sql / promql 您可以通过 `tracing_sample_ratio` 来配置不同 tracing 的采样率。 ```toml [logging] enable_otlp_tracing = true [logging.tracing_sample_ratio] default_ratio = 0.0 [[logging.tracing_sample_ratio.rules]] protocol = "mysql" ratio = 1.0 [[logging.tracing_sample_ratio.rules]] protocol = "grpc" request_types = ["inserts"] ratio = 0.3 ``` 上述配置制定了两条采样规则,并制定了默认采样率,GreptimeDB 会根据您提供的采样规则,从第一条开始匹配,并使用第一条匹配到的采样规则作为该 tracing 的采样率,如果没有任何规则匹配,则 `default_ratio` 会被作为默认采样率被使用。采样率的范围是 `[0.0, 1.0]`, `0.0` 代表所有 tracing 都不采样,`1.0` 代表采样所有 tracing。 比如上面提供的规则,使用 mysql 协议接入的所有调用都将被采样,使用 grpc 插入的数据会被采样 30%,其余所有 tracing 都不会被采样。 --- ## 运维部署及管理 GreptimeDB 可以部署在你自己的基础设施上,也可以通过全托管云服务 GreptimeCloud 进行管理。 本指南概述了部署策略、配置、监控和管理的相关内容。 ## GreptimeDB 架构 在进行 GreptimeDB 的部署和管理之前,有必要了解其[架构](/user-guide/concepts/architecture.md)。 ## 自托管 GreptimeDB 部署 本节概述了自托管环境中部署和管理 GreptimeDB 的关键点。 ### 配置和部署 - **配置:** 在部署 GreptimeDB 前,[检查配置](configuration.md)以确保满足你的相关需要,包括协议设置、存储选项等。 - **鉴权:** 默认情况下鉴权没有被启动。了解如何[启用和配置鉴权](./authentication/overview.md)。 - **Kubernetes 部署:** 按照[部署指南](./deploy-on-kubernetes/overview.md)在 Kubernetes 上部署 GreptimeDB。 - **容量规划:** 通过[容量规划](/user-guide/deployments-administration/capacity-plan.md)确保集群能够处理业务所需的工作负载。 ### 组件管理 - **Cluster Failover:** 通过设置 [Remote WAL](./wal/remote-wal/configuration.md) 以实现高可用性。 - **管理元数据:** 为 GreptimeDB 设置[元数据存储](./manage-data/overview.md)。 ### 监控 - **监控:** 通过指标、Traces 和运行时信息[监控集群的健康状况和性能](./monitoring/overview.md)。 ### 数据管理和性能 - **数据管理:** 通过[管理数据策略](/user-guide/deployments-administration/manage-data/overview.md) 以防止数据丢失、降低成本并优化性能。 - **性能调优:** 查看[性能调优技巧](/user-guide/deployments-administration/performance-tuning/performance-tuning-tips.md)并学习如何[设计表结构](/user-guide/deployments-administration/performance-tuning/design-table.md)以提高性能。 ### 灾难恢复 - **灾难恢复:** 实施[灾难恢复策略](/user-guide/deployments-administration/disaster-recovery/overview.md)以保护你的数据并确保业务连续性。 ### 其他 - **在 Android 上运行:** 了解如何[在 Android 设备上运行 GreptimeDB](run-on-android.md)。 - **升级:** 按照[升级指南](/user-guide/deployments-administration/upgrade.md)升级 GreptimeDB。 --- ## 数据建模指南 表结构设计将极大影响写入和查询性能。 在写入数据之前,你需要了解业务中涉及到的数据类型、数据规模以及常用查询, 并根据这些数据特征进行数据建模。 本文档将详细介绍 GreptimeDB 的数据模型使用指南,以及常见场景的表结构设计方式。 ## 了解 GreptimeDB 的数据模型 在阅读本文档之前,请先阅读 GreptimeDB [数据模型文档](/user-guide/concepts/data-model.md)。 ## 基本概念 **基数(Cardinality)**:指数据集中唯一值的数量。可以分为"高基数"和"低基数": - **低基数(Low Cardinality)**:低基数列通常具有固定值。 唯一值的总数通常不超过1万个。 例如,`namespace`、`cluster`、`http_method` 通常是低基数的。 - **高基数(High Cardinality)**:高基数列包含大量的唯一值。 例如,`trace_id`、`span_id`、`user_id`、`uri`、`ip`、`uuid`、`request_id`、表的自增 ID,时间戳通常是高基数的。 ## 列类型 在 GreptimeDB 中,列被分为三种语义类型:`Tag`、`Field` 和 `Timestamp`。 时间戳通常表示数据采样的时间或日志/事件发生的时间。 GreptimeDB 使用 `TIME INDEX` 约束来标识 `Timestamp` 列。 因此,`Timestamp` 列也被称为 `TIME INDEX` 列。 如果你有多个时间戳数据类型的列,你只能将其中一个定义为 `TIME INDEX`,其他的定义为 `Field` 列。 在 GreptimeDB 中,Tag 列是可选的。Tag 列的主要用途包括: 1. 定义存储时数据的排序方式。 GreptimeDB 使用 `PRIMARY KEY` 约束来定义 tag 列和 tag 的排序顺序。 与传统数据库不同,GreptimeDB 的主键是用来定义时间序列的。 GreptimeDB 中的表按照 `(primary key, timestamp)` 的顺序对行进行排序。 这提高了具有相同 tag 数据的局部性。 如果没有定义 tag 列,GreptimeDB 按时间戳对行进行排序。 2. 唯一标识一个时间序列。 当表不是 append-only 模式时,GreptimeDB 根据时间戳在同一时间序列(主键)下去除重复行。 3. 便于从使用 label 或 tag 的其他时序数据库迁移。 这种顺序就是磁盘上 Parquet SST 文件中的物理行布局。 要了解数据在 SST 文件中如何组织,以及这种排序、tag 基数和索引为什么会影响性能,详见[存储引擎](/contributor-guide/datanode/storage-engine.md#sst-文件中的数据布局)文档。 ## 主键 ### 主键是可选的 错误的主键或索引可能会显著降低性能。 通常,你可以创建一个没有主键的仅追加表,因为对于许多场景来说,按时间戳排序数据已经有不错测性能了。 这也可以作为性能基准。 ```sql CREATE TABLE http_logs ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request_id STRING, request STRING, ) with ('append_mode'='true'); ``` `http_logs` 表是存储 HTTP 服务器日志的示例。 - `'append_mode'='true'` 选项将表创建为仅追加表。 这确保一个日志不会覆盖另一个具有相同时间戳的日志。 - 该表按时间对日志进行排序,因此按时间搜索日志效率很高。 ### 主键设计与 SST 格式 当有适合的列且满足以下条件之一时,可以使用主键: - 大多数查询可以从排序中受益。 - 你需要通过主键和时间索引对行进行去重(包括删除)。 例如,如果你总是只查询特定应用程序的日志,可以将 `application` 列设为主键(tag)。 ```sql SELECT message FROM http_logs WHERE application = 'greptimedb' AND access_time > now() - '5 minute'::INTERVAL; ``` 应用程序的数量通常是有限的。表 `http_logs_v2` 使用 `application` 作为主键。 它按应用程序对日志进行排序,因此查询同一应用程序下的日志速度更快,因为它只需要扫描少量行。设置 tag 还能减少磁盘空间,因为它提高了数据的局部性,对压缩更友好。 ```sql CREATE TABLE http_logs_v2 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request_id STRING, request STRING, PRIMARY KEY(application), ) with ('append_mode'='true'); ``` 过长的主键将对插入性能产生负面影响并增加内存占用。主键最好不超过 5 个列。 #### 选择合适的 SST 格式 GreptimeDB 支持两种 [SST 格式](/reference/sql/create.md#创建指定-sst-格式的表):`flat`(默认)和 `primary_key`。它们针对不同的主键基数进行了优化。 默认的 `flat` 格式适用于较广范围的主键基数,包括 `trace_id`、`span_id` 或 `user_id` 等高基数列。在 `flat` 格式下,当按某些列排序对查询有益,或者需要按这些列去重时,可以将高基数列放入主键。请注意,在高基数主键上进行去重始终是昂贵的——如果可以容忍重复,使用 append-only 表能获得最佳性能。 ```sql CREATE TABLE http_logs_v3 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING, http_refer STRING, user_agent STRING, request_id STRING, request STRING, PRIMARY KEY(application, request_id), ) with ('append_mode'='true'); ``` 当主键基数较低时(通常不超过 10 万个不同值),`primary_key` 格式可能会带来更好的性能。一般情况下,建议优先使用默认的 `flat` 格式,除非你已经验证 `primary_key` 更适合你的场景。 你可以通过 `ALTER TABLE` 修改已有表的 SST 格式。GreptimeDB 旧版本默认使用 `primary_key` 格式,因此如果你从旧版本升级,或者不确定一张表当前使用的是哪种格式,可以将其切换为 `flat`: ```sql -- 切换为 flat(默认)。 ALTER TABLE http_logs_v3 SET 'sst_format' = 'flat'; -- 在主键基数较低的场景下切换为 primary_key。 ALTER TABLE http_logs_v3 SET 'sst_format' = 'primary_key'; ``` 选取 tag 列的建议: - 在 `WHERE`/`GROUP BY`/`ORDER BY` 中频繁出现的低基数列。 这些列通常很少变化。 例如,`namespace`、`cluster` 或 AWS `region`。 - 无需将所有低基数列设为 tag,因为这可能影响写入和查询性能。 - 通常对 tag 使用短字符串和整数,避免 `FLOAT`、`DOUBLE`、`TIMESTAMP`。 - 在默认的 `flat` 格式下,`trace_id`、`span_id` 和 `user_id` 等高基数列也可以作为 tag 使用。 ## 索引 除了主键外,你还可以使用倒排索引按需加速特定查询。 GreptimeDB 支持倒排索引,可以加速对低基数列的过滤。 创建表时,可以使用 `INVERTED INDEX` 子句指定[倒排索引](/contributor-guide/datanode/data-persistence-indexing.md#倒排索引)列。 例如,`http_logs_v3` 为 `http_method` 列添加了倒排索引。 ```sql CREATE TABLE http_logs_v3 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING INVERTED INDEX, http_refer STRING, user_agent STRING, request_id STRING, request STRING, PRIMARY KEY(application), ) with ('append_mode'='true'); ``` 以下查询可以使用 `http_method` 列上的倒排索引。 ```sql SELECT message FROM http_logs_v3 WHERE application = 'greptimedb' AND http_method = `GET` AND access_time > now() - '5 minute'::INTERVAL; ``` 倒排索引支持以下运算符: - `=` - `<` - `<=` - `>` - `>=` - `IN` - `BETWEEN` - `~` ### 跳数索引 对于高基数列如 `trace_id`、`request_id`,使用[跳数索引](/user-guide/manage-data/data-index.md#跳数索引)更为合适。 这种方法的存储开销更低,资源使用量更少,特别是在内存和磁盘消耗方面。 示例: ```sql CREATE TABLE http_logs_v4 ( access_time TIMESTAMP TIME INDEX, application STRING, remote_addr STRING, http_status STRING, http_method STRING INVERTED INDEX, http_refer STRING, user_agent STRING, request_id STRING SKIPPING INDEX, request STRING, PRIMARY KEY(application), ) with ('append_mode'='true'); ``` 以下查询可以使用跳数索引过滤 `request_id` 列。 ```sql SELECT message FROM http_logs_v4 WHERE application = 'greptimedb' AND request_id = `25b6f398-41cf-4965-aa19-e1c63a88a7a9` AND access_time > now() - '5 minute'::INTERVAL; ``` 然而,请注意跳数索引的查询功能通常不如倒排索引丰富。 跳数索引无法处理复杂的过滤条件,在低基数列上可能有较低的过滤性能。它只支持等于运算符。 ### 全文索引 对于需要分词和按术语搜索的非结构化日志消息,GreptimeDB 提供了全文索引。 例如,`raw_logs` 表在 `message` 字段中存储非结构化日志。 ```sql CREATE TABLE IF NOT EXISTS `raw_logs` ( message STRING NULL FULLTEXT INDEX WITH(analyzer = 'English', case_sensitive = 'false'), ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), ) with ('append_mode'='true'); ``` `message` 字段使用 `FULLTEXT INDEX` 选项进行全文索引。 更多信息请参见[fulltext 列选项](/reference/sql/create.md#fulltext-列选项)。 存储和查询结构化日志通常比带有全文索引的非结构化日志性能更好。 建议[使用 Pipeline](/user-guide/logs/quick-start.md#创建-pipeline) 将日志转换为结构化日志。 ### 何时使用索引 GreptimeDB 中的索引十分灵活。 你可以为任何列创建索引,无论该列是 tag 还是 field。 为 time index 列创建额外索引没有意义。 另外,你一般不需要为所有列创建索引。 因为维护索引可能引入额外成本并阻塞 ingestion。 不良的索引可能会占用过多磁盘空间并使查询变慢。 你可以用没有额外索引的表作为 baseline。 如果查询性能已经可接受,就无需为表创建索引。 在以下情况可以为列创建索引: - 该列在过滤条件中频繁出现。 - 没有索引的情况下过滤该列不够快。 - 该列有合适的索引类型。 下表列出了所有索引类型的适用场景。 | | 倒排索引 | 全文索引 | 跳数索引| | ----- | ----------- | ------------- |------------- | | 适用场景 | - 过滤低基数列 | - 文本内容搜索 | - 精确过滤高基数列 | | 创建方法 | - 使用 `INVERTED INDEX` 指定 |- 在列选项中使用 `FULLTEXT INDEX` 指定 | - 在列选项中使用 `SKIPPING INDEX` 指定 | ## 去重 如果需要去重,可以使用默认表选项,相当于将 `append_mode` 设为 `false` 并启用去重功能。 ```sql CREATE TABLE IF NOT EXISTS system_metrics ( host STRING, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(host), TIME INDEX(ts) ); ``` 当表不是 append-only 的时候,GreptimeDB 会通过相同的主键和时间戳对行进行去重。 例如,`system_metrics` 表通过 `host` 和 `ts` 删除重复行。 ### 数据更新和合并 GreptimeDB 支持两种不同的去重策略:`last_row` 和 `last_non_null`。 你可以通过 `merge_mode` 表选项来指定策略。 GreptimeDB 使用基于 LSM-Tree 的存储引擎, 不会就地覆盖旧数据,而是允许多个版本的数据共存。 这些版本在查询时再合并。 默认的合并行为是 `last_row`,意味着只保留最近插入的行。 ![merge-mode-last-row](/merge-mode-last-row.png) 在 `last_row` 合并模式下, 对于相同主键和时间值,只返回最新的行, 所以更新一行时需要提供所有 field 的值。 对于只需要更新特定 field 值而其他 field 保持不变的场景, 可以将 `merge_mode` 选项设为 `last_non_null`。 该模式在查询时会选取每个字段的最新的非空值, 这样可以在更新时只提供需要更改的 field 的值。 ![merge-mode-last-non-null](/merge-mode-last-non-null.png) 为了与 InfluxDB 的更新行为一致,通过 InfluxDB line protocol 自动创建的表默认启用 `last_non_null` 合并模式。 `last_row` 合并模式不需要检查每个单独的字段值,因此通常比 `last_non_null` 模式更快。 请注意,append-only 表不能设置 `merge_mode`,因为它们不执行合并。 ### 何时使用 append-only 表 如果不需要以下功能,可以使用 append-only 表: - 去重 - 删除 GreptimeDB 通过去重功能实现 `DELETE`,因此 append-only 表目前不支持删除。 去重需要更多的计算并限制了写入和查询的并行性,所以使用 append-only 表通常具有更好的性能。 ## 宽表 vs. 多表 在监控或 IoT 场景中,通常同时收集多个指标。 我们建议将同时收集的指标放在单个表中,以提高读写吞吐量和数据压缩效率。 ![wide_table](/wide_table.png) 比较遗憾,Prometheus 的存储还是多表单值的方式,不过 GreptimeDB 的 Prometheus Remote Storage protocol 通过[Metric Engine](/contributor-guide/datanode/metric-engine.md)在底层使用宽表数据共享。 ## 分布式表 GreptimeDB 支持对数据表进行分区,以分散读写热点并实现水平扩展。 ### 关于分布式表的两个误解 作为时序数据库,GreptimeDB 在存储层自动基于 TIME INDEX 列对数据进行分区。 因此,你无需也不建议按时间分区数据 (例如,每天一个分区或每周一个表)。 此外,GreptimeDB 是列式存储数据库, 因此对表进行分区是指按行进行水平分区, 每个分区包含所有列。 ### 何时分区以及确定分区数量 单个表能够利用机器中的所有资源,特别是在查询的时候。 分区表并不总是能提高性能: - 分布式查询计划并不总是像本地查询计划那样高效。 - 分布式查询可能会引入网络间额外的数据传输。 因此,除非单台机器不足以服务表,否则无需分区表。 例如: - 本地磁盘空间不足以存储数据或在使用对象存储时缓存数据。 - 你需要更多 CPU 来提高查询性能或更多内存用于高开销的查询。 - 磁盘吞吐量成为瓶颈。 - 写入速率大于单个节点的吞吐量。 GreptimeDB 在每次主要版本更新时都会发布[benchmark report](https://github.com/GreptimeTeam/greptimedb/tree/v1.0.2/docs/benchmarks/tsbs), 里面提供了单个分区的写入吞吐量作为参考。 你可以在你的目标场景根据该报告来估计写入量是否接近单个分区的限制。 估计分区总数时,可以考虑写入吞吐量并额外预留 50% 的 CPU 资源,以确保查询性能和稳定性。也可以根据需要调整此比例。例如,如果查询较多,那么可以预留更多 CPU 资源。 ### 分区方法 GreptimeDB 使用表达式定义分区规则。 为获得最佳性能,建议选择均匀分布、稳定且与查询条件一致的分区键。 例如: - 按 trace id 的前缀分区。 - 按数据中心名称分区。 - 按业务名称分区。 分区键应该尽量贴合查询条件。 例如,如果大多数查询针对特定数据中心的数据,那么可以使用数据中心名称作为分区键。 如果不了解数据分布,可以对现有数据执行聚合查询以收集相关信息。 更多详情,请参考[表分区指南](/user-guide/deployments-administration/manage-data/table-sharding.md#partition) --- ## 性能调优技巧 GreptimeDB 实例的默认配置可能不适合所有场景。因此根据场景调整数据库配置和使用方式相当重要。 GreptimeDB 提供了各种指标来帮助监控和排查性能问题。官方仓库里提供了用于独立模式和集群模式的 [Grafana dashboard 模版](https://github.com/GreptimeTeam/greptimedb/tree/main/grafana)。 ## 查询 ### ANALYZE QUERY GreptimeDB 支持查询分析功能,通过 `EXPLAIN ANALYZE [VERBOSE] ` 语句可以看到逐步的查询耗时。 ### 指标 以下指标可用于诊断查询性能问题: | 指标 | 类型 | 描述 | |---|---|---| | greptime_mito_read_stage_elapsed_bucket | histogram | 存储引擎中查询不同阶段的耗时。 | | greptime_mito_cache_bytes | gauge | 缓存内容的大小 | | greptime_mito_cache_hit | counter | 缓存命中总数 | | greptime_mito_cache_miss | counter | 缓存未命中总数 | ### 增大缓存大小 可以监控 `greptime_mito_cache_bytes` 和 `greptime_mito_cache_miss` 指标来确定是否需要增加缓存大小。这些指标中的 `type` 标签表示缓存的类型。 如果 `greptime_mito_cache_miss` 指标一直很高并不断增加,或者 `greptime_mito_cache_bytes` 指标达到缓存容量,可能需要调整存储引擎的缓存大小配置。 以下是一个例子: ```toml [[region_engine]] [region_engine.mito] # 写入缓存的缓存大小。此缓存的 `type` 标签值为 `file`。 write_cache_size = "10G" # 在写入缓存未命中时从对象存储下载文件填充缓存 enable_refill_cache_on_read = true # SST 元数据的缓存大小。此缓存的 `type` 标签值为 `sst_meta`。 sst_meta_cache_size = "128MB" # 向量和箭头数组的缓存大小。此缓存的 `type` 标签值为 `vector`。 vector_cache_size = "512MB" # SST 行组页面的缓存大小。此缓存的 `type` 标签值为 `page`。 page_cache_size = "512MB" # 时间序列查询结果(例如 `last_value()`)的缓存大小。此缓存的 `type` 标签值为 `selector_result`。 selector_result_cache_size = "512MB" [region_engine.mito.index] ## 索引暂存目录的最大容量。 staging_size = "10GB" ``` 一些建议: - 至少将写入缓存设置为磁盘空间的 1/10。使用对象存储时,建议使用较大的写入缓存。 - 使用对象存储时,GreptimeDB 默认在缓存未命中时自动下载文件以填充写入缓存(`enable_refill_cache_on_read = true`)。这可以提高查询性能,但会增加网络流量。如果你想减少网络使用或存储成本,可以考虑禁用此选项。 - 如果数据库内存使用率低于 20%,则可以至少将 `page_cache_size` 设置为总内存大小的 1/4 - 如果缓存命中率低于 50%,则可以将缓存大小翻倍 - 如果使用全文索引,至少将 `staging_size` 设置为磁盘空间的 1/10 ### 选择合适的 SST 格式 GreptimeDB 支持两种 [SST 格式](/reference/sql/create.md#创建指定-sst-格式的表):`flat` 和 `primary_key`。根据主键的基数选择合适的格式可以显著提升性能。 - **`flat` 格式(默认)**:针对高基数主键进行了优化。如果主键包含 `trace_id` 或 `uuid` 等列,`flat` 格式可以提供更好的写入和查询性能。对于具有高基数主键的表,还可以考虑使用 [append-only](/reference/sql/create.md#创建-append-only-表) 表来进一步提升性能。 - **`primary_key` 格式**:当主键基数不高时,可能会提供更好的性能。 更多细节(包括如何修改已有表的格式)请参阅[选择合适的 SST 格式](/user-guide/deployments-administration/performance-tuning/design-table.md#选择合适的-sst-格式)。 ### 尽可能使用 append-only 表 一般来说,append-only 表具有更高的扫描性能,因为存储引擎可以跳过合并和去重操作。此外,如果表是 append-only 表,查询引擎可以使用统计信息来加速某些查询。 如果表不需要去重或性能优先于去重,我们建议为表启用 [append_mode](/reference/sql/create.md#创建-append-only-表)。例如,日志表应该是 append-only 表,因为日志消息可能具有相同的时间戳。 ### 禁用预写式日志(WAL) 如果您是从 Kafka 等可以重放的数据源消费并写入到 GreptimeDB,可以通过禁用 WAL 来进一步提升写入吞吐量。 请注意,当 WAL 被禁用后,未刷新到磁盘或对象存储的数据将无法恢复,需要从原始数据源重新恢复,比如重新从 Kafka 读取或重新抓取日志。 通过设置表选项 `skip_wal='true'` 来禁用 WAL: ```sql CREATE TABLE logs( message STRING, ts TIMESTAMP TIME INDEX ) WITH (skip_wal = 'true'); ``` ## 写入 ### 指标 以下指标有助于诊断写入问题: | 指标 | 类型 | 描述 | |---|---|---| | greptime_mito_write_stage_elapsed_bucket | histogram | 存储引擎中处理写入请求的不同阶段的耗时 | | greptime_mito_write_buffer_bytes | gauge | 当前为写入缓冲区(memtables)分配的字节数(估算) | | greptime_mito_write_rows_total | counter | 写入存储引擎的行数 | | greptime_mito_write_stall_total | gauge | 当前由于内存压力过高而被阻塞的行数 | | greptime_mito_write_reject_total | counter | 由于内存压力过高而被拒绝的行数 | | raft_engine_sync_log_duration_seconds_bucket | histogram | 将 WAL 刷入磁盘的耗时 | | greptime_mito_flush_elapsed | histogram | 刷入 SST 文件的耗时 | ### 批量写入行 批量写入是指通过同一个请求将多行数据发送到数据库。这可以显著提高写入吞吐量。建议的起始值是每批 1000 行。如果延迟和资源使用仍然可以接受,可以扩大攒批大小。 ### 按时间窗口写入 虽然 GreptimeDB 可以处理乱序数据,但乱序数据仍然会影响性能。GreptimeDB 从写入的数据中推断出时间窗口的大小,并根据时间戳将数据划分为多个时间窗口。如果写入的行不在同一个时间窗口内,GreptimeDB 需要将它们拆分,这会影响写入性能。 通常,实时数据不会出现上述问题,因为它们始终使用最新的时间戳。如果需要将具有较长时间范围的数据导入数据库,我们建议提前创建表并 [指定 compaction.twcs.time_window 选项](/reference/sql/create.md#创建自定义-compaction-参数的表)。 ## 表结构 ### 使用多值 在设计架构时,我们建议将可以一起收集的相关指标放在同一个表中。这也可以提高写入吞吐量和压缩率。 例如,以下三个表收集了 CPU 的使用率指标。 ```sql CREATE TABLE IF NOT EXISTS cpu_usage_user ( hostname STRING NULL, usage_value BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); CREATE TABLE IF NOT EXISTS cpu_usage_system ( hostname STRING NULL, usage_value BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); CREATE TABLE IF NOT EXISTS cpu_usage_idle ( hostname STRING NULL, usage_value BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); ``` 我们可以将它们合并为一个具有三个字段的表。 ```sql CREATE TABLE IF NOT EXISTS cpu ( hostname STRING NULL, usage_user BIGINT NULL, usage_system BIGINT NULL, usage_idle BIGINT NULL, ts TIMESTAMP(9) NOT NULL, TIME INDEX (ts), PRIMARY KEY (hostname) ); ``` --- ## 在安卓平台运行 从 v0.4.0 开始,GreptimeDB 支持在采用了 ARM64 CPU 和 Android API 23 版本以上的安卓平台运行。 ## 安装终端模拟器 您可以从 [GitHub release 页面](https://github.com/termux/termux-app/releases/latest) 下载 [Termux 终端模拟器](https://termux.dev/) 来运行 GreptimeDB. ## 下载 GreptimeDB 的二进制 请执行以下命令来下载安卓平台的 GreptimeDB 二进制: ```bash VERSION=$(curl -sL \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/repos/GreptimeTeam/greptimedb/releases/latest" | sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p') curl -sOL "https://github.com/GreptimeTeam/greptimedb/releases/download/${VERSION}/greptime-android-arm64-${VERSION}.tar.gz" tar zxvf ./greptime-android-arm64-${VERSION}.tar.gz ./greptime -V ``` 如果下载成功,以上命令将输出当前 GreptimeDB 的版本信息。 ## 创建 GreptimeDB 的配置文件 您可以通过以下命令来创建一个最小化的配置文件以允许从局域网访问 GreptimeDB: ```bash DATA_DIR="$(pwd)/greptimedb-data" mkdir -p ${DATA_DIR} cat < ./config.toml [http] addr = "0.0.0.0:4000" [grpc] bind_addr = "0.0.0.0:4001" [mysql] addr = "0.0.0.0:4002" [storage] data_home = "${DATA_DIR}" type = "File" EOF ``` ## 从命令行启动 GreptimeDB ```bash ./greptime --log-dir=$(pwd)/logs standalone start -c ./config.toml ``` ## 从局域网连接运行在安卓设备上的 GreptimeDB > 您可以通过`ifconfig`来获取您所使用的安卓设备的网络地址。 在启动 GreptimeDB 后,您可以从局域网内安装了 MySQL 客户端的设备上通过 MySQL 协议访问 GreptimeDB。 ```bash mysql -h -P 4002 ``` 连接成功后,您可以像在任何其他平台一样使用运行在安卓设备上的 GreptimeDB! ``` Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 5.1.10-alpha-msql-proxy Greptime Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> CREATE TABLE monitor (env STRING, host STRING, ts TIMESTAMP, cpu DOUBLE DEFAULT 0, memory DOUBLE, TIME INDEX (ts), PRIMARY KEY(env,host)); Query OK, 0 rows affected (0.14 sec) mysql> INSERT INTO monitor(ts, env, host, cpu, memory) VALUES -> (1655276557000,'prod', 'host1', 66.6, 1024), -> (1655276557000,'prod', 'host2', 66.6, 1024), -> (1655276557000,'prod', 'host3', 66.6, 1024), -> (1655276558000,'prod', 'host1', 77.7, 2048), -> (1655276558000,'prod', 'host2', 77.7, 2048), -> (1655276558000,'test', 'host3', 77.7, 2048), -> (1655276559000,'test', 'host1', 88.8, 4096), -> (1655276559000,'test', 'host2', 88.8, 4096), -> (1655276559000,'test', 'host3', 88.8, 4096); Query OK, 9 rows affected (0.14 sec) mysql> mysql> select * from monitor where env='test' and host='host3'; +------+-------+---------------------+------+--------+ | env | host | ts | cpu | memory | +------+-------+---------------------+------+--------+ | test | host3 | 2022-06-15 15:02:38 | 77.7 | 2048 | | test | host3 | 2022-06-15 15:02:39 | 88.8 | 4096 | +------+-------+---------------------+------+--------+ 2 rows in set (0.20 sec) ``` --- ## 问题排查 在遇到错误或者性能问题时,我们可以基于指标和日志了解 GreptimeDB 的状态。这些信息也可以帮助进一步排查问题的原因。 以下列举了部分常见异常情况的排查方法。对于无法简单定位原因的情况,提供指标和日志给官方团队也能提高官方排查问题的效率。 ## 查看 CPU 和 Memory 负载 可直接从 Dashboard 中查看对应组件的 CPU 和 Memory 负载,其中 CPU 显示的是 millicore,Memory 则是当前进程的 RSS。此时需要要关注对应的 CPU 和 Memory 负载是否有超过 Pod 的 Limit,如果 CPU 已经触碰到 Pod 的 Limit,那么将会触发 throttle,用户可感受的现象就是请求处理变慢;如果 Memory 已经到达 Limit 超过 70%,那么将有可能会被 OOM。 ## 创建 flow 失败 创建 flow 失败时,一个场景的原因是没有部署 flownode,可以检查 - 集群中是否部署了 flownode - 集群中 flownode 状态是否 READY 如果已经部署了 flownode,则可以通过排查 metasrv 和 flownode 的日志进一步排查,也可以通过内部表查看 flow 节点是否成功创建: ```sql select * from information_schema.cluster_info; ``` ## 对象存储配置问题 对象存储配置不对时,GreptimeDB 访问对象存储会出现异常。如果 GreptimeDB 没有存储任何数据,一般不需要访问对象存储,因此刚部署完成时可能观察不到错误。当创建一张表或者开始通过写入协议往 GreptimeDB 写入数据后,则可以观察到请求报错。 通常 DB 返回错误信息会包含对象存储的报错。可以通过 DB 的错误日志找到对象存储具体的报错信息。一些常见的错误原因包括 - Access Key 或 Secret Access Key 填写错误 - 对象存储的权限配置不对 - 如果使用的是腾讯云 COS 的 S3 兼容 API,由于腾讯云[禁用了 path-style 域名](https://cloud.tencent.com/document/product/436/102489),需要在 GreptimeDB 的 S3 配置中设置 `enable_virtual_host_style = true` 以 S3 为例,GreptimeDB 需要用到的权限包括 ```txt "s3:PutObject", "s3:ListBucket", "s3:GetObject", "s3:DeleteObject" ``` ## 写入吞吐低 通过大盘里的 Ingestion 相关面板可以观察到写入的吞吐: ![ingestion rate](/ingestion-rate.jpg) 如果写入吞吐低于预期压力,那么有可能是写入延时较高,DB 出现积压导致的。大盘在 `Frontend Requests` 区域中提供了一些面板来观察请求的耗时: ![p99-latencies](/dashboard-p99-latencies.jpg) 你可以通过 `Mito Engine` 区域的 `Write Stall` 面板观察是否有节点出现了 stall(stall 的值长时间超过 0)。 如果有,则说明节点写入出现了瓶颈。 ![write-stall](/write-stall.jpg) 通过观察 `Write Buffer` 的面板也可以观察用于写入的 buffer 的大小变化,如果 buffer 很快被写满,那么可以考虑成比例调大 `global_write_buffer_size` 和 `global_write_buffer_reject_size`: ![write-buffer](/write-buffer.jpg) 通过 Write Stage 面板可以查看写入耗时高的阶段: ![write-stage](/write-stage.jpg) 可以通过 Compaction/Flush 相关面板查看后台任务的情况 - 是否出现频繁的 flush 操作,如果有,则可以考虑成比例调大 `global_write_buffer_size` 和 `global_write_buffer_reject_size` - 是否有长时间的 compaction 和 flush 操作,如果有,则写入有可能受这些后台任务影响 此外,通过日志里 `flush memtables` 相关的日志可以看到单次 flush 的耗时, ## 写入内存消耗过高 DB 写入过程中会估算出当前所有 memtable 的总大小。可以通过 `Write Buffer` 面板查看 memtable 的内存占用。 ![write-buffer-memtable](/write-buffer-memtable.jpg) 注意这部分的值可能比实际申请的内存要小。 如果发现写入时 DB 的内存增长速度过快,或者写入经常出现 OOM 的情况,则可能跟表结构设计不合理有关。 一个常见的原因是主键(Primary Key)设计不合理。如果主键的数量过多,则会导致写入时消耗非常多的内存,可能导致数据库内存占用过大。出现这种情况时,往往 `Write Buffer` 会长期处于高位置。这种情况增加写入 buffer 的大小一般不会改善问题,需要减少主键的列数,或者去掉高基数的主键列。 ## 查询耗时高 如果查询的耗时较高,可以通过在查询前面加上 `EXPLAIN ANALYZE` 或 `EXPLAIN ANALYZE VERBOSE` 重新执行。查询的结果会带上各个阶段执行的耗时用于协助排查。 此外 `Read Stage` 的面板也能协助了解不同阶段的查询耗时: ![read-stage](/read-stage.jpg) ## 缓存写满 如果需要了解各个缓存的大小,可以通过 `Cached Bytes` 面板查询节不同缓存已经使用的大小: ![cached-bytes](/cached-bytes.jpg) 对于查询耗时高的节点,也可以通过查询缓存大小来判断是否缓存已经写满。 ## 对象存储耗时 可以通过大盘中的 `OpenDAL` 区域的面板查看对象存储操作的耗时,例如以下面板是对象存储写入操作的响应耗时: ![opendal](/opendal.jpg) 如果怀疑对象存储操作出现抖动,可以观察相关的面板。 --- ## 版本升级 ## 概览 本指南提供 GreptimeDB 的升级说明,包括每个版本的兼容性信息和破坏性变更。升级前,请确保查看与你的升级路径相关的破坏性变更。 完整的版本历史和功能新增,请参见[发行说明](/release-notes/)。 ## 升级到 v1.0 的路径 ### 从 v0.16 到 v1.0 如果你当前运行的是 v0.16,可以直接升级到 v1.0。请参见[从 v0.16 升级到 v1.0](#从-v016-升级到-v10) 了解所有相关的破坏性变更。 ### 从 v0.17 到 v1.0 如果你当前运行的是 v0.17,可以直接升级到 v1.0。请参见[从 v0.17 升级到 v1.0](#从-v017-升级到-v10) 了解破坏性变更。 ### 从更早版本升级 **重要提示:** 本指南仅涵盖从 v0.16 及更高版本的升级。 如果你运行的版本早于 v0.16,必须先按照当前版本的升级文档升级到 v0.16。成功升级到 v0.16 后,再使用本指南升级到 v1.0。 ## 各版本的破坏性变更 ### 从 v0.17 升级到 v1.0 #### 移除 Jaeger HTTP Header **影响:** HTTP header 废弃 HTTP header `x-greptime-jaeger-time-range-for-operations` 已被废弃并移除。 **需要的操作:** - 如果你在 Jaeger 数据源或代理中配置了此 header,请从配置中移除 - 此 header 将不再有任何效果 #### Metric Engine 默认启用稀疏主键编码 **影响:** 默认配置变更,带来性能提升 Metric Engine 现在默认启用**稀疏主键编码**,以提高指标场景的存储效率和查询性能。 **配置变更:** - **新的默认值:** `sparse_primary_key_encoding = true` - **已废弃:** `experimental_sparse_primary_key_encoding`(请使用 `sparse_primary_key_encoding` 代替) **需要的操作:** - 此变更不会导致数据格式兼容性问题 - 所有指标表将默认自动使用稀疏编码 - 如果想继续使用旧的编码方法,请显式设置: ```toml [metric_engine] sparse_primary_key_encoding = false ``` #### `greptime_identity` Pipeline JSON 行为变更 **影响:** JSON 处理逻辑变更 `greptime_identity` pipeline 中的 JSON 处理逻辑发生了重大变化: **新行为:** - 嵌套的 JSON 对象会自动展平为使用点号分隔的独立列(例如 `object.a`、`object.b`) - 数组存储为 JSON 字符串而不是 JSON 对象 - `flatten_json_object` 参数已被移除 - 新的 `max_nested_levels` 参数控制展平深度(默认:10 层) - 当超过深度限制时,剩余的嵌套结构将序列化为 JSON 字符串 **需要的操作:** 1. 检查使用 `greptime_identity` 的 pipeline 配置 2. 移除已废弃的 `flatten_json_object` 参数的任何使用 3. 调整引用嵌套 JSON 字段的查询以使用新的点号表示法 4. 如果有深层嵌套的 JSON(>10 层),考虑适当设置 `max_nested_levels` **示例:** v0.17 之前: ```json { "user": { "name": "Alice", "age": 30 } } ``` 存储为单个 JSON 列。 v1.0 之后: ``` user.name = "Alice" user.age = 30 ``` 存储为独立的列。 #### Metric Engine TSID 生成算法变更 **影响:** 时间序列 ID 生成优化,对查询有影响 TSID(时间序列 ID)生成算法已通过将 `mur3::Hasher128` 替换为高性能的 `fxhash::FxHasher` 进行优化,包括针对没有 NULL 标签的序列的快速路径。 **性能提升:** - 常规场景:快 5-6 倍 - 包含 NULL 标签的场景:快约 2.5 倍 **破坏性变更影响:** 这是一个**破坏性变更**,影响时间序列识别: - **升级前(时间 < t):** 数据使用旧算法生成 TSID - **升级后(时间 > t):** 数据使用新算法生成 TSID **查询行为:** - 时间范围**跨越升级时间 `t`** 的查询可能在时间 `t` 附近出现轻微的时间序列匹配差异 - 时间范围**不包含 `t`** 的查询不受影响 **需要的操作:** 选择以下升级策略之一: 1. **直接升级(推荐给大多数用户):** - 接受升级时间附近的轻微查询差异 - 适用于可以接受升级时间附近近似结果的场景 2. **导出-升级-导入(零容忍场景):** - 如果无法接受任何差异,使用此完全兼容的升级方法: 1. 升级前导出所有数据 2. 升级到 v1.0 3. 将数据导入回新版本 - 参考[备份与恢复文档](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data/) ### 从 v0.16 升级到 v1.0 如果你从 v0.16 升级,需要查看: 1. **从 v0.17 到 v1.0 的所有破坏性变更**(如上所列) 2. **v0.17.0 的破坏性变更**(如下所列) 这确保你了解 v0.16 和 v1.0 之间发生的所有变更。 ### v0.17.0 破坏性变更 #### 有序集聚合函数 **影响:** SQL 语法变更 有序集聚合函数现在需要 `WITHIN GROUP (ORDER BY …)` 子句。 **之前:** ```sql SELECT approx_percentile_cont(latency, 0.95) FROM metrics; ``` **之后:** ```sql SELECT approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) FROM metrics; ``` **需要的操作:** 更新所有使用有序集聚合函数(`approx_percentile_cont`、`approx_percentile_cont_weight` 等)的查询,包含 `WITHIN GROUP (ORDER BY …)` 子句。 #### MySQL 协议注释样式 **影响:** 注释语法严格性 MySQL 协议中不再允许不正确的注释样式。注释必须以 `--` 开头,而不是 `---`。 **之前:** ```sql --- 这是一个注释 SELECT * FROM table; ``` **之后:** ```sql -- 这是一个注释 SELECT * FROM table; ``` **需要的操作:** 更新任何使用 `---` 样式注释的 SQL 脚本或查询,改用标准的 `--` 格式。 ## v1.0 的其他变更(非破坏性) ### v1.0.0-beta.3 #### 缓存配置改进 缓存架构已重构以获得更好的性能: **新配置:** - `region_engine.mito.manifest_cache_size`(默认:256MB)- 专用的 manifest 文件缓存 **移除的配置:** - `storage.cache_path` - `storage.enable_read_cache` - `storage.cache_capacity` **需要的操作:** 更新配置文件以使用新的 `manifest_cache_size` 设置,并移除已废弃的存储缓存选项。 ### v1.0.0-beta.2 #### 改进的数据库兼容性 - 数值类型别名与 PostgreSQL 和 MySQL 标准对齐 - 更好的 PostgreSQL 扩展查询支持 - 改进的 MySQL 二进制协议处理 **需要的操作:** 测试你的应用程序以确保与改进后的行为兼容。 ## 将升级对业务带来的影响最小化 在升级 GreptimeDB 之前,请全面备份数据以防止潜在的数据丢失。此备份作为升级过程中出现任何问题时的安全保障。 ### 最佳实践 #### 滚动升级 在 Kubernetes 上采用[滚动升级](https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/)策略逐步更替 GreptimeDB 实例。该方案通过新旧实例渐进式替换,在确保服务持续可用的前提下实现零停机升级。 #### 自动重试 建议在客户端配置具备指数退避特性的自动重试策略,可有效规避升级过程中的瞬时服务不可用问题。 #### 暂停写操作 对于允许短暂维护的业务场景,可在升级窗口期暂时停止写入操作,此方案能最大限度保障数据一致性。 #### 双写 实施新旧版本双写机制,待新版本验证通过后逐步切换流量。该方案既能确保数据一致性校验,又可实现读流量灰度迁移。 ## 升级检查清单 在升级到 v1.0 之前,请完成以下检查清单: ### 升级前 - [ ] 查看与你的升级路径相关的所有破坏性变更 - [ ] **备份所有数据和配置** - [ ] 识别使用有序集聚合函数的查询(如果从 v0.16 或更早版本升级) - [ ] 识别使用 `greptime_identity` 处理 JSON 数据的 pipeline - [ ] 检查是否使用了已废弃的 Jaeger HTTP header(如果从 v0.17 或更早版本升级) - [ ] 如果使用 Metric Engine,检查指标表 ### 配置更新 - [ ] 更新配置文件(移除已废弃的缓存设置) - [ ] 如需要,更新 metric engine 配置(`sparse_primary_key_encoding`) - [ ] 更新 pipeline 配置(移除 `flatten_json_object`,如需要添加 `max_nested_levels`) ### 代码更新 - [ ] 更新使用有序集聚合的 SQL 查询以使用 `WITHIN GROUP (ORDER BY ...)` - [ ] 更新使用 `---` 注释的 SQL 脚本改用 `--` - [ ] 更新访问嵌套 JSON 字段的查询以使用点号表示法 - [ ] 如存在,移除 Jaeger header 配置 ### 测试与部署 - [ ] 在非生产环境中测试升级 - [ ] 验证查询结果,特别是: - 有序集聚合函数 - 嵌套 JSON 数据访问 - 指标查询(如果受 TSID 变更影响) - [ ] 规划滚动升级或维护窗口 - [ ] 准备回滚计划以防出现问题 - [ ] 升级后监控系统行为 ### Metric Engine 用户的特别考虑 如果由于 TSID 算法变更无法接受升级时间附近的查询差异: - [ ] 规划导出-升级-导入流程 - [ ] 为数据导出和导入分配充足时间 - [ ] 参考[备份与恢复文档](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data/) --- ## 本地 WAL 本节介绍如何配置 GreptimeDB Datanode 组件的本地 WAL。 ```toml [wal] provider = "raft_engine" file_size = "128MB" purge_threshold = "1GB" purge_interval = "1m" read_batch_size = 128 sync_write = false ``` ## 选项 如果你使用 Helm Chart 部署 GreptimeDB,可以参考[常见 Helm Chart 配置项](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md)了解如何通过注入配置文件以配置 Datanode。 | 配置项 | 描述 | 默认值 | | ----------------- | ----------------------------------------------------------------------------------------------- | ----------------- | | `provider` | WAL 的提供者。可选项:`raft_engine`(本地文件系统存储)、`kafka`(使用 Kafka 的远程 WAL 存储)或 `noop`(无操作 WAL 提供者) | `"raft_engine"` | | `dir` | 日志写入目录 | `{data_home}/wal` | | `file_size` | 单个 WAL 日志文件的大小 | `128MB` | | `purge_threshold` | 触发清理的 WAL 总大小阈值 | `1GB` | | `purge_interval` | 触发清理的时间间隔 | `1m` | | `read_batch_size` | 读取批次大小 | `128` | | `sync_write` | 是否在每次写入日志时调用 fsync | `false` | ## 最佳实践 ### 使用单独的高性能卷作为 WAL 目录 在部署 GreptimeDB 时,配置单独的卷作为 WAL 目录具有显著优势。这样做可以: - 使用高性能磁盘——包括专用物理卷或自定义的高性能 `StorageClass`,以提升 WAL 的写入吞吐量。 - 隔离 WAL I/O 与缓存文件访问,降低 I/O 竞争,提升整体系统性能。 如果你使用 Helm Chart 部署 GreptimeDB,可以参考[常见 Helm Chart 配置项](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md)了解如何配置专用 WAL 卷。 --- ## Noop WAL Noop WAL 是一种特殊的 WAL 提供者,用于 WAL 暂时不可用时的紧急情况。它不会存储任何 WAL 数据。 ## 可用性 Noop WAL **仅在集群模式下可用**,单机模式不支持。 ## 使用场景 - **WAL 暂时不可用**:当 WAL 提供者(如 Kafka)暂时不可用时,可以将 Datanode 切换到 Noop WAL 保持集群运行。 - **测试和开发**:适用于不需要 WAL 持久化的测试场景。 ## 数据丢失警告 **使用 Noop WAL 时,Datanode 关闭或重启会导致所有未刷新的数据丢失。** 仅应在 WAL 提供者不可用时临时使用,不建议用于生产环境,除非是紧急情况。 ## 配置 为 Datanode 配置 Noop WAL: ```toml [wal] provider = "noop" ``` 在 GreptimeDB 集群中,WAL 配置分为两部分: - **Metasrv** - 负责为新 Region 生成 WAL 元数据,应配置为 `raft_engine` 或 `kafka`。 - **Datanode** - 负责 WAL 数据读写,可在 WAL 提供者不可用时配置为 `noop`。 注意:Noop WAL 只能配置在 Datanode 上,Metasrv 不支持。使用 Noop WAL 时,Metasrv 仍使用原配置的 WAL 提供者。 ## 最佳实践 - 定期使用 `admin flush_table()` 或 `admin flush_region()` 刷新 Region,减少数据丢失。 - WAL 提供者恢复后,尽快切换回正常配置。 --- ## GreptimeDB WAL 概述 # 概述 [预写日志](/contributor-guide/datanode/wal.md#introduction)(WAL) 是 GreptimeDB 的关键组件之一,负责持久化记录每次数据修改操作,以确保内存中的数据在故障发生时不会丢失。GreptimeDB 支持三种 WAL 存储方案: - **本地 WAL**: 使用嵌入式存储引擎 [raft-engine](https://github.com/tikv/raft-engine) ,直接集成在 [Datanode](/user-guide/concepts/why-greptimedb.md) 服务中。 - **Remote WAL**: 使用 [Apache Kafka](https://kafka.apache.org/) 作为外部的 WAL 存储组件。 - **Noop WAL**: 无操作 WAL 提供者,用于 WAL 暂时不可用的紧急情况,不存储任何数据。 ## 本地 WAL ### 优点 - **低延迟**: 本地 WAL 运行于 Datanode 进程内,避免了网络传输开销,提供更低的写入延迟。 - **易于部署**: 由于 WAL 与 Datanode 紧耦合,无需引入额外组件,部署和运维更加简便。 - **零 RPO**: 在云环境中部署 GreptimeDB 时,可以结合云存储服务(如 AWS EBS 或 GCP Persistent Disk)将 WAL 数据持久化存储,从而实现零[恢复点目标](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Point_Objective) (RPO),即使发生故障也不会丢失任何已写入的数据。 ### 缺点 - **高 RTO**: 由于 WAL 与 Datanode 紧密耦合,[恢复时间目标](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Time_Objective) (RTO) 相对较高。在 Datanode 重启后,必须重放 WAL 以恢复最新数据,在此期间节点保持不可用。 - **单点访问限制**: 本地 WAL 与 Datanode 进程紧密耦合,仅支持单个消费者访问,限制了区域热备份和 [Region Migration](/user-guide/deployments-administration/manage-data/region-migration.md) 等功能的实现。 ## Remote WAL ### 优点 - **低 RTO**: 通过将 WAL 与 Datanode 解耦,[恢复时间目标](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Time_Objective) (RTO) 得以最小化。当 Datanode 崩溃时,Metasrv 会发起 [Region Failover](/user-guide/deployments-administration/manage-data/region-failover.md) ,将受影响 Region 迁移至健康节点,无需本地重放 WAL。 - **多消费者订阅**: Remote WAL 支持多个消费者同时订阅 WAL 日志,实现 Region 热备和 [Region Migration](/user-guide/deployments-administration/manage-data/region-migration.md) 等功能,提升系统的高可用性和灵活性。 ### 缺点 - **外部依赖**: Remote WAL 依赖外部 Kafka 集群,增加了部署和运维复杂度。 - **网络开销**: WAL 数据需通过网络传输,需合理规划集群网络带宽,确保低延迟与高吞吐量,尤其在写入密集型负载下。 ## Noop WAL Noop WAL 是一种特殊的 WAL 提供者,用于 WAL 暂时不可用的紧急情况。它不会存储任何 WAL 数据,仅在集群模式下可用。 详细配置说明请参阅 [Noop WAL](/user-guide/deployments-administration/wal/noop-wal.md)。 ## 后续步骤 - 如需配置本地 WAL 存储,请参阅[本地 WAL](/user-guide/deployments-administration/wal/local-wal.md)。 - 想了解更多 Remote WAL 相关信息,请参阅 [Remote WAL](/user-guide/deployments-administration/wal/remote-wal/configuration.md)。 - 想了解更多 Noop WAL 相关信息,请参阅 [Noop WAL](/user-guide/deployments-administration/wal/noop-wal.md)。 --- ## GreptimeDB Remote WAL 配置 # 配置 GreptimeDB 支持使用 Kafka 实现 Remote WAL 存储。要启用 Remote WAL,需要分别配置 Metasrv 和 Datanode。 如果你使用 Helm Chart 部署 GreptimeDB,可以参考[常见 Helm Chart 配置项](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md)了解如何配置 Remote WAL。 ## Metasrv 配置 Metasrv 负责 Kafka topics 的管理及过期 WAL 数据的自动清理。 ```toml [wal] provider = "kafka" broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] # WAL 数据清理策略 auto_prune_interval = "30m" auto_prune_parallelism = 10 flush_trigger_size = "512MB" checkpoint_trigger_size = "128MB" # Topic 自动创建配置 auto_create_topics = true num_topics = 64 replication_factor = 1 topic_name_prefix = "greptimedb_wal_topic" create_topic_timeout = "30s" ``` ### 配置 | 配置项 | 说明 | |----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `provider` | 设置为 `"kafka"` 以启用 Remote WAL。 | | `broker_endpoints` | Kafka broker 的地址列表。 | | `auto_prune_interval` | 自动清理过期 WAL 的间隔时间,设为 `"0s"` 表示禁用。 | | `auto_prune_parallelism` | 并发清理任务的最大数量。 | | `auto_create_topics` | 是否自动创建 Kafka topic,设为 `false` 时需手动预创建。 | | `num_topics` | 用于存储 WAL 的 Kafka topic 数量。 | | `replication_factor` | 每个 topic 的副本数量。 | | `topic_name_prefix` | Kafka topic 名称前缀,必须匹配正则 `[a-zA-Z_:-][a-zA-Z0-9_:\-\.@#]*`。 | | `flush_trigger_size` | 触发 region flush 操作的预估大小阈值(如 `"512MB"`)。计算公式为 `(latest_entry_id - flushed_entry_id) * avg_record_size`。当此值超过 `flush_trigger_size` 时,MetaSrv 会触发 region flush 操作。设为 `"0"` 时由系统自动控制。该配置还可控制 region 重放期间从 topic 重放的最大数据量,较小的值有助于缩短 Datanode 启动时的重放时间。 | | `checkpoint_trigger_size` | 触发 region checkpoint 操作的预估大小阈值(如 `"128MB"`)。计算公式为 `(latest_entry_id - last_checkpoint_entry_id) * avg_record_size`。当此值超过 `checkpoint_trigger_size` 时,MetaSrv 会启动检查点操作。设为 `"0"` 时由系统自动控制。较小的值有助于缩短 Datanode 启动时的重放时间。 | | `create_topic_timeout` | 创建 Kafka topic 的超时时间,默认值为 `"30s"`。 | #### Kafka Topic 与权限要求 请确保以下设置正确,以保证 Remote WAL 正常运行: - 如果 `auto_create_topics = false`: - 必须**在启动 Metasrv 之前**手动创建好所有 WAL topics; - Topic 名称必须符合 `{topic_name_prefix}_{index}` 的格式,其中 index 的取值范围是 `0` 到 `{num_topics - 1}`。例如,默认前缀为 `greptimedb_wal_topic`,且 `num_topics = 64` 时,需要创建从 `greptimedb_wal_topic_0` 到 `greptimedb_wal_topic_63` 的 topic。 - Topic 必须配置为支持**LZ4 压缩**。 - Kafka 用户需具备以下权限: - 对 topics 追加数据; - 读取 topics 中数据; - 删除 topics 中数据; - 若启用自动创建(`auto_create_topics = true`),还需具备 创建 topic 的权限。 ## Datanode 配置 Datanode 负责将数据写入 Kafka 并从中读取数据。 ```toml [wal] provider = "kafka" broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] max_batch_bytes = "1MB" overwrite_entry_start_id = true connect_timeout = "3s" timeout = "3s" ``` ### 配置 | 配置项 | 说明 | | -------------------------- | -------------------------------------------------------------------------------------------- | | `provider` | 设置为 `"kafka"` 以启用 Remote WAL。 | | `broker_endpoints` | Kafka broker 的地址列表。 | | `max_batch_bytes` | 每个写入批次的最大大小,默认不能超过 Kafka 配置的单条消息上限(通常为 1MB)。 | | `overwrite_entry_start_id` | 若设为 `true`,在 WAL 回放时跳过缺失的 entry,避免 out-of-range 错误(但可能掩盖数据丢失)。 | | `connect_timeout` | Kafka 客户端的连接超时时间,默认值为 `"3s"`。 | | `timeout` | Kafka 客户端操作的超时时间,默认值为 `"3s"`。 | #### 注意事项与限制 :::warning 重要:Kafka 保留策略配置 请非常小心地配置 Kafka 保留策略以避免数据丢失。GreptimeDB 会自动回收不需要的 WAL 数据,因此在大多数情况下你不需要设置保留策略。但是如果你确实需要设置,请确保以下几点: - **基于大小的保留策略**:通常不需要设置,因为数据库会管理自己的数据生命周期 - **基于时间的保留策略**:如果你选择设置此项,请确保保留时间**远大于自动刷新间隔** **(auto-flush-interval)** 以防止过早删除数据。 不当的保留设置可能导致数据丢失,如果 WAL 数据在 GreptimeDB 处理之前被删除。 ::: - 如果 `overwrite_entry_start_id = true`: - 确保 Metasrv 中的 `auto_prune_interval` 已启用,以允许自动清理 WAL; - Kafka topics 不应使用**基于大小保留策略**; - 如果启用基于时间的保留策略,请确保保留时间**远大于自动刷新间隔(auto-flush-interval)**,至少是它的两倍。 - 确保 Datanode 使用的 Kafka 用户具有以下权限: - 对 topics 追加数据; - 读取 topics 中数据; - 确保 `max_batch_bytes` 不超过 Kafka topic 的最大消息大小(通常为 1MB)。 ## Kafka 认证配置 Kafka 的认证参数在 Metasrv 和 Datanode 的 `[wal]` 段中配置。 ### SASL 认证 支持的 SASL 机制包括:`PLAIN`、`SCRAM-SHA-256` 和 `SCRAM-SHA-512`。 ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.sasl] type = "SCRAM-SHA-512" username = "user" password = "secret" ``` ### TLS 要启用 TLS,可在 `[wal.tls]` 段进行配置,支持以下几种方式: #### 使用系统 CA 证书 无需提供证书路径,自动使用系统信任的 CA: ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.tls] ``` #### 使用自定义 CA 证书 用于 Kafka 集群使用私有 CA 的场景: ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.tls] server_ca_cert_path = "/path/to/server.crt" ``` #### 使用双向 TLS(mTLS) 同时提供客户端证书与私钥: ```toml [wal] broker_endpoints = ["kafka.kafka-cluster.svc.cluster.local:9092"] [wal.tls] server_ca_cert_path = "/path/to/server_cert" client_cert_path = "/path/to/client_cert" client_key_path = "/path/to/key" ``` --- ## 管理 Kafka GreptimeDB 集群在启用 [Remote WAL](/user-guide/deployments-administration/wal/remote-wal/configuration.md) 时,会使用 Kafka 作为 WAL 存储。本文介绍如何部署和管理 Kafka 集群,使用的是 Bitnami 提供的 Kafka Helm [chart](https://github.com/bitnami/charts/tree/main/bitnami/kafka)。 ## 先决条件 - [Kubernetes](https://kubernetes.io/docs/setup/) >= v1.23 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 ## 安装 将以下内容保存为配置文件 `kafka.yaml`: ```yaml global: security: allowInsecureImages: true image: registry: docker.io repository: greptime/kafka tag: 3.9.0-debian-12-r12 controller: replicaCount: 3 resources: requests: cpu: 2 memory: 2Gi limits: cpu: 2 memory: 2Gi persistence: enabled: true size: 200Gi broker: replicaCount: 3 resources: requests: cpu: 2 memory: 2Gi limits: cpu: 2 memory: 2Gi persistence: enabled: true size: 200Gi listeners: client: # 部署到生产环境时,通常会使用一个更安全的协议,例如 SASL。 # 请参考 chart 的文档获取配置方法:https://artifacthub.io/packages/helm/bitnami/kafka#enable-security-for-kafka # 此处为了例子的简单,我们使用 plaintext 协议(无权限验证)。 protocol: plaintext ``` 安装 Kafka 集群: ```bash helm upgrade --install kafka \ oci://registry-1.docker.io/bitnamicharts/kafka \ --values kafka.yaml \ --version 32.4.3 \ --create-namespace \ -n kafka-cluster ``` 等待 Kafka 集群启动完成: ```bash kubectl wait --for=condition=ready pod \ -l app.kubernetes.io/instance=kafka \ -n kafka-cluster ``` ```bash kubectl get pods -n kafka-cluster ``` 检查 Kafka 集群状态: ```bash kubectl get pods -n kafka-cluster ```
Expected Output ```bash NAME READY STATUS RESTARTS AGE kafka-controller-0 1/1 Running 0 64s kafka-controller-1 1/1 Running 0 64s kafka-controller-2 1/1 Running 0 64s kafka-broker-0 1/1 Running 0 63s kafka-broker-1 1/1 Running 0 62s kafka-broker-2 1/1 Running 0 61s ```
--- ## 持续聚合 持续聚合是处理时间序列数据以提供实时洞察的关键方面。 Flow 引擎使开发人员能够无缝地执行持续聚合,例如计算总和、平均值和其他指标。 它在指定的时间窗口内高效地更新聚合数据,使其成为分析的宝贵工具。 持续聚合的三个主要用例示例如下: 1. **实时分析**:一个实时分析平台,不断聚合来自事件流的数据,提供即时洞察,同时可选择将数据降采样到较低分辨率。例如,此系统可以编译来自高频日志事件流(例如,每毫秒发生一次)的数据,以提供每分钟的请求数、平均响应时间和每分钟的错误率等最新洞察。 2. **实时监控**:一个实时监控系统,不断聚合来自事件流的数据,根据聚合数据提供实时警报。例如,此系统可以处理来自传感器事件流的数据,以提供当温度超过某个阈值时的实时警报。 3. **实时仪表盘**:一个实时仪表盘,显示每分钟的请求数、平均响应时间和每分钟的错误数。此仪表板可用于监控系统的健康状况,并检测系统中的任何异常。 在所有这些用例中,持续聚合系统不断聚合来自事件流的数据,并根据聚合数据提供实时洞察和警报。系统还可以将数据降采样到较低分辨率,以减少存储和处理的数据量。这使得系统能够提供实时洞察和警报,同时保持较低的数据存储和处理成本。 ## 实时分析示例 ### 日志统计 这个例子是根据输入表中的数据计算一系列统计数据,包括一分钟时间窗口内的总日志数、最小大小、最大大小、平均大小以及大小大于 550 的数据包数。 首先,创建一个 source 表 `ngx_access_log` 和一个 sink 表 `ngx_statistics`,如下所示: ```sql CREATE TABLE `ngx_access_log` ( `client` STRING NULL, `ua_platform` STRING NULL, `referer` STRING NULL, `method` STRING NULL, `endpoint` STRING NULL, `trace_id` STRING NULL FULLTEXT INDEX, `protocol` STRING NULL, `status` SMALLINT UNSIGNED NULL, `size` DOUBLE NULL, `agent` STRING NULL, `access_time` TIMESTAMP(3) NOT NULL, TIME INDEX (`access_time`) ) WITH( append_mode = 'true' ); ``` ```sql CREATE TABLE `ngx_statistics` ( `status` SMALLINT UNSIGNED NULL, `total_logs` BIGINT NULL, `min_size` DOUBLE NULL, `max_size` DOUBLE NULL, `avg_size` DOUBLE NULL, `high_size_count` BIGINT NULL, `time_window` TIMESTAMP time index, `update_at` TIMESTAMP NULL, PRIMARY KEY (`status`) ); ``` 然后创建名为 `ngx_aggregation` 的 flow 任务,包括 `count`、`min`、`max`、`avg` `size` 列的聚合函数,以及大于 550 的所有数据包的大小总和。聚合是在 `access_time` 列的 1 分钟固定窗口中计算的,并且还按 `status` 列分组。因此,你可以实时了解有关数据包大小和对其的操作的信息,例如,如果 `high_size_count` 在某个时间点变得太高,你可以进一步检查是否有任何问题,或者如果 `max_size` 列在 1 分钟时间窗口内突然激增,你可以尝试定位该数据包并进一步检查。 下方 SQL 语句中的 `EXPIRE AFTER '6h'` 参数确保 flow 计算仅使用过去 6 小时内的源数据。对于 sink 表中超过 6 小时的历史数据,本 flow 不会对其进行修改。有关`EXPIRE AFTER`的详细信息,请参阅[管理 Flow](manage-flow.md#expire-after) ```sql CREATE FLOW ngx_aggregation SINK TO ngx_statistics EXPIRE AFTER '6h' COMMENT 'aggregate nginx access logs' AS SELECT status, count(client) AS total_logs, min(size) as min_size, max(size) as max_size, avg(size) as avg_size, sum(case when `size` > 550 then 1 else 0 end) as high_size_count, date_bin('1 minutes'::INTERVAL, access_time) as time_window, FROM ngx_access_log GROUP BY status, time_window; ``` 要检查持续聚合是否正常工作,首先插入一些数据到源表 `ngx_access_log` 中。 ```sql INSERT INTO ngx_access_log VALUES ('android', 'Android', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 1000, 'agent', now() - INTERVAL '1' minute), ('ios', 'iOS', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 500, 'agent', now() - INTERVAL '1' minute), ('android', 'Android', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 600, 'agent', now()), ('ios', 'iOS', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 404, 700, 'agent', now()); ``` 则 `ngx_access_log` 表将被增量更新以包含以下数据: ```sql SELECT * FROM ngx_statistics; ``` ```sql +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | status | total_logs | min_size | max_size | avg_size | high_size_count | time_window | update_at | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | 200 | 2 | 500 | 1000 | 750 | 1 | 2025-04-24 06:46:00 | 2025-04-24 06:47:06.680000 | | 200 | 1 | 600 | 600 | 600 | 1 | 2025-04-24 06:47:00 | 2025-04-24 06:47:06.680000 | | 404 | 1 | 700 | 700 | 700 | 1 | 2025-04-24 06:47:00 | 2025-04-24 06:47:06.680000 | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ 3 rows in set (0.01 sec) ``` 尝试向 `ngx_access_log` 表中插入更多数据: ```sql INSERT INTO ngx_access_log VALUES ('android', 'Android', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 200, 500, 'agent', now()), ('ios', 'iOS', 'referer', 'GET', '/api/v1', 'trace_id', 'HTTP', 404, 800, 'agent', now()); ``` 结果表 `ngx_statistics` 将被增量更新,注意 `max_size`、`avg_size` 和 `high_size_count` 是如何更新的: ```sql SELECT * FROM ngx_statistics; ``` ```sql +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | status | total_logs | min_size | max_size | avg_size | high_size_count | time_window | update_at | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ | 200 | 2 | 500 | 1000 | 750 | 1 | 2025-04-24 06:46:00 | 2025-04-24 06:47:06.680000 | | 200 | 2 | 500 | 600 | 550 | 1 | 2025-04-24 06:47:00 | 2025-04-24 06:47:21.720000 | | 404 | 2 | 700 | 800 | 750 | 2 | 2025-04-24 06:47:00 | 2025-04-24 06:47:21.720000 | +--------+------------+----------+----------+----------+-----------------+---------------------+----------------------------+ 3 rows in set (0.01 sec) ``` `ngx_statistics` 表中的列解释如下: - `status`: HTTP 响应的状态码。 - `total_logs`: 相同状态码的日志总数。 - `min_size`: 相同状态码的数据包的最小大小。 - `max_size`: 相同状态码的数据包的最大大小。 - `avg_size`: 相同状态码的数据包的平均大小。 - `high_size_count`: 包大小大于 550 的数据包数。 - `time_window`: 聚合的时间窗口。 - `update_at`: 聚合结果更新的时间。 ### 按时间窗口查询国家 另一个实时分析的示例是从 `ngx_access_log` 表中查询所有不同的国家。 你可以使用以下查询按时间窗口对国家进行分组: ```sql /* source 表 */ CREATE TABLE ngx_access_log ( client STRING, country STRING, access_time TIMESTAMP TIME INDEX, PRIMARY KEY(client) )WITH( append_mode = 'true' ); /* sink 表 */ CREATE TABLE ngx_country ( country STRING, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(country) ); /* 创建 flow 任务以计算不同的国家 */ CREATE FLOW calc_ngx_country SINK TO ngx_country EXPIRE AFTER '7days'::INTERVAL COMMENT 'aggregate for distinct country' AS SELECT DISTINCT country, date_bin('1 hour'::INTERVAL, access_time) as time_window, FROM ngx_access_log GROUP BY country, time_window; ``` 上述查询将 `ngx_access_log` 表中的数据聚合到 `ngx_country` 表中,它计算了每个时间窗口内的不同国家。 `date_bin` 函数用于将数据聚合到一小时的间隔中。 `ngx_country` 表将不断更新聚合数据,以监控访问系统的不同国家。`EXPIRE AFTER` 参数将确保流式处理流程自动忽略 `access_time` 超过 7 天的数据且不再参与 flow 计算,详见 请参阅[管理 Flow](manage-flow.md#expire-after) 中的说明。 你可以向 source 表 `ngx_access_log` 插入一些数据: ```sql INSERT INTO ngx_access_log VALUES ('client1', 'US', now() - '2 hour'::INTERVAL), ('client2', 'US', now() - '2 hour'::INTERVAL), ('client3', 'UK', now() - '2 hour'::INTERVAL), ('client4', 'UK', now() - '1 hour'::INTERVAL), ('client5', 'CN', now() - '1 hour'::INTERVAL), ('client6', 'CN', now() - '1 hour'::INTERVAL), ('client7', 'JP', now()), ('client8', 'JP', now()), ('client9', 'KR', now()), ('client10', 'KR', now()); ``` 等待几秒钟,让 flow 将结果写入 sink 表,然后查询: ```sql select * from ngx_country; ``` ```sql +---------+---------------------+----------------------------+ | country | time_window | update_at | +---------+---------------------+----------------------------+ | CN | 2025-04-24 05:00:00 | 2025-04-24 06:55:17.217000 | | JP | 2025-04-24 06:00:00 | 2025-04-24 06:55:17.217000 | | KR | 2025-04-24 06:00:00 | 2025-04-24 06:55:17.217000 | | UK | 2025-04-24 04:00:00 | 2025-04-24 06:55:17.217000 | | UK | 2025-04-24 05:00:00 | 2025-04-24 06:55:17.217000 | | US | 2025-04-24 04:00:00 | 2025-04-24 06:55:17.217000 | +---------+---------------------+----------------------------+ ``` ## 实时监控示例 假设你有一个来自温度传感器网络的传感器事件流,你希望实时监控这些事件。 传感器事件包含传感器 ID、温度读数、读数的时间戳和传感器的位置等信息。 你希望不断聚合这些数据,以便在温度超过某个阈值时提供实时告警。持续聚合的查询如下: ```sql /* 创建 source 表 */ CREATE TABLE temp_sensor_data ( sensor_id INT, loc STRING, temperature DOUBLE, ts TIMESTAMP TIME INDEX )WITH( append_mode = 'true' ); /* 创建 sink 表 */ CREATE TABLE temp_alerts ( sensor_id INT, loc STRING, max_temp DOUBLE, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(sensor_id, loc) ); CREATE FLOW temp_monitoring SINK TO temp_alerts EXPIRE AFTER '1h' AS SELECT sensor_id, loc, max(temperature) as max_temp, date_bin('10 seconds'::INTERVAL, ts) as time_window, FROM temp_sensor_data GROUP BY sensor_id, loc, time_window HAVING max_temp > 100; ``` 上述查询将 `temp_sensor_data` 表中的数据不断聚合到 `temp_alerts` 表中。 它计算每个传感器和位置的最大温度读数,并过滤出最大温度超过 100 度的数据。 `temp_alerts` 表将不断更新聚合数据, 当温度超过阈值时提供实时警报(即 `temp_alerts` 表中的新行)。`EXPIRE AFTER '1h'` 使 flow 仅计算 `ts` 列处于 `(now - 1h, now)` 时间范围内的源数据,详见 [管理 Flow](manage-flow.md#expire-after) 中的说明。 现在我们已经创建了 flow 任务,可以向 source 表 `temp_sensor_data` 插入一些数据: ```sql INSERT INTO temp_sensor_data VALUES (1, 'room1', 98.5, now() - '10 second'::INTERVAL), (2, 'room2', 99.5, now()); ``` 表现在应该是空的,等待几秒钟让 flow 将结果更新到输出表: ```sql SELECT * FROM temp_alerts; ``` ```sql Empty set (0.00 sec) ``` 插入一些会触发警报的数据: ```sql INSERT INTO temp_sensor_data VALUES (1, 'room1', 101.5, now()), (2, 'room2', 102.5, now()); ``` 等待几秒钟,让 flow 将结果更新到输出表: ```sql SELECT * FROM temp_alerts; ``` ```sql +-----------+-------+----------+---------------------+----------------------------+ | sensor_id | loc | max_temp | time_window | update_at | +-----------+-------+----------+---------------------+----------------------------+ | 1 | room1 | 101.5 | 2025-04-24 06:58:20 | 2025-04-24 06:58:32.379000 | | 2 | room2 | 102.5 | 2025-04-24 06:58:20 | 2025-04-24 06:58:32.379000 | +-----------+-------+----------+---------------------+----------------------------+ ``` ## 实时仪表盘 假设你需要一个条形图来显示每个状态码的包大小分布,以监控系统的健康状况。持续聚合的查询如下: ```sql /* 创建 source 表 */ CREATE TABLE ngx_access_log ( client STRING, stat INT, size INT, access_time TIMESTAMP TIME INDEX )WITH( append_mode = 'true' ); /* 创建 sink 表 */ CREATE TABLE ngx_distribution ( stat INT, bucket_size INT, total_logs BIGINT, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(stat, bucket_size) ); /* 创建 flow 任务以计算每个状态码的包大小分布 */ CREATE FLOW calc_ngx_distribution SINK TO ngx_distribution EXPIRE AFTER '6h' AS SELECT stat, trunc(size, -1)::INT as bucket_size, count(client) AS total_logs, date_bin('1 minutes'::INTERVAL, access_time) as time_window, FROM ngx_access_log GROUP BY stat, time_window, bucket_size; ``` 该查询将 `ngx_access_log` 表中的数据汇总到 `ngx_distribution` 表中。 它计算每个时间窗口内的状态代码和数据包大小存储桶(存储桶大小为 10,由 `trunc` 指定,第二个参数为 -1)的日志总数。 `date_bin` 函数将数据分组为一分钟的间隔。 因此,`ngx_distribution` 表会不断更新, 提供每个状态代码的数据包大小分布的实时洞察。`EXPIRE AFTER '6h'` 使 flow 仅计算 `access_time` 列处于 `(now - 6h, now)` 时间范围内的源数据,详见 [管理 Flow](manage-flow.md#expire-after)。 现在我们已经创建了 flow 任务,可以向 source 表 `ngx_access_log` 插入一些数据: ```sql INSERT INTO ngx_access_log VALUES ('cli1', 200, 100, now()), ('cli2', 200, 104, now()), ('cli3', 200, 120, now()), ('cli4', 200, 124, now()), ('cli5', 200, 140, now()), ('cli6', 404, 144, now()), ('cli7', 404, 160, now()), ('cli8', 404, 164, now()), ('cli9', 404, 180, now()), ('cli10', 404, 184, now()); ``` 等待几秒钟,让 flow 将结果更新到 sink 表: ```sql SELECT * FROM ngx_distribution; ``` ```sql +------+-------------+------------+---------------------+----------------------------+ | stat | bucket_size | total_logs | time_window | update_at | +------+-------------+------------+---------------------+----------------------------+ | 200 | 100 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 200 | 120 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 200 | 140 | 1 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 404 | 140 | 1 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 404 | 160 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | | 404 | 180 | 2 | 2025-04-24 07:05:00 | 2025-04-24 07:05:56.308000 | +------+-------------+------------+---------------------+----------------------------+ 6 rows in set (0.00 sec) ``` ## 将 TQL 与 Flow 结合使用进行高级时序分析 :::warning 实验性特性 此实验性功能可能存在预期外的行为,其功能未来可能发生变化。 ::: TQL(时序查询语言)可以与 Flow 无缝集成,以执行高级时序计算,如速率计算、移动平均值和其他复杂的时间窗口操作。这种组合允许你创建连续聚合的 Flow,利用 TQL 强大的分析功能来获取实时洞察。 ### 理解 TQL Flow 组件 TQL 与 Flow 的集成提供了以下几个优势: 1. **时间范围指定**:`EVAL (start_time, end_time, step)` 语法允许精确控制计算窗口,详见 [TQL](/reference/sql/tql.md)。 2. **自动生成表结构**:GreptimeDB 根据 TQL 函数输出创建适当的 Sink 表。 3. **连续处理**:结合 Flow 的调度,TQL 函数在传入数据上持续运行。 4. **高级分析**:使用复杂的时序函数,如 `rate()`、`increase()` 和统计聚合。 ### 设置 Source 表 首先,让我们创建一个 Source 表来存储 HTTP 请求指标: ```sql CREATE TABLE http_requests_total ( host STRING, job STRING, instance STRING, byte DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY (host, job, instance) ); ``` 此表将作为基于 TQL 的 Flow 计算的数据源。`ts` 列作为时间索引, `byte` 表示想要分析的指标值。 ### 创建速率计算 Flow 现在我们将创建一个 Flow,它使用 TQL 来计算 `byte` 随时间的速率: ```sql CREATE FLOW calc_rate SINK TO rate_reqs EVAL INTERVAL '1m' AS TQL EVAL (now() - '1m'::interval, now(), '30s') rate(http_requests_total{job="my_service"}[1m]); ``` 此 Flow 定义包含几个关键组件: - **EVAL INTERVAL '1m'**:每分钟执行 Flow 以进行连续更新。 - **TQL EVAL**:指定从 1 分钟前到现在的时间范围进行评估,详见 [TQL](/reference/sql/tql.md)。 - **rate()**:计算变化率的 TQL 函数。 - **[1m]**:定义速率计算的 1 分钟回溯窗口。 ### 用 CTE 包装 TQL 如果你想让 Flow 定义更清晰,或者希望提前固定输出列名,可以在 `CREATE FLOW` 中用一个简单的 CTE 包装 `TQL EVAL`: ```sql CREATE FLOW calc_rate_cte SINK TO rate_reqs_cte EVAL INTERVAL '1m' AS WITH rate_data (ts, req_rate, host, job, instance) AS ( TQL EVAL (now() - '1m'::interval, now(), '30s') rate(http_requests_total{job="my_service"}[1m]) AS req_rate ) SELECT * FROM rate_data; ``` 当你希望在 GreptimeDB 推断 sink 表 schema 之前先重命名列时,这种写法会很有用,尤其适合值列名较长的 TQL 表达式。 这个能力目前是刻意限制范围的: - 只能使用一个 TQL CTE。 - Flow 查询必须以 `SELECT * FROM ` 结束。 - 不能再增加 `WHERE`、JOIN、额外投影或其他 CTE。 - 如果 CTE 名称使用了引号,外层查询也要保持同样的带引号写法。 ### 检查生成的 Sink 表 你可以检查自动创建的 Sink 表结构: ```sql SHOW CREATE TABLE rate_reqs; ``` ```sql +-----------+-------------------------------------+ | Table | Create Table | +-----------+-------------------------------------+ | rate_reqs | CREATE TABLE IF NOT EXISTS `rate_reqs` ( `ts` TIMESTAMP(3) NOT NULL, `prom_rate(ts_range,byte,ts,Int64(60000))` DOUBLE NULL, `host` STRING NULL, `job` STRING NULL, `instance` STRING NULL, TIME INDEX (`ts`), PRIMARY KEY (`host`, `job`, `instance`) ) ENGINE=mito | +-----------+-------------------------------------+ ``` 上述结果展示了 GreptimeDB 自动生成了用于存储 TQL 计算结果的合适 Schema,即创建一个与 PromQL 查询结果具有相同结构的表。 ### 使用示例数据进行测试 现在可以插入一些测试数据,看看 Flow 的实际效果: ```sql INSERT INTO TABLE http_requests_total VALUES ('localhost', 'my_service', 'instance1', 100, now() - INTERVAL '2' minute), ('localhost', 'my_service', 'instance1', 200, now() - INTERVAL '1' minute), ('remotehost', 'my_service', 'instance1', 300, now() - INTERVAL '30' second), ('remotehost', 'their_service', 'instance1', 300, now() - INTERVAL '30' second), ('localhost', 'my_service', 'instance1', 400, now()); ``` 这将创建一个随时间递增的简单值序列,当由我们的 TQL Flow 处理时,将产生对应的速率结果。 ### 触发 Flow 执行 要手动触发 Flow 计算并查看即时结果: ```sql ADMIN FLUSH_FLOW('calc_rate'); ``` 此命令强制 Flow 立即处理所有可用数据,而不是等待下一个计划的间隔。 ### 验证结果 最后,验证 Flow 是否已成功处理数据: ```sql SELECT count(*) > 0 FROM rate_reqs; ``` ```sql +---------------------+ | count(*) > Int64(0) | +---------------------+ | true | +---------------------+ ``` 此查询确认速率计算的 FLow 已产生结果并将结果写入了 Sink 表。 你还可以查询实际计算出的速率值: ```sql SELECT * FROM rate_reqs; ``` ```sql +---------------------+------------------------------------------+-----------+------------+-----------+ | ts | prom_rate(ts_range,byte,ts,Int64(60000)) | host | job | instance | +---------------------+------------------------------------------+-----------+------------+-----------+ | 2025-09-01 13:14:34 | 4.166666666666666 | localhost | my_service | instance1 | | 2025-09-01 13:15:04 | 4.444444444444444 | localhost | my_service | instance1 | +---------------------+------------------------------------------+-----------+------------+-----------+ 2 rows in set (0.03 sec) ``` 请注意,时间戳和确切的速率值可能会因你运行示例的时间而不同,但此示例的速率计算是相同的。 ### 清理 完成实验后,清理资源: ```sql DROP FLOW calc_rate; DROP TABLE http_requests; DROP TABLE rate_reqs; ``` ## 下一步 - [管理 Flow](manage-flow.md):深入了解 Flow 引擎的机制和定义 Flow 的 SQL 语法。 - [表达式](expressions.md):了解 Flow 引擎支持的数据转换表达式。 --- ## 表达式 ## 聚合函数 Flow 支持标准 SQL 查询所支持的所有聚合函数,例如 `COUNT`、`SUM`、`MIN`、`MAX` 等。 有关详细的函数列表,请参阅 [聚合函数](/reference/sql/functions/df-functions.md#aggregate-functions)。 ## 标量函数 Flow 支持标准 SQL 查询所支持的所有标量函数,详见我们的 [SQL 参考](/reference/sql/functions/overview.md)。 以下是一些 flow 中最常用的标量函数: - [`date_bin`](/reference/sql/functions/df-functions.md#date_bin): calculate time intervals and returns the start of the interval nearest to the specified timestamp. - [`date_trunc`](/reference/sql/functions/df-functions.md#date_trunc): truncate a timestamp value to a specified precision. - [`trunc`](/reference/sql/functions/df-functions.md#trunc): truncate a number to a whole number or truncated to the specified decimal places. --- ## 管理 Flow 每一个 `flow` 是 GreptimeDB 中的一个持续聚合查询。 它根据传入的数据持续更新并聚合数据。 本文档描述了如何创建和删除一个 flow。 ## 创建输入表 在创建 `flow` 之前,你需要先创建一张输入表来存储原始的输入数据,比如: ```sql CREATE TABLE temp_sensor_data ( sensor_id INT, loc STRING, temperature DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY(sensor_id, loc) ); ``` 但是如果你不想存储输入数据,可以在创建输入表时设置表选项 `WITH ('ttl' = 'instant')` 如下: ```sql CREATE TABLE temp_sensor_data ( sensor_id INT, loc STRING, temperature DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY(sensor_id, loc) ) WITH ('ttl' = 'instant'); ``` 将 `ttl` 设置为 `'instant'` 会使得输入表成为一张临时的表,也就是说它会自动丢弃一切插入的数据,而表本身一直会是空的,插入数据只会被送到 `flow` 任务处用作计算用途。 ## 创建 sink 表 在创建 flow 之前,你需要有一个 sink 表来存储 flow 生成的聚合数据。 虽然它与常规的时间序列表相同,但有一些重要的注意事项: - **列的顺序和类型**:确保 sink 表中列的顺序和类型与 flow 查询结果匹配。 - **时间索引**:为 sink 表指定 `TIME INDEX`,通常使用时间窗口函数生成的时间列。 - **更新时间**:Flow 引擎会自动将更新时间附加到每个计算结果行的末尾。此更新时间存储在 `update_at` 列中。请确保在 sink 表的 schema 中包含此列。 - **Tag**:使用 `PRIMARY KEY` 指定 Tag,与 time index 一起作为行数据的唯一标识,并优化查询性能。 例如: ```sql /* 创建 sink 表 */ CREATE TABLE temp_alerts ( sensor_id INT, loc STRING, max_temp DOUBLE, time_window TIMESTAMP TIME INDEX, update_at TIMESTAMP, PRIMARY KEY(sensor_id, loc) ); CREATE FLOW temp_monitoring SINK TO temp_alerts AS SELECT sensor_id, loc, max(temperature) AS max_temp, date_bin('10 seconds'::INTERVAL, ts) AS time_window FROM temp_sensor_data GROUP BY sensor_id, loc, time_window HAVING max_temp > 100; ``` sink 表包含列 `sensor_id`、`loc`、`max_temp`、`time_window` 和 `update_at`。 - 前四列分别对应 flow 的查询结果列 `sensor_id`、`loc`、`max(temperature)` 和 `date_bin('10 seconds'::INTERVAL, ts)`。 - `time_window` 列被指定为 sink 表的 `TIME INDEX`。 - `update_at` 列是 schema 中的最后一列,用于存储数据的更新时间。 - 最后的 `PRIMARY KEY` 指定 `sensor_id` 和 `loc` 作为 Tag 列。 这意味着 flow 将根据 Tag `sensor_id` 和 `loc` 以及时间索引 `time_window` 插入或更新数据。 ## 创建 flow 创建 flow 的语法是: ```sql CREATE [ OR REPLACE ] FLOW [ IF NOT EXISTS ] SINK TO [ EXPIRE AFTER ] [ COMMENT '' ] AS ; ``` 当指定 `OR REPLACE` 时,如果已经存在同名的 flow,它将被更新为新 flow。请注意,这仅影响 flow 任务本身,source 表和 sink 表将不会被更改。当指定 `IF NOT EXISTS` 时,如果 flow 已经存在,它将不执行任何操作,而不是报告错误。还需要注意的是,`OR REPLACE` 不能与 `IF NOT EXISTS` 一起使用。 - `flow-name` 是目录级别的唯一标识符。 - `sink-table-name` 是存储聚合数据的表名。 它可以是一个现有的表或一个新表。如果目标表不存在,`flow` 将创建目标表。 - `EXPIRE AFTER` 是一个可选的时间间隔,用于从 Flow 引擎中过期数据。 有关更多详细信息,请参考 [`EXPIRE AFTER`](#expire-after) 部分。 - `COMMENT` 是 flow 的描述。 - `SQL` 部分定义了用于持续聚合的查询。 它定义了为 flow 提供数据的源表。 每个 flow 可以有多个源表。 有关详细信息,请参考[编写查询](#编写-sql-查询) 部分。 一个创建 flow 的简单示例: ```sql CREATE FLOW IF NOT EXISTS my_flow SINK TO my_sink_table EXPIRE AFTER '1 hour'::INTERVAL COMMENT 'My first flow in GreptimeDB' AS SELECT max(temperature) as max_temp, date_bin('10 seconds'::INTERVAL, ts) as time_window, FROM temp_sensor_data GROUP BY time_window; ``` 创建的 flow 将每 10 秒计算一次 `max(temperature)` 并将结果存储在 `my_sink_table` 中。 所有在 1 小时内的数据都将用于 flow 计算。 ### EXPIRE AFTER `EXPIRE AFTER` 子句指定数据将在 flow 引擎中过期的时间间隔。 source 表中超出指定过期时间的数据将不再被包含在 flow 的计算范围内。 同理,sink 表中超过过期时间的历史数据也不会被更新。 这意味着 flow 引擎在聚合计算时会自动忽略早于该时间间隔的数据。这一机制有助于管理有状态查询(例如涉及 `GROUP BY` 的查询)的状态存储规模。 需特别注意的是: - `EXPIRE AFTER` 子句**不会删除** source 表或 sink 表中的数据,它仅控制 flow 引擎对数据的处理范围 - 若需删除表数据,请在创建表时通过 [`TTL` 策略](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据)实现 为 `EXPIRE AFTER` 设置合理的时间间隔,可有效限制 flow 的状态存储规模并避免内存溢出。该机制与流处理中的 ["水位线"](https://docs.risingwave.com/processing/watermarks) 概念有相似之处——两者均通过时间边界定义计算的有效数据范围,过期数据将不再参与流式计算过程。 例如,如果 flow 引擎在 10:00:00 处理聚合,并且设置了 `'1 hour'::INTERVAL`, 当前时刻若输入数据的 Time Index 超过 1 小时(即早于 09:00:00),则会被判定为过期数据并被忽略。 仅时间戳为 09:00:00 及之后的数据会参与聚合计算,并更新到目标表。 ### 编写 SQL 查询 flow 的 `SQL` 部分类似于标准的 `SELECT` 子句,但有一些不同之处。查询的语法如下: ```sql SELECT AGGR_FUNCTION(column1, column2,..) [, TIME_WINDOW_FUNCTION() as time_window] FROM GROUP BY {time_window | column1, column2,.. }; ``` 在 `SELECT` 关键字之后只允许以下类型的表达式: - 聚合函数:有关详细信息,请参阅[表达式](./expressions.md)文档。 - 时间窗口函数:有关详细信息,请参阅[定义时间窗口](#define-time-window)部分。 - 标量函数:例如 `col`、`to_lowercase(col)`、`col + 1` 等。这部分与 GreptimeDB 中的标准 `SELECT` 子句相同。 查询语法中的其他部分需要注意以下几点: - 必须包含一个 `FROM` 子句以指定 source 表。由于目前不支持 join 子句,因此只能聚合来自单个表的列。 - 支持 `WHERE` 和 `HAVING` 子句。`WHERE` 子句在聚合之前过滤数据,而 `HAVING` 子句在聚合之后过滤数据。 - `DISTINCT` 目前仅适用于 `SELECT DISTINCT column1 ..` 语法。它用于从结果集中删除重复行。`SELECT count(DISTINCT column1) ...` 尚不可用,但将来会添加。 - `GROUP BY` 子句的工作方式与标准查询相同,即按指定列对数据进行分组,在其中指定时间窗口列对于持续聚合场景至关重要。 `GROUP BY` 中的其他表达式可以是 literal、列名或 scalar 表达式。 - 不支持`ORDER BY`、`LIMIT` 和 `OFFSET`。 有关如何在实时分析、监控和仪表板中使用持续聚合的更多示例,请参阅[持续聚合](./continuous-aggregation.md)。 ### 定义时间窗口 时间窗口是持续聚合查询的重要属性。 它定义了数据在流中的聚合方式。 这些窗口是左闭右开的区间。 时间窗口对应于时间范围。 source 表中的数据将根据时间索引列映射到相应的窗口。 时间窗口也是聚合表达式计算的范围,因此每个时间窗口将在结果表中生成一行。 你可以在 `SELECT` 关键字之后使用 `date_bin()` 来定义固定的时间窗口。 例如: ```sql SELECT max(temperature) as max_temp, date_bin('10 seconds'::INTERVAL, ts) as time_window FROM temp_sensor_data GROUP BY time_window; ``` 在此示例中,`date_bin('10 seconds'::INTERVAL, ts)` 函数创建从 UTC 00:00:00 开始的 10 秒时间窗口。 `max(temperature)` 函数计算每个时间窗口内的最大温度值。 有关该函数行为的更多详细信息, 请参阅 [`date_bin`](/reference/sql/functions/df-functions.md#date_bin)。 :::tip 提示 目前,flow 依赖时间窗口表达式来确定如何增量更新结果。因此,建议尽可能使用相对较小的时间窗口。 ::: ## 刷新 flow 当 source 表中有新数据到达时,flow 引擎会在短时间内(比如数秒)自动处理聚合操作。 但你依然可以使用 `ADMIN FLUSH_FLOW` 命令手动触发 flow 引擎立即执行聚合操作。 ```sql ADMIN FLUSH_FLOW('') ``` ## 删除 flow 请使用以下 `DROP FLOW` 子句删除 flow: ```sql DROP FLOW [IF EXISTS] ``` 例如: ```sql DROP FLOW IF EXISTS my_flow; ``` --- ## 流计算 GreptimeDB 的 Flow 引擎实现了数据流的实时计算。 它特别适用于提取 - 转换 - 加载 (ETL) 过程或执行即时的过滤、计算和查询,例如求和、平均值和其他聚合。 Flow 引擎确保数据被增量和连续地处理, 根据到达的新的流数据更新最终结果。 你可以将其视为一个聪明的物化视图, 它知道何时更新结果视图表以及如何以最小的努力更新它。 使用案例包括: - 降采样数据点,使用如平均池化等方法减少存储和分析的数据量 - 提供近实时分析、可操作的信息 ## 程序模型 在将数据插入 source 表后, 数据会同时被写入到 Flow 引擎中。 在每个触发间隔(一秒)时, Flow 引擎执行指定的计算并将结果更新到 sink 表中。 source 表和 sink 表都是 GreptimeDB 中的时间序列表。 在创建 Flow 之前, 定义这些表的 schema 并设计 Flow 以指定计算逻辑是至关重要的。 此过程在下图中直观地表示: ![连续聚合](/flow-ani.svg) ## 快速入门示例 为了说明 GreptimeDB 的 Flow 引擎的功能, 考虑从 nginx 日志计算 user_agent 统计信息的任务。 source 表是 `nginx_access_log`, sink 表是 `user_agent_statistics`。 首先,创建 source 表 `nginx_access_log`。 为了优化计算 `user_agent` 字段的性能, 使用 `PRIMARY KEY` 关键字将其指定为 `TAG` 列类型。 ```sql CREATE TABLE ngx_http_log ( ip_address STRING, http_method STRING, request STRING, status_code INT16, body_bytes_sent INT32, user_agent STRING, response_size INT32, ts TIMESTAMP TIME INDEX, PRIMARY KEY (ip_address, http_method, user_agent, status_code) ) WITH ('append_mode'='true'); ``` 接下来,创建 sink 表 `user_agent_statistics`。 `update_at` 列跟踪数据的最后更新时间,由 Flow 引擎自动更新。 尽管 GreptimeDB 中的所有表都是时间序列表,但此计算不需要时间窗口。 因此增加了 `__ts_placeholder` 列作为时间索引占位列。 ```sql CREATE TABLE user_agent_statistics ( user_agent STRING, total_count INT64, update_at TIMESTAMP, __ts_placeholder TIMESTAMP TIME INDEX, PRIMARY KEY (user_agent) ); ``` 最后,创建 Flow `user_agent_flow` 以计算 `ngx_http_log` 表中每个 user_agent 的出现次数。 ```sql CREATE FLOW user_agent_flow SINK TO user_agent_statistics AS SELECT user_agent, COUNT(user_agent) AS total_count FROM ngx_http_log GROUP BY user_agent; ``` 一旦创建了 Flow, Flow 引擎将持续处理 `nginx_access_log` 表中的数据,并使用计算结果更新 `user_agent_statistics` 表。 要观察 Flow 的结果, 将示例数据插入 `nginx_access_log` 表。 ```sql INSERT INTO ngx_http_log VALUES ('192.168.1.1', 'GET', '/index.html', 200, 512, 'Mozilla/5.0', 1024, '2023-10-01T10:00:00Z'), ('192.168.1.2', 'POST', '/submit', 201, 256, 'curl/7.68.0', 512, '2023-10-01T10:01:00Z'), ('192.168.1.1', 'GET', '/about.html', 200, 128, 'Mozilla/5.0', 256, '2023-10-01T10:02:00Z'), ('192.168.1.3', 'GET', '/contact', 404, 64, 'curl/7.68.0', 128, '2023-10-01T10:03:00Z'); ``` 插入数据后, 查询 `user_agent_statistics` 表以查看结果。 ```sql SELECT * FROM user_agent_statistics; ``` 查询结果将显示 `user_agent_statistics` 表中每个 user_agent 的总数。 ```sql +-------------+-------------+----------------------------+---------------------+ | user_agent | total_count | update_at | __ts_placeholder | +-------------+-------------+----------------------------+---------------------+ | Mozilla/5.0 | 2 | 2024-12-12 06:45:33.228000 | 1970-01-01 00:00:00 | | curl/7.68.0 | 2 | 2024-12-12 06:45:33.228000 | 1970-01-01 00:00:00 | +-------------+-------------+----------------------------+---------------------+ ``` ## 下一步 - [持续聚合](./continuous-aggregation.md):探索时间序列数据处理中的主要场景,了解持续聚合的三种常见使用案例。 - [管理 Flow](manage-flow.md):深入了解 Flow 引擎的机制和定义 Flow 的 SQL 语法。 - [表达式](expressions.md):了解 Flow 引擎支持的数据转换表达式。 --- ## EMQX [EMQX](https://www.emqx.io/) 是一款开源的大规模分布式 MQTT 消息服务器,专为物联网和实时通信应用而设计。EMQX 支持多种协议,包括 MQTT (3.1、3.1.1 和 5.0)、HTTP、QUIC 和 WebSocket 等,保证各种网络环境和硬件设备的可访问性。 GreptimeDB 可以作为 EMQX 的数据系统。请参考[将 MQTT 数据写入 GreptimeDB](https://docs.emqx.com/zh/emqx/latest/data-integration/data-bridge-greptimedb.html) 了解如何将 GreptimeDB 集成到 EMQX 中。 --- ## Go GreptimeDB 提供了用于高吞吐量数据写入的 ingester 库。 它使用 gRPC 协议,支持自动生成表结构,无需在写入数据前创建表。 更多信息请参考 [自动生成表结构](/user-guide/ingest-data/overview.md#自动生成表结构)。 GreptimeDB 提供的 Go Ingest SDK 是一个轻量级、并发安全的库,使用起来非常简单。 ## 快速开始 Demo 你可以通过 [快速开始 Demo](https://github.com/GreptimeTeam/greptimedb-ingester-go/tree/main/examples) 来了解如何使用 GreptimeDB Go SDK。 ## 安装 使用下方的命令安装 Go Ingest SDK: ```shell go get -u github.com/GreptimeTeam/greptimedb-ingester-go@v0.7.2 ``` 引入到代码中: ```go greptime "github.com/GreptimeTeam/greptimedb-ingester-go" ingesterContext "github.com/GreptimeTeam/greptimedb-ingester-go/context" "github.com/GreptimeTeam/greptimedb-ingester-go/table" "github.com/GreptimeTeam/greptimedb-ingester-go/table/types" ) ``` ## 连接数据库 如果你在启动 GreptimeDB 时设置了 [`--user-provider`](/user-guide/deployments-administration/authentication/overview.md), 则需要提供用户名和密码才能连接到 GreptimeDB。 以下示例显示了使用 SDK 连接到 GreptimeDB 时如何设置用户名和密码。 ```go cfg := greptime.NewConfig("127.0.0.1"). // 将数据库名称更改为你的数据库名称 WithDatabase("public"). // 默认端口 4001 // WithPort(4001). // 如果服务配置了 TLS,设置 TLS 选项来启用安全连接 // WithInsecure(false). // 设置鉴权信息 // 如果数据库不需要鉴权,移除 WithAuth 方法即可 WithAuth("username", "password") cli, _ := greptime.NewClient(cfg) defer cli.Close() ``` ## 数据模型 表中的每条行数据包含三种类型的列:`Tag`、`Timestamp` 和 `Field`。更多信息请参考 [数据模型](/user-guide/concepts/data-model.md)。 列值的类型可以是 `String`、`Float`、`Int`、`JSON`, `Timestamp` 等。更多信息请参考 [数据类型](/reference/sql/data-types.md)。 ## 设置表选项 虽然在通过 SDK 向 GreptimeDB 写入数据时会自动创建时间序列表,但你仍然可以配置表选项。 SDK 支持以下表选项: - `auto_create_table`:默认值为 `True`。如果设置为 `False`,则表示表已经存在且不需要自动创建,这可以提高写入性能。 - `ttl`、`append_mode`、`merge_mode`:更多详情请参考[表选项](/reference/sql/create.md#table-options)。 你可以使用 `ingesterContext` 设置表选项。 例如设置 `ttl` 选项: ```go hints := []*ingesterContext.Hint{ { Key: "ttl", Value: "3d", }, } ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) ctx = ingesterContext.New(ctx, ingesterContext.WithHint(hints)) // 使用 ingesterContext 写入数据到 GreptimeDB // `data` 对象在之后的章节中描述 resp, err := cli.Write(ctx, data) if err != nil { return err } ``` 关于如何向 GreptimeDB 写入数据,请参考以下各节。 ## 低级 API GreptimeDB 的低级 API 通过向具有预定义模式的 `table` 对象添加 `row` 来写入数据。 ### 创建行数据 以下代码片段首先构建了一个名为 `cpu_metric` 的表,其中包括 `host`、`cpu_user`、`cpu_sys` 和 `ts` 列。 随后,它向表中插入了一行数据。 该表包含三种类型的列: - `Tag`:`host` 列,值类型为 `String`。 - `Field`:`cpu_user` 和 `cpu_sys` 列,值类型为 `Float`。 - `Timestamp`:`ts` 列,值类型为 `Timestamp`。 ```go // 为 CPU 指标构建表结构 cpuMetric, err := table.New("cpu_metric") if err != nil { // 处理错误 } // 添加一个 'Tag' 列,用于主机标识符 cpuMetric.AddTagColumn("host", types.STRING) // 添加一个 'Timestamp' 列,用于记录数据收集的时间 cpuMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) // 添加 'Field' 列,用于测量用户和系统 CPU 使用率 cpuMetric.AddFieldColumn("cpu_user", types.FLOAT) cpuMetric.AddFieldColumn("cpu_sys", types.FLOAT) // 插入示例数据 // 注意:参数必须按照定义的表结构中的列的顺序排列:host, ts, cpu_user, cpu_sys err = cpuMetric.AddRow("127.0.0.1", time.Now(), 0.1, 0.12) err = cpuMetric.AddRow("127.0.0.1", time.Now(), 0.11, 0.13) if err != nil { // 处理错误 } ``` 为了提高写入数据的效率,你可以一次创建多行数据以便写入到 GreptimeDB。 ```go cpuMetric, err := table.New("cpu_metric") if err != nil { // 处理错误 } cpuMetric.AddTagColumn("host", types.STRING) cpuMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) cpuMetric.AddFieldColumn("cpu_user", types.FLOAT) cpuMetric.AddFieldColumn("cpu_sys", types.FLOAT) err = cpuMetric.AddRow("127.0.0.1", time.Now(), 0.1, 0.12) if err != nil { // 处理错误 } memMetric, err := table.New("mem_metric") if err != nil { // 处理错误 } memMetric.AddTagColumn("host", types.STRING) memMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) memMetric.AddFieldColumn("mem_usage", types.FLOAT) err = memMetric.AddRow("127.0.0.1", time.Now(), 112) if err != nil { // 处理错误 } ``` ### 插入数据 下方示例展示了如何向 GreptimeDB 的表中插入行数据。 ```go resp, err := cli.Write(context.Background(), cpuMetric, memMetric) if err != nil { // 处理错误 } log.Printf("affected rows: %d\n", resp.GetAffectedRows().GetValue()) ``` ### 流式插入 当你需要插入大量数据时,例如导入历史数据,流式插入是非常有用的。 ```go err := cli.StreamWrite(context.Background(), cpuMetric, memMetric) if err != nil { // 处理错误 } ``` 在所有数据写入完毕后关闭流式写入。 一般情况下,连续写入数据时不需要关闭流式写入。 ```go affected, err := cli.CloseStream(ctx) ``` ## 高级 API SDK 的高级 API 使用 ORM 风格的对象写入数据, 它允许你以更面向对象的方式创建、插入和更新数据,为开发者提供了更友好的体验。 然而,高级 API 不如低级 API 高效。 这是因为 ORM 风格的对象在转换对象时可能会消耗更多的资源和时间。 ### 创建行数据 ```go type CpuMetric struct { Host string `greptime:"tag;column:host;type:string"` CpuUser float64 `greptime:"field;column:cpu_user;type:float64"` CpuSys float64 `greptime:"field;column:cpu_sys;type:float64"` Ts time.Time `greptime:"timestamp;column:ts;type:timestamp;precision:millisecond"` } func (CpuMetric) TableName() string { return "cpu_metric" } cpuMetrics := []CpuMetric{ { Host: "127.0.0.1", CpuUser: 0.10, CpuSys: 0.12, Ts: time.Now(), } } ``` ### 插入数据 ```go resp, err := cli.WriteObject(context.Background(), cpuMetrics) log.Printf("affected rows: %d\n", resp.GetAffectedRows().GetValue()) ``` ### 流式插入 当你需要插入大量数据时,例如导入历史数据,流式插入是非常有用的。 ```go err := streamClient.StreamWriteObject(context.Background(), cpuMetrics, memMetrics) ``` 在所有数据写入完毕后关闭流式写入。 一般情况下,连续写入数据时不需要关闭流式写入。 ```go affected, err := cli.CloseStream(ctx) ``` ## 插入 JSON 类型的数据 GreptimeDB 支持使用 [JSON 类型数据](/reference/sql/data-types.md#json-类型) 存储复杂的数据结构。 使用此 ingester 库,你可以通过字符串值插入 JSON 数据。 假如你有一个名为 `sensor_readings` 的表,并希望添加一个名为 `attributes` 的 JSON 列, 请参考以下代码片段。 在 [低级 API](#低级-api) 中, 你可以使用 `AddFieldColumn` 方法将列类型指定为 `types.JSON` 来添加 JSON 列。 然后使用 `struct` 或 `map` 插入 JSON 数据。 ```go sensorReadings, err := table.New("sensor_readings") // 此处省略了创建其他列的代码 // ... // 将列类型指定为 JSON sensorReadings.AddFieldColumn("attributes", types.JSON) // 使用 struct 插入 JSON 数据 type Attributes struct { Location string `json:"location"` Action string `json:"action"` } attributes := Attributes{ Location: "factory-1" } sensorReadings.AddRow(... , attributes) // 以下省略了写入数据的代码 // ... ``` 在 [高级 API](#高级-api) 中,你可以使用 `greptime:"field;column:details;type:json"` 标签将列类型指定为 JSON。 ```go type SensorReadings struct { // 此处省略了创建其他列的代码 // ... // 将列类型指定为 JSON Attributes string `greptime:"field;column:details;type:json"` // ... } // 使用 struct 插入 JSON 数据 type Attributes struct { Location string `json:"location"` Action string `json:"action"` } attributes := Attributes{ Action: "running" } sensor := SensorReadings{ // ... Attributes: attributes, } // 以下省略了写入数据的代码 // ... ``` 请参考 SDK 仓库中的 [示例](https://github.com/GreptimeTeam/greptimedb-ingester-go/tree/main/examples/jsondata) 获取插入 JSON 数据的可执行代码。 ## Bulk 写入 当你需要批量导入数据并且要求高吞吐写入时,可以使用 Bulk Write API。它专为批量导入的场景设计,能够高效地写入大规模数据。 通过在客户端使用 Arrow IPC 编码将多个表或对象聚合,并在一次 gRPC 请求中发送,与常规 Write API 相比,可以显著减少网络开销并提升整体写入性能。 ### 添加数据 你可以构建的数据对象添加到批量写入器中。 ```go // 构建 CPU 指标表 cpuMetric, err := table.New("cpu_metric") if err != nil { // 处理错误 } cpuMetric.AddTagColumn("host", types.STRING) cpuMetric.AddTimestampColumn("ts", types.TIMESTAMP_MILLISECOND) cpuMetric.AddFieldColumn("cpu_user", types.FLOAT64) cpuMetric.AddFieldColumn("cpu_sys", types.FLOAT64) // 添加多行数据 cpuMetric.AddRow("127.0.0.1", time.Now(), 0.1, 0.12) cpuMetric.AddRow("127.0.0.2", time.Now(), 0.2, 0.15) ``` ### 执行 bulk 写入 ```go resp, err := cli.BulkWrite(context.TODO(), cpuMetric) if err != nil { // 处理错误 } log.Printf("Bulk write affected rows: %d\n", resp.GetAffectedRows().GetValue()) ``` 请参考 SDK 仓库中的 [示例](https://github.com/GreptimeTeam/greptimedb-ingester-go/tree/main/examples/bulkwrite) 获取 bulk 写入的可执行代码。 ## Ingester 库参考 - [API 文档](https://pkg.go.dev/github.com/GreptimeTeam/greptimedb-ingester-go) --- ## Java Ingester for GreptimeDB GreptimeDB 提供了用于高吞吐量数据写入的 ingester 库。 它使用 gRPC 协议,支持无 schema 写入,无需在写入数据前创建表。 更多信息请参考 [自动生成表结构](/user-guide/ingest-data/overview.md#自动生成表结构)。 GreptimeDB 提供的 Java ingester SDK 是一个轻量级、高性能的客户端,专为高效的时间序列数据写入而设计。它利用 gRPC 协议提供非阻塞、纯异步的 API,在保持与应用程序无缝集成的同时提供高吞吐数据写入。 该客户端提供针对各种性能要求和使用场景优化的多种写入方法。你可以选择最适合你特定需求的方法——无论你需要低延迟操作的简单一元写入,还是处理大量时间序列数据时最大效率的高吞吐量批量流式传输。 ## 架构 ``` +-----------------------------------+ | Client Applications | | +------------------+ | | | Application Code | | | +------------------+ | +-------------+---------------------+ | v +-------------+---------------------+ | API Layer | | +---------------+ | | | GreptimeDB | | | +---------------+ | | / \ | | v v | | +-------------+ +-------------+ | +------------------+ | | BulkWrite | | Write | | | Data Model | | | Interface | | Interface | |------->| | | +-------------+ +-------------+ | | +------------+ | +-------|----------------|----------+ | | Table | | | | | +------------+ | v v | | | +-------|----------------|----------+ | v | | Transport Layer | | +------------+ | | +-------------+ +-------------+ | | | TableSchema| | | | BulkWrite | | Write | | | +------------+ | | | Client | | Client | | +------------------+ | +-------------+ +-------------+ | | | \ / | | | | \ / | | | | v v | | | | +-------------+ | | | | |RouterClient | | | +-----|--+-------------|---+--------+ | | | | | | | | v v v | +-----|----------------|---|--------+ | Network Layer | | +-------------+ +-------------+ | | | Arrow Flight| | gRPC Client | | | | Client | | | | | +-------------+ +-------------+ | | | | | +-----|----------------|------------+ | | v v +-------------------------+ | GreptimeDB Server | +-------------------------+ ``` - **API Layer**:为客户端应用程序提供与 GreptimeDB 交互的上层接口 - **Data Model**:定义时间序列数据的结构和组织,包括表和 schemas - **Transport Layer**:处理通信逻辑、请求路由和客户端管理 - **Network Layer**:使用 Arrow Flight 和 gRPC 底层协议通信 ## 使用方法 ### 安装 1. 安装 Java 开发工具包(JDK) 确保你的系统已安装 JDK 8 或更高版本。有关如何检查 Java 版本并安装 JDK 的更多信息,请参见 [Oracle JDK 安装概述文档](https://www.oracle.com/java/technologies/javase-downloads.html) 2. 将 GreptimeDB Java SDK 添加为依赖项 如果你使用的是 [Maven](https://maven.apache.org/),请将以下内容添加到 pom.xml 的依赖项列表中: ```xml io.greptime ingester-all 0.15.0 ``` 最新版本可以在 [这里](https://central.sonatype.com/search?q=io.greptime&name=ingester-all) 查看。 配置依赖项后,请确保它们对项目可用。这可能需要在 IDE 中刷新项目或运行依赖项管理器。 ### 客户端初始化 GreptimeDB Ingester Java 客户端的入口点是 `GreptimeDB` 类。你可以通过调用静态创建方法并传入适当的配置选项来创建客户端实例。 ```java // GreptimeDB 在默认目录 "greptime" 中有一个名为 "public" 的默认数据库, // 我们可以将其用作测试数据库 String database = "public"; // 默认情况下,GreptimeDB 使用 gRPC 协议在端口 4001 上监听。 // 我们可以提供多个指向同一 GreptimeDB 集群的端点。 // 客户端将基于负载均衡策略调用这些端点。 // 客户端执行定期健康检查并自动将请求路由到健康节点, // 为你的应用程序提供容错能力和改进的可靠性。 String[] endpoints = {"127.0.0.1:4001"}; // 设置认证信息。 AuthInfo authInfo = new AuthInfo("username", "password"); GreptimeOptions opts = GreptimeOptions.newBuilder(endpoints, database) // 如果数据库不需要认证,我们可以使用 `AuthInfo.noAuthorization()` 作为参数。 .authInfo(authInfo) // 如果你的服务器由 TLS 保护,请启用安全连接 //.tlsOptions(new TlsOptions()) // 好的开始 ^_^ .build(); // 初始化客户端 // 注意:客户端实例是线程安全的,应作为全局单例重用 // 以获得更好的性能和资源利用率。 GreptimeDB client = GreptimeDB.create(opts); ``` ### 写入数据 Ingester 通过 `Table` 抽象为写入数据到 GreptimeDB 提供了统一的方法。所有数据写入操作,包括高级 API,都建立在这个基础结构之上。要写入数据,你需要创建一个 `Table` 为其填充时间序列数据,最后将其写入数据库。 #### 创建和写入表 定义表结构并创建表: ```java // 创建表结构 TableSchema schema = TableSchema.newBuilder("metrics") .addTag("host", DataType.String) .addTag("region", DataType.String) .addField("cpu_util", DataType.Float64) .addField("memory_util", DataType.Float64) .addTimestamp("ts", DataType.TimestampMillisecond) .build(); // 从 schema 创建表数据容器 Table table = Table.from(schema); // 向表中添加行 // 值必须按照结构中定义的顺序提供 // 在这种情况下:addRow(host, region, cpu_util, memory_util, ts) table.addRow("host1", "us-west-1", 0.42, 0.78, System.currentTimeMillis()); table.addRow("host2", "us-west-2", 0.46, 0.66, System.currentTimeMillis()); // 添加更多行 // .. // 把表标记为完成以使其不可变。这将最终确定表的数据内容以进行写入。 // 如果你忘记了调用此方法,它将在表数据写入前自动在内部调用 table.complete(); // 写入数据库 CompletableFuture> future = client.write(table); ``` GreptimeDB 支持使用 [JSON 类型数据](/reference/sql/data-types.md#json-类型) 存储复杂的数据结构。你可以在表结构中定义 JSON 列,并使用 Map 对象插入数据: ```java // 为 sensor_readings 构建表结构 TableSchema sensorReadings = TableSchema.newBuilder("sensor_readings") // 省略创建其他列的代码 // ... // 将列类型指定为 JSON .addField("attributes", DataType.Json) .build(); // ... // 使用 map 插入 JSON 数据 Map attr = new HashMap<>(); attr.put("location", "factory-1"); Table table = Table.from(sensorReadings); table.addRow(... , attr); ``` ##### TableSchema `TableSchema` 定义了写入数据到 GreptimeDB 的结构。它指定表结构,包括列名、语义类型和数据类型。有关列语义类型(`Tag`、`Timestamp`、`Field`)的详细信息,请参考 [数据模型](/user-guide/concepts/data-model.md) 文档。 ##### Table `Table` 接口表示可以写入到 GreptimeDB 的数据。它提供添加行和操作数据的方法。本质上,`Table` 将数据临时存储在内存中,允许你在将数据发送到数据库之前累积多行进行批处理,这比写入单个行显著提高了写入效率。 表经历几个不同的生命周期阶段: 1. **创建**:使用 `Table.from(schema)` 从 schema 初始化表 2. **数据添加**:使用 `addRow()` 方法用行填充表 3. **完成**:添加所有行后使用 `complete()` 冻结表不允许再修改 4. **写入**:将完成的表发送到数据库 重要提醒: - 表不是线程安全的,应该单线程访问 - 写入后不能重用表 - 需要为每个写入操作创建新实例 - 关联的 `TableSchema` 是不可变的,可以在多个操作中安全地复用 ### 写入操作 虽然在通过 SDK 向 GreptimeDB 写入数据时会自动创建时间序列表, 但你仍然可以配置表选项。 SDK 支持以下表选项: - `auto_create_table`:默认为 `True`。如果设置为 `False`,表示表已经存在且不需要自动创建,这可以提高写入性能。 - `ttl`、`append_mode`、`merge_mode`:更多详情请参考 [表选项](/reference/sql/create.md#table-options)。 你可以使用 `Context` 设置表选项。 例如,要设置 `ttl` 选项,请使用以下代码: ```java Context ctx = Context.newDefault(); // 添加提示使数据库创建具有指定 TTL(生存时间)的表 ctx = ctx.withHint("ttl", "3d"); // 将压缩算法设置为 Zstd。 ctx = ctx.withCompression(Compression.Zstd); // 写入数据到 GreptimeDB 时使用 ctx CompletableFuture> future = client.write(Arrays.asList(table1, table2), WriteOp.Insert, ctx); ``` 有关如何向 GreptimeDB 写入数据,请参阅以下部分。 ### 批量写入 批量写入允许你在单个请求中向多个表写入数据。它返回 `CompletableFuture>` 是一个典型的异步编程方式。 对于大多数使用场景,这是向 GreptimeDB 写入数据的推荐方式。 ```java // 批量写入 API CompletableFuture> future = client.write(table1, table2, table3); // 出于性能考虑,SDK 被设计为纯异步的。 // 返回值是一个 CompletableFuture 对象。如果你想立即获取 // 结果,可以调用 `future.get()`,这将阻塞直到操作完成。 // 对于生产环境,建议使用回调或 // CompletableFuture API 等非阻塞方法。 Result result = future.get(); ``` ### 流式写入 流式写入 API 维护到 GreptimeDB 的持久连接,以便进行具有速率限制的连续数据写入。它允许通过单个流向多个表写入数据。 以下场景推荐使用此 API: - 中小规模的连续数据收集 - 通过一个连接管道写入多个表的数据 - 简单性和便利性比最大吞吐量更重要的情况 ```java // 创建流写入器 StreamWriter writer = client.streamWriter(); // 写入多个表 writer.write(table1) .write(table2) .write(table3); // 完成流并获取结果 CompletableFuture result = writer.completed(); ``` 你还可以为流式写入设置速率限制: ```java // 限制为每秒 1000 个数据点 StreamWriter writer = client.streamWriter(1000); ``` ### Bulk 写入 Bulk 写入 API 提供了一种高性能、内存高效的机制,用于将大量时间序列数据写入到 GreptimeDB 中。它利用堆外内存管理,在写入大批量数据时实现最佳吞吐量。 **重要说明**: 1. **需要手动创建表**:Bulk API **不会**自动创建表。你必须事先创建表,使用以下方法之一: - 常规写入 API(支持自动创建表),或 - SQL DDL 语句(CREATE TABLE) 2. **Schema 匹配**:Bulk API 中的表模板必须与现有表结构完全匹配。 此 API 仅支持每个流写入一个表,并处理大数据量(每次写入可高达 200MB+),具有自适应流量控制。性能优势包括: - 使用 Arrow 缓冲区的堆外内存管理减少不必要的内置拷贝 - 高效的二进制序列化和数据传输 - 可选压缩选项 - 批量操作 此方法特别适用于: - 大规模批处理和数据迁移 - 高吞吐量日志和传感器数据写入 - 具有苛刻性能要求的时间序列应用程序 - 处理高频数据收集的系统 以下是使用批处理写入 API 的典型模式: ```java // 使用表结构创建 BulkStreamWriter try (BulkStreamWriter writer = greptimeDB.bulkStreamWriter(schema)) { // 写入多个批次 for (int batch = 0; batch < batchCount; batch++) { // 为此批次获取 TableBufferRoot Table.TableBufferRoot table = writer.tableBufferRoot(1000); // 列缓冲区大小 // 向批次添加行 for (int row = 0; row < rowsPerBatch; row++) { Object[] rowData = generateRow(batch, row); table.addRow(rowData); } // 完成表以准备传输 table.complete(); // 发送批次并获取完成的 future CompletableFuture future = writer.writeNext(); // 等待批次被处理(可选) Integer affectedRows = future.get(); System.out.println("Batch " + batch + " wrote " + affectedRows + " rows"); } // 发出流完成信号 writer.completed(); } ``` #### 配置 可以使用多个选项配置 Bulk API 以优化性能: ```java BulkWrite.Config cfg = BulkWrite.Config.newBuilder() .allocatorInitReservation(64 * 1024 * 1024L) // 自定义内存分配:64MB 初始保留 .allocatorMaxAllocation(4 * 1024 * 1024 * 1024L) // 自定义内存分配:4GB 最大分配 .timeoutMsPerMessage(60 * 1000) // 每个请求 60 秒超时 .maxRequestsInFlight(8) // 并发控制:配置 8 个最大并发请求 .build(); // 启用 Zstd 压缩 Context ctx = Context.newDefault().withCompression(Compression.Zstd); BulkStreamWriter writer = greptimeDB.bulkStreamWriter(schema, cfg, ctx); ``` ### 资源管理 使用完客户端后正确关闭客户端很重要: ```java // 优雅地关闭客户端 client.shutdownGracefully(); ``` ### 性能调优 #### 压缩选项 Ingester 支持各种压缩算法以降低网络带宽占用并提高吞吐量。 ```java // 将压缩算法设置为 Zstd Context ctx = Context.newDefault().withCompression(Compression.Zstd); ``` #### 写入操作比较 了解不同写入方法的性能特征对于优化数据写入至关重要。 | 写入方法 | API | 吞吐量 | 延迟 | 内存效率 | CPU 使用 | 最佳用途 | 限制 | |----------|-----|---------|------|----------|----------|----------|------| | Batching Write | `write(tables)` | 较好 | 良好 | 高 | 较高 | 简单应用程序,低延迟需求 | 大量数据的吞吐量较低 | | Streaming Write | `streamWriter()` | 中等 | 良好 | 中等 | 中等 | 连续数据流,中等吞吐量 | 比常规写入更复杂 | | Bulk Write | `bulkStreamWriter()` | 最佳 | 较高 | 最佳 | 中等 | 最大吞吐量,大批量操作 | 延迟较高,需要手动创建表 | #### 缓冲区大小优化 使用 `BulkStreamWriter` 时,你可以配置列缓冲区大小: ```java // 获取具有特定列缓冲区大小的表缓冲区 Table.TableBufferRoot table = bulkStreamWriter.tableBufferRoot(columnBufferSize); ``` 此选项可以显著提高数据转换为底层格式的速度。为了获得最佳性能,我们建议将列缓冲区大小设置为 1024 或更大,具体取决于你的特定工作负载特征和可用内存。 ### 导出指标 Ingester 公开全面的指标,使你能够监控其性能、健康状况和操作状态。 有关可用指标及其使用的详细信息,请参考 [Ingester Prometheus Metrics](https://github.com/GreptimeTeam/greptimedb-ingester-java/tree/main/ingester-prometheus-metrics) 文档。 ## 主要配置选项 `GreptimeOptions` 是 GreptimeDB Java 客户端的主要配置类,用于配置客户端连接、写入选项、RPC 设置和各种其他参数。 对于生产环境,你可能需要配置这些常用选项。完整参考:[GreptimeOptions JavaDoc](https://javadoc.io/static/io.greptime/ingester-protocol/0.15.0/io/greptime/options/GreptimeOptions.html)。 **主要选项:** - `database`:目标数据库名称,格式为 `[catalog-]schema`(默认值:`public`) - `authInfo`:生产环境的身份验证凭据 - `rpcOptions.defaultRpcTimeout`:RPC 请求超时时间(默认值:60 秒) - `writeMaxRetries`:写入失败时的最大重试次数(默认值:1) - `maxInFlightWritePoints`:写入流控制的最大在途数据点数(默认值:655360) - `writeLimitedPolicy`:写入流量限制超出时的策略(默认值:AbortOnBlockingTimeoutPolicy 3秒) - `defaultStreamMaxWritePointsPerSecond`:StreamWriter 的速率限制(默认值:655360) ```java // Production-ready configuration RpcOptions rpcOpts = RpcOptions.newDefault(); rpcOpts.setDefaultRpcTimeout(30000); // 30 seconds timeout AuthInfo authInfo = new AuthInfo("username", "password"); GreptimeOptions options = GreptimeOptions.newBuilder("127.0.0.1:4001", "production_db") .authInfo(authInfo) .rpcOptions(rpcOpts) .writeMaxRetries(3) .maxInFlightWritePoints(1000000) .writeLimitedPolicy(new LimitedPolicy.AbortOnBlockingTimeoutPolicy(5, TimeUnit.SECONDS)) .defaultStreamMaxWritePointsPerSecond(50000) .build(); ``` ## FAQ ### 为什么我会遇到一些连接异常? 使用 GreptimeDB Java ingester SDK 时,你可能会遇到一些连接异常。 例如,异常是"`Caused by: java.nio.channels.UnsupportedAddressTypeException`"、 "`Caused by: java.net.ConnectException: connect(..) failed: Address family not supported by protocol`" 或 "`Caused by: java.net.ConnectException: connect(..) failed: Invalid argument`"。当你确定 GreptimeDB 服务器正在运行,并且其端点可达时。 这些连接异常可能都是因为在打包过程中,gRPC 的 `io.grpc.NameResolverProvider` 服务提供程序没有 打包到最终的 JAR 中。所以修复方法可以是: - 如果你使用 Maven Assembly 插件,请将 `metaInf-services` 容器描述符处理程序添加到你的 assembly 文件中,如下所示: ```xml ... metaInf-services ``` - 如果你使用 Maven Shade 插件,可以添加 `ServicesResourceTransformer`: ```xml ... org.apache.maven.plugins maven-shade-plugin 3.6.0 shade ... ``` ## API 文档和示例 - [API 参考](https://javadoc.io/doc/io.greptime/ingester-protocol/latest/index.html) - [示例](https://github.com/GreptimeTeam/greptimedb-ingester-java/tree/main/ingester-example/) --- ## 使用 SDK 写入数据 本指南将演示如何使用 SDK 在 GreptimeDB 中写入数据。 - [Go](go.md) - [Java](java.md) - [Rust](https://github.com/GreptimeTeam/greptimedb-ingester-rust) - [.NET](https://github.com/GreptimeTeam/greptimedb-ingester-dotnet) - [Erlang](https://github.com/GreptimeTeam/greptimedb-ingester-erl) - [TypeScript](https://github.com/GreptimeTeam/greptimedb-ingester-ts) --- ## InfluxDB Line Protocol GreptimeDB 支持 HTTP InfluxDB Line 协议。 ## 写入新数据 ### 协议 #### Post 指标 你可以通过 `/influxdb/write` API 写入数据。 以下是一个示例: ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/api/v2/write?db=public&precision=ms" \ -H "authorization: token {{greptime_user:greptimedb_password}}" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 1667446797450 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 1667446798450 monitor,host=127.0.0.1 cpu=0.5,memory=0.2 1667446798450' ``` ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/write?db=public&precision=ms&u=&p=" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 1667446797450 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 1667446798450 monitor,host=127.0.0.1 cpu=0.5,memory=0.2 1667446798450' ``` `/influxdb/write` 支持查询参数,包括: * `db`:指定要写入的数据库。默认值为 `public`。 * `precision`:定义请求体中提供的时间戳的精度,可接受的值为 `ns`(纳秒)、`us`(微秒)、`ms`(毫秒)和 `s`(秒),默认值为 `ns`(纳秒)。该 API 写入的时间戳类型为 `TimestampNanosecond`,因此默认精度为 `ns`(纳秒)。如果你在请求体中使用了其他精度的时间戳,需要使用此参数指定精度。该参数确保时间戳能够被准确解释并以纳秒精度存储。 你还可以在发送请求时省略 timestamp,GreptimeDB 将使用主机机器的当前系统时间(UTC 时间)作为 timestamp。例如: ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/api/v2/write?db=public" \ -H "authorization: token {{greptime_user:greptimedb_password}}" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 monitor,host=127.0.0.1 cpu=0.5,memory=0.2' ``` ```shell curl -i -XPOST "http://localhost:4000/v1/influxdb/write?db=public&u=&p=" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 monitor,host=127.0.0.1 cpu=0.5,memory=0.2' ``` #### 鉴权 GreptimeDB 与 InfluxDB 的行协议鉴权格式兼容,包括 V1 和 V2。 如果你在 GreptimeDB 中[配置了鉴权](/user-guide/deployments-administration/authentication/overview.md),需要在 HTTP 请求中提供用户名和密码。 InfluxDB 的 [V2 协议](https://docs.influxdata.com/influxdb/v1.8/tools/api/?t=Auth+Enabled#apiv2query-http-endpoint) 使用了类似 HTTP 标准 basic 认证方案的格式。 ```shell curl 'http://localhost:4000/v1/influxdb/api/v2/write?db=public' \ -H 'authorization: token {{username:password}}' \ -d 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4' ``` 对于 InfluxDB 的 [V1 协议](https://docs.influxdata.com/influxdb/v1.8/tools/api/?t=Auth+Enabled#query-string-parameters-1) 的鉴权格式。在 HTTP 查询字符串中添加 `u` 作为用户和 `p` 作为密码,如下所示: ```shell curl 'http://localhost:4000/v1/influxdb/write?db=public&u=&p=' \ -d 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4' ``` ### Telegraf GreptimeDB 支持 [InfluxDB 行协议](../for-iot/influxdb-line-protocol.md)也意味着 GreptimeDB 与 Telegraf 兼容。 要配置 Telegraf,只需将 GreptimeDB 的 URL 添加到 Telegraf 配置中: ```toml [[outputs.influxdb_v2]] urls = ["http://:4000/v1/influxdb"] token = ":" bucket = "" ## Leave empty organization = "" ``` ```toml [[outputs.influxdb]] urls = ["http://:4000/v1/influxdb"] database = "" username = "" password = "" ``` ## 数据模型 你可能已经熟悉了 [InfluxDB 的关键概念](https://docs.influxdata.com/influxdb/v2/reference/key-concepts/), GreptimeDB 的[数据模型](/user-guide/concepts/data-model.md) 是值得了解的新事物。 下方解释了 GreptimeDB 和 InfluxDB 数据模型的相似和不同之处: - 两者都是 [schemaless 写入](/user-guide/ingest-data/overview.md#自动生成表结构)的解决方案,这意味着在写入数据之前无需定义表结构。 - GreptimeDB 的表在自动创建时会设置表选项 [`merge_mode`](/reference/sql/create.md#创建带有-merge-模式的表)为 `last_non_null`。 这意味着表会通过保留每个字段的最新值来合并具有相同主键和时间戳的行,该行为与 InfluxDB 相同。 - 在 InfluxDB 中,一个点代表一条数据记录,包含一个 measurement、tag 集、field 集和时间戳。 在 GreptimeDB 中,它被表示为时间序列表中的一行数据。 表名对应于 measurement,列由三种类型组成:Tag、Field 和 Timestamp。 - GreptimeDB 使用 `TimestampNanosecond` 作为来自 [InfluxDB 行协议 API](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md) 的时间戳数据类型。 - GreptimeDB 使用 `Float64` 作为来自 InfluxDB 行协议 API 的数值数据类型。 以 InfluxDB 文档中的[示例数据](https://docs.influxdata.com/influxdb/v2/reference/key-concepts/data-elements/#sample-data)为例: |_time|_measurement|location|scientist|_field|_value| |---|---|---|---|---|---| |2019-08-18T00:00:00Z|census|klamath|anderson|bees|23| |2019-08-18T00:00:00Z|census|portland|mullen|ants|30| |2019-08-18T00:06:00Z|census|klamath|anderson|bees|28| |2019-08-18T00:06:00Z|census|portland|mullen|ants|32| 上述数据的 InfluxDB 行协议格式为: ```shell census,location=klamath,scientist=anderson bees=23 1566086400000000000 census,location=portland,scientist=mullen ants=30 1566086400000000000 census,location=klamath,scientist=anderson bees=28 1566086760000000000 census,location=portland,scientist=mullen ants=32 1566086760000000000 ``` 在 GreptimeDB 数据模型中,上述数据将被表示为 `census` 表中的以下内容: ```sql +---------------------+----------+-----------+------+------+ | greptime_timestamp | location | scientist | bees | ants | +---------------------+----------+-----------+------+------+ | 2019-08-18 00:00:00 | klamath | anderson | 23 | NULL | | 2019-08-18 00:06:00 | klamath | anderson | 28 | NULL | | 2019-08-18 00:00:00 | portland | mullen | NULL | 30 | | 2019-08-18 00:06:00 | portland | mullen | NULL | 32 | +---------------------+----------+-----------+------+------+ ``` `census` 表结构如下: ```sql +--------------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+----------------------+------+------+---------+---------------+ | location | String | PRI | YES | | TAG | | scientist | String | PRI | YES | | TAG | | bees | Float64 | | YES | | FIELD | | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | ants | Float64 | | YES | | FIELD | +--------------------+----------------------+------+------+---------+---------------+ ``` ## 参考 - [InfluxDB Line protocol](https://docs.influxdata.com/influxdb/v2.7/reference/syntax/line-protocol/) --- ## Kafka 请参考 [Kafka 文档](/user-guide/ingest-data/for-observability/kafka.md)了解如何将数据从 Kafka 写入到 GreptimeDB。 --- ## OpenTSDB GreptimeDB 支持通过 HTTP API 使用 OpenTSDB 协议。 ## 写入新数据 ### HTTP API GreptimeDB 还支持通过 HTTP 接口插入 OpenTSDB 数据,接口是 `/opentsdb/api/put`,使用的请求和响应格式与 OpenTSDB 的 `/api/put` 接口相同。 GreptimeDB 的 HTTP Server 默认监听 `4000` 端口。例如使用 curl 写入一个指标数据: ```shell curl -X POST http://127.0.0.1:4000/v1/opentsdb/api/put \ -H 'Authorization: Basic {{authentication}}' \ -d ' { "metric": "sys.cpu.nice", "timestamp": 1667898896, "value": 18, "tags": { "host": "web01", "dc": "hz" } } ' ``` 插入多个指标数据: ```shell curl -X POST http://127.0.0.1:4000/v1/opentsdb/api/put \ -H 'Authorization: Basic {{authentication}}' \ -d ' [ { "metric": "sys.cpu.nice", "timestamp": 1667898896, "value": 1, "tags": { "host": "web02", "dc": "hz" } }, { "metric": "sys.cpu.nice", "timestamp": 1667898897, "value": 9, "tags": { "host": "web03", "dc": "sh" } } ] ' ``` :::tip 注意 记得在路径前加上 GreptimeDB 的 HTTP API 版本 `v1`。 ::: --- ## 物联网(IoT)数据写入 数据的写入是物联网数据流程的关键部分。 它从各种来源(如传感器、设备和应用程序)收集数据并将其存储在中央位置以供进一步处理和分析。 数据写入过程对于确保数据的准确性、可靠性和安全性至关重要。 GreptimeDB 可处理并存储超大规模量级的数据以供分析, 支持各种数据格式、协议和接口,以便集成不同的物联网设备和系统。 - [SQL INSERT](sql.md):简单直接的数据插入方法。 - [gRPC SDK](./grpc-sdks/overview.md):提供高效、高性能的数据写入,特别适用于实时数据和复杂的物联网基础设施。 - [InfluxDB Line Protocol](influxdb-line-protocol.md):一种广泛使用的时间序列数据协议,便于从 InfluxDB 迁移到 GreptimeDB。该文档同样介绍了 Telegraf 的集成方式。 - [EMQX](emqx.md):支持大规模设备连接的 MQTT 代理,可直接将数据写入到 GreptimeDB。 - [OpenTSDB](opentsdb.md):使用 OpenTSDB 协议将数据写入到 GreptimeDB。 --- ## SQL 你可以使用 [MySQL](/user-guide/protocols/mysql.md) 或 [PostgreSQL](/user-guide/protocols/postgresql.md) 客户端执行 SQL 语句, 使用任何你喜欢的编程语言(如 Java JDBC)通过 MySQL 或 PostgreSQL 协议访问 GreptimeDB。 我们将使用 `monitor` 表作为示例来展示如何写入数据。有关如何创建 `monitor` 表的 SQL 示例,请参见[表管理](/user-guide/deployments-administration/manage-data/basic-table-operations.md#创建表)。 ## 创建表 在插入数据之前,你需要创建一个表。例如,创建一个名为 `monitor` 的表: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64 DEFAULT 0, memory FLOAT64, PRIMARY KEY(host)); ``` 上述语句将创建一个具有以下 schema 的表: ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | | cpu | Float64 | | YES | 0 | FIELD | | memory | Float64 | | YES | | FIELD | +--------+----------------------+------+------+---------------------+---------------+ 4 rows in set (0.01 sec) ``` 有关 `CREATE TABLE` 语句的更多信息,请参阅[表管理](/user-guide/deployments-administration/manage-data/basic-table-operations.md#create-a-table)。 ## 插入数据 让我们向 `monitor` 表中插入一些测试数据。你可以使用 `INSERT INTO` 语句: ```sql INSERT INTO monitor VALUES ("127.0.0.1", 1702433141000, 0.5, 0.2), ("127.0.0.2", 1702433141000, 0.3, 0.1), ("127.0.0.1", 1702433146000, 0.3, 0.2), ("127.0.0.2", 1702433146000, 0.2, 0.4), ("127.0.0.1", 1702433151000, 0.4, 0.3), ("127.0.0.2", 1702433151000, 0.2, 0.4); ``` ```sql Query OK, 6 rows affected (0.01 sec) ``` 你还可以插入数据时指定列名: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", 1702433141000, 0.5, 0.2), ("127.0.0.2", 1702433141000, 0.3, 0.1), ("127.0.0.1", 1702433146000, 0.3, 0.2), ("127.0.0.2", 1702433146000, 0.2, 0.4), ("127.0.0.1", 1702433151000, 0.4, 0.3), ("127.0.0.2", 1702433151000, 0.2, 0.4); ``` 通过上面的语句,我们成功的向 `monitor` 表中插入了六条数据。请参考 [`INSERT`](/reference/sql/insert.md) 获得更多写入数据的相关信息。 ## 时区 SQL 客户端中指定的时区将影响没有时区信息的字符串格式的时间戳。 该时间戳值将会自动添加客户端的时区信息。 例如,下面的 SQL 将时区设置为 `+8:00`: ```sql SET time_zone = '+8:00'; ``` 然后向 `monitor` 表中插入值: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-01-01 00:00:00", 0.4, 0.1), ("127.0.0.2", "2024-01-01 00:00:00+08:00", 0.5, 0.1); ``` 第一个时间戳值 `2024-01-01 00:00:00` 没有时区信息,因此它将自动添加客户端的时区信息。 在插入数据后,它将等同于第二个值 `2024-01-01 00:00:00+08:00`。 `+8:00` 时区下的结果如下: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-01-01 00:00:00 | 0.4 | 0.1 | | 127.0.0.2 | 2024-01-01 00:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` `UTC` 时区下的结果如下: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2023-12-31 16:00:00 | 0.4 | 0.1 | | 127.0.0.2 | 2023-12-31 16:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` --- ## Grafana Alloy [Grafana Alloy](https://grafana.com/docs/alloy/latest/) 是一个用于 OpenTelemetry (OTel)、Prometheus、Pyroscope、Loki 等其他指标、日志、追踪和分析工具的可观测性数据管道。 你可以将 GreptimeDB 集成为 Alloy 的数据接收端。 ## Prometheus Remote Write 将 GreptimeDB 配置为远程写入目标: ```hcl prometheus.remote_write "greptimedb" { endpoint { url = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/prometheus/write?db=${GREPTIME_DB:=public}" basic_auth { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } } } ``` - `GREPTIME_HOST`: GreptimeDB 主机地址,例如 `localhost`。 - `GREPTIME_DB`: GreptimeDB 数据库名称,默认是 `public`。 - `GREPTIME_USERNAME` 和 `GREPTIME_PASSWORD`: GreptimeDB 的[鉴权认证信息](/user-guide/deployments-administration/authentication/static.md)。 有关从 Prometheus 到 GreptimeDB 的数据模型转换的详细信息,请参阅 Prometheus Remote Write 指南中的[数据模型](/user-guide/ingest-data/for-observability/prometheus.md#数据模型)部分。 ## OpenTelemetry GreptimeDB 也可以配置为 OpenTelemetry Collector 的目标。 ### 指标 ```hcl otelcol.exporter.otlphttp "greptimedb" { client { endpoint = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/otlp/" headers = { "X-Greptime-DB-Name" = "${GREPTIME_DB:=public}", } auth = otelcol.auth.basic.credentials.handler } } otelcol.auth.basic "credentials" { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } ``` - `GREPTIME_HOST`: GreptimeDB 主机地址,例如 `localhost`。 - `GREPTIME_DB`: GreptimeDB 数据库名称,默认是 `public`。 - `GREPTIME_USERNAME` 和 `GREPTIME_PASSWORD`: GreptimeDB 的[鉴权认证信息](/user-guide/deployments-administration/authentication/static.md)。 有关从 OpenTelemetry 到 GreptimeDB 的指标数据模型转换的详细信息,请参阅 OpenTelemetry 指南中的[数据模型](/user-guide/ingest-data/for-observability/opentelemetry.md#数据模型)部分。 ### 日志 此示例通过 OpenTelemetry 管道将日志发送到 GreptimeDB。 对于生产环境中的日志管道,建议在 exporter 之前显式添加一个 batch processor。详情请参阅[批处理](#批处理)部分。 ```hcl loki.source.file "greptime" { targets = [ {__path__ = "/tmp/foo.txt"}, ] forward_to = [otelcol.receiver.loki.greptime.receiver] } otelcol.receiver.loki "greptime" { output { logs = [otelcol.processor.batch.greptimedb_logs.input] } } otelcol.processor.batch "greptimedb_logs" { send_batch_size = 5000 send_batch_max_size = 10000 timeout = "1s" output { logs = [otelcol.exporter.otlphttp.greptimedb_logs.input] } } otelcol.auth.basic "credentials" { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } otelcol.exporter.otlphttp "greptimedb_logs" { client { endpoint = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/otlp/" headers = { "X-Greptime-DB-Name" = "${GREPTIME_DB:=public}", "X-Greptime-Log-Table-Name" = "${GREPTIME_LOG_TABLE_NAME:=demo_logs}", "X-Greptime-Log-Extract-Keys" = "filename,log.file.name,loki.attribute.labels", } auth = otelcol.auth.basic.credentials.handler } sending_queue { queue_size = 10000 num_consumers = 10 } } ``` - `GREPTIME_HOST`: GreptimeDB 主机地址,例如 `localhost`。 - `GREPTIME_DB`: GreptimeDB 数据库名称,默认是 `public`。 - `GREPTIME_LOG_TABLE_NAME`: 目标日志表名,默认为 `demo_logs`。 - `GREPTIME_USERNAME` 和 `GREPTIME_PASSWORD`: GreptimeDB 的[鉴权认证信息](/user-guide/deployments-administration/authentication/static.md)。 - `X-Greptime-Log-Extract-Keys`: 从 OTLP 日志属性中提取的键。详情请参阅 [OTLP/HTTP API 文档](/user-guide/ingest-data/for-observability/opentelemetry.md#otlphttp-api-1)。 有关从 OpenTelemetry 到 GreptimeDB 的日志数据模型转换的详细信息,请参阅 OpenTelemetry 指南中的[数据模型](/user-guide/ingest-data/for-observability/opentelemetry.md#数据模型-1)部分。 ## Loki GreptimeDB 也支持通过 Loki Push 协议写入日志。 如果你的 Alloy 日志管道本身就是基于 Loki 组件构建的,建议优先使用原生的 Loki 写入路径。 关于 Loki 协议的详细说明和数据模型映射,请参阅 [Loki 指南](/user-guide/ingest-data/for-observability/loki.md)。 ### 日志 此示例仅使用 Loki 组件读取、处理并通过 Loki Push API 将日志发送到 GreptimeDB: ```hcl loki.source.file "greptime" { targets = [ {__path__ = "/tmp/foo.txt"}, ] forward_to = [loki.process.greptime.receiver] } loki.process "greptime" { forward_to = [loki.write.greptimedb.receiver] stage.static_labels { values = { job = "greptime", from = "alloy", } } } loki.write "greptimedb" { endpoint { url = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/loki/api/v1/push" headers = { "X-Greptime-DB-Name" = "${GREPTIME_DB:=public}", "X-Greptime-Log-Table-Name" = "${GREPTIME_LOG_TABLE_NAME:=loki_demo_logs}", } basic_auth { username = "${GREPTIME_USERNAME}" password = "${GREPTIME_PASSWORD}" } } } ``` - `GREPTIME_HOST`: GreptimeDB 主机地址,例如 `localhost`。 - `GREPTIME_DB`: GreptimeDB 数据库名称,默认是 `public`。 - `GREPTIME_LOG_TABLE_NAME`: 目标日志表名,默认为 `loki_demo_logs`。 - `GREPTIME_USERNAME` 和 `GREPTIME_PASSWORD`: GreptimeDB 的[鉴权认证信息](/user-guide/deployments-administration/authentication/static.md)。 该配置会读取 `/tmp/foo.txt`,添加两个静态标签,并通过 `loki.write` 将日志直接发送到 GreptimeDB。 ## 批处理 `otelcol.exporter.otlphttp` 默认不会启用批处理。 当 Alloy 读取突发日志时,例如文件或 Docker 容器中的大量历史积压日志,exporter 队列可能会在记录被充分聚合前就被塞满,从而导致 `sending queue is full` 这类错误。 根据生产环境中的测试反馈,仅启用 exporter 内部的 `sending_queue.batch` 配置,对于突发型日志负载仍然可能不够。 在 exporter 前增加 `otelcol.processor.batch` 通常是更可靠的做法,因为这样 exporter 接收到的是较大的批次,而不是大量单条日志记录。 如果你通过 OTLP/HTTP 写入日志,建议按以下顺序组织管道: 1. `loki.source.*` 2. `otelcol.receiver.loki` 3. `otelcol.processor.batch` 4. `otelcol.exporter.otlphttp` 如果你的管道已经是原生 Loki 方案,且不需要 OpenTelemetry 处理链路,建议优先使用 `loki.write` 和 Loki Push 协议。 :::tip 提示 有关 `loki.write`、`otelcol.processor.batch` 和 `otelcol.exporter.otlphttp` 的最新组件行为和调优建议,请参考 Grafana Alloy 官方文档。 ::: --- ## Elasticsearch ## 概述 GreptimeDB 支持使用 Elasticsearch 的 [`_bulk` API](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html) 来写入数据。我们会将 Elasticsearch 中的 Index 概念映射为 GreptimeDB 的 Table,同时用户可在 HTTP 请求的 URL 参数中用 `db` 来指定相应的数据库名。**不同于原生 Elasticsearch,该 API 仅支持数据写入,不支持数据的修改和删除**。在实现层面上,GreptimeDB 会将原生 Elasticsearch `_bulk` API 请求中的 `index` 和 `create` 命令都视为**创建操作**。除此之外,GreptimeDB 仅支持解析原生 `_bulk` API 命令请求中的 `_index` 字段而忽略其他字段。 ## HTTP API 在大多数日志收集器(比如下文中的 Logstash 和 Filebeat)的配置中,你只需要将 HTTP endpoint 配置为 `http://${db_host}:${db_http_port}/v1/elasticsearch`,比如 `http://localhost:4000/v1/elasticsearch`。 GreptimeDB 支持通过实现以下两个 HTTP endpoint 来实现 Elasticsearch 协议的数据写入: - **`/v1/elasticsearch/_bulk`**:用户可使用 POST 方法将数据以 NDJSON 格式写入到 GreptimeDB 中。 以下面请求为例,GreptimeDB 将会创建一个名为 `test` 的表,并写入两条数据: ```json POST /v1/elasticsearch/_bulk {"create": {"_index": "test", "_id": "1"}} {"name": "John", "age": 30} {"create": {"_index": "test", "_id": "2"}} {"name": "Jane", "age": 25} ``` - **`/v1/elasticsearch/${index}/_bulk`**:用户可使用 POST 方法将数据以 NDJSON 格式写入到 GreptimeDB 中的 `${index}` 表中。如果 POST 请求中也有 `_index` 字段,则 URL 中的 `${index}` 将被忽略。 以下面请求为例,GreptimeDB 将会创建一个名为 `test` 和 `another_index` 的表,并各自写入相应的数据: ```json POST /v1/elasticsearch/test/_bulk {"create": {"_id": "1"}} {"name": "John", "age": 30} {"create": {"_index": "another_index", "_id": "2"}} {"name": "Jane", "age": 25} ``` ### HTTP Header 参数 - `x-greptime-db-name`:指定写入的数据库名。如不指定,则默认使用 `public` 数据库; - `x-greptime-pipeline-name`:指定写入的 pipeline 名,如不指定,则默认使用 GreptimeDB 内部的 pipeline `greptime_identity`; - `x-greptime-pipeline-version`:指定写入的 pipeline 版本,如不指定,则默认对应 pipeline 的最新版本; 更多关于 Pipeline 的详细信息,请参考 [管理 Pipelines](/user-guide/logs/manage-pipelines.md) 文档。 ### URL 参数 你可以使用以下 HTTP URL 参数: - `db`:指定写入的数据库名。如不指定,则默认使用 `public` 数据库; - `pipeline_name`:指定写入的 pipeline 名,如不指定,则默认使用 GreptimeDB 内部的 pipeline `greptime_identity`; - `version`:指定写入的 pipeline 版本,如不指定,则默认对应 pipeline 的最新版本; - `msg_field`:`msg_field` 可指定包含原始日志数据的 JSON 字段名。比如在 Logstash 和 Filebeat 中,该字段通常为 `message`。如果用户指定了该参数,则 GreptimeDB 会尝试将该字段中的数据以 JSON 格式进行展开,如果展开失败,则该字段会被当成字符串进行处理。该配置选项目前仅在 URL 参数中生效。 ### 鉴权 Header 关于鉴权 Header 的详细信息,请参考 [Authorization](/user-guide/protocols/http.md#鉴权) 文档。 ## 使用方法 ### 使用 HTTP API 写入数据 你可以创建一个 `request.json` 文件,其中包含如下内容: ```json {"create": {"_index": "es_test", "_id": "1"}} {"name": "John", "age": 30} {"create": {"_index": "es_test", "_id": "2"}} {"name": "Jane", "age": 25} ``` 然后使用 `curl` 命令将该文件作为请求体发送至 GreptimeDB: ```bash curl -XPOST http://localhost:4000/v1/elasticsearch/_bulk \ -H "Authorization: Basic {{authentication}}" \ -H "Content-Type: application/json" -d @request.json ``` 我们可使用 `mysql` 客户端连接到 GreptimeDB,然后执行如下 SQL 语句来查看写入的数据: ```sql SELECT * FROM es_test; ``` 我们将可以看到如下结果: ``` mysql> SELECT * FROM es_test; +------+------+----------------------------+ | age | name | greptime_timestamp | +------+------+----------------------------+ | 30 | John | 2025-01-15 08:26:06.516665 | | 25 | Jane | 2025-01-15 08:26:06.521510 | +------+------+----------------------------+ 2 rows in set (0.13 sec) ``` ### Logstash 如果你正在使用 [Logstash](https://www.elastic.co/logstash) 来收集日志,可使用如下配置来将数据写入到 GreptimeDB: ``` output { elasticsearch { hosts => ["http://localhost:4000/v1/elasticsearch"] index => "my_index" parameters => { "pipeline_name" => "my_pipeline" "msg_field" => "message" } } } ``` 请关注以下与 GreptimeDB 相关的配置: - `hosts`: 指定 GreptimeDB 的 Elasticsearch 协议的 HTTP 地址,即 `http://${db_host}:${db_http_port}/v1/elasticsearch`; - `index`: 指定写入的表名; - `parameters`: 指定写入的 URL 参数,上面的例子中指定了 `pipeline_name` 和 `msg_field` 两个参数; ### Filebeat 如果你正在使用 [Filebeat](https://github.com/elastic/beats/tree/main/filebeat) 来收集日志,可使用如下配置来将数据写入到 GreptimeDB: ``` output.elasticsearch: hosts: ["http://localhost:4000/v1/elasticsearch"] index: "my_index" parameters: pipeline_name: my_pipeline msg_field: message ``` 请关注以下与 GreptimeDB 相关的配置: - `hosts`: 指定 GreptimeDB 的 Elasticsearch 协议的 HTTP 地址,即 `http://${db_host}:${db_http_port}/v1/elasticsearch`,可根据实际情况进行调整; - `index`: 指定写入的表名; - `parameters`: 指定写入的 URL 参数,上面的例子中指定了 `pipeline_name` 和 `msg_field` 两个参数; ### Telegraf 如果你正在使用 [Telegraf](https://github.com/influxdata/telegraf) 来收集日志,你可以使用其 Elasticsearch 插件来将数据写入到 GreptimeDB,如下所示: ```toml [[outputs.elasticsearch]] urls = [ "http://localhost:4000/v1/elasticsearch" ] index_name = "test_table" health_check_interval = "0s" enable_sniffer = false flush_interval = "1s" manage_template = false template_name = "telegraf" overwrite_template = false namepass = ["tail"] [outputs.elasticsearch.headers] "X-GREPTIME-DB-NAME" = "public" "X-GREPTIME-PIPELINE-NAME" = "greptime_identity" [[inputs.tail]] files = ["/tmp/test.log"] from_beginning = true data_format = "value" data_type = "string" character_encoding = "utf-8" interval = "1s" pipe = false watch_method = "inotify" ``` 请关注以下与 GreptimeDB 相关的配置: - `urls`: 指定 GreptimeDB 的 Elasticsearch 协议的 HTTP 地址,即 `http://${db_host}:${db_http_port}/v1/elasticsearch`; - `index_name`: 指定写入的表名; - `outputs.elasticsearch.header`: 指定写入的 HTTP Header,上面的例子中配置了 `X-GREPTIME-DB-NAME` 和 `X-GREPTIME-PIPELINE-NAME` 两个 HTTP Header; --- ## Fluent Bit [Fluent Bit](http://fluentbit.io/) 是一个快速且轻量级的遥测代理,用于 Linux、macOS、Windows 和 BSD 系列操作系统的日志、指标和跟踪。Fluent Bit 专注于性能,允许从不同来源收集和处理遥测数据而不增加复杂性。 你可以将 Fluent Bit 数据转发到 GreptimeDB。本文档介绍如何配置 Fluent Bit 以将日志、指标和跟踪发送到 GreptimeDB。 ## Http 使用 Fluent Bit 的 [HTTP 输出插件](https://docs.fluentbit.io/manual/pipeline/outputs/http),你可以将日志发送到 GreptimeDB。Http 接口目前支持日志的写入。 在配置 Fluent Bit 之前,请确保你已经了解[日志写入流程](/user-guide/logs/overview.md)和[如何使用 pipelines](/user-guide/logs/use-custom-pipelines.md)。 ``` [OUTPUT] Name http Match * Host greptimedb Port 4000 Uri /v1/ingest?db=public&table=your_table&pipeline_name=greptime_identity Format json Json_date_key scrape_timestamp Json_date_format iso8601 compress gzip http_User http_Passwd ``` - `uri`: **发送日志的端点。** - `format`: 日志的格式,需要是 `json`。 - `json_date_key`: JSON 对象中包含时间戳的键。 - `json_date_format`: 时间戳的格式。 - `compress`: 使用的压缩方法,例如 `gzip`。 - `header`: 发送请求时的头部信息,例如用于认证的 `Authorization`。如果没有,不要增加 Authorization 头部。 - `http_user` 和 `http_passwd`: GreptimeDB 的 [认证凭据](/user-guide/deployments-administration/authentication/static.md)。 在 `uri` 参数中: - `db` 是你要写入日志的数据库名称。 - `table` 是你要写入日志的表名称。 - `pipeline_name` 是你要用于处理日志的管道名称。 ## OpenTelemetry GreptimeDB 也可以配置为 OpenTelemetry 收集器。使用 Fluent Bit 的 [OpenTelemetry 输出插件](https://docs.fluentbit.io/manual/pipeline/outputs/opentelemetry),你可以将指标、日志和跟踪发送到 GreptimeDB。 ``` [OUTPUT] Name opentelemetry Match * Host 127.0.0.1 Port 4000 Metrics_uri /v1/otlp/v1/metrics Logs_uri /v1/otlp/v1/logs Traces_uri /v1/otlp/v1/traces Log_response_payload True Tls Off Tls.verify Off ``` - `Metrics_uri`, `Logs_uri`, 和 `Traces_uri`: 发送指标、日志和跟踪的端点。 我们建议不要在一个 output 同时写入 metrics log 和 trace,因为我们的写入接口它们各自有一些特殊的 header 选项用于指定一些参数,我们建议一个为 metrics log 和 trace 单独创建一个 opentelemetry output 例如: ``` # Only for metrics [OUTPUT] Name opentelemetry Alias opentelemetry_metrics Match * Host 127.0.0.1 Port 4000 Metrics_uri /v1/otlp/v1/metrics Log_response_payload True Tls Off Tls.verify Off # Only for logs [OUTPUT] Name opentelemetry Alias opentelemetry_logs Match * Host 127.0.0.1 Port 4000 Logs_uri /v1/otlp/v1/logs Log_response_payload True Tls Off Tls.verify Off Header X-Greptime-Log-Table-Name "" Header X-Greptime-Log-Pipeline-Name "" Header X-Greptime-DB-Name "" ``` 本示例中,使用的是 [OpenTelemetry OTLP/HTTP API](/user-guide/ingest-data/for-observability/opentelemetry.md#opentelemetry-collectors) 接口。如需更多信息,请参阅 [OpenTelemetry](/user-guide/ingest-data/for-observability/opentelemetry.md) 文档。 ## Prometheus Remote Write 将 GreptimeDB 配置为远程写入目标: ``` [OUTPUT] Name prometheus_remote_write Match internal_metrics Host 127.0.0.1 Port 4000 Uri /v1/prometheus/write?db= Tls Off http_user http_passwd ``` - `Uri`: 发送指标的端点。 - `http_user` 和 `http_passwd`: GreptimeDB 的 [认证凭据](/user-guide/deployments-administration/authentication/static.md)。 在 `Uri` 参数中: - `db` 是你要写入指标的数据库名称。 有关从 Prometheus 到 GreptimeDB 的数据模型转换的详细信息,请参阅 Prometheus Remote Write 指南中的[数据模型](/user-guide/ingest-data/for-observability/prometheus.md#data-model)部分。 --- ## InfluxDB Line Protocol(For-observability) 请参考 [InfluxDB Line Protocol 文档](../for-iot/influxdb-line-protocol.md) 了解如何使用 InfluxDB Line Protocol 将数据写入到 GreptimeDB。 --- ## Kafka(For-observability) 如果你使用 Kafka 或兼容 Kafka 的消息队列进行可观测性数据传输,可以直接将数据写入到 GreptimeDB 中。 这里我们使用 Vector 作为工具将数据从 Kafka 传输到 GreptimeDB。 ## 指标 从 Kafka 写入指标到 GreptimeDB 时,消息应采用 InfluxDB 行协议格式。例如: ```txt census,location=klamath,scientist=anderson bees=23 1566086400000000000 ``` 然后配置 Vector 使用 `influxdb` 解码器来处理这些消息。 ```toml [sources.metrics_mq] # 指定源类型为 Kafka type = "kafka" # Kafka 的消费者组 ID group_id = "vector0" # 要消费消息的 Kafka 主题列表 topics = ["test_metric_topic"] # 要连接的 Kafka 地址 bootstrap_servers = "kafka:9092" # `influxdb` 表示消息应采用 InfluxDB 行协议格式 decoding.codec = "influxdb" [sinks.metrics_in] inputs = ["metrics_mq"] # 指定接收器类型为 `greptimedb_metrics` type = "greptimedb_metrics" # GreptimeDB 服务器的端点 # 将 替换为实际的主机名或 IP 地址 endpoint = ":4001" dbname = "" username = "" password = "" tls = {} ``` 有关 InfluxDB 行协议指标如何映射到 GreptimeDB 数据的详细信息,请参阅 InfluxDB 行协议文档中的[数据模型](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md#数据模型)部分。 ## 日志 开发人员通常处理两种类型的日志:JSON 日志和纯文本日志。 例如以下从 Kafka 发送的日志示例。 纯文本日志: ```txt 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" ``` 或 JSON 日志: ```json { "timestamp": "2024-12-23T10:00:00Z", "level": "INFO", "message": "Service started" } ``` GreptimeDB 将这些日志转换为具有多个列的结构化数据,并自动创建必要的表。 Pipeline 在写入到 GreptimeDB 之前将日志处理为结构化数据。 不同的日志格式需要不同的 [Pipeline](/user-guide/logs/quick-start.md#write-logs-by-pipeline) 来解析,详情请继续阅读下面的内容。 ### JSON 格式的日志 对于 JSON 格式的日志(例如 `{"timestamp": "2024-12-23T10:00:00Z", "level": "INFO", "message": "Service started"}`), 你可以使用内置的 [`greptime_identity`](/user-guide/logs/manage-pipelines.md#greptime_identity) pipeline 直接写入日志。 此 pipeline 根据 JSON 日志消息中的字段自动创建列。 你只需要配置 Vector 的 `transforms` 设置以解析 JSON 消息,并使用 `greptime_identity` pipeline,如以下示例所示: ```toml [sources.logs_in] type = "kafka" # Kafka 的消费者组 ID group_id = "vector0" # 要消费消息的 Kafka 主题列表 topics = ["test_log_topic"] # 要连接的 Kafka 代理地址 bootstrap_servers = "kafka:9092" # 将日志转换为 JSON 格式 [transforms.logs_json] type = "remap" inputs = ["logs_in"] source = ''' . = parse_json!(.message) ''' [sinks.logs_out] # 指定此接收器将接收来自 `logs_json` 源的数据 inputs = ["logs_json"] # 指定接收器类型为 `greptimedb_logs` type = "greptimedb_logs" # GreptimeDB 服务器的端点 endpoint = "http://:4000" compression = "gzip" # 将 替换为实际值 dbname = "" username = "" password = "" # GreptimeDB 中的表名,如果不存在,将自动创建 table = "demo_logs" # 使用内置的 `greptime_identity` 管道 pipeline_name = "greptime_identity" ``` ### 文本格式的日志 对于文本格式的日志,例如下面的访问日志格式,你需要创建自定义 pipeline 来解析它们: ``` 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" ``` #### 创建 pipeline 要创建自定义 pipeline, 请参阅[使用自定义 pipeline](/user-guide/logs/use-custom-pipelines.md)文档获取详细说明。 #### 写入数据 创建 pipeline 后,将其配置到 Vector 配置文件中的 `pipeline_name` 字段。 ```toml # sample.toml [sources.log_mq] # 指定源类型为 Kafka type = "kafka" # Kafka 的消费者组 ID group_id = "vector0" # 要消费消息的 Kafka 主题列表 topics = ["test_log_topic"] # 要连接的 Kafka 地址 bootstrap_servers = "kafka:9092" [sinks.sink_greptime_logs] # 指定接收器类型为 `greptimedb_logs` type = "greptimedb_logs" # 指定此接收器将接收来自 `log_mq` 源的数据 inputs = [ "log_mq" ] # 使用 `gzip` 压缩以节省带宽 compression = "gzip" # GreptimeDB 服务器的端点 # 将 替换为实际的主机名或 IP 地址 endpoint = "http://:4000" dbname = "" username = "" password = "" # GreptimeDB 中的表名,如果不存在,将自动创建 table = "demo_logs" # 你创建的自定义管道名称 pipeline_name = "your_custom_pipeline" ``` ## Demo 有关数据转换和写入的可运行演示,请参阅 [Kafka Ingestion Demo](https://github.com/GreptimeTeam/demo-scene/tree/main/kafka-ingestion)。 --- ## Loki ## 使用方法 ### API 要通过原始 HTTP API 将日志发送到 GreptimeDB,请使用以下信息: * **URL**: `http{s}:///v1/loki/api/v1/push` * **Headers**: * `X-Greptime-DB-Name`: `` * `Authorization`: `Basic` 认证,这是一个 Base64 编码的 `:` 字符串。更多信息,请参考 [认证](https://docs.greptime.com/user-guide/deployments-administration/authentication/static/) 和 [HTTP API](https://docs.greptime.com/user-guide/protocols/http#authentication)。 * `X-Greptime-Log-Table-Name`: ``(可选)- 存储日志的表名。如果未提供,默认表名为 `loki_logs`。 请求使用二进制 protobuf 编码负载。定义的格式与 [logproto.proto](https://github.com/grafana/loki/blob/main/pkg/logproto/logproto.proto) 相同。 ### 示例代码 [Grafana Alloy](https://grafana.com/docs/alloy/latest/) 是一个供应商中立的 OpenTelemetry (OTel) Collector 发行版。Alloy 独特地结合了社区中最好的开源可观测性信号。 它提供了一个 Loki 导出器,可以用来将日志发送到 GreptimeDB。以下是一个配置示例: ``` loki.source.file "greptime" { targets = [ {__path__ = "/tmp/foo.txt"}, ] forward_to = [loki.write.greptime_loki.receiver] } loki.write "greptime_loki" { endpoint { url = "${GREPTIME_SCHEME:=http}://${GREPTIME_HOST:=greptimedb}:${GREPTIME_PORT:=4000}/v1/loki/api/v1/push" headers = { "x-greptime-db-name" = "${GREPTIME_DB:=public}", "x-greptime-log-table-name" = "${GREPTIME_LOG_TABLE_NAME:=loki_demo_logs}", } } external_labels = { "job" = "greptime", "from" = "alloy", } } ``` 此配置从文件 `/tmp/foo.txt` 读取日志并将其发送到 GreptimeDB。日志存储在表 `loki_demo_logs` 中,并带有 label `job` 和 `from`。 更多信息,请参考 [Grafana Alloy loki.write 文档](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.write/)。 你可以运行以下命令来检查表中的数据: ```sql SELECT * FROM loki_demo_logs; +----------------------------+------------------------+--------------+-------+----------+ | greptime_timestamp | line | filename | from | job | +----------------------------+------------------------+--------------+-------+----------+ | 2024-11-25 11:02:31.256251 | Greptime is very cool! | /tmp/foo.txt | alloy | greptime | +----------------------------+------------------------+--------------+-------+----------+ 1 row in set (0.01 sec) ``` ## 数据模型 Loki 日志数据模型根据以下规则映射到 GreptimeDB 数据模型: **没有 label 的默认表结构:** ```sql DESC loki_demo_logs; +---------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------------+---------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | line | String | | YES | | FIELD | | structured_metadata | Json | | YES | | FIELD | +---------------------+---------------------+------+------+---------+---------------+ 3 rows in set (0.00 sec) ``` - `greptime_timestamp`: 日志条目的时间戳 - `line`: 日志消息内容 - `structured_metadata`: 日志条目的结构化元数据,JSON 格式 如果 Loki 请求数据中含有 label,它们将作为 tag 添加到表结构中(如上例中的 `job` 和 `from`)。 **重要说明:** - 所有 label 都被视为字符串类型的 tag - 请不要尝试使用 SQL 预先创建表来指定 tag 列,这会导致类型不匹配和写入失败 ### 表结构示例 以下是带有 label 的表结构示例: ```sql DESC loki_demo_logs; +---------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------------+---------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | line | String | | YES | | FIELD | | structured_metadata | Json | | YES | | FIELD | | filename | String | PRI | YES | | TAG | | from | String | PRI | YES | | TAG | | job | String | PRI | YES | | TAG | +---------------------+---------------------+------+------+---------+---------------+ 6 rows in set (0.00 sec) ``` ```sql SHOW CREATE TABLE loki_demo_logs\G *************************** 1. row *************************** Table: loki_demo_logs Create Table: CREATE TABLE IF NOT EXISTS `loki_demo_logs` ( `greptime_timestamp` TIMESTAMP(9) NOT NULL, `line` STRING NULL, `filename` STRING NULL, `from` STRING NULL, `job` STRING NULL, TIME INDEX (`greptime_timestamp`), PRIMARY KEY (`filename`, `from`, `job`) ) ENGINE=mito WITH( append_mode = 'true' ) 1 row in set (0.00 sec) ``` ## 在 Loki Push API 中使用 pipeline :::warning 实验性特性 此实验性功能可能存在预期外的行为,其功能未来可能发生变化。 ::: 从 `v0.15` 版本开始,GreptimeDB 支持使用 pipeline 来处理 Loki Push 请求。 你可以简单地设置 HTTP 头 `x-greptime-pipeline-name` 为目标 pipeline 名称来启用 pipeline 处理。 **注意:** 当请求数据通过 pipeline 引擎时,GreptimeDB 会为 label 和元数据列名添加前缀: - 每个 label 名前添加 `loki_label_` 前缀 - 每个结构化元数据名前添加 `loki_metadata_` 前缀 - 原始的 Loki 日志行被命名为 `loki_line` ### Pipeline 示例 以下是一个完整的示例,演示如何在 Loki Push API 中使用 Pipeline。 **步骤 1:准备日志文件** 假设我们有一个名为 `logs.json` 的日志文件,包含 JSON 格式的日志条目: ```json {"timestamp":"2025-08-21 14:23:17.892","logger":"sdk.tool.DatabaseUtil","level":"ERROR","message":"Connection timeout exceeded for database pool","trace_id":"a7f8c92d1e4b4c6f9d2e5a8b3f7c1d9e","source":"application"} {"timestamp":"2025-08-21 14:23:18.156","logger":"core.scheduler.TaskManager","level":"WARN","message":"Task queue capacity reached 85% threshold","trace_id":"b3e9f4a6c8d2e5f7a1b4c7d9e2f5a8b3","source":"scheduler"} {"timestamp":"2025-08-21 14:23:18.423","logger":"sdk.tool.NetworkUtil","level":"INFO","message":"Successfully established connection to remote endpoint","trace_id":"c5d8e7f2a9b4c6d8e1f4a7b9c2e5f8d1","source":"network"} ``` 每一行都是一个独立的 JSON 对象,包含日志信息。 **步骤 2:创建 Pipeline 配置** 以下是解析 JSON 日志条目的 pipeline 配置: ```yaml # pipeline.yaml version: 2 processors: - vrl: source: | message = parse_json!(.loki_line) target = { "log_time": parse_timestamp!(message.timestamp, "%Y-%m-%d %T%.3f"), "log_level": message.level, "log_source": message.source, "logger": message.logger, "message": message.message, "trace_id": message.trace_id, } . = target transform: - field: log_time type: time, ms index: timestamp ``` pipeline 的配置相对直观: 使用 `vrl` 处理器将日志行解析为 JSON 对象,然后将其中的字段提取到根目录。 `log_time` 在 transform 部分中被指定为时间索引,其他字段将由 pipeline 引擎自动推导,详见 [pipeline version 2](/reference/pipeline/pipeline-config.md#版本-2-中的-transform)。 请注意,输入字段名为 `loki_line`,它包含来自 Loki 的原始日志行。 **步骤 3:配置 Grafana Alloy** 准备一个 Alloy 配置文件来读取日志文件并将其发送到 GreptimeDB: ``` loki.source.file "greptime" { targets = [ {__path__ = "/logs.json"}, ] forward_to = [loki.write.greptime_loki.receiver] } loki.write "greptime_loki" { endpoint { url = "http://127.0.0.1:4000/v1/loki/api/v1/push" headers = { "x-greptime-pipeline-name" = "pp", } } external_labels = { "job" = "greptime", "from" = "alloy", } } ``` 在 `greptime_loki` 中,通过 `x-greptime-pipeline-name` 的 HTTP 头来指示写入的数据需要被 pipeline 引擎处理。 **步骤 4:部署和运行** 1. 首先,启动你的 GreptimeDB 实例。参见[这里](/getting-started/installation/overview.md)快速启动。 2. [上传](/user-guide/logs/manage-pipelines.md#create-a-pipeline) pipeline 配置到数据库: ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/pp" -F "file=@pipeline.yaml" ``` 3. 启动 Alloy Docker 容器来处理日志: ```shell docker run --rm \ -v ./config.alloy:/etc/alloy/config.alloy \ -v ./logs.json:/logs.json \ --network host \ grafana/alloy:latest \ run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data \ /etc/alloy/config.alloy ``` **步骤 5:验证结果** 日志处理完成后,您可以验证它们是否已成功摄取和解析。数据库日志将显示摄取活动。 使用 MySQL 客户端查询表以查看解析的日志数据: ```sql mysql> show tables; +-----------+ | Tables | +-----------+ | loki_logs | | numbers | +-----------+ 2 rows in set (0.00 sec) mysql> select * from loki_logs limit 1 \G *************************** 1. row *************************** log_time: 2025-08-21 14:23:17.892000 log_level: ERROR log_source: application logger: sdk.tool.DatabaseUtil message: Connection timeout exceeded for database pool trace_id: a7f8c92d1e4b4c6f9d2e5a8b3f7c1d9e 1 row in set (0.01 sec) ``` 此输出演示了 pipeline 引擎已成功解析原始 JSON 日志行,并将结构化数据提取到单独的列中。 有关 pipeline 配置和功能的更多详细信息,请参考[pipeline 文档](/reference/pipeline/pipeline-config.md)。 --- ## OpenTelemetry Protocol (OTLP) [OpenTelemetry](https://opentelemetry.io/) 是一个供应商中立的开源可观测性框架,用于检测、生成、收集和导出观测数据,例如 traces, metrics 和 logs。 OpenTelemetry Protocol (OTLP) 定义了观测数据在观测源和中间进程(例如收集器和观测后端)之间的编码、传输机制。 ## OpenTelemetry Collectors 你可以很简单地将 GreptimeDB 配置为 OpenTelemetry 采集器写入的目标。 有关更多信息,请参阅 [OTel Collector](otel-collector.md) 和[Grafana Alloy](alloy.md) 示例。 ## HTTP 基础端点 适用于所有信号类型的[HTTP 基础端点](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_endpoint) URL:`http{s}:///v1/otlp` 当需要将多种信号类型(指标、日志和链路追踪)发送到同一目标数据库时,这个统一端点非常有用,可以简化你的 OpenTelemetry 配置。 ## Metrics GreptimeDB 通过原生支持 [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) 协议,可以作为后端存储服务来接收 OpenTelemetry 指标数据。 ### OTLP/HTTP API 使用下面的信息通过 Opentelemetry SDK 库发送 Metrics 到 GreptimeDB: - URL: `https:///v1/otlp/v1/metrics` - Headers: - `X-Greptime-DB-Name`: `` - `Authorization`: `Basic` 认证,是 `:` 的 Base64 编码字符串。更多信息请参考 [鉴权](https://docs.greptime.cn/user-guide/deployments-administration/authentication/static/) 和 [HTTP API](https://docs.greptime.cn/user-guide/protocols/http#authentication)。 请求中使用 binary protobuf 编码 payload,因此你需要使用支持 `HTTP/protobuf` 的包。例如,在 Node.js 中,可以使用 [`exporter-trace-otlp-proto`](https://www.npmjs.com/package/@opentelemetry/exporter-trace-otlp-proto);在 Go 中,可以使用 [`go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp);在 Java 中,可以使用 [`io.opentelemetry:opentelemetry-exporter-otlp`](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-exporter-otlp);在 Python 中,可以使用 [`opentelemetry-exporter-otlp-proto-http`](https://pypi.org/project/opentelemetry-exporter-otlp-proto-http/)。 :::tip 注意 包名可能会根据 OpenTelemetry 的发展发生变化,因此建议你参考 OpenTelemetry 官方文档以获取最新信息。 ::: 请参考 Opentelementry 的官方文档获取它所支持的编程语言的更多信息。 ### 示例代码 下面是一些编程语言设置请求的示例代码: ```ts const auth = Buffer.from(`${username}:${password}`).toString('base64') const exporter = new OTLPMetricExporter({ url: `https://${dbHost}/v1/otlp/v1/metrics`, headers: { Authorization: `Basic ${auth}`, 'X-Greptime-DB-Name': db, }, timeoutMillis: 5000, }) ``` ```Go auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", *username, *password))) exporter, err := otlpmetrichttp.New( context.Background(), otlpmetrichttp.WithEndpoint(*dbHost), otlpmetrichttp.WithURLPath("/v1/otlp/v1/metrics"), otlpmetrichttp.WithHeaders(map[string]string{ "X-Greptime-DB-Name": *dbName, "Authorization": "Basic " + auth, }), otlpmetrichttp.WithTimeout(time.Second*5), ) ``` ```Java String endpoint = String.format("https://%s/v1/otlp/v1/metrics", dbHost); String auth = username + ":" + password; String b64Auth = new String(Base64.getEncoder().encode(auth.getBytes())); OtlpHttpMetricExporter exporter = OtlpHttpMetricExporter.builder() .setEndpoint(endpoint) .addHeader("X-Greptime-DB-Name", db) .addHeader("Authorization", String.format("Basic %s", b64Auth)) .setTimeout(Duration.ofSeconds(5)) .build(); ``` ```python auth = f"{username}:{password}" b64_auth = base64.b64encode(auth.encode()).decode("ascii") endpoint = f"https://{host}/v1/otlp/v1/metrics" exporter = OTLPMetricExporter( endpoint=endpoint, headers={"Authorization": f"Basic {b64_auth}", "X-Greptime-DB-Name": db}, timeout=5) ``` 关于示例代码,请参考 Opentelementry 的官方文档获取它所支持的编程语言获取更多信息。 ### 兼容 Prometheus 从 `v0.16` 开始,GreptimeDB 为 OTLP 指标写入引入了一种 Prometheus 兼容模式。 如果指标以这种兼容模式写入,你可以像查询 Prometheus 原生指标一样使用 PromQL 直接查询这些指标。 如果你之前没有使用过 OTLP 指标写入,那么 GreptimeDB 会默认使用新的兼容模式。 否则,GreptimeDB 会对已经存在的表保留原有的数据模型,只有对新创建的指标表使用兼容模式写入。 GreptimeDB 会首先对数据进行预处理,包括: 1. 将指标名(表名)和标签名转换成 Prometheus 风格的命名(例如:将 `.` 替换为 `_`)。具体信息请参考[这里](https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#metric-metadata-1) 以下是一些转换示例: | OTLP 指标 / 属性 | OTLP 类型 / 单位 | Prometheus 等效名称 | | :--- | :--- | :--- | | `cache.hit_ratio` | Gauge / `1` | `cache_hit_ratio` | | `memory.usage` | Gauge / `By` | `memory_usage_bytes` | | `queue.length` | Gauge / `{item}` | `queue_length` | | `http.server.request.duration` | Histogram / `s` | `http_server_request_duration_seconds` | | `rpc.server.duration` | Histogram / `ms` | `rpc_server_duration_seconds` | | `http.client.request.size` | Sum (Monotonic) / `By` | `http_client_request_size_bytes_total` | | `system.network.io` | Sum (Monotonic) / `By` | `system_network_io_bytes_total` | | `http.status_code` (属性) | - | `http_status_code` | | `service.name` (属性) | - | `service_name` | 2. 默认丢弃一些 resource 属性和全部的 scope 属性。默认保存的 resource 属性列表可以参考[这里](https://prometheus.io/docs/guides/opentelemetry/#promoting-resource-attributes)。你可以通过配置项对这个行为进行调整 注意: OTLP 的 `Sum` 和 `Histogram` 指标的数据可能是增量时序(delta temporality)类型的。 GreptimeDB 将会直接保存它们,不会进行累计值(cumulative value)的计算。 参考[这里](https://grafana.com/blog/2023/09/26/opentelemetry-metrics-a-guide-to-delta-vs.-cumulative-temporality-trade-offs/)获取更多背景信息。 你可以通过设置 HTTP 请求头来调整预处理的行为。以下是选项列表: 1. `x-greptime-otlp-metric-promote-all-resource-attrs`: 保存所有 resource 资源。默认是 `false`。 2. `x-greptime-otlp-metric-promote-resource-attrs`: 如果不保存所有 resource 资源,需要保存的资源名称列表,用 `;` 连接。 3. `x-greptime-otlp-metric-ignore-resource-attrs`: 如果保存所有的 resource 资源,需要丢弃的资源名称列表,用 `;` 连接。 4. `x-greptime-otlp-metric-promote-scope-attrs`: 是否需要保存 scope 资源。默认是 `false`。 ### 数据模型 兼容 Prometheus 的 OTLP 指标数据模型按照下方的规则被映射到 GreptimeDB 数据模型中: - Metric 的名称将被作为 GreptimeDB 表的名称,当表不存在时会自动创建。 - 只有特定 resource 属性会被默认保留。详情和配置选项见上一小节。属性在 GreptimeDB 表中会被作为 tag 列。 - 参考 [Prometheus 数据模型](./prometheus.md#数据模型)了解更多数据模型信息。 - ExponentialHistogram 暂时未被支持。 如果你在 `v0.16` 之前使用 OTLP 指标,那么数据将以非兼容模式保存。以下是数据模型在映射上的差别: - 所有的 Attribute,包含 resource 级别、scope 级别和 data_point 级别,都被作为 GreptimeDB 表的 tag 列。 - Summary 类型的每个 quantile 被作为单独的数据列,列名 `greptime_pxx`,其中 xx 是 quantile 的数据,如 90 / 99 等。 ## Logs GreptimeDB 是能够通过 [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) 协议原生地消费 OpenTelemetry 日志。 ### OTLP/HTTP API 要通过 OpenTelemetry SDK 库将 OpenTelemetry 日志发送到 GreptimeDB,请使用以下信息: - **URL:** `https:///v1/otlp/v1/logs` - **Headers:** - `X-Greptime-DB-Name`: `` - `Authorization`: `Basic` 认证,这是一个 Base64 编码的 `:` 字符串。更多信息,请参考 [鉴权](/user-guide/deployments-administration/authentication/static.md) 和 [HTTP API](/user-guide/protocols/http.md#鉴权)。 - `X-Greptime-Log-Table-Name`: ``(可选)- 存储日志的表名。如果未提供,默认表名为 `opentelemetry_logs`。 - `X-Greptime-Log-Extract-Keys`: ``(可选)- 从属性中提取对应 key 的值到表的顶级字段。key 应以逗号(`,`)分隔。例如,`key1,key2,key3` 将从属性中提取 `key1`、`key2` 和 `key3`,并将它们提升到日志的顶层,设置为标签。如果提取的字段类型是数组、浮点数或对象,将返回错误。如果提供了 pipeline name,此设置将被忽略。 - `X-Greptime-Log-Pipeline-Name`: ``(可选)- 处理日志的 pipeline 名称。如果未提供,将使用 `X-Greptime-Log-Extract-Keys` 来处理日志。 - `X-Greptime-Log-Pipeline-Version`: ``(可选)- 处理日志的 pipeline 的版本。如果未提供,将使用 pipeline 的最新版本。 请求使用二进制 protobuf 编码负载,因此您需要使用支持 `HTTP/protobuf` 的包。 :::tip 提示 包名可能会根据 OpenTelemetry 的更新而变化,因此我们建议您参考官方 OpenTelemetry 文档以获取最新信息。 ::: 有关 OpenTelemetry SDK 的更多信息,请参考您首选编程语言的官方文档。 ### 示例代码 请参考 [OpenTelemetry Collector 文档](otel-collector.md)中的示例代码,里面包含了如何将 OpenTelemetry 日志发送到 GreptimeDB。 也可参考 [Alloy 文档](alloy.md#日志)中的示例代码,了解如何将 OpenTelemetry 日志发送到 GreptimeDB。 ### 数据模型 OTLP 日志数据模型根据以下规则映射到 GreptimeDB 数据模型: 默认表结构: ```sql +-----------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------------+---------------------+------+------+---------+---------------+ | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | trace_id | String | | YES | | FIELD | | span_id | String | | YES | | FIELD | | severity_text | String | | YES | | FIELD | | severity_number | Int32 | | YES | | FIELD | | body | String | | YES | | FIELD | | log_attributes | Json | | YES | | FIELD | | trace_flags | UInt32 | | YES | | FIELD | | scope_name | String | PRI | YES | | TAG | | scope_version | String | | YES | | FIELD | | scope_attributes | Json | | YES | | FIELD | | scope_schema_url | String | | YES | | FIELD | | resource_attributes | Json | | YES | | FIELD | | resource_schema_url | String | | YES | | FIELD | +-----------------------+---------------------+------+------+---------+---------------+ 14 rows in set (0.00 sec) ``` - 您可以使用 `X-Greptime-Log-Table-Name` 指定存储日志的表名。如果未提供,默认表名为 `opentelemetry_logs`。 - 所有属性,包括资源属性、范围属性和日志属性,将作为 JSON 列存储在 GreptimeDB 表中。 - 日志的时间戳将用作 GreptimeDB 中的时间戳索引,列名为 `timestamp`。建议使用 `time_unix_nano` 作为时间戳列。如果未提供 `time_unix_nano`,将使用 `observed_time_unix_nano`。 ### Append-only 模式 通过此接口创建的表,默认为[Append-only 模式](/user-guide/deployments-administration/performance-tuning/design-table.md#何时使用-append-only-表)。 ## Traces GreptimeDB 支持直接写入 OpenTelemetry 协议的 traces 数据,并内置 OpenTelemetry 的 traces 的表模型来让用户方便地查询和分析 traces 数据。 ### OTLP/HTTP API 你可以使用 [OpenTelemetry SDK](https://opentelemetry.io/docs/languages/) 或其他类似的技术方案来为应用添加 traces 数据。你还可以用 [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) 来收集 traces 数据,并使用 GreptimeDB 作为后端存储。 要通过 OpenTelemetry SDK 库将 OpenTelemetry 的 traces 数据发送到 GreptimeDB,请使用以下信息: - URL: `http{s}:///v1/otlp/v1/traces` - Headers: - `Content-Type`: 应配置为 `application/x-protobuf` - `Authorization`: `Basic` 认证。 - `X-Greptime-DB-Name`: `` - `X-Greptime-Trace-Table-Name`: ``(可选)- 存储 traces 的表名。如果未提供,默认表名为 `opentelemetry_traces`。 - `X-Greptime-Pipeline-Name`: `greptime_trace_v1`(必选)- 处理 traces 的 pipeline 名称。 GreptimeDB 会通过 **HTTP 协议** 接受 **protobuf 编码的 traces 数据**。 ### 示例代码 你可以直接将 OpenTelemetry traces 数据发送到 GreptimeDB,也可以使用 OpenTelemetry Collector 来收集 traces 数据,并使用 GreptimeDB 作为后端存储,请参考 [OpenTelemetry Collector 文档](/user-guide/traces/read-write.md#opentelemetry-collector)中的示例代码,了解如何将 OpenTelemetry traces 数据发送到 GreptimeDB。 ### 数据模型 GreptimeDB 将 OTLP traces 数据模型映射到表结构。默认情况下,Trace 数据存储在 `opentelemetry_traces` 表中。 ```sql +------------------------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------------------------+---------------------+------+------+---------+---------------+ | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | timestamp_end | TimestampNanosecond | | YES | | FIELD | | duration_nano | UInt64 | | YES | | FIELD | | parent_span_id | String | | YES | | FIELD | | trace_id | String | | YES | | FIELD | | span_id | String | | YES | | FIELD | | span_kind | String | | YES | | FIELD | | span_name | String | | YES | | FIELD | | span_status_code | String | | YES | | FIELD | | span_status_message | String | | YES | | FIELD | | trace_state | String | | YES | | FIELD | | scope_name | String | | YES | | FIELD | | scope_version | String | | YES | | FIELD | | service_name | String | PRI | YES | | TAG | | span_attributes.net.sock.peer.addr | String | | YES | | FIELD | | span_attributes.peer.service | String | | YES | | FIELD | | span_events | Json | | YES | | FIELD | | span_links | Json | | YES | | FIELD | +------------------------------------+---------------------+------+------+---------+---------------+ ``` - 每一行代表一个单一的 span。 - `service_name` 用作 **Tag**(**主键**的一部分)。 - `timestamp` 用作 **时间索引**(Time Index)。 - Resource Attributes 和 Span Attributes 将被自动展平为单独的列。 - 注意:`resource_attributes.service.name` 被排除在打平之外,因为它已经存储在 `service_name` 列中。 - `span_events` 和 `span_links` 默认存储为 `JSON` 数据类型。 有关数据模型和辅助表的更多详细信息,请参阅 [Trace 数据模型](/user-guide/traces/data-model.md)。 注意: 1. `greptime_trace_v1` 处理方式默认通过 `trace_id` 字段将数据切分成不同的分区以提升性能。**请确保 `trace_id` 的第一个字符是分布均匀的**。 2. 在非测试的场合下,可以通过设置 `ttl` 以避免持久化数据量过大。通过设置 `x-greptime-hints: ttl=7d` HTTP 请求头,在创建 trace 表时会添加一个 7 天的 `ttl` 表选项。见[此文档](/reference/sql/create.md#表选项)了解更多关于表选项 `ttl` 的信息。 ### 辅助表 GreptimeDB 会自动创建辅助表(例如 `opentelemetry_traces_services` 和 `opentelemetry_traces_operations`),以便于搜索服务和操作。详情请参阅[辅助表](/user-guide/traces/data-model.md#辅助表)。 ### Append-only 模式 通过此接口创建的表,默认为[Append-only 模式](/user-guide/deployments-administration/performance-tuning/design-table.md#何时使用-append-only-表)。 --- ## OTel Collector [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) 提供了一种与供应商无关的 OTEL 实现,用于接收、处理和导出可观测数据。它可以作为数据的中间层,将数据从不同的源发送到 GreptimeDB。 以下是使用 OpenTelemetry Collector 将数据发送到 GreptimeDB 的配置示例。 ```yaml extensions: basicauth/client: client_auth: username: password: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp/traces: endpoint: 'http://127.0.0.1:4000/v1/otlp' # auth: # authenticator: basicauth/client headers: # x-greptime-db-name: '' x-greptime-pipeline-name: 'greptime_trace_v1' tls: insecure: true otlphttp/logs: endpoint: 'http://127.0.0.1:4000/v1/otlp' # auth: # authenticator: basicauth/client headers: # x-greptime-db-name: '' # x-greptime-log-table-name: '' # x-greptime-pipeline-name: '' tls: insecure: true otlphttp/metrics: endpoint: 'http://127.0.0.1:4000/v1/otlp' # auth: # authenticator: basicauth/client headers: # x-greptime-db-name: '' tls: insecure: true service: # extensions: [basicauth/client] pipelines: traces: receivers: [otlp] exporters: [otlphttp/traces] logs: receivers: [otlp] exporters: [otlphttp/logs] metrics: receivers: [otlp] exporters: [otlphttp/metrics] ``` 在上面的配置中,我们定义了一个接收器 `otlp`,它可以接收来自 OpenTelemetry 的数据。我们还定义了三个导出器 `otlphttp/traces`、`otlphttp/logs` 和 `otlphttp/metrics`,它们将数据发送到 GreptimeDB 的 OTLP 路径。 在 otlphttp 协议的基础上,我们增加了一些 header 用来指定一些参数,比如 `x-greptime-pipeline-name` 和 `x-greptime-log-table-name`: * `x-greptime-pipeline-name` 用来指定要使用的 pipeline 名称 * `x-greptime-log-table-name` 用来指定数据将要写入 GreptimeDB 的表名。 如果你在 GreptimeDB 设置了[鉴权](/user-guide/deployments-administration/authentication/overview.md)。则需要使用 `basicauth/client` 扩展来处理基本的身份验证。 这里我们强烈建议使用不同的导出器来分别处理 traces、logs 和 metrics 数据,一方面是因为 GreptimeDB 会支持一些特定的 header 来自定义一些处理流程,另一方面也可以做好数据隔离。 关于 OpenTelemetry 协议的更多信息,请阅读[文档](/user-guide/ingest-data/for-observability/opentelemetry.md)。 --- ## 可观测场景数据写入 在可观测性场景中,实时监控和分析系统性能的能力至关重要。 GreptimeDB 与领先的可观测性工具无缝集成,为你提供系统健康和性能指标的全面视图。 - [在 GreptimeDB 中存储万亿级日志,并快速获得分析结果](/user-guide/logs/overview.md). - [Prometheus Remote Write](prometheus.md):将 GreptimeDB 作为 Prometheus 的远程存储,适用于实时监控和警报。 - [Vector](vector.md):将 GreptimeDB 用作 Vector 的接收端,适用于复杂的数据流水线和多样化的数据源。 - [OpenTelemetry](opentelemetry.md):将 telemetry 数据收集并导出到 GreptimeDB,以获取详细的可观测性洞察。 - [InfluxDB Line Protocol](influxdb-line-protocol.md):一种广泛使用的时间序列数据协议,便于从 InfluxDB 迁移到 GreptimeDB。该文档同样介绍了 Telegraf 的集成方式。 - [Loki](loki.md):一种广泛使用的日志写入协议,便于从 Loki 迁移到 GreptimeDB。本文档还介绍了 Alloy 集成方法。 --- ## Prometheus GreptimeDB 可以作为 Prometheus 的长期存储解决方案,提供无缝集成体验。 ## 配置 Remote Write ### Prometheus 配置文件 要将 GreptimeDB 集成到 Prometheus 中, 请按照以下步骤更新你的 [Prometheus 配置文件](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#configuration-file)(`prometheus.yml`): ```yaml remote_write: - url: http://localhost:4000/v1/prometheus/write?db=public # 如果启用了身份验证,请取消注释并设置鉴权信息 # basic_auth: # username: greptime_user # password: greptime_pwd remote_read: - url: http://localhost:4000/v1/prometheus/read?db=public # 如果启用了身份验证,请取消注释并设置鉴权信息 # basic_auth: # username: greptime_user # password: greptime_pwd ``` - URL 中的 host 和 port 表示 GreptimeDB 服务器。在此示例中,服务器运行在 `localhost:4000` 上。你可以将其替换为你自己的服务器地址。有关 GreptimeDB 中 HTTP 协议的配置,请参阅 [协议选项](/user-guide/deployments-administration/configuration.md#protocol-options)。 - URL 中的 `db` 参数表示要写入的数据库。它是可选的。默认情况下,数据库设置为 `public`。 - `basic_auth` 是身份鉴权配置。如果 GreptimeDB 启用了鉴权,请填写用户名和密码。请参阅 [鉴权认证文档](/user-guide/deployments-administration/authentication/overview.md)。 ### Grafana Alloy 配置文件 如果你使用 Grafana Alloy,请在 Alloy 配置文件(`config.alloy`)中配置 Remote Write。有关更多信息,请参阅 [Alloy 文档](alloy.md#prometheus-remote-write)。 ### Vector 配置文件 如果你使用 Vector ,请在 Vector 配置文件(`vector.toml`)中配置 Remote Write。有关更多信息,请参阅 [Vector 文档](vector.md#使用-prometheus-remote-write-协议). ## 数据模型 在 GreptimeDB 的[数据模型](/user-guide/concepts/data-model.md)中,数据被组织成具有 tag、time index 和 field 的表。 GreptimeDB 可以被视为多值数据模型,自动将多个 Prometheus 指标分组到相应的表中。 这样可以实现高效的数据管理和查询。 ![数据模型](/PromQL-multi-value-data-model.png) 当指标通过远程写入端点写入 GreptimeDB 时,它们将被转换为以下形式: | Sample Metrics | In GreptimeDB | GreptimeDB Data Types | | -------------- | ------------------------- | --------------------- | | Name | Table (Auto-created) Name | String | | Value | Column (Field) | Double | | Timestamp | Column (Time Index) | Timestamp | | Label | Column (Tag) | String | 例如,以下 Prometheus 指标: ```txt prometheus_remote_storage_samples_total{instance="localhost:9090", job="prometheus", remote_name="648f0c", url="http://localhost:4000/v1/prometheus/write"} 500 ``` 将被转换为表 `prometheus_remote_storage_samples_total` 中的一行: | Column | Value | Column Data Type | | :----------------- | :------------------------------------------ | :----------------- | | instance | localhost:9090 | String | | job | prometheus | String | | remote_name | 648f0c | String | | url | `http://localhost:4000/v1/prometheus/write` | String | | greptime_value | 500 | Double | | greptime_timestamp | The sample's unix timestamp | Timestamp | ## 通过使用 metric engine 提高效率 Prometheus Remote Write 写入数据的方式经常会创建大量的小表,这些表在 GreptimeDB 中被归类为逻辑表。 然而,拥有大量的小表对于数据存储和查询性能来说是低效的。 为了解决这个问题,GreptimeDB 引入了 [metric engine](/contributor-guide/datanode/metric-engine.md) 功能,将逻辑表表示的数据存储在单个物理表中。 这种方法减少了存储开销并提高了列式压缩效率。 GreptimeDB 默认启用 metric engine,你不需要指定任何额外的配置。 默认情况下,使用的物理表为 `greptime_physical_table`。 如果你想使用特定的物理表,可以在 Remote Write URL 中指定 `physical_table` 参数。 如果指定的物理表不存在,它将被自动创建。 ```yaml remote_write: - url: http://localhost:4000/v1/prometheus/write?db=public&physical_table=greptime_physical_table ``` 虽然数据被存储在物理表中,但查询可以在逻辑表上执行以提供从指标角度的直观视角。 例如,当成功写入数据时,你可以使用以下命令显示逻辑表: ```sql show tables; ``` ```sql +---------------------------------------------------------------+ | Tables | +---------------------------------------------------------------+ | prometheus_remote_storage_enqueue_retries_total | | prometheus_remote_storage_exemplars_pending | | prometheus_remote_storage_read_request_duration_seconds_count | | prometheus_rule_group_duration_seconds | | ...... | +---------------------------------------------------------------+ ``` 物理表本身也可以进行查询。 它包含了所有逻辑表的列,方便进行多表连接分析和计算。 要查看物理表的 schema,请使用 `DESC TABLE` 命令: ```sql DESC TABLE greptime_physical_table; ``` 物理表包含了所有逻辑表的列: ```sql +--------------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+----------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampMillisecond | PRI | NO | | TIMESTAMP | | greptime_value | Float64 | | YES | | FIELD | | __table_id | UInt32 | PRI | NO | | TAG | | __tsid | UInt64 | PRI | NO | | TAG | | device | String | PRI | YES | | TAG | | instance | String | PRI | YES | | TAG | | job | String | PRI | YES | | TAG | | error | String | PRI | YES | | TAG | ... ``` 你可以使用 `SELECT` 语句根据需要从物理表中过滤数据。 例如,根据逻辑表 A 的 `device` 条件和逻辑表 B 的 `job` 条件来过滤数据: ```sql SELECT * FROM greptime_physical_table WHERE greptime_timestamp > "2024-08-07 03:27:26.964000" AND device = "device1" AND job = "job1"; ``` ### 在 GreptimeDB 集群上使用 metric engine 在使用 Prometheus remote write 写入 GreptimeDB 集群时,用户可能注意到集群中只有 一 个 datanode 承载写入压力,其他节点没有流量。这是由于在默认配置下,集群中只有 一个 metric engine 物理表,且该表只有一个分区。承载此分区的节点将承担所有写入流 量。 为什么我们没有创建更多的分区呢?[GreptimeDB 的表分 区](/user-guide/deployments-administration/manage-data/table-sharding.md)基于预 定义的分区列。然而在 Prometheus 生态中并没有普遍存在的列(Prometheus 中的标签) 适合作为默认分区列。 因此,我们推荐用户基于自己的数据模型创建分区规则。例如,在监控 Kubernetes 集群的 场景下,`namespace` 可能是一个比较好的分区键。这个分区键应当具备一定的基数用于区 分数据。并且我们推荐用户在初始时创建 datanode 数量大约 2 倍至 3 倍的分区数量,为日后 集群扩容负载均衡做准备。 以下是一个分区的物理表例子: ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, namespace STRING PRIMARY KEY, TIME INDEX (greptime_timestamp), ) PARTITION ON COLUMNS (namespace) ( namespace <'g', namespace >= 'g' AND namespace < 'n', namespace >= 'n' AND namespace < 't', namespace >= 't' ) ENGINE = metric with ( "physical_metric_table" = "", ); ``` 注意这里用户并不需要手动指定所有可能的主键(标签),metric engine 将会自动添加。 只有涉及到分区规则的列需要进行提前指定。 ## 特殊标签 :::warning 实验性特性 此实验性功能可能存在预期外的行为,其功能未来可能发生变化。 ::: 一般来说,一次 Remote write 请求的全部数据会以同样的配置项被写入到数据库中,例如,开启 metric engine 后使用的同一个物理表配置。 即使指标的数量在增长,所有的逻辑表(即指标们)都会保存到同一张物理表中。 对于写入这可能是没问题的。但是对于需要查询一小部分指标的场景,这种设置可能会拖慢查询速度,因为所有的指标都聚集在一张物理表上,而数据库需要对全表的数据进行扫描。 如果你可以预见大量的数据写入和每次只需查询小部分指标的场景,那么可以在写入时对存储位置进行划分以减缓后续查询的压力。 对于一个 Remote write 请求中的每个指标,这种精细的控制可以通过写入时的配置项来达成。 从 `v0.15` 开始,GreptimeDB 新增了对特殊标签的支持。 这些标签(与它们的值)会在解析阶段被转换成写入时的配置项,使请求内的单个指标可以被更精细地控制。 这些标签不是互斥的,它们可以通过组合的方式达成更多样化的控制选择。 以下是指标特殊标签的一个示例,注意这不是实际的数据模型。 | `__name__` | `x_greptime_database` | `x_greptime_physical_table` | `pod_name_label` | `__normal_label_with_underscore_prefix__` | `timestamp` | `value` | |--------------------|-------------------------|-------------------------------|-----------------------|---------------------------------------------|---------------------------|-----------| | `some_metric_name` | `public` | `p_1` | `random_k8s_pod_name` | `true` | `2025-06-17 16:31:52.000` | `12.1` | 上述特殊标签只是在 Prometheus 中的普通有效标签。 GreptimeDB 可以识别一些标签的名称,并将它们转换成写入时的配置项。 就像自定义的 HTTP header 一样,你可以通过设定一些有效的 HTTP header 键值对来指示后续的操作,只是这些 header 键值对在特定的程序之外不起任何作用。 以下是所有 GreptimeDB 支持的标签名称: - `x_greptime_database` - `x_greptime_physical_table` ### 设置标签 如何将标签设置到指标上,与你所使用的收集指标并发送到数据库的工具(或者代码)相关。 如果你使用 Prometheus 从源获取指标并使用 Remote write 将他们发送到 GreptimeDB 中,可以在全局设定中增加 `external_labels` 的配置。 参考这个[文档](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#configuration-file)。 对于其他的收集工具也是一样的。对于你所使用的工具,你可能需要查找相应的设置。 ### `x_greptime_database` 这个选项决定指标数据会被保存到哪个数据库中,该数据库需要被提前创建好(例如通过 `create database xxx` SQL 语句)。 一般来说,同样的技术栈会产生同样名称的指标。 例如你有两个 Kubernetes 集群,但是运行了不同的应用,然后通过一个指标收集工具同时收集两个集群的指标。 这两个集群会产生名称一样但是标签和值完全不同的指标。 如果这些指标被写入到同一个数据库中,那么在使用 Grafana 大盘浏览这些指标的时候,就需要对大盘的每个图表手动设置标签值,才能区分集群进行查看。 这样既繁琐又低效。 在这种情况下,你可以在写入时将指标保存到两个不同的数据库中,然后使用两个大盘分别浏览这些指标。 ### `x_greptime_physical_table` 如果指标通过 metric engine 进行存储,那么每个指标的逻辑表背后是一张物理表。 默认下,所有的指标都使用同一张物理表。 随着指标数量的增长,这张物理表会变成一张超级宽表。如果指标的写入频率不同,那么物理表的数据将会是稀疏的。 在全量指标数据集中查找一个特定的指标或者标签将会消耗大量时间,因为数据库需要扫描所有不相关的数据。 这种场景下,将指标写入到不同的物理表可以减轻单一物理表的压力,这对通过写入频率来聚合指标的场景非常有用。 注意,指标的逻辑表在创建时就与物理表一一关联。在同一数据库下为同一指标设定不同的物理表不会生效。 ## 在 Remote write 中使用 pipeline :::warning 实验性特性 此实验性功能可能存在预期外的行为,其功能未来可能发生变化。 ::: 从 `v0.15` 开始,GreptimeDB 支持在 Prometheus Remote Write 协议入口使用 pipeline 处理数据。 你可以通过在 HTTP header 中将 `x-greptime-pipeline-name` 的值设置为需要执行的 pipeline 名称来使用 pipeline 处理流程。 以下是一个非常简单的 pipeline 配置例子,使用 `vrl` 处理器来对每个指标增加一个 `source` 标签: ```YAML version: 2 processors: - vrl: source: | .source = "local_laptop" . transform: - field: greptime_timestamp type: time, ms index: timestamp ``` 结果如下所示 ``` mysql> select * from `go_memstats_mcache_inuse_bytes`; +----------------------------+----------------+--------------------+---------------+--------------+ | greptime_timestamp | greptime_value | instance | job | source | +----------------------------+----------------+--------------------+---------------+--------------+ | 2025-07-11 07:42:03.064000 | 1200 | node_exporter:9100 | node-exporter | local_laptop | | 2025-07-11 07:42:18.069000 | 1200 | node_exporter:9100 | node-exporter | local_laptop | +----------------------------+----------------+--------------------+---------------+--------------+ 2 rows in set (0.01 sec) ``` 更多配置详情请参考 [pipeline 相关文档](/reference/pipeline/pipeline-config.md)。 ## 性能优化 默认情况下,metric engine 会自动创建一个名为 `greptime_physical_table` 的物理表。 为了优化性能,你可以选择创建一个具有自定义配置的物理表。 ### 启用跳数索引 默认情况下,metric engine 不会为列创建索引。你可以通过设置 `index.type` 为 `skipping` 来设置索引类型。 创建一个带有跳数索引的物理表。所有自动添加的列都将应用跳数索引。 ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, TIME INDEX (greptime_timestamp), ) engine = metric with ( "physical_metric_table" = "", "index.type" = "skipping" ); ``` 有关更多配置,请参阅 [create table](/reference/sql/create.md#create-table) 部分。 ## VictoriaMetrics Remote Write VictoriaMetrics 对 Prometheus 远程写入协议进行了轻微修改,以实现更好的压缩效果。 当你使用 `vmagent` 将数据发送到兼容的后端时,该协议会被自动启用。 GreptimeDB 也支持这个变种。只需将 GreptimeDB 的 Remote Write URL 配置为 `vmagent`。 例如,如果你在本地安装了 GreptimeDB: ```shell vmagent -remoteWrite.url=http://localhost:4000/v1/prometheus/write ``` --- ## Vector :::tip 注意 本文档基于 Vector v0.49.0 版本编写。 以下的所有示例配置均基于此版本。对于各个 sink 的 host 和 port 配置请根据自己 GreptimeDB 实例的实际情况进行调整。 下文中的所有 port 值均为默认值。 ::: Vector 是高性能的可观测数据管道。 它原生支持 GreptimeDB 指标数据接收端。 通过 Vector,你可以从各种来源接收指标数据,包括 Prometheus、OpenTelemetry、StatsD 等。 GreptimeDB 可以作为 Vector 的 Sink 组件来接收指标数据。 ## 写入指标数据 GreptimeDB 支持多种指标数据写入方式,包括: - 使用 [`greptimedb_metrics` sink](https://vector.dev/docs/reference/configuration/sinks/greptimedb_metrics/) - 使用 InfluxDB 行协议格式将指标数据写入 GreptimeDB - 使用 Prometheus Remote Write 协议将指标数据写入 GreptimeDB ### 使用 `greptimedb_metrics` sink #### 示例 以下是一个使用 `greptimedb_metrics` sink 写入宿主机指标的示例配置: ```toml # sample.toml [sources.in] type = "host_metrics" [sinks.my_sink_id] inputs = ["in"] type = "greptimedb_metrics" endpoint = ":4001" dbname = "" username = "" password = "" new_naming = true ``` Vector 使用 gRPC 与 GreptimeDB 进行通信,因此 Vector sink 的默认端口是 `4001`。 如果你在使用 [自定义配置](/user-guide/deployments-administration/configuration.md#configuration-file) 启动 GreptimeDB 时更改了默认的 gRPC 端口,请使用你自己的端口。 如有更多需求请前往 [Vector GreptimeDB Configuration](https://vector.dev/docs/reference/configuration/sinks/greptimedb_metrics/) 查看更多配置项。 #### 数据模型 我们使用这样的规则将 Vector 指标存入 GreptimeDB: - 使用 `_` 作为 GreptimeDB 的表名,例如 `host_cpu_seconds_total`; - 将指标中的时间戳作为 GreptimeDB 的时间索引,默认列名 `ts`; - 指标所关联的 tag 列将被作为 GreptimeDB 的 tag 字段; - Vector 的指标,和其他指标类似,有多种子类型: - Counter 和 Gauge 类型的指标,数值直接被存入 `val` 列; - Set 类型,我们将集合的数据个数存入 `val` 列; - Distribution 类型,各个百分位数值点分别存入 `pxx` 列,其中 xx 是 quantile 数值,此外我们还会记录 `min/max/avg/sum/count` 列; - AggregatedHistoragm 类型,每个 bucket 的数值将被存入 `bxx` 列,其中 xx 是 bucket 数值的上限,此外我们还会记录 `sum/count` 列; - AggregatedSummary 类型,各个百分位数值点分别存入 `pxx` 列,其中 xx 是 quantile 数值,此外我们还会记录 `sum/count` 列; - Sketch 类型,各个百分位数值点分别存入 `pxx` 列,其中 xx 是 quantile 数值,此外我们还会记录 `min/max/avg/sum` 列; ### 使用 InfluxDB 行协议格式 可以使用 `influx` sink 来写入指标数据。我们推荐使用 v2 版本的 InfluxDB 行协议格式。 以下是一个使用 `influx` sink 写入宿主机指标的示例配置: ```toml # sample.toml [sources.my_source_id] type = "internal_metrics" [sinks.my_sink_id] type = "influxdb_metrics" inputs = [ "my_source_id" ] bucket = "public" endpoint = "http://:4000/v1/influxdb" org = "" token = "" ``` 上述配置使用的是 InfluxDB 行协议的 v2 版本。Vector 会根据 TOML 配置中的字段来判断 InfluxDB 协议的版本,所以请务必确保配置中存在 `bucket`、`org` 和 `token` 字段。具体字段的解释如下: - `type`: InfluxDB 行协议的值为 `influxdb_metrics`. - `bucket`: GreptimeDB 中的 database 名称。 - `org`: GreptimeDB 中的组织名称(需置空)。 - `token`: 用于身份验证的令牌(需置空)。由于 Influx 行协议的 token 有特殊形式,必须以 `Token ` 开头。这和 GreptimeDB 的鉴权方式有所不同,且目前不兼容。如果使用的是含有鉴权的 GreptimeDB 实例,请使用 `greptimedb_metrics`。 更多细节请参考 [InfluxDB Line Protocol 文档](../for-iot/influxdb-line-protocol.md) 了解如何使用 InfluxDB Line Protocol 将数据写入到 GreptimeDB。 ### 使用 Prometheus Remote Write 协议 以下是一个使用 Prometheus Remote Write 协议写入宿主机指标的示例配置: ```toml # sample.toml [sources.my_source_id] type = "internal_metrics" [sinks.prometheus_remote_write] type = "prometheus_remote_write" inputs = [ "my_source_id" ] endpoint = "http://:4000/v1/prometheus/write?db=" compression = "snappy" auth = { strategy = "basic", username = "", password = "" } ``` ## 写入日志数据 GreptimeDB 支持多种日志数据写入方式,包括: - 使用 [`greptimedb_logs` sink](https://vector.dev/docs/reference/configuration/sinks/greptimedb_logs/) 将日志数据写入 GreptimeDB。 - 使用 Loki 协议将日志数据写入 GreptimeDB。 我们强烈建议所有的用户使用 `greptimedb_logs` sink 来写入日志数据,因为它是为 GreptimeDB 优化的,能够更好地支持 GreptimeDB 的特性。 并且推荐开启各种协议的压缩功能,以提高数据传输效率。 ### 使用 `greptimedb_logs` sink (推荐) ```toml # sample.toml [sources.my_source_id] type = "demo_logs" count = 10 format = "apache_common" interval = 1 [sinks.my_sink_id] type = "greptimedb_logs" inputs = [ "my_source_id" ] compression = "gzip" dbname = "public" endpoint = "http://:4000" extra_headers = { "skip_error" = "true" } pipeline_name = "greptime_identity" table = "" username = "" password = "" [sinks.my_sink_id.extra_params] source = "vector" x-greptime-pipeline-params = "max_nested_levels=10" ``` 此示例展示了如何使用 `greptimedb_logs` sink 将生成的 demo 日志数据写入 GreptimeDB。更多信息请参考 [Vector greptimedb_logs sink](https://vector.dev/docs/reference/configuration/sinks/greptimedb_logs/) 文档。 ### 使用 Loki 协议 #### 示例 ```toml [sources.generate_syslog] type = "demo_logs" format = "syslog" count = 100 interval = 1 [transforms.remap_syslog] inputs = ["generate_syslog"] type = "remap" source = """ .labels = { "host": .host, "service": .service, } .structured_metadata = { "source_type": .source_type } """ [sinks.my_sink_id] type = "loki" inputs = ["remap_syslog"] compression = "snappy" endpoint = "http://:4000" out_of_order_action = "accept" path = "/v1/loki/api/v1/push" encoding = { codec = "raw_message" } labels = { "*" = "{{labels}}" } structured_metadata = { "*" = "{{structured_metadata}}" } auth = {strategy = "basic", user = "", password = ""} ``` 上述配置为使用 Loki 协议将日志数据写入 GreptimeDB。具体的配置项说明如下: - `compression`:设置了数据传输时的压缩算法,这里使用了 `snappy`。 - `endpoint`:指定了 Loki 的接收地址。 - `out_of_order_action`:设置了如何处理乱序的日志,这里选择了 `accept`,表示接受乱序日志。GreptimeDB 支持乱序日志的写入。 - `path`:指定了 Loki 的 API 路径。 - `encoding`:设置了数据的编码方式,这里使用了 `raw_message`。 - `labels`:指定了日志的标签,这里将 `labels` 的内容映射为 `{{labels}}`。即 remap_syslog 中的 `labels` 字段。 - `structured_metadata`:指定了结构化元数据,这里将 `structured_metadata` 的内容映射为 `{{structured_metadata}}`。即 remap_syslog 中的 `structured_metadata` 字段。 关于 `labels` 和 `structured_metadata` 的含义,请参考 [Loki 文档](https://grafana.com/docs/loki/latest/get-started/labels/bp-labels/)。 对于 loki 协议,`labels` 默认会使用时序场景下的 Tag 类型,请注意这部分字段不要使用高基数字段。 `structured_metadata` 将会整体存储为一个 json 字段。 请注意,由于 Vector 的配置里不允许设置 header 所以无法指定 pipeline。 如果需要使用 pipeline 功能,请考虑使用 `greptimedb_logs` sink。 --- ## 写入数据 GreptimeDB 支持自动生成表结构和灵活的数据写入方法, 使你能够轻松地根据特定场景写入数据。 ## 自动生成表结构 GreptimeDB 支持无 schema 写入,即在数据写入时自动创建表格并添加必要的列。 这种能力确保你无需事先手动定义 schema,从而更容易管理和集成各种数据源。 此功能适用于所有协议和集成,除了 [SQL](./for-iot/sql.md)。 ## 推荐的数据写入方法 GreptimeDB 支持针对特定场景的各种数据写入方法,以确保最佳性能和集成灵活性。 - [可观测场景](./for-observability/overview.md):适用于实时监控和警报。 - [物联网场景](./for-iot/overview.md):适用于实时数据和复杂的物联网基础设施。 ## 下一步 - [查询数据](/user-guide/query-data/overview.md): 学习如何通过查询 GreptimeDB 数据库来探索数据。 - [管理数据](/user-guide/manage-data/overview.md): 学习如何更新和删除数据等,确保数据完整性和高效的数据管理。 --- ## Grafana Alloy(Integrations) 你可以将 GreptimeDB 设置为 Grafana Alloy 的数据接收端。 更多信息,请参考[通过 Grafana Alloy 写入数据](/user-guide/ingest-data/for-observability/alloy.md)指南。 --- ## Coroot Coroot 是一个开源的 APM 和可观测性工具, 是 DataDog 和 NewRelic 的替代方案。 预定义的仪表板具备指标、日志、链路追踪、持续性能分析 和基于 SLO 的告警功能。 GreptimeDB 可以配置为 Coroot 中的 Prometheus 数据存储。 要将 GreptimeDB 集成到 Coroot 中, 需要在 Coroot 仪表板中导航到 Settings, 选择 Prometheus 配置,然后输入以下信息: - Prometheus URL: `http{s}:///v1/prometheus` - 如果你在 GreptimeDB 上[启用了身份验证](/user-guide/deployments-administration/authentication/static.md),请勾选 HTTP basic auth 并输入 GreptimeDB 用户名和密码。如果没有启用身份认证,保留未勾选状态即可。 - Remote Write URL: `http{s}:///v1/prometheus/write?db=` ## 示例配置 如果你的 GreptimeDB 被部署在 `localhost`,HTTP 服务端口为 `4000`,已启用身份验证, 并且使用默认数据库 `public`, 请使用以下配置: - Prometheus URL: `http://localhost:4000/v1/prometheus` - 启用 HTTP basic auth 选项并输入 GreptimeDB 用户名和密码 - Remote Write URL: `http://localhost:4000/v1/prometheus/write?db=public` 下图是 Coroot 的配置示例: 配置保存成功后, 你就可以开始使用 Coroot 监控实例了。 下图展示了使用 GreptimeDB 作为数据源的 Coroot 仪表板示例: ![coroot-cpu](/coroot-cpu.png) --- ## DBeaver [DBeaver](https://dbeaver.io/) 是一个免费、开源且跨平台的数据库工具,支持所有流行的数据库。 由于其易用性和丰富的功能集,它在开发人员和数据库管理员中非常受欢迎。 你可以使用 DBeaver 通过 MySQL Driver 连接到 GreptimeDB。 点击 DBeaver 工具栏中的“New Database Connection”按钮,以创建 GreptimeDB 的新连接。 选择 MySQL 并点击“下一步”以配置连接。 如果你还没有安装 MySQL Driver,请先安装。 接下来输入以下连接信息: - Connect by Host - Host:如果 GreptimeDB 运行在本机,则为 `localhost` - Port:如果使用默认的 GreptimeDB 配置,则为 `4002` - Database:`public`,你也可以使用你创建的其他数据库名称 - 如果你的 GreptimeDB 启用了身份验证,请输入 username 和 password,否则留空 点击“Test Connection”以验证连接设置,然后点击“Finish”以保存连接。 有关 MySQL 与 GreptimeDB 交互的更多信息,请参阅 [MySQL 协议文档](/user-guide/protocols/mysql.md)。 --- ## EMQX(Integrations) GreptimeDB 可以作为 EMQX 的数据系统。 更多信息请参考 [通过 EMQX 写入数据](/user-guide/ingest-data/for-iot/emqx.md) 指南。 --- ## Fluent Bit(Integrations) 你可以将 GreptimeDB 设置为 Fluent Bit 的数据接收端。 更多信息,请参考[通过 Fluent Bit 写入数据](../ingest-data/for-observability/fluent-bit.md)指南。 --- ## Grafana GreptimeDB 服务可以配置为 [Grafana 数据源](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/)。 你可以选择使用以下三个数据源之一连接 GreptimeDB 与 Grafana:GreptimeDB、Prometheus 或 MySQL。 ## GreptimeDB 数据源插件 [GreptimeDB 数据源插件(v2.x)](https://github.com/GreptimeTeam/greptimedb-grafana-datasource)基于 ClickHouse 插件开发并附加了特定于 GreptimeDB 的功能。 该插件完美适配了 GreptimeDB 的数据模型, 从而提供了更好的用户体验。 ### 安装 GreptimeDB 数据源插件目前仅支持在本地 Grafana 中的安装, 在安装插件前请确保 Grafana 已经安装并运行。 你可以任选以下一种安装方式: - 下载安装包并解压到相关目录:从[发布页面](https://github.com/GreptimeTeam/greptimedb-grafana-datasource/releases/latest/)获取最新版本,解压文件到你的 [grafana 插件目录](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#plugins)。 - 使用 Grafana Cli 下载并安装: ```shell grafana cli --pluginUrl https://github.com/GreptimeTeam/greptimedb-grafana-datasource/releases/latest/download/info8fcc-greptimedb-datasource.zip plugins install info8fcc ``` - 使用我们 [预构建的 Grafana 镜 像](https://hub.docker.com/r/greptime/grafana-greptimedb),已经提前包含了 GreptimeDB 数据源插件 `docker run -p 3000:3000 greptime/grafana-greptimedb:latest` 注意,安装插件后可能需要重新启动 Grafana 服务器。 ### Connection 配置 在 Grafana 中单击 Add data source 按钮,选择 GreptimeDB 作为类型。 ![grafana-add-greptimedb-data-source](/grafana-add-greptimedb-data-source.png) 在 GreptimeDB server URL 中填写以下地址: ```txt http://:4000 ``` 在 Auth 部分中单击 basic auth,并在 Basic Auth Details 中填写 GreptimeDB 的用户名和密码。未设置可留空: - User: `` - Password: `` 然后单击 Save & Test 按钮以测试连接。 ### 基础查询设置 在进行所有类型查询选择前,需要先设置要查询的数据库和表 | 设置项 | 对应值 | |-----------|-------------| | Database| 选择数据库 | Table | 选择表格 ![DB Table Config](/grafana/dbtable.png) --- ### Table 查询 当查询结果不包含`时间列`时可以选择 `Table` 类型进行查询 | 设置项 | 对应值 | |-----------|-------------| | Columns | 选择要查询的列,可多选 | Filters | 设置筛选条件 ![Table Query](/grafana/table.png) --- ### Metrics 查询 当查询结果包含`时间列`和`数值列`时可以选择 `Time Series` 类型进行查询 | 主要设置项 | 对应值 | |-----------|-------------| | Time | 选择时间列 | Columns | 选择数值列 ![Time Series](/grafana/series1.png) --- ### Logs 查询 当要查询 Logs 数据时选择 `Logs` 类型进行查询 * Logs: 对日志数据进行查询。需要设置 `Time` 列和 `Message` 列。 | 主要设置项 | 对应值 | |-----------|--------------------| | Time | 选择时间列 | Message | 选择日志内容列 | Log Level| 日志等级(非必填) ![Logs](/grafana/logs.png) #### logs Context 查询 根据日志行的 context 列的值进行近似时间范围查询 * 需要先设置 context 相关的列。 ![Context Config](/grafana/context2.png) * 然后查询的时候包含 context 相关列。 ![Logs Query Config](/grafana/context1.png) --- ### Traces 查询 当要查询 Traces 数据时选择 `Traces` 类型进行查询 | 主要设置项 | 对应值 | |-----------|---------------------| | Trace Model | 选择 `Trace Search` 以查询 Trace 列表 | Trace Id Column | 初始值 `trace_id` | Span Id Column | 初始值 `span_id` | Parent Span ID Column | 初始值 `parent_span_id` | Service Name Column | 初始值 `service_name` | Operation Name Column | 初始值 `span_name` | Start Time Column | 初始值 `timestamp` | Duration Time Column | 初始值 `duration_nano` | Duration Unit | 初始值 `nano_seconds` | Tags Column | 可多选,对应以 `span_attributes` 开头的列 | Service Tags Column| 可多选,对应以 `resource_attributes` 开头的列 ![Traces](/grafana/traceconfig.png) ## Prometheus 数据源 单击 Add data source 按钮,然后选择 Prometheus 作为类型。 在 HTTP 中填写 Prometheus server URL ```txt http://:4000/v1/prometheus ``` 在 Auth 部分中单击 basic auth,并在 Basic Auth Details 中填写 GreptimeDB 的用户名和密码: - User: `` - Password: `` 在 Custom HTTP Headers 部分中点击 Add header: - Header: `x-greptime-db-name` - Value: `` 然后单击 Save & Test 按钮以测试连接。 有关如何使用 PromQL 查询数据,请参阅 [Prometheus 查询语言](/user-guide/query-data/promql.md)文档。 ## MySQL 数据源 单击 Add data source 按钮,然后选择 MySQL 作为类型。在 MySQL Connection 中填写以下信息: - Host: `:4002` - Database: `` - User: `` - Password: `` - Session timezone: `UTC` 然后单击 Save & Test 按钮以测试连接。 注意目前我们只能使用 raw SQL 创建 Grafana Panel。由于时间戳数据类型的区别,Grafana 的 SQL Builder 暂时无法选择时间戳字段。 关于如何用 SQL 查询数据,请参考[使用 SQL 查询数据](/user-guide/query-data/sql.md)文档。 --- ## Kafka(Integrations) 你可以使用 Vector 作为从 Kafka 到 GreptimeDB 的数据传输工具。 请前往[通过 Kafka 写入数据](/user-guide/ingest-data/for-observability/kafka.md)了解更多信息。 --- ## Model Context Protocol (MCP) :::warning 实验性功能 GreptimeDB MCP Server 目前处于实验阶段并在积极开发中。API 和功能可能会在没有通知的情况下发生变化。请在生产环境中谨慎使用。 ::: [GreptimeDB MCP Server](https://github.com/GreptimeTeam/greptimedb-mcp-server) 提供了模型上下文协议的实现,使 Claude 等 AI 助手能够安全地探索和分析您的 GreptimeDB 数据库。 查看我们的[演示视频和文章](https://mp.weixin.qq.com/s/gbTuMLoG4b151Hs8KCSGxg),了解 MCP Server 的实际应用效果,更直观地理解其功能。 ## 什么是 MCP? 模型上下文协议(MCP)是一种标准协议,允许 AI 助手与外部数据源和工具进行交互。通过 GreptimeDB MCP Server,您可以让 AI 助手实现: - 列出和探索数据库表 - 读取表数据和模式 - 执行 SQL 查询 - 通过自然语言分析时序数据 ## 安装 使用 pip 安装 GreptimeDB MCP Server: ```bash pip install greptimedb-mcp-server ``` ## 配置 MCP 服务器可以通过环境变量或命令行参数进行配置。主要配置选项包括: - 数据库连接设置(主机、端口、用户名、密码) - 数据库名称 - 时区设置 ### 示例:Claude Desktop 集成 要与 Claude Desktop 集成,请在您的 `claude_desktop_config.json` 中添加以下配置: ```json { "mcpServers": { "greptimedb": { "command": "python", "args": ["-m", "greptimedb_mcp_server"], "env": { "GREPTIMEDB_HOST": "localhost", "GREPTIMEDB_PORT": "4002", "GREPTIMEDB_USERNAME": "your_username", "GREPTIMEDB_PASSWORD": "your_password", "GREPTIMEDB_DATABASE": "your_database" } } } } ``` ## 了解更多 有关详细的配置选项、高级用法和故障排除,请参阅 [GreptimeDB MCP Server 文档](https://github.com/GreptimeTeam/greptimedb-mcp-server)。 :::note GreptimeDB MCP Server 是一个仍在开发中的实验性项目。在处理敏感数据时请谨慎使用。 ::: --- ## Metabase [Metabase](https://github.com/metabase/metabase) 是一个用 Clojure 编写的开源 BI 工具,可以通过社区维护的数据库驱动将 GreptimeDB 添加到 Metabase。 ## 安装 从 [发布 页](https://github.com/greptimeteam/greptimedb-metabase-driver/releases/latest/) 下载最新的驱动插件文件 `greptimedb.metabase-driver.jar`,并将文件拷贝到 Metabase 的工作目录下 `plugins/` 目录中(如果不存在需要创建 `plugins/`)。当 Metabase 启 动时,会自动检测到插件。 ## 添加 GreptimeDB 数据库 选择 *设置* / *管理员设置* / *数据库*, 点击 *添加数据库* 按钮并选择 GreptimeDB 作为 *数据库类型*. 进一步添加其他数据库信息: - 端口请填写 GreptimeDB 的 Postgres 协议端口 `4003`。 - 如果没有开启[认证](/user-guide/deployments-administration/authentication/overview.md),用户名和密码字段 是可选的。 - 默认填写 `public` 作为 *数据库名*。如果是使用 GreptimeCloud 的实例,可以从控制 台复制数据库名称。 --- ## MindsDB [MindsDB](https://mindsdb.com/) 是一个开源的机器学习平台,使开发人员能够轻松地将 先进的机器学习能力与现有数据库集成。 使用 MindsDB 扩展,你的 GreptimeDB 实例可以开箱即用。 你可以使用 MySQL 协议将 GreptimeDB 配置为 MindsDB 中的数据源: ```sql CREATE DATABASE greptime_datasource WITH ENGINE = 'greptimedb', PARAMETERS = { "host": "", "port": 4002, "database": "", "user": "", "password": "", "ssl": True }; ``` - `` 是你的 GreptimeDB 实例的主机名或 IP 地址。 - `` 是你想要连接的数据库名称。 - `` 和 `` 是你 [GreptimeDB 的鉴权信息](/user-guide/deployments-administration/authentication/static.md)。 MindsDB 是许多机器学习功能的优秀门户,包括您存储在我们实例中的时间序列数据的时间序列预测。 访问 [MindsDB docs](https://docs.mindsdb.com/what-is-mindsdb) 了解更多。 --- ## 工具集成 GreptimeDB 可以与流行的数据写入、查询和可视化工具无缝集成。 本章节提供了将 GreptimeDB 与以下工具集成的指导: --- ## Prometheus(Integrations) ## Remote Write GreptimeDB 可以用作 Prometheus 的远程存储后端。 详细信息请参考[使用 Prometheus Remote Write 写入数据](/user-guide/ingest-data/for-observability/prometheus.md)。 ## Prometheus Query Language (PromQL) GreptimeDB 支持使用 Prometheus 查询语言 (PromQL) 来查询数据。 更多信息请参考[使用 PromeQL 查询数据](/user-guide/query-data/promql.md)。 --- ## Streamlit [Streamlit](https://streamlit.io/) 是一种更快的构建和分享数据应用的方式。 可以基于 GreptimeDB 构建基于 Streamlit 的数据应用。 你需要创建一个 SQL 连接在应用程序中使用 GreptimeDB 数据。 由于 GreptimeDB 的 [MySQL 协议兼容性](/user-guide/protocols/mysql.md),你可以在连接时将 GreptimeDB 视为 MySQL。 以下是从 Streamlit 连接到 GreptimeDB 的示例代码片段: ```python st.title('GreptimeDB Streamlit 演示') conn = st.connection("greptimedb", type="sql", url="mysql://:@:4002/") df = conn.query("SELECT * FROM ...") ``` - `` 是 GreptimeDB 实例的主机名或 IP 地址。 - `` 是要连接的数据库的名称。 - `` 和 `` 是 [GreptimeDB 鉴权认证信息](/user-guide/deployments-administration/authentication/static.md)。 创建连接后,你可以对 GreptimeDB 实例运行 SQL 查询。结果集会自动转换为 Pandas dataframe,就像在 Streamlit 中使用普通数据源一样。 --- ## Superset [Apache Superset](https://superset.apache.org) 是开源的 BI 工具,用 Python 编写。 以下内容可以帮助你把 GreptimeDB 作为 Superset 的数据源。 ## 安装 ### 用 Docker Compose 运行 Superset [Docker compose](https://superset.apache.org/docs/installation/docker-compose) 是 Superset 的推荐使用方式。在这种运行方式下,需要在 Superset 代码目录下的 `docker/` 中添加一个 `requirements-local.txt`。 并将 GreptimeDB 依赖加入到 `requirements-local.txt`: ```txt greptimedb-sqlalchemy ``` 启动 Supertset 服务: ```bash docker compose -f docker-compose-non-dev.yml up ``` ### 本地运行 Superset 假如你通过 [Pypi 包安装和运行 Superset](https://superset.apache.org/docs/installation/pypi),需要将 GreptimeDB 的依赖安装到相同的 Python 环境。 ```bash pip install greptimedb-sqlalchemy ``` ## 添加 GreptimeDB 数据库 准备添加,选择 *设置* / *数据库连接*. 添加数据库,并在支持的数据库列表中选择 *GreptimeDB*。 根据 SQLAlchemy URI 的规范,填写以下格式的数据库连接地址。 ``` greptimedb://:@:/ ``` - 如果没有启动[认证](/user-guide/deployments-administration/authentication/overview.md),可以忽略 `:@` 部分。 - 默认端口 `4003` (我们用 PostgresSQL 协议通信)。 - 默认数据库 `public`。如果是使用 GreptimeCloud 实例,可以从控制台复制数据库名称。 --- ## Telegraf 请参考 InfluxDB 行协议文档中的 [Telegraf 部分](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md#telegraf) 了解如何使用 Telegraf 向 GreptimeDB 写入数据。 --- ## Vector(Integrations) 请前往[使用 Vector 写入数据](/user-guide/ingest-data/for-observability/vector.md)查看如何使用 Vector 将数据传输到 GreptimeDB。 --- ## 全文搜索 本文档详细介绍如何利用 GreptimeDB 的查询语言对日志数据进行高效搜索和分析。 GreptimeDB 支持通过 SQL 语句灵活查询数据。本节将介绍特定的搜索功能和查询语句,帮助你提升日志查询效率。 ## 使用 `matches_term` 函数进行精确匹配 在 SQL 查询中,你可以使用 `matches_term` 函数执行精确的词语/短语匹配,这在日志分析中尤其实用。`matches_term` 函数支持对 `String` 类型列进行精确匹配。你也可以使用 `@@` 操作符作为 `matches_term` 的简写形式。下面是一个典型示例: ```sql -- 使用 matches_term 函数 SELECT * FROM logs WHERE matches_term(message, 'error') OR matches_term(message, 'fail'); -- 使用 @@ 操作符(matches_term 的简写形式) SELECT * FROM logs WHERE message @@ 'error' OR message @@ 'fail'; ``` `matches_term` 函数专门用于精确匹配,使用方式如下: - `text`:需要进行匹配的文本列,该列应包含 `String` 类型的文本数据。 - `term`:要匹配的词语或短语,遵循以下规则: - 区分大小写 - 匹配项必须由非字母数字字符(包括空格、标点符号等)或文本开头/结尾界定 - 支持完整词语匹配和短语匹配 ## 查询语句示例 ### 简单词语匹配 `matches_term` 函数执行精确词语匹配,这意味着它只会匹配由非字母数字字符或文本开头/结尾界定的完整词语。这对于在日志中查找特定的错误消息或状态码特别有用。 ```sql -- 使用 matches_term 函数 SELECT * FROM logs WHERE matches_term(message, 'error'); -- 使用 @@ 操作符 SELECT * FROM logs WHERE message @@ 'error'; ``` 此查询将返回所有 `message` 列中包含完整词语 "error" 的记录。该函数确保你不会得到部分匹配或词语内的匹配。 匹配和不匹配的示例: - ✅ "An error occurred!" - 匹配,因为 "error" 是一个完整词语 - ✅ "Critical error: system failure" - 匹配,因为 "error" 由空格和冒号界定 - ✅ "error-prone" - 匹配,因为 "error" 由连字符界定 - ❌ "errors" - 不匹配,因为 "error" 是更大词语的一部分 - ❌ "error123" - 不匹配,因为 "error" 后面跟着数字 - ❌ "errorLogs" - 不匹配,因为 "error" 是驼峰命名词语的一部分 ### 多关键词搜索 你可以使用 `OR` 运算符组合多个 `matches_term` 条件来搜索包含多个关键词中任意一个的日志。当你想要查找可能包含不同错误变体或不同类型问题的日志时,这很有用。 ```sql -- 使用 matches_term 函数 SELECT * FROM logs WHERE matches_term(message, 'critical') OR matches_term(message, 'error'); -- 使用 @@ 操作符 SELECT * FROM logs WHERE message @@ 'critical' OR message @@ 'error'; ``` 此查询将查找包含完整词语 "critical" 或 "error" 的日志。每个词语都是独立匹配的,结果包括匹配任一条件的日志。 匹配和不匹配的示例: - ✅ "critical error: system failure" - 匹配两个词语 - ✅ "An error occurred!" - 匹配 "error" - ✅ "critical failure detected" - 匹配 "critical" - ❌ "errors" - 不匹配,因为 "error" 是更大词语的一部分 - ❌ "critical_errors" - 不匹配,因为词语是更大词语的一部分 ### 排除条件搜索 你可以使用 `NOT` 运算符与 `matches_term` 结合来从搜索结果中排除某些词语。当你想要查找包含一个词语但不包含另一个词语的日志时,这很有用。 ```sql -- 使用 matches_term 函数 SELECT * FROM logs WHERE matches_term(message, 'error') AND NOT matches_term(message, 'critical'); -- 使用 @@ 操作符 SELECT * FROM logs WHERE message @@ 'error' AND NOT message @@ 'critical'; ``` 此查询将查找包含词语 "error" 但不包含词语 "critical" 的日志。这对于过滤掉某些类型的错误或专注于特定的错误类别特别有用。 匹配和不匹配的示例: - ✅ "An error occurred!" - 匹配,因为它包含 "error" 但不包含 "critical" - ❌ "critical error: system failure" - 不匹配,因为它包含两个词语 - ❌ "critical failure detected" - 不匹配,因为它包含 "critical" ### 多条件必要搜索 你可以使用 `AND` 运算符要求日志消息中必须存在多个词语。这对于查找包含特定词语组合的日志很有用。 ```sql -- 使用 matches_term 函数 SELECT * FROM logs WHERE matches_term(message, 'critical') AND matches_term(message, 'error'); -- 使用 @@ 操作符 SELECT * FROM logs WHERE message @@ 'critical' AND message @@ 'error'; ``` 此查询将查找同时包含完整词语 "critical" 和 "error" 的日志。两个条件都必须满足,日志才会包含在结果中。 匹配和不匹配的示例: - ✅ "critical error: system failure" - 匹配,因为它包含两个词语 - ❌ "An error occurred!" - 不匹配,因为它只包含 "error" - ❌ "critical failure detected" - 不匹配,因为它只包含 "critical" ### 短语匹配 `matches_term` 函数也可以匹配精确的短语,包括带空格的短语。这对于查找包含多个词语的特定错误消息或状态更新很有用。 ```sql -- 使用 matches_term 函数 SELECT * FROM logs WHERE matches_term(message, 'system failure'); -- 使用 @@ 操作符 SELECT * FROM logs WHERE message @@ 'system failure'; ``` 此查询将查找包含精确短语 "system failure" 的日志。整个短语必须完全匹配,包括词语之间的空格。 匹配和不匹配的示例: - ✅ "Alert: system failure detected" - 匹配,因为短语被正确界定 - ✅ "system failure!" - 匹配,因为短语被正确界定 - ❌ "system-failure" - 不匹配,因为词语由连字符而不是空格分隔 - ❌ "system failure2023" - 不匹配,因为短语后面跟着数字 ### 不区分大小写匹配 虽然 `matches_term` 默认区分大小写,但你可以通过在匹配前将文本转换为小写来实现不区分大小写的匹配。 ```sql -- 使用 matches_term 函数 SELECT * FROM logs WHERE matches_term(lower(message), 'warning'); -- 使用 @@ 操作符 SELECT * FROM logs WHERE lower(message) @@ 'warning'; ``` 此查询将查找包含词语 "warning" 的日志,无论其大小写如何。`lower()` 函数在匹配前将整个消息转换为小写。 匹配和不匹配的示例: - ✅ "Warning: high temperature" - 匹配,因为大小写转换后匹配 - ✅ "WARNING: system overload" - 匹配,因为大小写转换后匹配 - ❌ "warned" - 不匹配,因为它是不同的词语 - ❌ "warnings" - 不匹配,因为它是不同的词语 --- ## 管理 Pipeline 在 GreptimeDB 中,每个 `pipeline` 是一个数据处理单元集合,用于解析和转换写入的日志内容。本文档旨在指导你如何创建和删除 Pipeline,以便高效地管理日志数据的处理流程。 有关 Pipeline 的具体配置,请阅读 [Pipeline 配置](/reference/pipeline/pipeline-config.md)。 ## 鉴权 在使用 HTTP API 进行 Pipeline 管理时,你需要提供有效的鉴权信息。 请参考[鉴权](/user-guide/protocols/http.md#鉴权)文档了解详细信息。 ## 上传 Pipeline GreptimeDB 提供了专用的 HTTP 接口用于创建 Pipeline。 假设你已经准备好了一个 Pipeline 配置文件 pipeline.yaml,使用以下命令上传配置文件,其中 `test` 是你指定的 Pipeline 的名称: ```shell ## 上传 pipeline 文件。test 为 Pipeline 的名称 curl -X "POST" "http://localhost:4000/v1/pipelines/test" \ -H "Authorization: Basic {{authentication}}" \ -F "file=@pipeline.yaml" ``` 你可以在所有 Database 中使用创建的 Pipeline。 ## Pipeline 版本 你可以使用相同的名称上传多个版本的 pipeline。 每次你使用现有名称上传 pipeline 时,都会自动创建一个新版本。 你可以在[写入日志](/reference/pipeline/write-log-api.md#http-api)、[查询](#查询-pipeline)或[删除](#删除-pipeline) pipeline 时指定要使用的版本。 如果未指定版本,默认使用最后上传的版本。 成功上传 pipeline 后,响应将包含版本信息: ```json {"name":"nginx_pipeline","version":"2024-06-27 12:02:34.257312110Z"} ``` 版本是 UTC 格式的时间戳,表示 pipeline 的创建时间。 此时间戳作为每个 pipeline 版本的唯一标识符。 ## 删除 Pipeline 可以使用以下 HTTP 接口删除 Pipeline: ```shell ## test 为 Pipeline 的名称 curl -X "DELETE" "http://localhost:4000/v1/pipelines/test?version=2024-06-27%2012%3A02%3A34.257312110Z" \ -H "Authorization: Basic {{authentication}}" ``` 上面的例子中,我们删除了名为 `test` 的 Pipeline。`version` 参数是必须的,用于指定要删除的 Pipeline 的版本号。 ## 查询 Pipeline 可以使用以下 HTTP 接口查询 Pipeline: ```shell ## test 是 Pipeline 的名称,该查询将返回最新版本的 Pipeline。 curl "http://localhost:4000/v1/pipelines/test" \ -H "Authorization: Basic {{authentication}}" ``` ```shell ## 如果你想查询某个 Pipeline 的历史版本,可以在 URL 中添加 `version` 参数 curl "http://localhost:4000/v1/pipelines/test?version=2025-04-01%2006%3A58%3A31.335251882%2B0000" \ -H "Authorization: Basic {{authentication}}" ``` 如果这个 pipeline 存在,输出会如下所示: ```json { "pipelines": [ { "name": "test", "version": "2025-04-01 06:58:31.335251882", "pipeline": "version: 2\nprocessors:\n - dissect:\n fields:\n - message\n patterns:\n - '%{ip_address} - - [%{timestamp}] \"%{http_method} %{request_line}\" %{status_code} %{response_size} \"-\" \"%{user_agent}\"'\n ignore_missing: true\n - date:\n fields:\n - timestamp\n formats:\n - \"%d/%b/%Y:%H:%M:%S %z\"\n - select:\n type: exclude\n fields:\n - message\n\ntransform:\n - fields:\n - ip_address\n type: string\n index: inverted\n tag: true\n - fields:\n - status_code\n type: int32\n index: inverted\n tag: true\n - fields:\n - request_line\n - user_agent\n type: string\n index: fulltext\n - fields:\n - response_size\n type: int32\n - fields:\n - timestamp\n type: time\n index: timestamp\n" } ], "execution_time_ms": 7 } ``` 在上面的输出中,`pipeline` 字段是 YAML 格式的字符串。 你可以使用 [`jq -r`](https://jqlang.org/) 以更易读的方式展示它: ```shell curl "http://localhost:4000/v1/pipelines/test?version=2025-04-01%2006%3A58%3A31.335251882%2B0000" \ -H "Authorization: Basic {{authentication}}" \ | jq -r '.pipelines[0].pipeline' ``` ```yml version: 2 processors: - dissect: fields: - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" - select: type: exclude fields: - message transform: - fields: - ip_address type: string index: inverted tag: true - fields: - status_code type: int32 index: inverted tag: true - fields: - request_line - user_agent type: string index: fulltext - fields: - response_size type: int32 - fields: - timestamp type: time index: timestamp ``` 或者使用 SQL 来查询 Pipeline: ```sql SELECT * FROM greptime_private.pipelines; ``` 请注意,如果你使用 MySQL 或者 PostgreSQL 协议作为连接 GreptimeDB 的方式,查询出来的 Pipeline 时间信息精度可能有所不同,可能会丢失纳秒级别的精度。 为了解决这个问题,可以将 `created_at` 字段强制转换为 timestamp 来查看 Pipeline 的创建时间。例如,下面的查询将 `created_at` 以 `bigint` 的格式展示: ```sql SELECT name, pipeline, created_at::bigint FROM greptime_private.pipelines; ``` 查询结果如下: ``` name | pipeline | greptime_private.pipelines.created_at ------+-----------------------------------+--------------------------------------- test | processors: +| 1719489754257312110 | - date: +| | field: time +| | formats: +| | - "%Y-%m-%d %H:%M:%S%.3f"+| | ignore_missing: true +| | +| | transform: +| | - fields: +| | - id1 +| | - id2 +| | type: int32 +| | - fields: +| | - type +| | - logger +| | type: string +| | index: inverted +| | - fields: +| | - log +| | type: string +| | index: fulltext +| | - field: time +| | type: time +| | index: timestamp +| | | (1 row) ``` 然后可以使用程序将 SQL 结果中的 bigint 类型的时间戳转换为时间字符串。 ```shell timestamp_ns="1719489754257312110"; readable_timestamp=$(TZ=UTC date -d @$((${timestamp_ns:0:10}+0)) +"%Y-%m-%d %H:%M:%S").${timestamp_ns:10}Z; echo "Readable timestamp (UTC): $readable_timestamp" ``` 输出: ```shell Readable timestamp (UTC): 2024-06-27 12:02:34.257312110Z ``` 输出的 `Readable timestamp (UTC)` 即为 Pipeline 的创建时间同时也是版本号。 ## 问题调试 首先,请参考 [快速入门示例](/user-guide/logs/quick-start.md#使用-pipeline-写入日志)来查看 Pipeline 正确的执行情况。 ### 调试创建 Pipeline 在创建 Pipeline 的时候你可能会遇到错误,例如使用如下配置创建 Pipeline: ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/test" \ -H "Content-Type: application/x-yaml" \ -H "Authorization: Basic {{authentication}}" \ -d $'processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - gsub: fields: - message pattern: "\\\." replacement: - "-" ignore_missing: true transform: - fields: - message type: string - field: time type: time index: timestamp ' ``` Pipeline 配置存在错误。`gsub` processor 期望 `replacement` 字段为字符串,但当前配置提供了一个数组。因此,该 Pipeline 创建失败,并显示以下错误消息: ```json {"error":"Failed to parse pipeline: 'replacement' must be a string"} ``` 因此,你需要修改 `gsub` processor 的配置,将 `replacement` 字段的值更改为字符串类型。 ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/test" \ -H "Content-Type: application/x-yaml" \ -H "Authorization: Basic {{authentication}}" \ -d $'processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - gsub: fields: - message pattern: "\\\." replacement: "-" ignore_missing: true transform: - fields: - message type: string - field: time type: time index: timestamp ' ``` 此时 Pipeline 创建成功,可以使用 `dryrun` 接口测试该 Pipeline。 ### 调试日志写入 我们可以使用 `dryrun` 接口测试 Pipeline。我们将使用错误的日志数据对其进行测试,其中消息字段的值为数字格式,会导致 Pipeline 在处理过程中失败。 **此接口仅仅用于测试 Pipeline 的处理结果,不会将日志写入到 GreptimeDB 中。** ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/_dryrun?pipeline_name=test" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d $'{"message": 1998.08,"time":"2024-05-25 20:16:37.217"}' ``` 输出: ```json {"error":"Processor gsub: expect string value, but got Float(1998.08)"} ``` 输出显示 Pipeline 处理失败,因为 `gsub` Processor 期望的是字符串类型,而不是浮点数类型。我们需要修改日志数据的格式,确保 Pipeline 能够正确处理。 我们再将 message 字段的值修改为字符串类型,然后再次测试该 Pipeline。 ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/_dryrun?pipeline_name=test" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d $'{"message": "1998.08","time":"2024-05-25 20:16:37.217"}' ``` 此时 Pipeline 处理成功,输出如下: ```json [ { "rows": [ [ { "data_type": "STRING", "key": "message", "semantic_type": "FIELD", "value": "1998-08" }, { "data_type": "TIMESTAMP_NANOSECOND", "key": "time", "semantic_type": "TIMESTAMP", "value": 1716668197217000000 } ] ], "schema": [ { "column_type": "FIELD", "data_type": "STRING", "fulltext": false, "name": "message" }, { "column_type": "TIMESTAMP", "data_type": "TIMESTAMP_NANOSECOND", "fulltext": false, "name": "time" } ], "table_name": "dry_run" } ] ``` 可以看到,`1998.08` 字符串中的 `.` 已经被替换为 `-`,Pipeline 处理成功。 ## 从 Pipeline 配置生成表的建表语句 使用 Pipeline 时,GreptimeDB 默认会在首次数据写入时自动创建目标表。 但是,你可能希望预先手动创建表以添加自定义表选项,例如添加分区规则以获得更好的性能。 虽然自动创建的表结构对于给定的 Pipeline 配置是确定的, 但根据配置手动编写表的建表语句可能会很繁琐。`/ddl` API 简化了这一过程。 对于现有的 Pipeline,你可以使用 `/v1/pipelines/{pipeline_name}/ddl` 来生成建表语句。 此 API 会检查 Pipeline 配置中的 transform 定义并推断出相应的表结构。 你可以在第一次写入数据之前使用此 API 来生成基础的建表语句,进行参数调整并手动建表。 常见的调整选项包括: - 增加[数据分区规则](/user-guide/deployments-administration/manage-data/table-sharding.md) - 调整[索引的参数](/user-guide/manage-data/data-index.md) - 增加其他[表选项](/reference/sql/create.md#表选项) 以下是演示如何使用此 API 的示例。考虑以下 Pipeline 配置: ```YAML # pipeline.yaml processors: - dissect: fields: - message patterns: - '%{ip_address} - %{username} [%{timestamp}] "%{http_method} %{request_line} %{protocol}" %{status_code} %{response_size}' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" transform: - fields: - timestamp type: time index: timestamp - fields: - ip_address type: string index: skipping - fields: - username type: string tag: true - fields: - http_method type: string index: inverted - fields: - request_line type: string index: fulltext - fields: - protocol type: string - fields: - status_code type: int32 index: inverted tag: true - fields: - response_size type: int64 on_failure: default default: 0 - fields: - message type: string ``` 首先,使用以下命令将 Pipeline 上传到数据库: ```bash curl -X "POST" "http://localhost:4000/v1/pipelines/pp" -F "file=@pipeline.yaml" ``` 然后,使用以下命令查询表的建表语句: ```bash curl -X "GET" "http://localhost:4000/v1/pipelines/pp/ddl?table=test_table" ``` API 返回以下 JSON 格式的输出: ```JSON { "sql": { "sql": "CREATE TABLE IF NOT EXISTS `test_table` (\n `timestamp` TIMESTAMP(9) NOT NULL,\n `ip_address` STRING NULL SKIPPING INDEX WITH(false_positive_rate = '0.01', granularity = '10240', type = 'BLOOM'),\n `username` STRING NULL,\n `http_method` STRING NULL INVERTED INDEX,\n `request_line` STRING NULL FULLTEXT INDEX WITH(analyzer = 'English', backend = 'bloom', case_sensitive = 'false', false_positive_rate = '0.01', granularity = '10240'),\n `protocol` STRING NULL,\n `status_code` INT NULL INVERTED INDEX,\n `response_size` BIGINT NULL,\n `message` STRING NULL,\n TIME INDEX (`timestamp`),\n PRIMARY KEY (`username`, `status_code`)\n)\nENGINE=mito\nWITH(\n append_mode = 'true'\n)" }, "execution_time_ms": 3 } ``` 格式化响应中的 `sql` 字段后,你可以看到推断出的表结构: ```SQL CREATE TABLE IF NOT EXISTS `test_table` ( `timestamp` TIMESTAMP(9) NOT NULL, `ip_address` STRING NULL SKIPPING INDEX WITH(false_positive_rate = '0.01', granularity = '10240', type = 'BLOOM'), `username` STRING NULL, `http_method` STRING NULL INVERTED INDEX, `request_line` STRING NULL FULLTEXT INDEX WITH(analyzer = 'English', backend = 'bloom', case_sensitive = 'false', false_positive_rate = '0.01', granularity = '10240'), `protocol` STRING NULL, `status_code` INT NULL INVERTED INDEX, `response_size` BIGINT NULL, `message` STRING NULL, TIME INDEX (`timestamp`), PRIMARY KEY (`username`, `status_code`) ) ENGINE=mito WITH( append_mode = 'true' ) ``` 你可以将推断出的表的建表语句作为起点。 根据你的需求自定义建表语句后,在通过 Pipeline 写入数据之前手动执行它。 **注意事项:** 1. 该 API 仅从 Pipeline 配置推断表结构;它不会检查表是否已存在。 2. 该 API 不考虑表后缀。如果你在 Pipeline 配置中使用 `dispatcher`、`table_suffix` 或表后缀 hint,你需要手动调整表名。 --- ## 日志 GreptimeDB 提供了专为满足现代可观测需求而设计的日志管理解决方案, 它可以和主流日志收集器无缝集成, 提供了灵活的使用 pipeline 转换日志的功能 和包括全文搜索的查询功能。 核心功能点包括: - **统一存储**:将日志与指标和 Trace 数据一起存储在单个数据库中 - **Pipeline 处理数据**:使用可自定义的 pipeline 转换和丰富原始日志,支持多种日志收集器和格式 - **高级查询**:基于 SQL 的分析,并具有全文搜索功能 - **实时数据处理**:实时处理和查询日志以进行监控和警报 ## 日志收集流程 ![log-collection-flow](/log-collection-flow.drawio.svg) 上图展示了日志收集的整体架构, 它包括四阶段流程:日志源、日志收集器、Pipeline 处理和在存储到 GreptimeDB 中。 ### 日志源 日志源是基础设施中产生日志数据的基础层。 GreptimeDB 支持从各种源写入数据以满足全面的可观测性需求: - **应用程序**:来自微服务架构、Web 应用程序、移动应用程序和自定义软件组件的应用程序级日志 - **IoT 设备**:来自物联网生态系统的设备日志、传感器事件日志和运行状态日志 - **基础设施**:云平台日志、容器编排日志(Kubernetes、Docker)、负载均衡器日志以及网络基础设施组件日志 - **系统组件**:操作系统日志、内核事件、系统守护进程日志以及硬件监控日志 - **自定义源**:特定于你环境或应用程序的任何其他日志源 ### 日志收集器 日志收集器负责高效地从各种源收集日志数据并转发到存储后端。 GreptimeDB 可以与行业标准的日志收集器无缝集成, 包括 Vector、Fluent Bit、Apache Kafka、OpenTelemetry Collector 等。 GreptimeDB 作为这些收集器的 sink 后端, 提供强大的数据写入能力。 在写入过程中,GreptimeDB 的 pipeline 系统能够实时转换和丰富日志数据, 确保在存储前获得最佳的结构和质量。 ### Pipeline 处理 GreptimeDB 的 pipeline 机制将原始日志转换为结构化、可查询的数据: - **解析**:从非结构化日志消息中提取结构化数据 - **转换**:使用额外的上下文和元数据丰富日志 - **索引**:配置必要的索引以提升查询性能,例如全文索引、时间索引等 ### 存储日志到 GreptimeDB 通过 pipeline 处理后,日志存储在 GreptimeDB 中,支持灵活的分析和可视化: - **SQL 查询**:使用熟悉的 SQL 语法分析日志数据 - **基于时间的分析**:利用时间序列功能进行时间分析 - **全文搜索**:在日志消息中执行高级文本搜索 - **实时分析**:实时查询日志进行监控和告警 ## 快速开始 你可以使用内置的 `greptime_identity` pipeline 快速开始日志写入。更多信息请参考[快速开始](./quick-start.md)指南。 ## 集成到日志收集器 GreptimeDB 与各种日志收集器无缝集成,提供全面的日志记录解决方案。集成过程包括以下关键步骤: 1. **选择合适的日志收集器**:根据你的基础设施要求、数据源和性能需求选择收集器 2. **分析输出格式**:了解你选择的收集器产生的日志格式和结构 3. **配置 Pipeline**:在 GreptimeDB 中创建和配置 pipeline 来解析、转换和丰富传入的日志数据 4. **存储和查询**:在 GreptimeDB 中高效存储处理后的日志,用于实时分析和监控 要成功将你的日志收集器与 GreptimeDB 集成,你需要: - 首先了解 pipeline 在 GreptimeDB 中的工作方式 - 然后在你的日志收集器中配置 sink 设置,将数据发送到 GreptimeDB 请参考以下指南获取将 GreptimeDB 集成到日志收集器的详细说明: - [Vector](/user-guide/ingest-data/for-observability/vector.md#using-greptimedb_logs-sink-recommended) - [Kafka](/user-guide/ingest-data/for-observability/kafka.md#logs) - [Fluent Bit](/user-guide/ingest-data/for-observability/fluent-bit.md#http) - [OpenTelemetry Collector](/user-guide/ingest-data/for-observability/otel-collector.md) - [Loki](/user-guide/ingest-data/for-observability/loki.md#using-pipeline-with-loki-push-api) ## 了解更多关于 Pipeline 的信息 - [使用自定义 Pipeline](./use-custom-pipelines.md):解释如何创建和使用自定义 pipeline 进行日志写入。 - [管理 Pipeline](./manage-pipelines.md):解释如何创建和删除 pipeline。 ## 查询日志 - [全文搜索](./fulltext-search.md):使用 GreptimeDB 查询语言有效搜索和分析日志数据的指南。 ## 参考 - [内置 Pipeline](/reference/pipeline/built-in-pipelines.md):GreptimeDB 为日志写入提供的内置 pipeline 详细信息。 - [写入日志的 API](/reference/pipeline/write-log-api.md):描述向 GreptimeDB 写入日志的 HTTP API。 - [Pipeline 配置](/reference/pipeline/pipeline-config.md):提供 GreptimeDB 中 pipeline 各项具体配置的信息。 --- ## GreptimeDB Logs 快速上手 # 快速入门 本指南将引导你完成使用 GreptimeDB 日志服务的基本步骤。 你将学习如何使用内置的 `greptime_identity` pipeline 写入日志并集成日志收集器。 GreptimeDB 提供了强大的基于 pipeline 的日志写入系统。 你可以使用内置的 `greptime_identity` pipeline 快速写入 JSON 格式的日志, 该 pipeline 具有以下特点: - 自动处理从 JSON 到表列的字段映射 - 如果表不存在则自动创建表 - 灵活支持变化的日志结构 - 需要最少的配置即可开始使用 ## 直接通过 HTTP 写入日志 GreptimeDB 日志写入最简单的方法是通过使用 `greptime_identity` pipeline 发送 HTTP 请求。 例如,你可以使用 `curl` 发送带有 JSON 日志数据的 POST 请求: ```shell curl -X POST \ "http://localhost:4000/v1/ingest?db=public&table=demo_logs&pipeline_name=greptime_identity" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d '[ { "timestamp": "2024-01-15T10:30:00Z", "level": "INFO", "service": "web-server", "message": "用户登录成功", "user_id": 12345, "ip_address": "192.168.1.100" }, { "timestamp": "2024-01-15T10:31:00Z", "level": "ERROR", "service": "database", "message": "连接超时", "error_code": 500, "retry_count": 3 } ]' ``` 关键参数包括: - `db=public`:目标数据库名称(你的数据库名称) - `table=demo_logs`:目标表名称(如果不存在则自动创建) - `pipeline_name=greptime_identity`:使用 `greptime_identity` pipeline 进行 JSON 处理 - `Authorization` 头:使用 base64 编码的 `username:password` 进行基本身份验证,请参阅 [HTTP 鉴权指南](/user-guide/protocols/http.md#authentication) 成功的请求返回: ```json { "output": [{"affectedrows": 2}], "execution_time_ms": 15 } ``` 成功写入日志后, 相应的表 `demo_logs` 会根据 JSON 字段自动创建相应的列,其 schema 如下: ```sql +--------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+---------------------+------+------+---------+---------------+ | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | ip_address | String | | YES | | FIELD | | level | String | | YES | | FIELD | | message | String | | YES | | FIELD | | service | String | | YES | | FIELD | | timestamp | String | | YES | | FIELD | | user_id | Int64 | | YES | | FIELD | | error_code | Int64 | | YES | | FIELD | | retry_count | Int64 | | YES | | FIELD | +--------------------+---------------------+------+------+---------+---------------+ ``` ## 与日志收集器集成 对于生产环境, 你通常会使用日志收集器自动将日志转发到 GreptimeDB。 以下是如何配置 Vector 使用 `greptime_identity` pipeline 向 GreptimeDB 发送日志的示例: ```toml [sinks.my_sink_id] type = "greptimedb_logs" dbname = "public" endpoint = "http://:4000" pipeline_name = "greptime_identity" table = "" username = "" password = "" # 根据需要添加其他配置 ``` 关键配置参数包括: - `type = "greptimedb_logs"`:指定 GreptimeDB 日志接收器 - `dbname`:目标数据库名称 - `endpoint`:GreptimeDB HTTP 端点 - `pipeline_name`:使用 `greptime_identity` pipeline 进行 JSON 处理 - `table`:目标表名称(如果不存在则自动创建) - `username` 和 `password`:HTTP 基本身份验证的凭证 有关 Vector 配置和选项的详细信息, 请参阅 [Vector 集成指南](/user-guide/ingest-data/for-observability/vector.md#使用-greptimedb_logs-sink-推荐)。 ## 下一步 你已成功写入了第一批日志,以下是推荐的后续步骤: - **了解更多关于内置 Pipeline 的行为**:请参阅[内置 Pipeline](/reference/pipeline/built-in-pipelines.md)指南,了解可用的内置 pipeline 及其配置的详细信息 - **与流行的日志收集器集成**:有关将 GreptimeDB 与 Fluent Bit、Fluentd 等各种日志收集器集成的详细说明,请参阅[日志概览](./overview.md)中的[集成到日志收集器](./overview.md#集成到日志收集器)部分 - **使用自定义 Pipeline**:要了解使用自定义 pipeline 进行高级日志处理和转换的信息,请参阅[使用自定义 Pipeline](./use-custom-pipelines.md)指南 --- ## 使用自定义 Pipeline 基于你的 pipeline 配置, GreptimeDB 能够将日志自动解析和转换为多列的结构化数据, 当内置 pipeline 无法处理特定的文本日志格式时, 你可以创建自定义 pipeline 来定义如何根据你的需求解析和转换日志数据。 ## 识别你的原始日志格式 在创建自定义 pipeline 之前,了解原始日志数据的格式至关重要。 如果你正在使用日志收集器且不确定日志格式, 有两种方法可以检查你的日志: 1. **阅读收集器的官方文档**:配置你的收集器将数据输出到控制台或文件以检查日志格式。 2. **使用 `greptime_identity` pipeline**:使用内置的 `greptime_identity` pipeline 将示例日志直接写入到 GreptimeDB 中。 `greptime_identity` pipeline 将整个文本日志视为单个 `message` 字段,方便你直接看到原始日志的内容。 一旦了解了要处理的日志格式, 你就可以创建自定义 pipeline。 本文档使用以下 Nginx 访问日志条目作为示例: ```txt 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" ``` ## 创建自定义 Pipeline GreptimeDB 提供 HTTP 接口用于创建 pipeline。 以下是创建方法。 首先,创建一个示例 pipeline 配置文件来处理 Nginx 访问日志, 将其命名为 `pipeline.yaml`: ```yaml version: 2 processors: - dissect: fields: - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" - select: type: exclude fields: - message - vrl: source: | .greptime_ttl = "7d" . transform: - fields: - ip_address type: string index: inverted tag: true - fields: - status_code type: int32 index: inverted tag: true - fields: - request_line - user_agent type: string index: fulltext - fields: - response_size type: int32 - fields: - timestamp type: time index: timestamp ``` 上面的 pipeline 配置使用 [version 2](/reference/pipeline/pipeline-config.md#transform-in-version-2) 格式, 包含 `processors` 和 `transform` 部分来结构化你的日志数据: **Processors**:用于在转换前预处理日志数据: - **数据提取**:`dissect` 处理器使用 pattern 匹配来解析 `message` 字段并提取结构化数据,包括 `ip_address`、`timestamp`、`http_method`、`request_line`、`status_code`、`response_size` 和 `user_agent`。 - **时间戳处理**:`date` 处理器使用格式 `%d/%b/%Y:%H:%M:%S %z` 解析提取的 `timestamp` 字段并将其转换为适当的时间戳数据类型。 - **字段选择**:`select` 处理器从最终输出中排除原始 `message` 字段,同时保留所有其他字段。 - **表选项**:`vrl` 处理器根据提取的字段设置表选项,例如向表名添加后缀和设置 TTL。`greptime_ttl = "7d"` 配置表数据的保存时间为 7 天。 **Transform**:定义如何转换和索引提取的字段: - **字段转换**:每个提取的字段都转换为适当的数据类型并根据需要配置相应的索引。像 `http_method` 这样的字段在没有提供显式配置时保留其默认数据类型。 - **索引策略**: - `ip_address` 和 `status_code` 使用倒排索引作为标签进行快速过滤 - `request_line` 和 `user_agent` 使用全文索引以获得最佳文本搜索能力 - `timestamp` 是必需的时间索引列 有关 pipeline 配置选项的详细信息, 请参考 [Pipeline 配置](/reference/pipeline/pipeline-config.md) 文档。 ## 上传 Pipeline 执行以下命令上传 pipeline 配置: ```shell curl -X "POST" \ "http://localhost:4000/v1/pipelines/nginx_pipeline" \ -H 'Authorization: Basic {{authentication}}' \ -F "file=@pipeline.yaml" ``` 成功执行后,将创建一个名为 `nginx_pipeline` 的 pipeline 并返回以下结果: ```json {"name":"nginx_pipeline","version":"2024-06-27 12:02:34.257312110Z"}. ``` 你可以为同一个 pipeline 名称创建多个版本。 所有 pipeline 都存储在 `greptime_private.pipelines` 表中。 参考[查询 Pipeline](manage-pipelines.md#查询-pipeline) 来查看 pipeline 数据。 ## 使用 Pipeline 写入日志 以下示例使用 `nginx_pipeline` pipeline 将日志写入 `custom_pipeline_logs` 表来格式化和转换日志消息: ```shell curl -X POST \ "http://localhost:4000/v1/ingest?db=public&table=custom_pipeline_logs&pipeline_name=nginx_pipeline" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d '[ { "message": "127.0.0.1 - - [25/May/2024:20:16:37 +0000] \"GET /index.html HTTP/1.1\" 200 612 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\"" }, { "message": "192.168.1.1 - - [25/May/2024:20:17:37 +0000] \"POST /api/login HTTP/1.1\" 200 1784 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36\"" }, { "message": "10.0.0.1 - - [25/May/2024:20:18:37 +0000] \"GET /images/logo.png HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0\"" }, { "message": "172.16.0.1 - - [25/May/2024:20:19:37 +0000] \"GET /contact HTTP/1.1\" 404 162 \"-\" \"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1\"" } ]' ``` 命令执行成功后将返回以下输出: ```json {"output":[{"affectedrows":4}],"execution_time_ms":79} ``` `custom_pipeline_logs` 表内容根据 pipeline 配置自动创建: ```sql +-------------+-------------+-------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+ | ip_address | http_method | status_code | request_line | user_agent | response_size | timestamp | +-------------+-------------+-------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+ | 10.0.0.1 | GET | 304 | /images/logo.png HTTP/1.1 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0 | 0 | 2024-05-25 20:18:37 | | 127.0.0.1 | GET | 200 | /index.html HTTP/1.1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 | 612 | 2024-05-25 20:16:37 | | 172.16.0.1 | GET | 404 | /contact HTTP/1.1 | Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1 | 162 | 2024-05-25 20:19:37 | | 192.168.1.1 | POST | 200 | /api/login HTTP/1.1 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 | 1784 | 2024-05-25 20:17:37 | +-------------+-------------+-------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+ ``` 有关日志写入 API 端点 `/ingest` 的更详细信息, 包括附加参数和配置选项, 请参考[日志写入 API](/reference/pipeline/write-log-api.md) 文档。 ## 查询日志 我们使用 `custom_pipeline_logs` 表作为示例来查询日志。 ### 通过 tag 查询日志 通过 `custom_pipeline_logs` 中的多个 tag 列, 你可以灵活地通过 tag 查询数据。 例如,查询 `status_code` 为 200 且 `http_method` 为 GET 的日志。 ```sql SELECT * FROM custom_pipeline_logs WHERE status_code = 200 AND http_method = 'GET'; ``` ```sql +------------+-------------+----------------------+---------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | ip_address | status_code | request_line | user_agent | response_size | timestamp | http_method | +------------+-------------+----------------------+---------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | 127.0.0.1 | 200 | /index.html HTTP/1.1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 | 612 | 2024-05-25 20:16:37 | GET | +------------+-------------+----------------------+---------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ 1 row in set (0.02 sec) ``` ### 全文搜索 对于文本字段 `request_line` 和 `user_agent`,你可以使用 `matches_term` 函数来搜索日志。 还记得我们在[创建 pipeline](#create-a-pipeline) 时为这两列创建了全文索引。 这带来了高性能的全文搜索。 例如,查询 `request_line` 列包含 `/index.html` 或 `/api/login` 的日志。 ```sql SELECT * FROM custom_pipeline_logs WHERE matches_term(request_line, '/index.html') OR matches_term(request_line, '/api/login'); ``` ```sql +-------------+-------------+----------------------+--------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | ip_address | status_code | request_line | user_agent | response_size | timestamp | http_method | +-------------+-------------+----------------------+--------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ | 127.0.0.1 | 200 | /index.html HTTP/1.1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 | 612 | 2024-05-25 20:16:37 | GET | | 192.168.1.1 | 200 | /api/login HTTP/1.1 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 | 1784 | 2024-05-25 20:17:37 | POST | +-------------+-------------+----------------------+--------------------------------------------------------------------------------------------------------------------------+---------------+---------------------+-------------+ 2 rows in set (0.00 sec) ``` 你可以参考[全文搜索](fulltext-search.md) 文档了解 `matches_term` 函数的详细用法。 ## 使用 Pipeline 的好处 使用 pipeline 处理日志带来了结构化的数据和自动的字段提取, 这使得查询和分析更加高效。 你也可以在没有 pipeline 的情况下直接将日志写入数据库, 但这种方法限制了高性能分析能力。 ### 直接插入日志(不使用 Pipeline) 为了比较,你可以创建一个表来存储原始日志消息: ```sql CREATE TABLE `origin_logs` ( `message` STRING FULLTEXT INDEX, `time` TIMESTAMP TIME INDEX ) WITH ( append_mode = 'true' ); ``` 使用 `INSERT` 语句将日志插入表中。 注意你需要为每个日志手动添加时间戳字段: ```sql INSERT INTO origin_logs (message, time) VALUES ('127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"', '2024-05-25 20:16:37.217'), ('192.168.1.1 - - [25/May/2024:20:17:37 +0000] "POST /api/login HTTP/1.1" 200 1784 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"', '2024-05-25 20:17:37.217'), ('10.0.0.1 - - [25/May/2024:20:18:37 +0000] "GET /images/logo.png HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"', '2024-05-25 20:18:37.217'), ('172.16.0.1 - - [25/May/2024:20:19:37 +0000] "GET /contact HTTP/1.1" 404 162 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"', '2024-05-25 20:19:37.217'); ``` ### 表结构比较:Pipeline 转换后 vs 原始日志 在上面的示例中,表 `custom_pipeline_logs` 是通过使用 pipeline 写入日志自动创建的, 而表 `origin_logs` 是通过直接写入日志创建的。 让我们看一看这两个表之间的差异。 ```sql DESC custom_pipeline_logs; ``` ```sql +---------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------+---------------------+------+------+---------+---------------+ | ip_address | String | PRI | YES | | TAG | | status_code | Int32 | PRI | YES | | TAG | | request_line | String | | YES | | FIELD | | user_agent | String | | YES | | FIELD | | response_size | Int32 | | YES | | FIELD | | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | http_method | String | | YES | | FIELD | +---------------+---------------------+------+------+---------+---------------+ 7 rows in set (0.00 sec) ``` ```sql DESC origin_logs; ``` ```sql +---------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------+----------------------+------+------+---------+---------------+ | message | String | | YES | | FIELD | | time | TimestampMillisecond | PRI | NO | | TIMESTAMP | +---------+----------------------+------+------+---------+---------------+ ``` 以上表结构显示了关键差异: `custom_pipeline_logs` 表(使用 pipeline 创建)自动将日志数据结构化为多列: - `ip_address`、`status_code` 作为索引标签用于快速过滤 - `request_line`、`user_agent` 具有全文索引用于文本搜索 - `response_size`、`http_method` 作为常规字段 - `timestamp` 作为时间索引 `origin_logs` 表(直接插入)将所有内容存储在单个 `message` 列中。 ### 为什么使用 Pipeline? 建议使用 pipeline 方法将日志消息拆分为多列, 这具有明确查询特定列中特定值的优势。 有几个关键原因使得基于列的匹配查询比全文搜索更优越: - **性能**:基于列的查询通常比全文搜索更快 - **存储效率**:GreptimeDB 的列式存储能更好地压缩结构化数据;标签的倒排索引比全文索引消耗更少的存储空间 - **查询简单性**:基于标签的查询更容易编写、理解和调试 ## 下一步 - **全文搜索**:阅读[全文搜索](fulltext-search.md) 指南,了解 GreptimeDB 中的高级文本搜索功能和查询技术 - **Pipeline 配置**:阅读 [Pipeline 配置](/reference/pipeline/pipeline-config.md) 文档,了解更多关于为各种日志格式和处理需求创建和自定义 pipeline 的信息 --- ## 数据索引 GreptimeDB 提供了多种索引机制来提升查询性能。作为数据库中的核心组件,索引通过建立高效的数据检索路径,显著优化了数据的查询操作。 ## 概述 在 GreptimeDB 中,索引是在表创建时定义的,其设计目的是针对不同的数据类型和查询模式来优化查询性能。目前支持的索引类型包括: - 倒排索引(Inverted Index) - 跳数索引(Skipping Index) - 全文索引(Fulltext Index) 需要说明的是,本章节重点讨论数据值索引。虽然主键(PRIMARY KEY)和 TIME INDEX 也在某种程度上具有索引的特性,但不在本章讨论范围内。 ## 索引类型 ### 倒排索引 倒排索引主要用于优化 Tag 列的查询效率。它通过在唯一值和对应数据行之间建立映射关系,实现对特定标签值的快速定位。 Tag 列不会被自动建立倒排索引, 你需要考虑以下使用场景手动为 Tag 列建立倒排索引: - 基于标签值的数据查询 - 字符串列的过滤操作 - Tag 列的精确查询 示例: ```sql CREATE TABLE monitoring_data ( host STRING INVERTED INDEX, `region` STRING PRIMARY KEY INVERTED INDEX, cpu_usage DOUBLE, `timestamp` TIMESTAMP TIME INDEX, ); ``` 需要注意的是,当列的基数非常大时,倒排索引可能会带来较高的维护成本,导致内存占用增加和索引体积膨胀。这种情况下,建议考虑使用跳数索引作为替代方案。 ### 跳数索引 跳数索引是专为列式存储系统(如 GreptimeDB)优化设计的索引类型。它通过维护数据块内值域范围的元数据,使查询引擎能够在进行范围查询时快速跳过不相关的数据块。与其他索引相比,跳数索引的存储开销相对较小。 **适用场景:** - 数据分布稀疏的场景,例如日志中的 MAC 地址 - 在大规模数据集中查询出现频率较低的值 示例: ```sql CREATE TABLE sensor_data ( `domain` STRING PRIMARY KEY, device_id STRING SKIPPING INDEX, temperature DOUBLE, `timestamp` TIMESTAMP TIME INDEX, ); ``` 跳数索引支持 `WITH` 选项: * `type`: 索引类型,目前仅支持 `BLOOM` 类型。 * `granularity`: (适用于 `BLOOM` 类型)每个过滤器覆盖的数据块大小。粒度越小,过滤效果越好,但索引大小会增加。默认为 `10240`。 * `false_positive_rate`: (适用于 `BLOOM` 类型)错误识别块的概率。该值越低,准确性越高(过滤效果越好),但索引大小会增加。该值为介于 `0` 和 `1` 之间的浮点数。默认为 `0.01`。 例如: ```sql CREATE TABLE sensor_data ( `domain` STRING PRIMARY KEY, device_id STRING SKIPPING INDEX WITH(type='BLOOM', granularity=1024, false_positive_rate=0.01), temperature DOUBLE, `timestamp` TIMESTAMP TIME INDEX, ); ``` 然而,跳数索引无法处理复杂的过滤条件,并且其过滤性能通常不如倒排索引或全文索引。 ### 全文索引 全文索引专门用于优化字符串列的文本搜索操作。它支持基于词的匹配和文本搜索功能,能够实现对文本内容的高效检索。你可以使用灵活的关键词、短语或模式匹配来查询文本数据。 **适用场景:** - 文本内容搜索 - 模式匹配查询 - 大规模文本过滤 示例: ```sql CREATE TABLE logs ( `message` STRING FULLTEXT INDEX, `level` STRING PRIMARY KEY, `timestamp` TIMESTAMP TIME INDEX, ); ``` #### 配置选项 在创建或修改全文索引时,您可以使用 `FULLTEXT INDEX WITH` 指定以下选项: - `analyzer`:设置全文索引的语言分析器 - 支持的值:`English`、`Chinese` - 默认值:`English` - 注意:由于中文文本分词的复杂性,中文分析器构建索引需要的时间显著更长。建议仅在中文文本搜索是主要需求时使用。 - `case_sensitive`:决定全文索引是否区分大小写 - 支持的值:`true`、`false` - 默认值:`false` - 注意:设置为 `true` 可能会略微提高区分大小写查询的性能,但会降低不区分大小写查询的性能。此设置不会影响 `matches_term` 查询的结果。 - `backend`:设置全文索引的后端实现 - 支持的值:`bloom`、`tantivy` - 默认值:`bloom` - `granularity`:(适用于 `bloom` 后端)每个过滤器覆盖的数据块大小。粒度越小,过滤效果越好,但索引大小会增加。 - 支持的值:正整数 - 默认值:`10240` - `false_positive_rate`:(适用于 `bloom` 后端)错误识别块的概率。该值越低,准确性越高(过滤效果越好),但索引大小会增加。该值为介于 `0` 和 `1` 之间的浮点数。 - 支持的值:介于 `0` 和 `1` 之间的浮点数 - 默认值:`0.01` #### 后端选择 GreptimeDB 提供两种全文索引后端用于高效日志搜索: 1. **Bloom 后端** - 最适合:通用日志搜索 - 特点: - 使用 Bloom 过滤器进行高效过滤 - 存储开销较低 - 在不同查询模式下性能稳定 - 限制: - 对于高选择性查询稍慢 - 存储成本示例: - 原始数据:约 10GB - Bloom 索引:约 1GB 2. **Tantivy 后端** - 最适合:高选择性查询(如 TraceID 等唯一值) - 特点: - 使用倒排索引实现快速精确匹配 - 对高选择性查询性能优异 - 限制: - 存储开销较高(接近原始数据大小) - 对低选择性查询性能较慢 - 存储成本示例: - 原始数据:约 10GB - Tantivy 索引:约 10GB #### 性能对比 下表显示了不同查询方法之间的性能对比(以 Bloom 为基准): | 查询类型 | 高选择性(如 TraceID) | 低选择性(如 "HTTP") | |------------|----------------------------------|--------------------------------| | LIKE | 慢 50 倍 | 1 倍 | | Tantivy | 快 5 倍 | 慢 5 倍 | | Bloom | 1 倍(基准) | 1 倍(基准) | 主要观察结果: - 对于高选择性查询(如唯一值),Tantivy 提供最佳性能 - 对于低选择性查询,Bloom 提供更稳定的性能 - Bloom 在存储方面比 Tantivy 有明显优势(测试案例中为 1GB vs 10GB) #### 配置示例 **创建带全文索引的表** ```sql -- 使用 Bloom 后端(大多数情况推荐) CREATE TABLE logs ( timestamp TIMESTAMP(9) TIME INDEX, `message` STRING FULLTEXT INDEX WITH ( backend = 'bloom', analyzer = 'English', case_sensitive = 'false' ) ); -- 使用 Tantivy 后端(用于高选择性查询) CREATE TABLE logs ( timestamp TIMESTAMP(9) TIME INDEX, `message` STRING FULLTEXT INDEX WITH ( backend = 'tantivy', analyzer = 'English', case_sensitive = 'false' ) ); ``` **修改现有表** ```sql -- 在现有列上启用全文索引 ALTER TABLE monitor MODIFY COLUMN load_15 SET FULLTEXT INDEX WITH ( analyzer = 'English', case_sensitive = 'false', backend = 'bloom' ); -- 更改全文索引配置 ALTER TABLE logs MODIFY COLUMN message SET FULLTEXT INDEX WITH ( analyzer = 'English', case_sensitive = 'false', backend = 'tantivy' ); ``` ## 修改索引 你可以随时通过`ALTER TABLE`语句来更改列的索引类型,阅读[文档](/reference/sql/alter#alter-table)以获取更多信息。 ## 最佳实践 1. 根据实际的数据特征和查询模式选择合适的索引类型 2. 只为频繁出现在 WHERE 子句中的列创建索引 3. 在查询性能、写入性能和资源消耗之间寻找平衡 4. 定期监控索引使用情况并持续优化索引策略 ## 性能考虑 索引虽然能够显著提升查询性能,但也会带来一定开销: - 需要额外的存储空间维护索引结构 - 索引维护会影响数据刷新和压缩性能 - 索引缓存会占用系统内存 建议根据具体应用场景和性能需求,合理规划索引策略。 --- ## 管理数据(Manage-data) ## 更新数据 ### 使用相同的 tag 和 time index 更新数据 更新操作可以通过插入操作来实现。 如果某行数据具有相同的 tag 和 time index,旧数据将被新数据替换,这意味着你只能更新 field 类型的列。 想要更新数据,只需使用与现有数据相同的 tag 和 time index 插入新数据即可。 有关列类型的更多信息,请参阅[数据模型](/user-guide/concepts/data-model.md)。 :::warning 注意 尽管更新操作的性能与插入数据相同,过多的更新可能会对查询性能产生负面影响。 ::: #### 更新表中的所有字段 在更新数据时,默认情况下所有字段都将被新值覆盖, 而 [InfluxDB 行协议](/user-guide/protocols/influxdb-line-protocol.md) 除外,它只会[更新表中的部分字段](#更新表中的部分字段)。 以下示例使用 SQL 演示了更新表中所有字段的行为。 假设你有一个名为 `monitor` 的表,具有以下 schema。 `host` 列表示 tag,`ts` 列表示 time index。 ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64, memory FLOAT64, PRIMARY KEY(host) ); ``` 向 `monitor` 表中插入一行新数据: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.8, 0.1); ``` 检查表中的数据: ```sql SELECT * FROM monitor; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.8 | 0.1 | +-----------+---------------------+------+--------+ 1 row in set (0.00 sec) ``` 要更新数据,你可以使用与现有数据相同的 `host` 和 `ts` 值,并将新的 `cpu` 值设置为 `0.5`: ```sql INSERT INTO monitor (host, ts, cpu, memory) -- 与现有数据相同的标签 `127.0.0.1` 和相同的时间索引 2024-07-11 20:00:00 VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.5, 0.1); ``` 新数据将为: ```sql SELECT * FROM monitor; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ 1 row in set (0.01 sec) ``` 当使用默认的合并策略时, 如果在 `INSERT INTO` 语句中省略了某列, 它们将被默认值覆盖。 例如: ```sql INSERT INTO monitor (host, ts, cpu) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.5); ``` `monitor` 表中 `memory` 列的默认值为 `NULL`。因此,新数据将为: ```sql SELECT * FROM monitor; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.5 | NULL | +-----------+---------------------+------+--------+ 1 row in set (0.01 sec) ``` ### 更新表中的部分字段 默认情况下, [InfluxDB 行协议](/user-guide/protocols/influxdb-line-protocol.md) 支持此种更新策略。 你还可以使用 SQL 在创建表时通过指定 `merge_mode` 选项为 `last_non_null` 来启用此行为。 示例如下: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64, memory FLOAT64, PRIMARY KEY(host) ) WITH ('merge_mode'='last_non_null'); ``` ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.8, 0.1); ``` 要更新 `monitor` 表中的特定字段, 你可以只插入带有要更新的字段的新数据。 例如: ```sql INSERT INTO monitor (host, ts, cpu) VALUES ("127.0.0.1", "2024-07-11 20:00:00", 0.5); ``` 这将更新 `cpu` 字段,同时保持 `memory` 字段不变。 结果将为: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` 请注意, `last_non_null` 无法将旧值更新为 `NULL`。 例如: ```sql INSERT INTO monitor (host, ts, cpu, memory) VALUES ("127.0.0.1", "2024-07-11 20:00:01", 0.8, 0.1); ``` ```sql INSERT INTO monitor (host, ts, cpu) VALUES ("127.0.0.1", "2024-07-11 20:00:01", NULL); ``` 不会更新任何内容: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-07-11 20:00:01 | 0.8 | 0.1 | +-----------+---------------------+------+--------+ ``` 有关 `merge_mode` 选项的更多信息,请参阅 [CREATE TABLE](/reference/sql/create.md#创建带有-merge-模式的表) 语句。 ### 通过创建带有 `append_mode` 选项的表来避免更新数据 在创建表时,GreptimeDB 支持 `append_mode` 选项,该选项始终将新数据插入表中。 当你想要保留所有历史数据(例如日志)时十分有用。 你只能使用 SQL 创建带有 `append_mode` 选项的表。 成功创建表后,所有[写入数据的协议](/user-guide/ingest-data/overview.md)都将在表中始终插入新数据。 例如,你可以创建一个带有 `append_mode` 选项的 `app_logs` 表,如下所示。 `host` 和 `log_level` 列表示 tag,`ts` 列表示 time index。 ```sql CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host STRING, api_path STRING FULLTEXT INDEX, log_level STRING, `log` STRING FULLTEXT INDEX, PRIMARY KEY (host, log_level) ) WITH ('append_mode'='true'); ``` 向 `app_logs` 表中插入一行新数据: ```sql INSERT INTO app_logs (ts, host, api_path, log_level, `log`) VALUES ('2024-07-11 20:00:10', 'host1', '/api/v1/resource', 'ERROR', 'Connection timeout'); ``` 检查表中的数据: ```sql SELECT * FROM app_logs; ``` 输出将为: ```sql +---------------------+-------+------------------+-----------+--------------------+ | ts | host | api_path | log_level | log | +---------------------+-------+------------------+-----------+--------------------+ | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection timeout | +---------------------+-------+------------------+-----------+--------------------+ 1 row in set (0.01 sec) ``` 你可以插入具有相同 tag 和 time index 的新数据: ```sql INSERT INTO app_logs (ts, host, api_path, log_level, `log`) -- 与现有数据相同的标签 `host1` 和 `ERROR`,相同的时间索引 2024-07-11 20:00:10 VALUES ('2024-07-11 20:00:10', 'host1', '/api/v1/resource', 'ERROR', 'Connection reset'); ``` 然后,你将在表中找到两行数据: ```sql SELECT * FROM app_logs; ``` ```sql +---------------------+-------+------------------+-----------+--------------------+ | ts | host | api_path | log_level | log | +---------------------+-------+------------------+-----------+--------------------+ | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection reset | | 2024-07-11 20:00:10 | host1 | /api/v1/resource | ERROR | Connection timeout | +---------------------+-------+------------------+-----------+--------------------+ 2 rows in set (0.01 sec) ``` ## 删除数据 你可以通过指定 tag 和 time index 来有效地删除数据。 未指定 tag 和 time index 进行删除数据不高效,因为它需要两个步骤:查询数据,然后按 tag 和 time index 进行删除。 有关列类型的更多信息,请参阅[数据模型](/user-guide/concepts/data-model.md)。 :::warning 警告 过多的删除可能会对查询性能产生负面影响。 ::: 只能使用 SQL 删除数据。 例如,要从 `monitor` 表中删除具有 tag `host` 和 time index `ts` 的行: ```sql DELETE FROM monitor WHERE host='127.0.0.2' AND ts=1667446798450; ``` 输出将为: ```sql Query OK, 1 row affected (0.00 sec) ``` 有关 `DELETE` 语句的更多信息,请参阅 [SQL DELETE](/reference/sql/delete.md)。 ## 删除表中的所有数据 要删除表中的所有数据,可以使用 SQL 中的 `TRUNCATE TABLE` 语句。 例如,要清空 `monitor` 表: ```sql TRUNCATE TABLE monitor; ``` 有关 `TRUNCATE TABLE` 语句的更多信息,请参阅 [SQL TRUNCATE TABLE](/reference/sql/truncate.md) 文档。 ## 使用 TTL 策略保留数据 Time to Live (TTL) 允许你设置定期删除表中数据的策略, 你可以使用 TTL 自动删除数据库中的过期数据。 设置 TTL 策略具有以下好处: - 通过清理过期数据来降低存储成本。 - 减少数据库在某些查询中需要扫描的行数,从而提高查询性能。 > 请注意,因 TTL 策略而过期的数据,并不是在 TTL 到期时立刻删除的,而是发生在 compaction 时。compaction 是一个后台任务。 > 如果你在测试 TTL 策略,查询过期数据之前请确保 flush 和 compaction 都已触发过了。 > 你可以使用我们的 ”[ADMIN](/reference/sql/admin.md)“ 函数来手动触发。 你可以在创建每个表时设置 TTL。 例如,以下 SQL 语句创建了一个名为 `monitor` 的表,并设置了 7 天的 TTL 策略: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, cpu FLOAT64, memory FLOAT64, PRIMARY KEY(host) ) WITH ('ttl'='7d'); ``` 你还可以创建数据库级别的 TTL 策略。 例如,以下 SQL 语句创建了一个名为 `test` 的数据库,并设置了 7 天的 TTL 策略: ```sql CREATE DATABASE test WITH ('ttl'='7d'); ``` 你可以同时为 table 和 database 设置 TTL 策略。 如果 table 有自己的 TTL 策略,则该策略将优先于 database 的 TTL 策略, 否则 database 的 TTL 策略将被应用于 table。 `'ttl'` 参数的值可以是持续时间(例如 `1hour 12min 5s`)、`instant` 或 `forever`。有关详细信息,请参阅 [CREATE](/reference/sql/create.md#创建指定-ttl-的表) 语句的文档。 使用 [`ALTER`](/reference/sql/alter.md#修改表的参数) 来修改现有表或数据库的 TTL: ```sql -- 针对表 ALTER TABLE monitor SET 'ttl'='1 month'; -- 针对数据库 ALTER DATABASE test SET 'ttl'='1 month'; ``` 如果你想移除 TTL 策略,可以使用如下 SQL 语句: ```sql -- 针对表移除 'ttl' 设置 ALTER TABLE monitor UNSET 'ttl'; -- 针对数据库移除 'ttl' 设置 ALTER DATABASE test UNSET 'ttl'; ``` 有关 TTL 策略的更多信息,请参阅 [CREATE](/reference/sql/create.md) 语句。 ## 更多数据管理操作 有关更高级的数据管理操作,例如基本表操作、表分片和 Region 迁移,请参阅 Administration 部分的[数据管理](/user-guide/deployments-administration/manage-data/overview.md)。 --- ## 从 ClickHouse 迁移 本指南详细介绍如何将业务平滑迁移自 ClickHouse 到 GreptimeDB,涵盖迁移前的准备、数据模型调整、表结构重构、双写保障以及数据导出与导入的具体方法,帮助实现系统的无缝切换。 ## 迁移前须知 - **兼容性** 虽然 GreptimeDB 支持 SQL 协议,但与 ClickHouse 在数据建模、索引设计和压缩机制等方面存在根本差异。请查阅 [SQL 兼容性](/reference/sql/compatibility.md) 文档以及官方[建模建议](/user-guide/deployments-administration/performance-tuning/design-table.md),在迁移过程中重构表结构与数据流。 - **数据模型差异** ClickHouse 属于通用大数据分析引擎,GreptimeDB 则重点优化时序、指标及日志可观测场景。两者在数据模型、索引体系与压缩算法等方面均有差别,模型设计时需充分考虑业务场景及兼容性。 --- ## 重新设计数据模型与表结构 ### 时间索引 - ClickHouse 的表未必有 time index 字段,迁移时需明确选择业务主要的时间字段作为时间索引,并在 GreptimeDB 建表时指定,如日志记录时间/链路追踪时间等。 - 时间精度(秒、毫秒、微秒等)应按实际需求选定,且一旦设定不可更改。 ### 主键与宽表建议 - 主键:类似 ClickHouse 的 `order by`,去掉时间戳列;但不建议包含 log_id、user_id 或 UUID 等高基数字段,以避免主键膨胀、写放大和低效查询。 - 宽表 vs 多表:同一个观测点采集多种指标时建议采用宽表,有助于提升批量写入效率和压缩比。 ### 索引规划 - 倒排索引:为低基数列建立索引,提高筛选效率。 - 跳数索引:按需使用,适用于稀疏值或大表中偶尔查询的特定值。 - 全文索引:按需使用,适用于字符串字段的文本检索,避免在高基数或高变动字段上建立无用索引。 - 更多信息详见[数据索引](/user-guide/manage-data/data-index.md)。 ### 表分区 ClickHouse 通过 `PARTITION BY` 语法支持分区,GreptimeDB 提供类似能力,语法不同,请参阅[表分片](/user-guide/deployments-administration/manage-data/table-sharding.md)文档。 ### TTL GreptimeDB 支持通过表选项 `ttl` 设置生命周期,详见[使用 TTL 策略管理数据存储](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据)。 ### 表结构举例 ClickHouse 表: ```sql CREATE TABLE example ( timestamp DateTime, host String, app String, metric String, value Float64 ) ENGINE = MergeTree() TTL timestamp + INTERVAL 30 DAY ORDER BY (timestamp, host, app, metric); ```` GreptimeDB 推荐表结构: ```sql CREATE TABLE example ( `timestamp` TIMESTAMP NOT NULL, host STRING, app STRING INVERTED INDEX, metric STRING INVERTED INDEX, `value` DOUBLE, PRIMARY KEY (host, app, metric), TIME INDEX (`timestamp`) ) with(ttl='30d'); ``` > 主键及时间索引的选型应结合业务数据量及查询场景慎重设计。如果 host 基数很大(如百万级监控主机),可不做主键,改为跳数索引。 ### 典型日志表迁移 > GreptimeDB 已内置 otel 日志建模方案,操作详见[官方文档](/user-guide/ingest-data/for-observability/opentelemetry.md#logs)。 ClickHouse 日志表结构: ```sql CREATE TABLE logs ( timestamp DateTime, host String, service String, log_level String, log_message String, trace_id String, span_id String, INDEX inv_idx(log_message) TYPE ngrambf_v1(4, 1024, 1, 0) GRANULARITY 1 ) ENGINE = MergeTree ORDER BY (timestamp, host, service); ``` 推荐的 GreptimeDB 表结构: - 时间索引:`timestamp`(根据日志频率选定精度) - 主键:`host`, `service`(常用过滤/聚合字段) - 字段列:`log_message`, `trace_id`, `span_id`(高基数、唯一标识或原始内容) ```sql CREATE TABLE logs ( `timestamp` TIMESTAMP NOT NULL, host STRING, service STRING, log_level STRING, log_message STRING FULLTEXT INDEX WITH ( backend = 'bloom', analyzer = 'English', case_sensitive = 'false' ), trace_id STRING SKIPPING INDEX, span_id STRING SKIPPING INDEX, PRIMARY KEY (host, service), TIME INDEX (`timestamp`) ); ``` **说明:** - `host` 和 `service` 作为常用过滤项列入主键,如主机数量非常多,可移出主键,改为跳数索引。 - `log_message` 作为原始文本内容建立全文索引。**若要全文索引生效,查询时 SQL 语法也需调整,详见[日志检索文档](/user-guide/logs/fulltext-search.md)**。 - `trace_id` 和 `span_id` 通常为高基数字段,建议仅做跳数索引。 ### 典型链路表迁移 > GreptimeDB 已内置 otel 链路建模方案,详见[官方文档](/user-guide/ingest-data/for-observability/opentelemetry.md#traces)。 ClickHouse 链路表结构设计: ```sql CREATE TABLE traces ( timestamp DateTime, trace_id String, span_id String, parent_span_id String, service String, operation String, duration UInt64, status String, tags Map(String, String) ) ENGINE = MergeTree() ORDER BY (timestamp, trace_id, span_id); ``` GreptimeDB 推荐表结构: - 时间索引:`timestamp`(采集/起始时间) - 主键:`service`, `operation`(常用过滤/聚合属性) - 字段列:`trace_id`, `span_id`, `parent_span_id`, `duration`, `tags`(高基数或 Map 字段) ```sql CREATE TABLE traces ( `timestamp` TIMESTAMP NOT NULL, service STRING, operation STRING, `status` STRING, trace_id STRING SKIPPING INDEX, span_id STRING SKIPPING INDEX, parent_span_id STRING SKIPPING INDEX, duration DOUBLE, tags STRING, -- 如为结构化 JSON 可原样存储,必要时用 Pipeline 展开字段 PRIMARY KEY (service, operation), TIME INDEX (`timestamp`) ); ``` **说明:** - `service` 与 `operation` 作为主键,便于链路调度和按服务聚合。 - `trace_id`、`span_id`、`parent_span_id` 用跳数索引,不作为主键。 - 高基数字段仅作普通字段,便于写入效率;`tags` 推荐用字符串或 json,复杂属性可结合 [ETL Pipeline](/user-guide/logs/quick-start.md#使用-pipeline-写入日志) 展开。 - 若业务量极大可考虑多表分区(如多服务场景区分)。 双写保障迁移策略 -------- 迁移期间,为避免数据丢失和写入不一致,建议采用双写: - 应用需同时写入 ClickHouse 和 GreptimeDB,双系统并行。 - 通过日志和校验对比数据,可保证一致性,数据无误后再切换全部流量。 历史数据导出与导入 --------- 1. **迁移前开启双写** 应用同时写入 ClickHouse 和 GreptimeDB,校验数据一致性,减少数据缺失风险。 2. **从 ClickHouse 导出数据** 利用 ClickHouse 命令将数据导出为 CSV、TSV、Parquet 等格式样例: ```sh clickhouse client --query="SELECT * FROM example INTO OUTFILE 'example.csv' FORMAT CSVWithNames" ``` 导出的 CSV 内容类似: ```csv "timestamp","host","app","metric","value" "2024-04-25 10:00:00","host01","nginx","cpu_usage",12.7 "2024-04-25 10:00:00","host02","redis","cpu_usage",8.4 ... ``` 3. **导入数据到 GreptimeDB** > 需先在 GreptimeDB 创建好目标表。 支持 SQL 命令批量导入,或用 [REST API](/reference/http-endpoints.md#协议端点) 分批导入大数据量。 可用 [`COPY FROM` 命令](/reference/sql/copy.md#copy-from): ```sql COPY example FROM "/path/to/example.csv" WITH (FORMAT = 'CSV'); ``` 或转换为标准 INSERT 语句分批导入。 验证与流量切换 ------- - 导入完成后,使用 GreptimeDB 查询接口与 ClickHouse 进行数据对比。 - 校验数据及监控无误后,可正式切换业务写入到 GreptimeDB,并关闭双写。 常见问题与优化建议 --------- ### SQL/类型不兼容怎么办? 迁移前需梳理所有查询 SQL 并按官方文档 ([SQL 查询](/user-guide/query-data/sql.md)、[日志检索](/user-guide/logs/fulltext-search.md)) 重写或翻译不兼容语法和类型。 ### 如何高效批量导入大规模数据? 大表或历史全量数据建议分分区/分片导出导入,并密切监控速度和进度。 ### 高基数字段如何处理? 避免作为主键,直接存为字段,必要时分表拆分。 ### 宽表如何规划? 每个监控对象(采集端)建议聚合到单表,如 `host_metrics` 专表存储服务器所有指标。 如果您需要更详细的迁移方案或示例脚本,请提供具体表结构和数据量信息。[GreptimeDB 官方社区](https://github.com/orgs/GreptimeTeam/discussions)将为您提供进一步支持。欢迎加入 [Greptime Slack](http://greptime.com/slack) 交流。 --- ## 从 InfluxDB 迁移 ```shell curl -X POST 'http://{{host}}:4000/v1/influxdb/api/v2/write?db={{db-name}}' \ -H 'authorization: token {{greptime_user:greptimedb_password}}' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` ```shell curl 'http://{{host}}:4000/v1/influxdb/write?db={{db-name}}&u={{greptime_user}}&p={{greptimedb_password}}' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` 有关详细的配置说明,请参考 [通过 Telegraf 写入数据](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md#telegraf) 文档。 ```js 'use strict' /** @module write **/ /** Environment variables **/ const url = 'http://:4000/v1/influxdb' const token = ':' const org = '' const bucket = '' const influxDB = new InfluxDB({ url, token }) const writeApi = influxDB.getWriteApi(org, bucket) writeApi.useDefaultTags({ region: 'west' }) const point1 = new Point('temperature') .tag('sensor_id', 'TLM01') .floatField('value', 24.0) writeApi.writePoint(point1) ``` ```python from influxdb_client.client.write_api import SYNCHRONOUS bucket = "" org = "" token = ":" url="http://:4000/v1/influxdb" client = influxdb_client.InfluxDBClient( url=url, token=token, org=org ) # Write script write_api = client.write_api(write_options=SYNCHRONOUS) p = influxdb_client.Point("my_measurement").tag("location", "Prague").field("temperature", 25.3) write_api.write(bucket=bucket, org=org, record=p) ``` ```go bucket := "" org := "" token := ":" url := "http://:4000/v1/influxdb" client := influxdb2.NewClient(url, token) writeAPI := client.WriteAPIBlocking(org, bucket) p := influxdb2.NewPoint("stat", map[string]string{"unit": "temperature"}, map[string]interface{}{"avg": 24.5, "max": 45}, time.Now()) writeAPI.WritePoint(context.Background(), p) client.Close() ``` ```java private static String url = "http://:4000/v1/influxdb"; private static String org = ""; private static String bucket = ""; private static char[] token = ":".toCharArray(); public static void main(final String[] args) { InfluxDBClient influxDBClient = InfluxDBClientFactory.create(url, token, org, bucket); WriteApiBlocking writeApi = influxDBClient.getWriteApiBlocking(); Point point = Point.measurement("temperature") .addTag("location", "west") .addField("value", 55D) .time(Instant.now().toEpochMilli(), WritePrecision.MS); writeApi.writePoint(point); influxDBClient.close(); } ``` ```php $client = new Client([ "url" => "http://:4000/v1/influxdb", "token" => ":", "bucket" => "", "org" => "", "precision" => InfluxDB2\Model\WritePrecision::S ]); $writeApi = $client->createWriteApi(); $dateTimeNow = new DateTime('NOW'); $point = Point::measurement("weather") ->addTag("location", "Denver") ->addField("temperature", rand(0, 20)) ->time($dateTimeNow->getTimestamp()); $writeApi->write($point); ``` 推荐使用 Grafana 可视化 GreptimeDB 数据, 请参考 [Grafana 文档](/user-guide/integrations/grafana.md) 了解如何配置 GreptimeDB。 ```shell for file in data.*; do curl -i --retry 3 \ -X POST "http://${GREPTIME_HOST}:4000/v1/influxdb/write?db=${GREPTIME_DB}&u=${GREPTIME_USERNAME}&p=${GREPTIME_PASSWORD}" \ --data-binary @${file} sleep 1 done ``` --- ## 从 Loki 迁移 本指南介绍如何将 Loki 日志写入迁移到 GreptimeDB。 GreptimeDB 支持 Loki Push API 写入日志,因此现有的 Loki 兼容写入端通常只需少量配置变更即可将日志发送到 GreptimeDB。 GreptimeDB 的 Loki 兼容端点用于日志写入。 对于查询和仪表盘,请使用 GreptimeDB SQL、[全文检索](/user-guide/logs/fulltext-search.md)、[GreptimeDB Dashboard](/getting-started/installation/greptimedb-dashboard.md) 以及 [Grafana 集成](/user-guide/integrations/grafana.md),而不是 LogQL。 ## 迁移前须知 请先检查当前 Loki 部署,并决定日志在 GreptimeDB 中的存储方式: * 梳理所有向 Loki 写入日志的组件,例如 Grafana Alloy、OpenTelemetry Collector、Promtail、Fluent Bit、Vector 或自定义客户端。 * 规划目标 GreptimeDB 数据库和表名。如果没有提供表名 Header,GreptimeDB 会将 Loki 日志写入 `loki_logs`。 * 检查 Loki stream labels。GreptimeDB 会将 labels 存储为标签列,因此应避免使用 request ID、user ID、trace ID 等高基数字段作为 label。 * 确认是否只需要保存原始日志行,还是需要使用 GreptimeDB Pipeline 将日志行解析为结构化列。 * 规划历史数据迁移。GreptimeDB 不会直接导入 Loki chunk 或 index 文件;请通过原始日志源、归档文件或导出的记录,将历史日志重放到 GreptimeDB 的日志写入 API。 对于新的采集器配置,推荐使用 [Grafana Alloy](/user-guide/integrations/alloy.md)。 如果仍在使用已有的 Loki 兼容客户端,可以通过修改 Loki Push URL 并添加 GreptimeDB Header,将其重定向到 GreptimeDB。 ## 迁移步骤 ### 配置 GreptimeDB Loki 端点 将 Loki Push 请求发送到: ```text http{s}://:4000/v1/loki/api/v1/push ``` 使用以下 GreptimeDB 专用 Header: | Header | 是否必需 | 说明 | | --- | --- | --- | | `X-Greptime-DB-Name` | 否 | 目标数据库名,默认值为 `public`。 | | `X-Greptime-Log-Table-Name` | 否 | 目标日志表名,默认值为 `loki_logs`。 | | `Authorization` | 取决于部署 | 使用 Base64 编码的 `:` 进行 Basic 认证。 | | `X-Greptime-Pipeline-Name` 或 `X-Greptime-Log-Pipeline-Name` | 否 | 在写入前用于解析 Loki 条目的 Pipeline 名称。 | GreptimeDB 接受与 Loki 相同的 Push 请求体格式: * `Content-Type: application/x-protobuf`:Snappy 压缩的 Loki `PushRequest`。 * `Content-Type: application/json`:包含顶层 `streams` 数组的 JSON 请求体。 以下 JSON 请求可用于快速检查连通性: ```bash curl -X POST "http://localhost:4000/v1/loki/api/v1/push" \ -H "Content-Type: application/json" \ -H "X-Greptime-DB-Name: public" \ -H "X-Greptime-Log-Table-Name: loki_demo_logs" \ --data-raw '{ "streams": [ { "stream": { "job": "api", "env": "prod" }, "values": [ ["1731748568804293888", "request completed", {"trace_id": "abc"}] ] } ] }' ``` ### 双写 Loki 和 GreptimeDB 迁移期间,请同时写入 Loki 和 GreptimeDB,直到完成写入、保留策略、仪表盘和告警验证。 以下 Alloy 示例保留现有 Loki sink,并新增一个 GreptimeDB Loki 兼容 sink: ```hcl loki.source.file "app" { targets = [ {__path__ = "/var/log/app/*.log"}, ] forward_to = [loki.process.app.receiver] file_match { enabled = true } } loki.process "app" { forward_to = [ loki.write.existing_loki.receiver, loki.write.greptimedb.receiver, ] stage.static_labels { values = { job = "app", env = "prod", } } } loki.write "existing_loki" { endpoint { url = "http://loki:3100/loki/api/v1/push" } } loki.write "greptimedb" { endpoint { url = "http://greptimedb:4000/v1/loki/api/v1/push" headers = { "X-Greptime-DB-Name" = "public", "X-Greptime-Log-Table-Name" = "loki_app_logs", } basic_auth { username = "" password = "" } } } ``` 如果你的采集器已经配置了 Loki 输出,迁移初期请先保持 labels 和处理阶段不变。 只修改 GreptimeDB sink 的 URL、数据库 Header、表名 Header 和认证配置。 该示例遵循 [Grafana Alloy 指南](/user-guide/ingest-data/for-observability/alloy.md)中的 Loki 组件模式:`loki.source.file` 读取文件,`loki.process` 在 Loki pipeline 中保留 label 处理,`loki.write.endpoint` 则承载 GreptimeDB URL、自定义 Header 以及可选的 Basic 认证配置。 由于该示例在 `__path__` 中使用了 glob 匹配模式,`file_match` 会启用 Alloy 内置的文件发现能力,将该模式展开为实际匹配的文件。如果你使用的是明确的文件路径,可以省略 `file_match`。 ### 验证直接写入的数据模型 不使用 Pipeline 时,GreptimeDB 会将 Loki 条目存储在原始日志表中: | Loki 数据 | GreptimeDB 列 | | --- | --- | | Entry timestamp | `greptime_timestamp` 时间索引 | | Log line | `line` 字段列 | | Structured metadata | `structured_metadata` JSON 字段列 | | Stream labels | 字符串标签列 | 直接写入时,请让 GreptimeDB 在首次写入时自动创建表。 不要通过 SQL 预先创建直接写入表来指定 label 列。 Labels 是动态的,会成为自动生成表结构中的标签列。 如果需要自定义表结构,请使用 Pipeline,并根据 Pipeline 配置创建表。 使用 SQL 验证写入结果: ```sql DESC loki_app_logs; SELECT greptime_timestamp, line, job, env, structured_metadata FROM loki_app_logs ORDER BY greptime_timestamp DESC LIMIT 10; ``` 也可以检查该表是否被识别为 Loki 日志数据: ```sql SELECT table_schema, table_name, signal_type, source FROM information_schema.table_semantics WHERE table_name = 'loki_app_logs'; ``` 也可以打开 `http://:4000/dashboard` 访问 [GreptimeDB Dashboard](/getting-started/installation/greptimedb-dashboard.md),并使用 Log View 查询写入的日志。 ### 使用 Pipeline 解析 Loki 日志行 如果 Loki 日志行包含 JSON、logfmt、Nginx access logs 或其他需要展开为可查询列的结构化格式,请使用 GreptimeDB Pipeline。 如果使用 AI 编码代理来创建 Pipeline,可以为它提供 [`greptimedb-pipeline` Skill](/faq-and-others/vibecoding.md#greptimedb-skills),帮助它生成、dry-run 并迭代 Pipeline 配置。 当请求中包含 `X-Greptime-Pipeline-Name` 或 `X-Greptime-Log-Pipeline-Name` 时,GreptimeDB 会将每条 Loki 条目按以下输入字段送入 Pipeline: | Pipeline 输入字段 | 说明 | | --- | --- | | `greptime_timestamp` | Loki 条目的时间戳。 | | `loki_line` | 原始 Loki 日志行。 | | `loki_label_` | Loki stream label 值。 | | `loki_metadata_` | Loki structured metadata 值。 | 例如,假设 Alloy 读取以下 ZooKeeper 日志文件: ```text 2015-08-25 11:23:58,959 - WARN [LearnerHandler-/10.10.34.11:45441:Leader@574] - Committing zxid 0xf00000000 from /10.10.34.13:2888 not first! 2015-08-25 11:23:58,960 - WARN [LearnerHandler-/10.10.34.11:45441:Leader@576] - First is 0x0 2015-08-25 11:23:58,960 - INFO [LearnerHandler-/10.10.34.11:45441:Leader@598] - Have quorum of supporters; starting up and setting last processed zxid: 0xf00000000 2015-08-25 11:26:27,891 - INFO [/10.10.34.13:3888:QuorumCnxManager$Listener@493] - Received connection request /10.10.34.12:57513 2015-08-25 11:26:27,897 - INFO [WorkerReceiver[myid=3]:FastLeaderElection@542] - Notification: 2 (n.leader), 0xd0000001b (n.zxid), 0x1 (n.round), LOOKING (n.state), 2 (n.sid), 0xd (n.peerEPoch), LEADING (my state) 2015-08-25 11:26:27,898 - INFO [WorkerReceiver[myid=3]:FastLeaderElection@542] - Notification: 3 (n.leader), 0xd0000001b (n.zxid), 0x3 (n.round), LOOKING (n.state), 2 (n.sid), 0xe (n.peerEPoch), LEADING (my state) 2015-08-25 11:26:28,138 - INFO [LearnerHandler-/10.10.34.12:38330:LearnerHandler@263] - Follower sid: 2 : info : org.apache.zookeeper.server.quorum.QuorumPeer$QuorumServer@7761c32f 2015-08-25 11:26:28,159 - INFO [LearnerHandler-/10.10.34.12:38330:LearnerHandler@318] - Synchronizing with Follower sid: 2 maxCommittedLog=0x0 minCommittedLog=0x0 peerLastZxid=0xd0000001b 2015-08-25 11:26:28,159 - INFO [LearnerHandler-/10.10.34.12:38330:LearnerHandler@395] - Sending SNAP 2015-08-25 11:26:28,159 - INFO [LearnerHandler-/10.10.34.12:38330:LearnerHandler@419] - Sending snapshot last zxid of peer is 0xd0000001b zxid of leader is 0xf00000000sent zxid of db as 0xf00000000 ``` 创建一个 Pipeline,提取 ZooKeeper 时间戳、日志级别、线程、源码行号和消息: ```yaml # zk_pipeline.yaml version: 2 processors: - regex: fields: - loki_line, zk patterns: - '^(?\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}) - (?[A-Z]+)\s+\[(?.*)@(?\d+)\] - (?.*)$' ignore_missing: true - date: fields: - zk_timestamp formats: - "%Y-%m-%d %H:%M:%S,%3f" timezone: "UTC" - select: fields: - zk_timestamp - zk_level - zk_thread - zk_source_line - zk_message - loki_label_job - loki_label_env transform: - field: zk_timestamp type: time index: timestamp - fields: - zk_level - loki_label_job - loki_label_env type: string tag: true - field: zk_thread type: string index: inverted - field: zk_source_line type: int32 - field: zk_message type: string index: fulltext ``` 示例日志中的时间戳没有包含时区。请将 `timezone` 设置为日志生产端使用的时区。 上传 Pipeline: ```bash curl -X POST "http://localhost:4000/v1/pipelines/zk_logs" \ -F "file=@zk_pipeline.yaml" ``` 然后在 GreptimeDB Loki sink 中添加 Pipeline Header: ```hcl loki.write "greptimedb" { endpoint { url = "http://greptimedb:4000/v1/loki/api/v1/push" headers = { "X-Greptime-DB-Name" = "public", "X-Greptime-Log-Table-Name" = "loki_zookeeper_logs", "X-Greptime-Pipeline-Name" = "zk_logs", } } } ``` Alloy 通过该 sink 发送 ZooKeeper 日志文件后,GreptimeDB 会先应用该 Pipeline,再将处理后的行写入 `loki_zookeeper_logs`。 通过 Pipeline 写入后,可以查询结构化列: ```sql SELECT zk_timestamp, loki_label_job AS job, loki_label_env AS env, zk_level, zk_thread, zk_source_line, zk_message FROM loki_zookeeper_logs WHERE zk_level = 'WARN' ORDER BY zk_timestamp DESC LIMIT 10; ``` 如需在解析后的 message 字段上使用全文检索,请参阅[全文检索](/user-guide/logs/fulltext-search.md)。 ### 迁移历史日志 完整迁移历史日志时,应将数据重放到 GreptimeDB,而不是复制 Loki 存储文件。 常见做法包括: * 使用 Alloy、Vector、Fluent Bit 或自定义脚本,从原始日志文件或对象存储归档中重放日志。 * 将选定的 Loki 查询结果导出为按行分隔的记录,转换为 Loki Push JSON 后写入 GreptimeDB。 * 仅回填切换后必须可查询的保留窗口,并通过双写覆盖新增数据。 回填时,请保留原始纳秒时间戳,以便 GreptimeDB 保留事件发生时间。 建议按有限时间范围分批导入,便于验证和重试。 ### 切换读写流量 在停止写入 Loki 之前,请验证: * 每个重要 service、namespace 和 environment 的最新日志都已写入 GreptimeDB。 * 同一时间窗口内的行数或抽样记录与 Loki 匹配。 * GreptimeDB 保留策略满足日志保留要求。 * 仪表盘和告警已从 LogQL 改写为 SQL 或 GreptimeDB 日志查询。 * 常用检索列已经具备全文索引或跳数索引。 验证完成后,从采集器配置中移除 Loki sink,仅保留 GreptimeDB sink 作为日志目的端。 ## 故障排查 ### 不支持的 Content-Type Loki protobuf Push 客户端请设置 `Content-Type` 为 `application/x-protobuf`;JSON 请求请设置为 `application/json`。 ### Protobuf decode 或 Snappy 错误 Loki protobuf Push 请求体必须经过 Snappy 压缩。 不要发送未经过 Snappy 压缩的原始 protobuf 字节。 ### GreptimeDB 中缺少 labels 请检查 `loki.write` 之前的采集器处理阶段。 只有发送请求时仍保留在 Loki stream 上的 labels 才会成为 GreptimeDB 标签列。 ### 表结构不匹配 对于 Loki 直接写入,请让 GreptimeDB 自动创建表。 如果需要自定义表结构,请使用 Pipeline,并根据 Pipeline 配置生成或创建表。 ## 相关文档 * [Loki 协议](/user-guide/ingest-data/for-observability/loki.md) * [Grafana Alloy](/user-guide/ingest-data/for-observability/alloy.md) * [管理 Pipeline](/user-guide/logs/manage-pipelines.md) * [全文检索](/user-guide/logs/fulltext-search.md) --- ## 从 MySQL 迁移 本文档将指引您完成从 MySQL 迁移到 GreptimeDB。 ## 在开始迁移之前 请注意,尽管 GreptimeDB 支持 MySQL 的协议,并不意味着 GreptimeDB 实现了 MySQL 的所有功能。你可以参考 - [ANSI 兼容性](/reference/sql/compatibility.md)查看在 GreptimeDB 中使用 SQL 的约束。 - [数据建模指南](/user-guide/deployments-administration/performance-tuning/design-table.md)创建合适的表结构。 - [数据索引指南](/user-guide/manage-data/data-index.md)用于索引规划。 ## 迁移步骤 ### 在 GreptimeDB 中创建数据库和表 在从 MySQL 迁移数据之前,你首先需要在 GreptimeDB 中创建相应的数据库和表。 由于 GreptimeDB 有自己的 SQL 语法用于创建表,因此你不能直接重用 MySQL 生成的建表 SQL。 当你为 GreptimeDB 编写创建表的 SQL 时,首先请了解其“[数据模型](/user-guide/concepts/data-model.md)”。然后,在创建表的 SQL 中请考虑以下几点: 1. 由于 time index 列在表创建后无法更改,所以你需要仔细选择 time index 列。时间索引最好设置为数据生成时的自然时间戳,因为它提供了查询数据的最直观方式,以及最佳的查询性能。例如,在 IOT 场景中,你可以使用传感器采集数据时的时间作为 time index;或者在可观测场景中使用事件的发生时间。 2. 不建议在此迁移过程中另造一个时间戳用作时间索引,例如使用 `DEFAULT current_timestamp()` 创建的新列。也不建议使用具有随机时间戳的列。 3. 选择合适的 time index 精度也至关重要。和 time index 的选择一样,一旦表创建完毕,time index 的精度就无法变更了。请根据你的数据集在[这里](/reference/sql/data-types.md#与-mysql-和-postgresql-兼容的数据类型)找到最适合的时间戳类型。 4. 仅在真正需要时才选择主键。GreptimeDB 中的主键与 MySQL 中的主键不同。仅在以下情况下才应使用主键: - 大部分查询可以受益于排序。 - 您需要通过主键和时间索引来删除重复行(包括删除)。 通常会被查询。标签列中的值是附加到收集源的标签,通常用于描述这些源的特定特征。标签列会被索引,从而使对它们的查询具有高性能。 否则,设置主键是可选的,并且可能会损害性能。阅读[主键](/user-guide/deployments-administration/performance-tuning/design-table.md#主键)了解详情。 最后,请参阅“[CREATE](/reference/sql/create.md)” SQL 文档,了解有关选择合适的数据类型和“ttl”或“compaction”选项等的更多详细信息。 5. 选择合适的索引以加快查询速度。 - 倒排索引:非常适合按低基数列进行过滤,并快速查找具有特定值的行。 - 跳数索引:适用于稀疏数据。 - 全文索引:可以在大型文本列中实现高效的关键字和模式搜索。 有关详细信息和最佳实践,请参阅[数据索引](/user-guide/manage-data/data-index.md) 文档。 ### 双写 GreptimeDB 和 MySQL 双写 GreptimeDB 和 MySQL 是迁移过程中防止数据丢失的有效策略。通过使用 MySQL 的客户端库(JDBC + 某个 MySQL 驱动),你可以建立两个客户端实例 —— 一个用于 GreptimeDB,另一个用于 MySQL。有关如何使用 SQL 将数据写入 GreptimeDB,请参考[写入数据](/user-guide/ingest-data/for-iot/sql.md)部分。 若无需保留所有历史数据,你可以双写一段时间以积累业务所需的最新数据,然后停止向 MySQL 写入数据并仅使用 GreptimeDB。如果需要完整迁移所有历史数据,请按照接下来的步骤操作。 ### 从 MySQL 导出数据 [mysqldump](https://dev.mysql.com/doc/refman/8.4/en/mysqldump.html) 是一个常用的、从 MySQL 导出数据的工具。使用 mysqldump,我们可以从 MySQL 中导出后续可直接导入到 GreptimeDB 的数据。例如,如果我们想要从 MySQL 导出两个数据库 `db1` 和 `db2`,我们可以使用以下命令: ```bash mysqldump -h127.0.0.1 -P3306 -umysql_user -p --compact -cnt --skip-extended-insert --databases db1 db2 > /path/to/output.sql ``` 替换 `-h`、`-P` 和 `-u` 参数为 MySQL 服务的正确值。`--databases` 参数用于指定要导出的数据库。输出将写入 `/path/to/output.sql` 文件。 `/path/to/output.sql` 文件应该具有如下内容: ```plaintext ~ ❯ cat /path/to/output.sql USE `db1`; INSERT INTO `foo` (`ts`, `a`, `b`) VALUES (1,'hello',1); INSERT INTO ... USE `db2`; INSERT INTO `foo` (`ts`, `a`, `b`) VALUES (2,'greptime',2); INSERT INTO ... ``` ### 将数据导入 GreptimeDB [MySQL Command-Line Client](https://dev.mysql.com/doc/refman/8.4/en/mysql.html) 可用于将数据导入 GreptimeDB。继续上面的示例,假设数据导出到文件 `/path/to/output.sql`,那么我们可以使用以下命令将数据导入 GreptimeDB: ```bash mysql -h127.0.0.1 -P4002 -ugreptime_user -p -e "source /path/to/output.sql" ``` 替换 `-h`、`-P` 和 `-u` 参数为你的 GreptimeDB 服务的值。`source` 命令用于执行 `/path/to/output.sql` 文件中的 SQL 命令。若需要进行 debug,添加 `-vvv` 以查看详细的执行结果。 总结一下,数据迁移步骤如下图所示: ![migrate mysql data steps](/migration-mysql.jpg) 数据迁移完成后,你可以停止向 MySQL 写入数据,并继续使用 GreptimeDB! 如果您需要更详细的迁移方案或示例脚本,请提供具体的表结构和数据量信息。[GreptimeDB 官方社区](https://github.com/orgs/GreptimeTeam/discussions)将为您提供进一步的支持。欢迎加入 [Greptime Slack](http://greptime.com/slack) 社区交流。 --- ## 从 PostgreSQL 迁移 本文档将指引您完成从 PostgreSQL 迁移到 GreptimeDB。 ## 在开始迁移之前 请注意,尽管 GreptimeDB 支持 PostgreSQL 的协议,并不意味着 GreptimeDB 实现了 PostgreSQL 的所有功能。你可以参考 - [ANSI 兼容性](/reference/sql/compatibility.md)查看在 GreptimeDB 中使用 SQL 的约束。 - [数据建模指南](/user-guide/deployments-administration/performance-tuning/design-table.md)创建合适的表结构。 - [数据索引指南](/user-guide/manage-data/data-index.md)用于索引规划。 ## 迁移步骤 ### 在 GreptimeDB 中创建数据库和表 在从 PostgreSQL 迁移数据之前,你首先需要在 GreptimeDB 中创建相应的数据库和表。 由于 GreptimeDB 有自己的 SQL 语法用于创建表,因此你不能直接重用 PostgreSQL 生成的建表 SQL。 当你为 GreptimeDB 编写创建表的 SQL 时,首先请了解其“[数据模型](/user-guide/concepts/data-model.md)”。然后,在创建表的 SQL 中请考虑以下几点: 1. 由于 time index 列在表创建后无法更改,所以你需要仔细选择 time index 列。时间索引最好设置为数据生成时的自然时间戳,因为它提供了查询数据的最直观方式,以及最佳的查询性能。例如,在 IOT 场景中,你可以使用传感器采集数据时的时间作为 time index;或者在可观测场景中使用事件的发生时间。 2. 不建议在此迁移过程中另造一个时间戳用作时间索引,例如使用 `DEFAULT current_timestamp()` 创建的新列。也不建议使用具有随机时间戳的列。 3. 选择合适的 time index 精度也至关重要。和 time index 的选择一样,一旦表创建完毕,time index 的精度就无法变更了。请根据你的数据集在[这里](/reference/sql/data-types.md#与-mysql-和-postgresql-兼容的数据类型)找到最适合的时间戳类型。 4. 仅在真正需要时才选择主键。GreptimeDB 中的主键与 PosgreSQL 中的主键不同。仅在以下情况下才应使用主键: - 大部分查询可以受益于排序。 - 您需要通过主键和时间索引来删除重复行(包括删除)。 通常会被查询。标签列中的值是附加到收集源的标签,通常用于描述这些源的特定特征。标签列会被索引,从而使对它们的查询具有高性能。 否则,设置主键是可选的,并且可能会损害性能。阅读[主键](/user-guide/deployments-administration/performance-tuning/design-table.md#主键)了解详情。 最后,请参阅“[CREATE](/reference/sql/create.md)” SQL 文档,了解有关选择合适的数据类型和“ttl”或“compaction”选项等的更多详细信息。 5. 选择合适的索引以加快查询速度。 - 倒排索引:非常适合按低基数列进行过滤,并快速查找具有特定值的行。 - 跳数索引:适用于稀疏数据。 - 全文索引:可以在大型文本列中实现高效的关键字和模式搜索。 有关详细信息和最佳实践,请参阅[数据索引](/user-guide/manage-data/data-index.md) 文档。 ### 双写 GreptimeDB 和 PostgreSQL 双写 GreptimeDB 和 PostgreSQL 是迁移过程中防止数据丢失的有效策略。通过使用 PostgreSQL 的客户端库(JDBC + 某个 PostgreSQL 驱动),你可以建立两个客户端实例 —— 一个用于 GreptimeDB,另一个用于 PostgreSQL。有关如何使用 SQL 将数据写入 GreptimeDB,请参考[写入数据](/user-guide/ingest-data/for-iot/sql.md)部分。 若无需保留所有历史数据,你可以双写一段时间以积累业务所需的最新数据,然后停止向 PostgreSQL 写入数据并仅使用 GreptimeDB。如果需要完整迁移所有历史数据,请按照接下来的步骤操作。 ### 从 PostgreSQL 导出数据 [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html) 是一个常用的、从 PostgreSQL 导出数据的工具。使用 pg_dump,我们可以从 PostgreSQL 中导出后续可直接导入到 GreptimeDB 的数据。例如,如果我们想要从 PostgreSQL 的 database `postgres` 中导出以 `db` 开头的 schema,我们可以使用以下命令: ```bash pg_dump -h127.0.0.1 -p5432 -Upostgres -ax --column-inserts -n 'db*' postgres | grep -v "^SE" > /path/to/output.sql ``` 替换 `-h`、`-p` 和 `-U` 参数为 PostgreSQL 服务的正确值。`-n` 参数用于指定要导出的 schema。数据库 `postgres` 被放在了 `pg_dump` 命令的最后。注意这里我们将 pg_dump 的输出经过了一个特殊的 `grep` 命令以过滤掉不需要的 `SET` 和 `SELECT` 行。最终输出将写入 `/path/to/output.sql` 文件。 `/path/to/output.sql` 文件应该具有如下内容: ```plaintext ~ ❯ cat /path/to/output.sql -- -- PostgreSQL database dump -- -- Dumped from database version 16.4 (Debian 16.4-1.pgdg120+1) -- Dumped by pg_dump version 16.4 -- -- Data for Name: foo; Type: TABLE DATA; Schema: db1; Owner: postgres -- INSERT INTO db1.foo (ts, a) VALUES ('2024-10-31 00:00:00', 1); INSERT INTO db1.foo (ts, a) VALUES ('2024-10-31 00:00:01', 2); INSERT INTO db1.foo (ts, a) VALUES ('2024-10-31 00:00:01', 3); INSERT INTO ... -- -- Data for Name: foo; Type: TABLE DATA; Schema: db2; Owner: postgres -- INSERT INTO db2.foo (ts, b) VALUES ('2024-10-31 00:00:00', '1'); INSERT INTO db2.foo (ts, b) VALUES ('2024-10-31 00:00:01', '2'); INSERT INTO db2.foo (ts, b) VALUES ('2024-10-31 00:00:01', '3'); INSERT INTO ... -- -- PostgreSQL database dump complete -- ``` ### 将数据导入 GreptimeDB ”[psql -- PostgreSQL interactive terminal](https://www.postgresql.org/docs/current/app-psql.html)“可用于将数据导入 GreptimeDB。继续上面的示例,假设数据导出到文件 `/path/to/output.sql`,那么我们可以使用以下命令将数据导入 GreptimeDB: ```bash psql -h127.0.0.1 -p4003 -d public -f /path/to/output.sql ``` 替换 `-h` 和 `-p` 参数为你的 GreptimeDB 服务的值。psql 命令中的 `-d` 参数用于指定数据库,该参数不能省略,`-d` 的值 `public` 是 GreptimeDB 默认使用的数据库。你还可以添加 `-a` 以查看详细的执行结果,或使用 `-s` 进入单步执行模式。 总结一下,数据迁移步骤如下图所示: ![migrate postgresql data steps](/migration-postgresql.jpg) 数据迁移完成后,你可以停止向 PostgreSQL 写入数据,并继续使用 GreptimeDB! 如果您需要更详细的迁移方案或示例脚本,请提供具体的表结构和数据量信息。[GreptimeDB 官方社区](https://github.com/orgs/GreptimeTeam/discussions)将为您提供进一步的支持。欢迎加入 [Greptime Slack](http://greptime.com/slack) 社区交流。 --- ## 从 Prometheus 迁移 有关 Prometheus 将数据写入 GreptimeDB 的配置信息,请参阅 [Remote Write](/user-guide/ingest-data/for-observability/prometheus.md#配置-remote-write) 文档。 有关使用 Prometheus 查询语言在 GreptimeDB 中查询数据的详细信息,请参阅 PromQL 文档中的 [HTTP API](/user-guide/query-data/promql.md#prometheus-的-http-api) 部分。 要在 Grafana 中将 GreptimeDB 添加为 Prometheus 数据源,请参阅 [Grafana](/user-guide/integrations/grafana#prometheus-数据源) 的集成文档。 --- ## 迁移到 GreptimeDB 你可以从多种数据库和可观测系统迁移到 GreptimeDB,例如 InfluxDB、MySQL、PostgreSQL、Prometheus、Loki 等。 --- ## 用户指南 欢迎使用 GreptimeDB 用户指南。 GreptimeDB 是用于指标、事件和日志的统一可观测性数据库, 可提供从边缘到云的任何规模的实时洞察。 ## 理解 GreptimeDB 的概念 在深入了解 GreptimeDB 之前, 建议先熟悉数据模型、关键概念和功能。 请参阅 [概念文档](./concepts/overview.md)。 ## 根据你的使用场景写入数据 GreptimeDB 支持[多种协议](./protocols/overview.md)和[集成工具](./integrations/overview.md), 以便根据你的需求写入数据。 ### 可观测性指标场景 如果你计划将 GreptimeDB 用于存储可观测性指标、日志和链路追踪, 请参阅[可观测性文档](./ingest-data/for-observability/overview.md)。 该文档解释了如何使用 Otel-Collector, Vector、Kafka、Prometheus 和 InfluxDB 行协议等工具导入数据。 对于日志存储解决方案, 请参考 [日志文档](./logs/overview.md)。 该文档详细说明了如何使用 Pipeline 写入结构化的文本日志。 对于链路追踪(trace)存储解决方案, 请参考 [trace 文档](./traces/overview.md)。 该文档解释了使用 OpenTelemetry 导入数据以及使用 Jaeger 查询数据的方法。 ### 物联网和边缘计算场景 对于物联网和边缘计算场景, [物联网文档](./ingest-data/for-iot/overview.md)提供了从多种来源导入数据的全面指导。 ## 查询数据以获取洞察 GreptimeDB 提供了强大的[数据查询](./query-data/overview.md)功能。 ### SQL 支持 你可以使用 SQL 进行范围查询、聚合等操作。 有关详细说明,请参阅 [SQL 查询文档](./query-data/sql.md)。 ### Prometheus 查询语言 (PromQL) GreptimeDB 支持使用 PromQL 查询数据。 请参考 [PromQL 文档](./query-data/promql.md) 以获取指导。 ### 流计算 对于实时数据处理和分析,GreptimeDB 提供了[流计算](./flow-computation/overview.md), 支持对数据流进行复杂计算。 ## 使用索引加速查询 倒排索引、跳数索引和全文索引等索引可以显著提升查询性能。 有关如何有效使用这些索引的更多信息,请参阅[数据索引文档](./manage-data/data-index.md)。 ## 从其他数据库迁移到 GreptimeDB 你可以轻松从其他数据库迁移数据到 GreptimeDB, 请按照[迁移文档](./migrate-to-greptimedb/overview.md)中的分步说明进行操作。 ## 管理和部署 GreptimeDB 当你准备好部署 GreptimeDB 时, 请查阅[部署及管理文档](/user-guide/deployments-administration/overview.md)获取有关服务端部署和管理的详细指南。 --- ## Elasticsearch(Protocols) 请参考[使用 Elasticsearch 协议写入数据](/user-guide/ingest-data/for-observability/elasticsearch.md)获取详细信息。 --- ## gRPC GreptimeDB 提供了 [gRPC SDK](/user-guide/ingest-data/for-iot/grpc-sdks/overview.md),用于高效和高性能的数据摄入。 如果没有适用于你的编程语言的 SDK,你可以按照贡献者指南[创建自己的 SDK](/contributor-guide/how-to/how-to-write-sdk.md)。 --- ## HTTP API GreptimeDB 提供了 HTTP API 用于与数据库进行交互。如需查看完整的 API 端点列表,请查看 [HTTP Endpoints](/reference/http-endpoints.md)。 ## Base URL API Base URL 是 `http(s)://{{host}}:{{port}}/`。 - 对于在本地机器上运行的 GreptimeDB 实例,Base URL 是 `http://localhost:4000/`,默认端口配置为 `4000`。你可以在[配置文件](/user-guide/deployments-administration/configuration.md#protocol-options)中更改服务的 host 和 port。 - 对于 GreptimeCloud,Base URL 是 `https://{{host}}/`。你可以在 GreptimeCloud 控制台的 "Connection Information" 中找到 host。 在以下内容中,我们使用 `http://{{API-host}}/` 作为 Base URL 来演示 API。 ## 通用 Headers ### 鉴权 假设你已经正确设置了数据库[鉴权](/user-guide/deployments-administration/authentication/overview.md), GreptimeDB 支持 HTTP API 中内置的 `Basic` 鉴权机制。要设置鉴权,请按照以下步骤操作: 1. 使用 `` 格式和 `Base64` 算法对用户名和密码进行编码。 2. 将编码后的凭据附加到下列 HTTP 请求头之一中: - `Authorization : Basic ` - `x-greptime-auth : Basic ` 以下是一个示例。如果要使用用户名 `greptime_user` 和密码 `greptime_pwd` 连接到 GreptimeDB,请使用以下命令: ```shell curl -X POST \ -H 'Authorization: Basic Z3JlcHRpbWVfdXNlcjpncmVwdGltZV9wd2Q=' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=show tables' \ http://localhost:4000/v1/sql ``` 在此示例中,`Z3JlcHRpbWVfdXNlcjpncmVwdGltZV9wd2Q=` 表示 `greptime_user:greptime_pwd` 的 Base64 编码值。请确保用自己配置的用户名和密码替换它,并使用 Base64 进行编码。 :::tip 注意 InfluxDB 使用自己的鉴权格式,请参阅 [InfluxDB](./influxdb-line-protocol.md) 获取详细信息。 ::: ### 请求超时设置 GreptimeDB 支持在 HTTP 请求中使用 `X-Greptime-Timeout` 请求头,用于指定数据库服务器中运行的请求超时时间。 例如,以下请求为查询设置了 `120s` 的超时时间: ```bash curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'X-Greptime-Timeout: 120s' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=show tables' \ http://localhost:4000/v1/sql ``` ### Hints GreptimeDB 支持在 HTTP 请求中使用 `x-greptime-hints` 请求头来传递影响请求行为的键值对。 这些 hints 主要用于在数据写入时[自动建表](/user-guide/ingest-data/overview.md#自动生成表结构)的场景下设置表选项。 格式为逗号分隔的 `key=value` 对: ``` x-greptime-hints: key1=value1, key2=value2 ``` 支持的 hints: | Hint | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | `auto_create_table` | Boolean | `true` | 插入数据时,如果表不存在是否自动创建。 | | `ttl` | 时间字符串 | 无 | 设置表的[数据过期时间](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据),例如 `7d`、`24h`。过期数据将被自动清理。 | | `append_mode` | Boolean | `false` | 启用表的 [append-only 模式](/reference/sql/create.md#创建-append-only-表),该模式禁用按主键去重,支持重复行。 | | `merge_mode` | String | 无 | 设置表的 [merge 模式](/reference/sql/create.md#创建带有-merge-模式的表),例如 `last_non_null`、`last_row`。 | | `physical_table` | String | 无 | 指定 [metric 引擎](/contributor-guide/datanode/metric-engine.md)的物理表名。 | | `skip_wal` | Boolean | `false` | 跳过表的 WAL(Write-Ahead Log)写入。 | | `sst_format` | String | 无 | 设置表的 SST(Sorted String Table)文件格式。可选值:`flat`、`primary_key`。 | 例如,以下请求为自动创建的表设置 TTL 和 append 模式: ```bash curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'x-greptime-hints: ttl=7d, append_mode=true' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=INSERT INTO my_table VALUES (...)' \ http://localhost:4000/v1/sql ``` ## Admin APIs :::tip 注意 这些 API 在 GreptimeCloud 中无法使用。 ::: 请参考 [Admin APIs 接口](/reference/http-endpoints.md#管理-api)文档以获取更多信息。 ## POST SQL 语句 要通过 HTTP API 向 GreptimeDB 服务器提交 SQL 语句,请使用以下格式: ```shell curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'X-Greptime-Timeout: {{timeout}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql={{SQL-statement}}' \ http://{{API-host}}/v1/sql ``` ### Headers - [`Authorization`](#鉴权) - [`X-Greptime-Timeout`](#请求超时设置) - `Content-Type`: `application/x-www-form-urlencoded`. - `X-Greptime-Timezone`: 当前 SQL 查询的时区。可选。请参阅[时区](#时区)。 ### Query string parameters - `db`: 数据库名称。可选。如果未提供,将使用默认数据库 `public`。 - `format`: 输出格式。可选。默认为 `greptimedb_v1` 的 JSON 格式。 除了默认的 JSON 格式外,HTTP API 还允许你通过提供 `format` 查询参数来自定义输出格式,值如下: - `influxdb_v1`: [influxdb 查询 API](https://docs.influxdata.com/influxdb/v1/tools/api/#query-http-endpoint) 兼容格式。附加参数: - `epoch`: `[ns,u,µ,ms,s,m,h]`,返回指定精度的时间戳 - `csv`: 以逗号分隔值格式输出 - `csvWithNames`: 以逗号分隔值格式输出,包含列名标题 - `csvWithNamesAndTypes`: 以逗号分隔值格式输出,包含列名和数据类型标题 - `arrow`: [Arrow IPC 格式](https://arrow.apache.org/docs/python/feather.html)。此接口输出流式格式。附加参数: - `compression`: `zstd` 或 `lz4`,默认:无压缩 - `table`: 控制台输出的 ASCII 表格格式 - `null`: 简洁的纯文本输出,仅显示行数和执行时间,用于评估查询性能。 ### Body - `sql`: SQL 语句。必填。 ### 响应 响应是一个 JSON 对象,包含以下字段: - `output`: SQL 执行结果,请参阅下面的示例以了解详细信息。 - `execution_time_ms`: 语句的执行时间(毫秒)。 ### 示例 #### `INSERT` 语句 例如,要向数据库 `public` 的 `monitor` 表中插入数据,请使用以下命令: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=INSERT INTO monitor VALUES ("127.0.0.1", 1667446797450, 0.1, 0.4), ("127.0.0.2", 1667446798450, 0.2, 0.3), ("127.0.0.1", 1667446798450, 0.5, 0.2)' \ http://localhost:4000/v1/sql?db=public ``` Response 包含受影响的行数: ```shell {"output":[{"affectedrows":3}],"execution_time_ms":11} ``` #### `SELECT` 语句 你还可以使用 HTTP API 执行其他 SQL 语句。例如,从 `monitor` 表中查询数据: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public ``` Response 包含 JSON 格式的查询数据: ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "host", "data_type": "String" }, { "name": "ts", "data_type": "TimestampMillisecond" }, { "name": "cpu", "data_type": "Float64" }, { "name": "memory", "data_type": "Float64" } ] }, "rows": [ [ "127.0.0.1", 1720728000000, 0.5, 0.1 ] ], "total_rows": 1 } } ], "execution_time_ms": 7 } ``` Response 包含以下字段: - `output`: 执行结果。 - `records`: 查询结果。 - `schema`: 结果的 schema,包括每列的 schema。 - `rows`: 查询结果的行,每行是一个包含 schema 中对应列值的数组。 - `execution_time_ms`: 语句的执行时间(毫秒)。 #### 时区 GreptimeDB 支持 HTTP 请求中的 `X-Greptime-Timezone` header。 它用于为当前 SQL 查询指定时区。 例如,以下请求使用时区 `+1:00` 进行查询: ```bash curl -X POST \ -H 'Authorization: Basic {{authentication}}' \ -H 'X-Greptime-Timezone: +1:00' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=SHOW VARIABLES time_zone;' \ http://localhost:4000/v1/sql ``` 查询后的结果为: ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "TIME_ZONE", "data_type": "String" } ] }, "rows": [ [ "+01:00" ] ] } } ], "execution_time_ms": 27 } ``` 有关时区如何影响数据的写入和查询,请参考[写入数据](/user-guide/ingest-data/for-iot/sql.md#time-zone)和[查询数据](/user-guide/query-data/sql.md#时区)部分中的 SQL 文档。 #### 使用 `table` 格式输出查询数据 你可以在查询字符串参数中使用 `table` 格式,以 ASCII 表格格式获取输出。 ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=table ``` 输出 ``` ┌─host────────┬─ts────────────┬─cpu─┬─memory─┐ │ "127.0.0.1" │ 1667446797450 │ 0.1 │ 0.4 │ │ "127.0.0.1" │ 1667446798450 │ 0.5 │ 0.2 │ │ "127.0.0.2" │ 1667446798450 │ 0.2 │ 0.3 │ └─────────────┴───────────────┴─────┴────────┘ ``` #### 使用 `csvWithNames` 格式输出查询数据 ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=csvWithNames ``` 输出: ```csv host,ts,cpu,memory 127.0.0.1,1667446797450,0.1,0.4 127.0.0.1,1667446798450,0.5,0.2 127.0.0.2,1667446798450,0.2,0.3 ``` 将 `format` 改为 `csvWithNamesAndTypes`: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=csvWithNamesAndTypes ``` 输出: ```csv host,ts,cpu,memory String,TimestampMillisecond,Float64,Float64 127.0.0.1,1667446797450,0.1,0.4 127.0.0.1,1667446798450,0.5,0.2 127.0.0.2,1667446798450,0.2,0.3 ``` #### 使用 `influxdb_v1` 格式输出查询数据 你可以在查询字符串参数中使用 `influxdb_v1` 格式,以 InfluxDB 查询 API 兼容格式获取输出。 ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql?db=public&format=influxdb_v1&epoch=ms ``` ```json { "results": [ { "statement_id": 0, "series": [ { "name": "", "columns": [ "host", "ts", "cpu", "memory" ], "values": [ ["127.0.0.1", 1667446797450, 0.1, 0.4], ["127.0.0.1", 1667446798450, 0.5, 0.2], ["127.0.0.2", 1667446798450, 0.2, 0.3] ] } ] } ], "execution_time_ms": 2 } ``` ### 使用 GreptimeDB 的 SQL 方言解析 SQL 为了解析和理解使用 GreptimeDB SQL 方言编写的查询(例如在仪表盘等工具里,为了更好的用户体验,提前解析 SQL 获取表名等),您可以使用 `/v1/sql/parse` 接口来获取 SQL 查询的结构化结果: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "sql=SELECT * FROM monitor" \ http://localhost:4000/v1/sql/parse ``` ```json [ { "Query": { "inner": { "with": null, "body": { "Select": { "select_token": { "token": { "Word": { "value": "SELECT", "quote_style": null, "keyword": "SELECT" } }, "span": { "start": { "line": 1, "column": 1 }, "end": { "line": 1, "column": 7 } } }, "optimizer_hint": null, "distinct": null, "select_modifiers": null, "top": null, "top_before_distinct": false, "projection": [ { "Wildcard": { "wildcard_token": { "token": "Mul", "span": { "start": { "line": 1, "column": 8 }, "end": { "line": 1, "column": 9 } } }, "opt_ilike": null, "opt_exclude": null, "opt_except": null, "opt_replace": null, "opt_rename": null } } ], "exclude": null, "into": null, "from": [ { "relation": { "Table": { "name": [ { "Identifier": { "value": "monitor", "quote_style": null, "span": { "start": { "line": 1, "column": 15 }, "end": { "line": 1, "column": 22 } } } } ], "alias": null, "args": null, "with_hints": [], "version": null, "with_ordinality": false, "partitions": [], "json_path": null, "sample": null, "index_hints": [] } }, "joins": [] } ], "lateral_views": [], "prewhere": null, "selection": null, "connect_by": [], "group_by": { "Expressions": [ [], [] ] }, "cluster_by": [], "distribute_by": [], "sort_by": [], "having": null, "named_window": [], "qualify": null, "window_before_qualify": false, "value_table_mode": null, "flavor": "Standard" } }, "order_by": null, "limit_clause": null, "fetch": null, "locks": [], "for_clause": null, "settings": null, "format_clause": null, "pipe_operators": [] }, "hybrid_cte": null } } ] ``` ## POST PromQL 查询 ### API 返回 Prometheus 查询结果格式 GreptimeDB 兼容 Prometheus 查询语言 (PromQL),可以用于查询 GreptimeDB 中的数据。 有关所有兼容的 API,请参阅 [Prometheus 查询语言](/user-guide/query-data/promql#prometheus-http-api) 文档。 ### API 返回 GreptimeDB JSON 格式 GreptimeDB 同样暴露了一个自己的 HTTP API 用于 PromQL 查询,即在当前的 API 路径 `/v1` 的后方拼接 `/promql`。 该接口的返回值是 GreptimeDB 的 JSON 格式,而不是 Prometheus 的格式。 如下示例: ```shell curl -X GET \ -H 'Authorization: Basic {{authorization if exists}}' \ -G \ --data-urlencode 'query=avg(system_metrics{idc="idc_a"})' \ --data-urlencode 'start=1667446797' \ --data-urlencode 'end=1667446799' \ --data-urlencode 'step=1s' \ 'http://localhost:4000/v1/promql?db=public' ``` 接口中的参数和 Prometheus' HTTP API 的 [`range_query`](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) 接口相似: - `db=`:在使用 GreptimeDB 进行鉴权操作时必填,如果使用的是 `public` 数据库则可以忽略该参数。注意这个参数需要被设置在 query param 中,或者通过 `--header 'x-greptime-db-name: '` 设置在 HTTP 请求头中。 - `query=`:必填。Prometheus 表达式查询字符串。 - `start=`:必填。开始时间戳,包含在内。它用于设置 `TIME INDEX` 列中的时间范围。 - `end=`:必填。结束时间戳,包含在内。它用于设置 `TIME INDEX` 列中的时间范围。 - `step=`:必填。查询步长,可以使用持续时间格式或秒数的浮点数。 - `format`: 输出格式。可选。默认为 `greptimedb_v1` 的 JSON 格式。 除了默认的 JSON 格式外,HTTP API 还允许你通过提供 `format` 查询参数来自定义输出格式,值如下: - `influxdb_v1`: [influxdb 查询 API](https://docs.influxdata.com/influxdb/v1/tools/api/#query-http-endpoint) 兼容格式。附加参数: - `epoch`: `[ns,u,µ,ms,s,m,h]`,返回指定精度的时间戳 - `csv`: 以逗号分隔值格式输出 - `csvWithNames`: 以逗号分隔值格式输出,包含列名标题 - `csvWithNamesAndTypes`: 以逗号分隔值格式输出,包含列名和数据类型标题 - `arrow`: [Arrow IPC 格式](https://arrow.apache.org/docs/python/feather.html)。附加参数: - `compression`: `zstd` 或 `lz4`,默认:无压缩 - `table`: 控制台输出的 ASCII 表格格式 - `null`: 简洁的纯文本输出,仅显示行数和执行时间,用于评估查询性能。 以下是每种参数的类型的示例: - rfc3339 - `2015-07-01T20:11:00Z` (default to seconds resolution) - `2015-07-01T20:11:00.781Z` (with milliseconds resolution) - `2015-07-02T04:11:00+08:00` (with timezone offset) - unix timestamp - `1435781460` (default to seconds resolution) - `1435781460.781` (with milliseconds resolution) - duration - `1h` (1 hour) - `5d1m` (5 days and 1 minute) - `2` (2 seconds) - `2s` (also 2 seconds) 结果格式与 [Post SQL 语句](#post-sql-语句)中描述的 `/sql` 接口相同。 ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "ts", "data_type": "TimestampMillisecond" }, { "name": "AVG(system_metrics.cpu_util)", "data_type": "Float64" }, { "name": "AVG(system_metrics.memory_util)", "data_type": "Float64" }, { "name": "AVG(system_metrics.disk_util)", "data_type": "Float64" } ] }, "rows": [ [ 1667446798000, 80.1, 70.3, 90 ], [ 1667446799000, 80.1, 70.3, 90 ] ] } } ], "execution_time_ms": 5 } ``` ## Post Influxdb line protocol 数据 ```shell curl -X POST \ -H 'Authorization: token {{username:password}}' \ -d '{{Influxdb-line-protocol-data}}' \ http://{{API-host}}/v1/influxdb/api/v2/write?precision={{time-precision}} ``` ```shell curl -X POST \ -d '{{Influxdb-line-protocol-data}}' \ http://{{API-host}}/v1/influxdb/write?u={{username}}&p={{password}}&precision={{time-precision}} ``` ### Headers - `Authorization`: **与其他 API 不同**,InfluxDB 行协议 API 使用 InfluxDB 鉴权格式。对于 V2 协议,Authorization 是 `token {{username:password}}`。 ### Query string parameters - `u`: 用户名。可选。它是 V1 的鉴权用户名。 - `p`: 密码。可选。它是 V1 的鉴权密码。 - `db`: 数据库名称。可选。默认值是 `public`。 - `precision`: 定义请求体中提供的时间戳的精度。请参考用户指南中的 [InfluxDB 行协议](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md)文档。 ### Body InfluxDB 行协议数据点。请参考 [InfluxDB 行协议](https://docs.influxdata.com/influxdb/v1/write_protocols/line_protocol_tutorial/#syntax) 文档。 ### 示例 请参考用户指南中的 [InfluxDB 行协议](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md)。 ## 管理 Pipeline 的 API 在将日志写入 GreptimeDB 时,你可以使用 HTTP API 来管理 Pipeline。 请参考 [管理 Pipeline](/user-guide/logs/manage-pipelines.md) 文档。 --- ## InfluxDB Line Protocol(Protocols) ## 写入数据 请参考[写入数据](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md)文档来了解如何使用 InfluxDB Line Protocol 向 GreptimeDB 写入数据。 ## HTTP API 请参考 [HTTP API](http.md#post-influxdb-line-protocol-数据) 文档来了解 Influxdb Line Protocol 的接口详情。 ## PING GreptimeDB 同样支持 InfluxDB 的 `ping` 和 `health` API。 使用 `curl` 请求 `ping` API: ```shell curl -i "127.0.0.1:4000/v1/influxdb/ping" ``` ```shell HTTP/1.1 204 No Content date: Wed, 22 Feb 2023 02:29:44 GMT ``` Use `curl` to request `health` API. ```shell curl -i "127.0.0.1:4000/v1/influxdb/health" ``` ```shell HTTP/1.1 200 OK content-length: 0 date: Wed, 22 Feb 2023 02:30:46 GMT ``` --- ## Loki(Protocols) 请参考[使用 Loki 协议写入数据](/user-guide/ingest-data/for-observability/loki.md)获取详细信息。 --- ## MySQL ## 连接数据库 你可以通过 MySQL 连接到 GreptimeDB,端口为 `4002`。 ```shell mysql -h -P 4002 -u -p ``` - 请参考[鉴权认证](/user-guide/deployments-administration/authentication/overview.md) 来设置 GreptimeDB 的用户名和密码。 - 如果你想使用其他端口连接 MySQL,请参考配置文档中的[协议选项](/user-guide/deployments-administration/configuration.md#协议选项)。 ## 管理表 请参考[表管理](/user-guide/deployments-administration/manage-data/basic-table-operations.md)。 ## 写入数据 请参考[写入数据](/user-guide/ingest-data/for-iot/sql.md). ## 查询数据 请参考[查询数据](/user-guide/query-data/sql.md). ## 时区 GreptimeDB 的 MySQL 协议接口遵循原始 MySQL 服务器的 [时区处理方式](https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html)。 默认情况下,MySQL 使用服务器的时区来处理时间戳。要覆盖这一行为,可以使用 SQL 语句 `SET time_zone = '';` 来为当前会话设置 `time_zone` 变量。`time_zone` 的值可以是: - 服务器的时区:`SYSTEM`。 - UTC 的偏移量,例如 `+08:00`。 - 任何时区的命名,例如 `Europe/Berlin`。 一些 MySQL 客户端,例如 Grafana 的 MySQL 数据源,允许你为当前会话设置时区。想要知道当前设定的时区,可以通过 SQL 语句 `SELECT @@time_zone;` 来查询。 你可以使用 `SELECT` 来查看当前的时区设置。例如: ```sql SELECT @@system_time_zone, @@time_zone; ``` 结果显示系统时区和会话时区都设置为 `UTC`: ```SQL +--------------------+-------------+ | @@system_time_zone | @@time_zone | +--------------------+-------------+ | UTC | UTC | +--------------------+-------------+ ``` 将会话时区更改为 `+1:00`: ```SQL SET time_zone = '+1:00' ``` 你可以看到系统时区和会话时区之间的差异: ```SQL SELECT @@system_time_zone, @@time_zone; +--------------------+-------------+ | @@system_time_zone | @@time_zone | +--------------------+-------------+ | UTC | +01:00 | +--------------------+-------------+ ``` 有关时区如何影响数据的插入和查询,请参考 [写入数据](/user-guide/ingest-data/for-iot/sql.md#时区) 和 [查询数据](/user-guide/query-data/sql.md#时区) 中的 SQL 文档。 ## 查询超时 可以通过 SQL 语句 `SET max_execution_time = ` 或 `SET MAX_EXECUTION_TIME = ` 为当前会话设置 `max_execution_time` 变量,该变量指定**只读语句**执行的最大时间(以毫秒为单位)。如果查询的执行时间超过指定时间,服务器将终止该查询。 例如,将最大执行时间设置为 10 秒: ```SQL SET max_execution_time=10000; ``` --- ## OpenTelemetry (OTLP) GreptimeDB 可以通过 [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) 协议写入 OpenTelemetry 指标。 请参考[使用 OpenTelemetry 写入数据](/user-guide/ingest-data/for-observability/opentelemetry.md)文档获取详细信息。 --- ## OpenTSDB(Protocols) 请参考[使用 OpenTSDB 写入数据](/user-guide/ingest-data/for-iot/opentsdb.md)获取详细信息。 --- ## 协议 --- ## PostgreSQL ## 连接数据库 你可以通过端口 `4003` 使用 PostgreSQL 连接到 GreptimeDB。 只需在命令中添加 `-U` 参数,后跟你的用户名和密码。以下是一个示例: ```shell psql -h -p 4003 -U -d public ``` - 请参考[鉴权认证](/user-guide/deployments-administration/authentication/overview.md) 来设置 GreptimeDB 的用户名和密码。 - 如果你想使用其他端口连接 PostgreSQL,请参考配置文档中的[协议选项](/user-guide/deployments-administration/configuration.md#协议选项)。 ## 管理表 请参考[管理表](/user-guide/deployments-administration/manage-data/basic-table-operations.md)。 ## 写入数据 请参考[写入数据](/user-guide/ingest-data/for-iot/sql.md). ## 读取数据 请参考 [读取数据](../query-data/sql.md). ## 时区 GreptimeDB 的 PostgreSQL 协议遵循原始 PostgreSQL 的 [时区处理方式](https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-TIMEZONES)。 默认情况下,PostgreSQL 使用服务器的时区来处理时间戳。 你可以使用 SQL 语句 `SET TIMEZONE TO '';` 为当前会话设置 `time_zone` 变量来覆盖服务器时区。 `time_zone` 的值可以是: - 时区的全称,例如 `America/New_York`。 - 时区的缩写,例如 `PST`。 - UTC 的偏移量,例如 `+08:00`。 你可以使用 `SHOW` 来查看当前的时区设置。例如: ```sql SHOW VARIABLES time_zone; ``` ```sql TIME_ZONE ----------- UTC ``` 将会话时区更改为 `+1:00`: ```SQL SET TIMEZONE TO '+1:00' ``` 有关时区如何影响数据的插入和查询,请参考[写入数据](/user-guide/ingest-data/for-iot/sql.md#时区)和[查询数据](/user-guide/query-data/sql.md#时区)中的 SQL 文档。 ## 外部数据 利用 Postgres 的 [FDW 扩 展](https://www.postgresql.org/docs/current/postgres-fdw.html),GreptimeDB 可以 被配置为 Postgres 的外部数据服务。这使得我们可以用 Postgres 服务器上无缝地查询 GreptimeDB 里的时序数据,并且可以利用 join 查询同时关联两边的数据。 举个例子,类似设备信息类的物联网元数据,通常存储在 Postgres 这样的关系型数据库中。 现在我们可以利用这个功能,先在 Postgres 利用关系查询过滤出满足条件的设备 ID,然 后直接关联的 GreptimeDB 承载的外部表上查询设备的时序数据。 ### 配置 首先要确保 GreptimeDB 打开了 Postgres 协议,并且她可以被 Postgres 服务器访问到。 在 Postgres 上开启 fdw 扩展。 ```sql CREATE EXTENSION postgres_fdw; ``` 将 GreptimeDB 添加为远程服务器。 ```sql CREATE SERVER greptimedb FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'greptimedb_host', dbname 'public', port '4003'); ``` 把 Postgres 用户映射到 GreptimeDB 上。这一步是必须步骤。如果你没有在 GreptimeDB 开源版本上启用认证,这里可以填写任意的认证信息。 ```sql CREATE USER MAPPING FOR postgres SERVER greptimedb OPTIONS (user 'greptime', password '...'); ``` 在 Postgres 创建与 GreptimeDB 映射的外部表。这一步是为了告知 Postgres 相应表的数 据结构。注意需要将 GreptimeDB 的数据类型映射到 Postgres 类型上。 对于这样的 GreptimeDB 表: ```sql CREATE TABLE grpc_latencies ( ts TIMESTAMP TIME INDEX, host STRING, method_name STRING, latency DOUBLE, PRIMARY KEY (host, method_name) ) with('append_mode'='true'); CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host STRING, api_path STRING FULLTEXT INDEX, log_level STRING, log STRING FULLTEXT INDEX, PRIMARY KEY (host, log_level) ) with('append_mode'='true'); ``` 其 Postgres 外部表定义如下: ```sql CREATE FOREIGN TABLE ft_grpc_latencies ( ts TIMESTAMP, host VARCHAR, method_name VARCHAR, latency DOUBLE precision ) SERVER greptimedb OPTIONS (table_name 'grpc_latencies'); CREATE FOREIGN TABLE ft_app_logs ( ts TIMESTAMP, host VARCHAR, api_path VARCHAR, log_level VARCHAR, log VARCHAR ) SERVER greptimedb OPTIONS (table_name 'app_logs'); ``` 为了帮助用户生成这些语句,我们在 GreptimeDB 里增强了 `SHOW CREATE TABLE` 来直接 输出可执行的语句。 ```sql SHOW CREATE TABLE grpc_latencies FOR postgres_foreign_table; ``` 注意在输出的语句中你需要把服务器名 `greptimedb` 替换为之前在 `CREATE SERVER` 语句 里使用的名字。 ### 执行查询 至此你可以通过 Postgres 发起查询。并且可以使用一些同时存在于 GreptimeDB 和 Postgres 上的函数,如 `date_trunc` 等。 ```sql SELECT * FROM ft_app_logs ORDER BY ts DESC LIMIT 100; SELECT date_trunc('MINUTE', ts) as t, host, avg(latency), count(latency) FROM ft_grpc_latencies GROUP BY host, t; ``` ## 语句执行超时 你可以通过 SQL 语句 `SET statement_timeout = ` 或 `SET STATEMENT_TIMEOUT = ` 为当前会话设置 `statement_timeout` 变量,该变量指定语句执行的最大时间(以毫秒为单位)。如果语句的执行时间超过指定时间,服务器将终止该语句。 例如,将最大执行时间设置为 10 秒: ```SQL SET statement_timeout=10000; ``` --- ## 公共表表达式(CTE) CTE 与 [视图](./view.md) 类似,它们帮助您简化查询的复杂性,将长而复杂的 SQL 语句分解,并提高可读性和可重用性。 您已经在 [快速开始](/getting-started/quick-start.md#关联-metricslogs-和-traces) 文档中阅读了一个 CTE 的例子。 ## 什么是公共表表达式(CTE)? 公共表表达式 (CTE) 是可以在 `SELECT`、`INSERT`、`UPDATE` 或 `DELETE` 语句中引用的临时结果集。CTE 有助于将复杂的查询分解成更可读的部分,并且可以在同一个查询中多次引用。 ## CTE 的基本语法 CTE 通常使用 `WITH` 关键字定义。基本语法如下: ```sql WITH cte_name [(column1, column2, ...)] AS ( QUERY ) SELECT ... FROM cte_name; ``` ## 示例解释 接下来,我们将通过一个完整的示例来演示如何使用 CTE,包括数据准备、CTE 创建和使用。 ### 步骤 1:创建示例数据 假设我们有以下两个表: - `grpc_latencies`:包含 gRPC 请求延迟数据。 - `app_logs`:包含应用程序日志信息。 ```sql CREATE TABLE grpc_latencies ( ts TIMESTAMP TIME INDEX, host VARCHAR(255), latency FLOAT, PRIMARY KEY(host), ); INSERT INTO grpc_latencies VALUES ('2023-10-01 10:00:00', 'host1', 120), ('2023-10-01 10:00:00', 'host2', 150), ('2023-10-01 10:00:05', 'host1', 130); CREATE TABLE app_logs ( ts TIMESTAMP TIME INDEX, host VARCHAR(255), `log` TEXT, log_level VARCHAR(50), PRIMARY KEY(host, log_level), ); INSERT INTO app_logs VALUES ('2023-10-01 10:00:00', 'host1', 'Error on service', 'ERROR'), ('2023-10-01 10:00:00', 'host2', 'All services OK', 'INFO'), ('2023-10-01 10:00:05', 'host1', 'Error connecting to DB', 'ERROR'); ``` ### 步骤 2:定义和使用 CTE 我们将创建两个 CTE 来分别计算第 95 百分位延迟和错误日志的数量。 ```sql WITH metrics AS ( SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ), logs AS ( SELECT ts, host, COUNT(*) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' BY (host) ) SELECT metrics.ts, metrics.host, metrics.p95_latency, COALESCE(logs.num_errors, 0) AS num_errors FROM metrics LEFT JOIN logs ON metrics.host = logs.host AND metrics.ts = logs.ts ORDER BY metrics.ts; ``` 输出: ```sql +---------------------+-------+-------------+------------+ | ts | host | p95_latency | num_errors | +---------------------+-------+-------------+------------+ | 2023-10-01 10:00:00 | host2 | 150 | 0 | | 2023-10-01 10:00:00 | host1 | 120 | 1 | | 2023-10-01 10:00:05 | host1 | 130 | 1 | +---------------------+-------+-------------+------------+ ``` ### 详细说明 1. **定义 CTEs**: - `metrics`: ```sql metrics AS ( SELECT ts, host, approx_percentile_cont(0.95) WITHIN GROUP (ORDER BY latency) RANGE '5s' AS p95_latency FROM grpc_latencies ALIGN '5s' FILL PREV ), ``` 这里我们使用[范围查询](/user-guide/query-data/sql.md#按时间窗口聚合数据)计算每个 `host` 在每个 5 秒时间窗口内的第 95 百分位延迟。 - `logs`: ```sql logs AS ( SELECT ts, host, COUNT(*) RANGE '5s' AS num_errors FROM app_logs WHERE log_level = 'ERROR' ALIGN '5s' BY (host) ) ``` 同样地,我们计算每个 `host` 在每个 5 秒时间窗口内的错误日志数量。 2. **使用 CTEs**: 在最终的查询部分: ```sql SELECT metrics.ts, metrics.host, metrics.p95_latency, COALESCE(logs.num_errors, 0) AS num_errors FROM metrics LEFT JOIN logs ON metrics.host = logs.host AND metrics.ts = logs.ts ORDER BY metrics.ts; ``` 我们对两个 CTE 结果集进行左连接,以获得最终的综合分析结果。 ## 在 CTE 中使用 TQL GreptimeDB 支持在 CTE 中使用 [TQL](/reference/sql/tql.md)(Telemetry 查询语言),将 PromQL 的时序计算能力与 SQL 强大的后处理能力(过滤、JOIN、聚合等)相结合。 ### 基本语法 ```sql WITH cte_name AS ( TQL EVAL (start, end, step) promql_expression AS value_alias ) SELECT * FROM cte_name; ``` ### 关键点 1. **列名**: - 时间索引列名取决于表结构(例如,自定义表使用 `ts`,Prometheus 远程写入的默认使用 `greptime_timestamp`) - 值的列名取决于 PromQL 表达式,可能无法预测,因此更推荐使用 TQL 中的 `AS` 进行值别名以确保可预测的值列名:`TQL EVAL (...) expression AS my_value` - **重要**:一般情况下不建议在 CTE 定义中使用列别名(如 `WITH cte_name (ts, val) AS (...)`),因为 TQL EVAL 结果的列数量和顺序可能变化,特别是在 Prometheus 场景中标签可能动态添加或删除。更适合在结果列稳定的场景使用,例如简单的 `CREATE FLOW` TQL CTE。 2. **支持的命令**:CTE 中仅支持 `TQL EVAL`。不能在 CTE 中使用 `TQL ANALYZE` 和 `TQL EXPLAIN`。 3. **回溯参数**:可选的第四个参数控制回溯持续时间(默认:5 分钟)。 4. **在 `CREATE FLOW` 中使用 TQL CTE**:GreptimeDB 支持在 `CREATE FLOW` 中写 `WITH ... AS (TQL EVAL ...)`,但只支持最简单的形式:单个 TQL CTE,后面紧跟 `SELECT * FROM `。Flow 定义里不支持额外 SQL CTE、过滤、JOIN 或自定义列投影。 ### 示例 以下示例使用 Kubernetes 监控指标来演示实际用例。 #### 使用 SQL 过滤 TQL 结果 此示例使用 PromQL 计算每个 Pod 的 CPU 使用率,然后使用 SQL 过滤和排序结果: ```sql WITH cpu_usage AS ( TQL EVAL (now() - interval '1' hour, now(), '5m') sum by (namespace, pod) (rate(container_cpu_usage_seconds_total{container!=""}[5m])) AS cpu_cores ) SELECT greptime_timestamp as ts, namespace, pod, cpu_cores FROM cpu_usage WHERE cpu_cores > 0.5 ORDER BY cpu_cores DESC; ``` #### 关联多个指标 此示例展示了 PromQL 单独无法实现的能力:关联不同指标进行分析。它将 CPU 使用率与请求速率关联,以分析资源效率: ```sql WITH cpu_data AS ( TQL EVAL (now() - interval '1' hour, now(), '5m') sum by (pod) (rate(container_cpu_usage_seconds_total{container!=""}[5m])) AS cpu_cores ), request_data AS ( TQL EVAL (now() - interval '1' hour, now(), '5m') sum by (pod) (rate(http_requests_total[5m])) AS req_per_sec ) SELECT c.greptime_timestamp as ts, c.pod, c.cpu_cores, r.req_per_sec FROM cpu_data c JOIN request_data r ON c.greptime_timestamp = r.greptime_timestamp AND c.pod = r.pod WHERE r.req_per_sec > 1; ``` 在 JOIN 多个 TQL CTE 时,请确保: - `by (...)` 子句包含匹配的维度 - JOIN 条件包含时间戳和标签列 ## 总结 通过 CTE,您可以将复杂的 SQL 查询分解为更易于管理和理解的部分。在本示例中,我们分别创建了两个 CTE 来计算第 95 百分位延迟和错误日志的数量,然后将它们合并到最终查询中进行分析。CTE 中的 TQL 支持通过将 PromQL 风格的查询与 SQL 处理无缝集成来扩展这种能力。阅读更多关于 [WITH](/reference/sql/with.md) 和 [TQL](/reference/sql/tql.md) 的内容。 更多 TQL + CTE 示例请参阅博客文章[当 PromQL 遇上 SQL:用混合查询解锁 Kubernetes 监控分析](https://greptime.cn/blogs/2026-01-08-tql-alias-k8s-monitoring)。 --- ## Jaeger 查询(实验功能) :::warning Jaeger 查询接口目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: GreptimeDB 目前支持以下 [Jaeger](https://www.jaegertracing.io/) 查询接口: - `/api/services`: 获取所有 Service。 - `/api/operations?service={service}`: 获取指定 Service 的所有 Operations。 - `/api/services/{service}/operations`: 获取指定 Service 的所有 Operations。 - `/api/traces`: 根据查询参数获取 traces 数据。 你可以使用 Grafana 的 [Jaeger 插件](https://grafana.com/docs/grafana/latest/datasources/jaeger/)(推荐) 或者 [Jaeger UI](https://github.com/jaegertracing/jaeger-ui) 来查询 GreptimeDB 中的 traces 数据。当你在使用 Jaeger UI 的时候,可将 `packages/jaeger-ui/vite.config.mts` 的 `proxyConfig` 配置为 GreptimeDB 的地址,比如: ```ts const proxyConfig = { target: 'http://localhost:4000/v1/jaeger', secure: false, changeOrigin: true, ws: true, xfwd: true, }; ``` 目前 GreptimeDB 对 Jaeger 协议接口在 `/v1/jaeger` 路径下。 ## 快速开始 我们将以 Grafana 中使用 Jaeger 插件为例,介绍如何查询 GreptimeDB 中的 traces 数据。在开始之前,请确保你已经正常启动了 GreptimeDB。 ### 启动应用生成 traces 数据并写入 GreptimeDB 你可以参考 [OpenTelemetry 官方文档](https://opentelemetry.io/docs/languages/) 来选择任意你熟悉的编程语言来生成 traces 并将其写入到 GreptimeDB 中。你也可以参考[配置 OpenTelemetry Collector](/user-guide/traces/read-write.md#opentelemetry-collector) 文档。 ### 配置 Jaeger 插件 1. 打开 Grafana,添加 Jaeger 数据源: ![添加 Jaeger 数据源](/add-jaeger-data-source.jpg) 2. 根据实际情况,填写 Jaeger 地址,然后 **Save and Test** 即可。比如: ``` http://localhost:4000/v1/jaeger ``` 3. 使用 Jaeger Explore 来查看数据: ![Jaeger Explore](/jaeger-explore.png) ### 自定义数据表 GreptimeDB 的 Jaeger 兼容接口默认使用 `opentelemetry_traces` 表作为其数据源。如 果用户使用了其他表,可以通过 HTTP 头 `x-greptime-trace-table-name` 进行设置。 Grafana 用户可以在数据源的配置界面进行设置。 --- ## 日志查询(实验功能) :::warning 日志查询接口目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: GreptimeDB 提供了一个专门用于查询日志数据的 HTTP 接口。通过这个功能,你可以使用简单的查询界面来搜索和处理日志记录。这是对 GreptimeDB 现有功能(如 SQL 查询和 Flow 计算)的补充。你仍然可以像之前一样使用已有的工具和工作流程来查询日志数据。 ## 接口地址 ```http POST /v1/logs ``` ## 请求头 - [认证](/user-guide/protocols/http.md#authentication) - `Content-Type`: `application/json` ## 请求格式 请求体应为 JSON 格式(在实验阶段可能会随补丁版本有所变化)。关于最新的请求格式,请参考[源代码实现](https://github.com/GreptimeTeam/greptimedb/blob/main/src/log-query/src/log_query.rs): ## 响应格式 此接口的响应格式与 SQL 查询接口相同。详情请参阅 [SQL 查询响应格式](/user-guide/protocols/http/#response)。 ## 使用限制 - 最大结果数量:1000 条记录 - 仅支持包含时间戳和字符串列的表格 ## 使用示例 以下示例展示了如何使用日志查询接口来查询日志数据(请注意,在实验性阶段这个例子可能会失效): ```shell curl -X "POST" "http://localhost:4000/v1/logs" \ -H "Authorization: Basic {{authentication}}" \ -H "Content-Type: application/json" \ -d $' { "table": { "catalog_name": "greptime", "schema_name": "public", "table_name": "my_logs" }, "time_filter": { "start": "2025-01-23" }, "limit": { "fetch": 1 }, "columns": [ "message" ], "filters": [ { "column_name": "message", "filters": [ { "Contains": "production" } ] } ], "context": "None", "exprs": [] } ' ``` 在这个查询中,我们在 `greptime.public.my_logs` 表中搜索 `message` 字段包含 `production` 的日志记录。我们还设定了时间过滤条件,只获取 `2025-01-23` 当天的日志,并将结果限制为仅返回 1 条记录。 响应结果类似于以下内容: ```json { "output": [ { "records": { "schema": { "column_schemas": [ { "name": "message", "data_type": "String" } ] }, "rows": [ [ "Everything is in production" ] ], "total_rows": 1 } } ], "execution_time_ms": 30 } ``` --- ## 查询数据 ## 查询语言 - [SQL](./sql.md) - [PromQL](promql.md) - [Log Query](./log-query.md) (实验性功能) 从 v0.9 开始,GreptimeDB 开始支持查询视图和公共表表达式(CTE),用于简化查询语句: * [View](./view.md) * [公共表表达式(CTE)](./cte.md) ## 推荐的查询库 由于 GreptimeDB 使用 SQL 作为主要查询语言,并支持 [MySQL](/user-guide/protocols/mysql.md) 和 [PostgreSQL](/user-guide/protocols/postgresql.md) 协议, 你可以使用支持 MySQL 或 PostgreSQL 的成熟 SQL Driver 来查询数据。 有关更多信息,请参考[SQL 工具](/reference/sql-tools.md)文档。 ## 查询外部数据 GreptimeDB 具有查询外部数据文件的能力,更多信息请参考[查询外部数据](./query-external-data.md)文档。 --- ## Prometheus Query Language GreptimeDB 可以作为 Grafana 中 Prometheus 的替代品,因为 GreptimeDB 支持 PromQL(Prometheus Query Language)。GreptimeDB 在 Rust 中重新实现了 PromQL,并通过接口将能力开放,包括 Prometheus 的 HTTP API、GreptimeDB 的 HTTP API 和 SQL 接口。 ## Prometheus 的 HTTP API GreptimeDB 实现了兼容 Prometheus 的一系列 API,通过 `/v1/prometheus` 路径对外提 供服务: - Instant queries `/api/v1/query` - Range queries `/api/v1/query_range` - Series `/api/v1/series` - Label names `/api/v1/labels` - Label values `/api/v1/label//values` 这些接口的输入和输出与原生的 Prometheus HTTP API 相同,用户可以把 GreptimeDB 当 作 Prometheus 的直接替换。例如,在 Grafana 中我们可以设置 `http://localhost:4000/v1/prometheus/` 作为其 Prometheus 数据源的地址。 访问 [Prometheus 文档](https://prometheus.io/docs/prometheus/latest/querying/api) 获得更详细的说明。 你可以通过设置 HTTP 请求的 `db` 参数来指定 GreptimeDB 中的数据库名。 例如,以下查询将返回 `public` 数据库中 `process_cpu_seconds_total` 指标的 CPU 使用率: ```shell curl -X POST \ -H 'Authorization: Basic {{authorization if exists}}' \ --data-urlencode 'query=irate(process_cpu_seconds_total[1h])' \ --data-urlencode 'start=2024-11-24T00:00:00Z' \ --data-urlencode 'end=2024-11-25T00:00:00Z' \ --data-urlencode 'step=1h' \ 'http://localhost:4000/v1/prometheus/api/v1/query_range?db=public' ``` 如果你使用启用了身份验证的 GreptimeDB,则需要 Authorization header,请参阅[鉴权](/user-guide/protocols/http.md#鉴权)。 该 API 的查询字符串参数与原始 [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) 的查询字符串参数相同。 你需要在 HTTP 的 query param 设置 `db` 参数,或者通过 `--header 'x-greptime-db-name: '` 设置在 HTTP 请求头中。 输出格式与 Prometheus API 完全兼容: ```json { "status": "success", "data": { "resultType": "matrix", "result": [ { "metric": { "job": "node", "instance": "node_exporter:9100", "__name__": "process_cpu_seconds_total" }, "values": [ [ 1732618800, "0.0022222222222222734" ], [ 1732622400, "0.0009999999999999788" ], [ 1732626000, "0.0029999999999997585" ], [ 1732629600, "0.002222222222222175" ] ] } ] } } ``` ## SQL GreptimeDB 还扩展了 SQL 语法以支持 PromQL。可以用 `TQL`(Time-series Query Language)为关键字开始写入参数和进行查询。该语法如下: ```sql TQL [EVAL|EVALUATE] (, , ) ``` `` 指定查询开始时间范围,`` 指定查询结束时间。 `` 识别查询步幅。它们均可为无引号数字(表示``和``的 UNIX 时间戳,以及``的秒数持续时间),或带引号的字符串(表示``和``的 RFC3339 时间戳,以及``的字符串格式的持续时间)。 例如: ```sql TQL EVAL (1676738180, 1676738780, '10s') sum(some_metric) ``` 你可以在所有支持 SQL 的地方编写上述命令,包括 GreptimeDB HTTP API、SDK、PostgreSQL 和 MySQL 客户端等。 ## GreptimeDB 的扩展 ### 指定数值列 基于表模型,GreptimeDB 支持在单个表(或在 Prometheus 中称为指标)中查询多个字段。默认情况下,查询将应用于每个值字段 (field)。或者也可以使用特殊的过滤器 `__field__` 来查询特定的字段: ```promql metric{__field__="field1"} ``` 反选或正则表达式也都支持 ```promql metric{__field__!="field1"} metric{__field__=~"field_1|field_2"} metric{__field__!~"field_1|field_2"} ``` ### 指定数据库 不同于 Prometheus,GreptimeDB 包含数据库概念。如果要进行跨数据库的 PromQL 查询, 可以使用 `__database__` 来指定数据库名称。 ```promql metric{__database__="mydatabase"} ``` 注意 `__database__` 仅支持 `=` 匹配。 ## 局限 尽管 GreptimeDB 支持丰富的数据类型,但 PromQL 的实现仍然局限于以下类型: - timestamp: `Timestamp` - tag: `String` - value: `Double` GreptimeDB 目前已实现了大部分(超过 90%)的 PromQL 功能。您可以在下方查看详细的兼容性列表,或者通过此 [issue](https://github.com/GreptimeTeam/greptimedb/issues/1042) 了解我们最新的功能支持情况。 选择器引用不存在的列时,其行为与 Prometheus 一致:不报错且选择器会被静默忽略。但若 `__name__` 选择器引用了不存在的指标(或等效形式),GreptimeDB 则会报告错误。 支持字符串和浮点数,与 PromQL 的[规则](https://prometheus.io/docs/prometheus/latest/querying/basics/#literals)相同。 ### 选择器 Instant 选择器和 Range 选择器均已支持。需要注意的是,在 Prometheus 和 GreptimeDB 中,指标名称的标签匹配有一个特殊限制:不支持反向匹配(例如 `{__name__!="request_count"}`)。但其他匹配方式,如等值匹配和正则匹配都是完全支持的。 时间区间和时间偏移修饰符均已支持,但目前尚未支持 `@` 修饰符。 当选择不存在的列时,它们将被视为一个所有值都为 `""` 的列。该行为与 Prometheus 和 VictoriaMetrics 一致。 ### 时间精度 PromQL 的时间戳精度受制于查询语法的限制,最高只支持毫秒级精度的计算。然而,GreptimeDB 支持存储微秒和纳秒等高精度时间。在使用 PromQL 进行计算时,这些高精度时间将被隐式转换为毫秒精度进行计算。 ### Binary - 支持: | Operator | | :------- | | add | | sub | | mul | | div | | mod | | eqlc | | neq | | gtr | | lss | | gte | | lte | | power | | atan2 | | and | | or | | unless | - 不支持: 无 ### Aggregators - 支持: | Aggregator | Example | | :----------- | :------------------------------------------- | | sum | `sum by (foo)(metric)` | | avg | `avg by (foo)(metric)` | | min | `min by (foo)(metric)` | | max | `max by (foo)(metric)` | | stddev | `stddev by (foo)(metric)` | | stdvar | `stdvar by (foo)(metric)` | | topk | `topk(3, rate(instance_cpu_time_ns[5m]))` | | bottomk | `bottomk(3, rate(instance_cpu_time_ns[5m]))` | | count_values | `count_values("version", build_version)` | | count | `count (metric)` | | quantile | `quantile(0.9, cpu_usage)` | - 不支持: | Aggregator | Progress | | :--------- | :------- | | count | TBD | | grouping | TBD | ### Instant Functions - 支持: | Function | Example | | :----------------- | :-------------------------------- | | abs | `abs(metric)` | | ceil | `ceil(metric)` | | exp | `exp(metric)` | | ln | `ln(metric)` | | log2 | `log2(metric)` | | log10 | `log10(metric)` | | sqrt | `sqrt(metric)` | | acos | `acos(metric)` | | asin | `asin(metric)` | | atan | `atan(metric)` | | sin | `sin(metric)` | | cos | `cos(metric)` | | tan | `tan(metric)` | | acosh | `acosh(metric)` | | asinh | `asinh(metric)` | | atanh | `atanh(metric)` | | sinh | `sinh(metric)` | | cosh | `cosh(metric)` | | scalar | `scalar(metric)` | | tanh | `tanh(metric)` | | timestamp | `timestamp()` | | sort | `sort(http_requests_total)` | | sort_desc | `sort_desc(http_requests_total)` | | histogram_quantile | `histogram_quantile(phi, metric)` | | predicate_linear | `predict_linear(metric, 120)` | | absent | `absent(nonexistent{job="myjob"})`| | sgn | `sgn(metric)` | | pi | `pi()` | | deg | `deg(metric)` | | rad | `rad(metric)` | | floor | `floor(metric)` | | clamp | `clamp(metric, 0, 12)` | | clamp_max | `clamp_max(metric, 12)` | | clamp_min | `clamp_min(metric, 0)` | - 不支持: | Function | Progress | | :------------------------- | :------- | | *other multiple input fns* | TBD | ### Range Functions - 支持: | Function | Example | | :----------------- | :----------------------------- | | idelta | `idelta(metric[5m])` | | \_over_time | `count_over_time(metric[5m])` | | stddev_over_time | `stddev_over_time(metric[5m])` | | stdvar_over_time | `stdvar_over_time(metric[5m])` | | changes | `changes(metric[5m])` | | delta | `delta(metric[5m])` | | rate | `rate(metric[5m])` | | deriv | `deriv(metric[5m])` | | increase | `increase(metric[5m])` | | irate | `irate(metric[5m])` | | reset | `reset(metric[5m])` | - 不支持: 无 ### Label 及其他函数 - 支持: | Function | Example | | :------------ | :------------------------------------------------------------------------------------------------ | | label_join | `label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")` | | label_replace | `label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")` | | sort_by_label | `sort_by_label(metric, "foo", "bar")` | | sort_by_label_desc | `sort_by_label_desc(metric, "foo", "bar")` | - 不支持: 无 --- ## 查询外部数据 ## 对文件进行查询 目前,我们支持 `Parquet`、`CSV`、`ORC` 和 `NDJson` 格式文件的查询。 以 [Taxi Zone Lookup Table](https://d37ci6vzurychx.cloudfront.net/misc/taxi+_zone_lookup.csv) 数据为例。 ```bash curl "https://d37ci6vzurychx.cloudfront.net/misc/taxi+_zone_lookup.csv" -o /tmp/taxi+_zone_lookup.csv ``` 创建一个外部表: ```sql CREATE EXTERNAL TABLE taxi_zone_lookup with (location='/tmp/taxi+_zone_lookup.csv',format='csv'); ``` 检查外部表的组织和结构: ```sql DESC TABLE taxi_zone_lookup; ``` ```sql +--------------------+----------------------+------+------+--------------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+----------------------+------+------+--------------------------+---------------+ | LocationID | Int64 | | YES | | FIELD | | Borough | String | | YES | | FIELD | | Zone | String | | YES | | FIELD | | service_zone | String | | YES | | FIELD | | greptime_timestamp | TimestampMillisecond | PRI | NO | 1970-01-01 00:00:00+0000 | TIMESTAMP | +--------------------+----------------------+------+------+--------------------------+---------------+ 4 rows in set (0.00 sec) ``` :::tip 注意 在这里,你可能会注意到出现了一个 `greptime_timestamp` 列,这个列作为表的时间索引列,在文件中并不存在。这是因为在创建外部表时,我们没有指定时间索引列,`greptime_timestamp` 列被自动添加作为时间索引列,并且默认值为 `1970-01-01 00:00:00+0000`。你可以在 [create](/reference/sql/create.md#create-external-table) 文档中查找更多详情。 ::: 现在就可以查询外部表了: ```sql SELECT `Zone`, `Borough` FROM taxi_zone_lookup LIMIT 5; ``` ```sql +-------------------------+---------------+ | Zone | Borough | +-------------------------+---------------+ | Newark Airport | EWR | | Jamaica Bay | Queens | | Allerton/Pelham Gardens | Bronx | | Alphabet City | Manhattan | | Arden Heights | Staten Island | +-------------------------+---------------+ ``` ## 对目录进行查询 首先下载一些数据: ```bash mkdir /tmp/external curl "https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2022-01.parquet" -o /tmp/external/yellow_tripdata_2022-01.parquet curl "https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2022-02.parquet" -o /tmp/external/yellow_tripdata_2022-02.parquet ``` 验证下载情况: ```bash ls -l /tmp/external total 165368 -rw-r--r-- 1 wenyxu wheel 38139949 Apr 28 14:35 yellow_tripdata_2022-01.parquet -rw-r--r-- 1 wenyxu wheel 45616512 Apr 28 14:36 yellow_tripdata_2022-02.parquet ``` 创建外部表 ```sql CREATE EXTERNAL TABLE yellow_tripdata with(location='/tmp/external/',format='parquet'); ``` 执行查询: ```sql SELECT count(*) FROM yellow_tripdata; ``` ```sql +-----------------+ | COUNT(UInt8(1)) | +-----------------+ | 5443362 | +-----------------+ 1 row in set (0.48 sec) ``` ```sql SELECT * FROM yellow_tripdata LIMIT 5; ``` ```sql +----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+-------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+---------------------+ | VendorID | tpep_pickup_datetime | tpep_dropoff_datetime | passenger_count | trip_distance | RatecodeID | store_and_fwd_flag | PULocationID | DOLocationID | payment_type | fare_amount | extra | mta_tax | tip_amount | tolls_amount | improvement_surcharge | total_amount | congestion_surcharge | airport_fee | greptime_timestamp | +----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+-------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+---------------------+ | 1 | 2022-02-01 00:06:58 | 2022-02-01 00:19:24 | 1 | 5.4 | 1 | N | 138 | 252 | 1 | 17 | 1.75 | 0.5 | 3.9 | 0 | 0.3 | 23.45 | 0 | 1.25 | 1970-01-01 00:00:00 | | 1 | 2022-02-01 00:38:22 | 2022-02-01 00:55:55 | 1 | 6.4 | 1 | N | 138 | 41 | 2 | 21 | 1.75 | 0.5 | 0 | 6.55 | 0.3 | 30.1 | 0 | 1.25 | 1970-01-01 00:00:00 | | 1 | 2022-02-01 00:03:20 | 2022-02-01 00:26:59 | 1 | 12.5 | 1 | N | 138 | 200 | 2 | 35.5 | 1.75 | 0.5 | 0 | 6.55 | 0.3 | 44.6 | 0 | 1.25 | 1970-01-01 00:00:00 | | 2 | 2022-02-01 00:08:00 | 2022-02-01 00:28:05 | 1 | 9.88 | 1 | N | 239 | 200 | 2 | 28 | 0.5 | 0.5 | 0 | 3 | 0.3 | 34.8 | 2.5 | 0 | 1970-01-01 00:00:00 | | 2 | 2022-02-01 00:06:48 | 2022-02-01 00:33:07 | 1 | 12.16 | 1 | N | 138 | 125 | 1 | 35.5 | 0.5 | 0.5 | 8.11 | 0 | 0.3 | 48.66 | 2.5 | 1.25 | 1970-01-01 00:00:00 | +----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+-------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+---------------------+ 5 rows in set (0.11 sec) ``` :::tip 注意 查询结果中包含 `greptime_timestamp` 列的值,尽管它在原始文件中并不存在。这个列的所有值均为 `1970-01-01 00:00:00+0000`,这是因为我们在创建外部表时,自动添加列 `greptime_timestamp`,并且默认值为 `1970-01-01 00:00:00+0000`。你可以在 [create](/reference/sql/create.md#create-external-table) 文档中查找更多详情。 ::: --- ## SQL(Query-data) GreptimeDB 在查询数据时支持完整的 `SQL` 语法。 在这篇文档中,我们将使用 `monitor` 表中的数据作为示例来演示如何查询数据。关于如何创建 `monitor` 表格并向其中插入数据,请参考[表管理](/user-guide/deployments-administration/manage-data/basic-table-operations.md#创建表)和[写入数据](/user-guide/ingest-data/for-iot/sql.md)。 ## 基础查询 通过 `SELECT` 语句来查询数据。例如,下面的查询返回 `monitor` 表中的所有数据: ```sql SELECT * FROM monitor; ``` 查询结果如下: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2022-11-03 03:39:57 | 0.1 | 0.4 | | 127.0.0.1 | 2022-11-03 03:39:58 | 0.5 | 0.2 | | 127.0.0.2 | 2022-11-03 03:39:58 | 0.2 | 0.3 | +-----------+---------------------+------+--------+ 3 rows in set (0.00 sec) ``` `SELECT` 字段列表中也支持使用函数。 例如,你可以使用 `count()` 函数来获取表中的总行数: ```sql SELECT count(*) FROM monitor; ``` ```sql +-----------------+ | COUNT(UInt8(1)) | +-----------------+ | 3 | +-----------------+ ``` 使用函数 `avg()` 返回某个字段的平均值: ```sql SELECT avg(cpu) FROM monitor; ``` ```sql +---------------------+ | AVG(monitor.cpu) | +---------------------+ | 0.26666666666666666 | +---------------------+ 1 row in set (0.00 sec) ``` 你还可以只返回函数的结果,例如从时间戳中提取一年中的第几天。 SQL 语句中的 `DOY` 是 `day of the year` 的缩写: ```sql SELECT date_part('DOY', '2021-07-01 00:00:00'); ``` 结果: ```sql +----------------------------------------------------+ | date_part(Utf8("DOY"),Utf8("2021-07-01 00:00:00")) | +----------------------------------------------------+ | 182 | +----------------------------------------------------+ 1 row in set (0.003 sec) ``` 时间函数的参数和结果与 SQL 客户端的时区保持一致。 例如,当客户端的时区设置为 `+08:00` 时,下面两个查询的结果是相同的: ```sql select to_unixtime('2024-01-02 00:00:00'); select to_unixtime('2024-01-02 00:00:00+08:00'); ``` 请参考 [SELECT](/reference/sql/select.md) 和 [Functions](/reference/sql/functions/overview.md) 获取更多信息。 ## 限制返回的行数 时间序列数据通常是海量的。 为了节省带宽和提高查询性能,你可以使用 `LIMIT` 语句来限制 `SELECT` 语句返回的行数。 例如,下面的查询限制返回的行数为 10: ```sql SELECT * FROM monitor LIMIT 10; ``` ## 过滤数据 你可以使用 `WHERE` 子句来过滤 `SELECT` 语句返回的行。 时序数据库中常见的场景是按照标签或时间索引来过滤数据。 例如,按照标签 `host` 来过滤数据: ```sql SELECT * FROM monitor WHERE host='127.0.0.1'; ``` 按照时间索引 `ts` 来过滤数据,返回 `2022-11-03 03:39:57` 之后的数据: ```sql SELECT * FROM monitor WHERE ts > '2022-11-03 03:39:57'; ``` 你可以使用 `AND` 关键字来组合多个约束条件: ```sql SELECT * FROM monitor WHERE host='127.0.0.1' AND ts > '2022-11-03 03:39:57'; ``` ### 使用时间索引过滤数据 按照时间索引来过滤数据是时序数据库的一个关键特性。 当处理 Unix 时间值时,数据库会默认将其类型认定为相关列的值类型。 例如,当 `monitor` 表中的 `ts` 列的值类型为 `TimestampMillisecond` 时, 你可以使用下面的查询来过滤数据: Unix 时间值 `1667446797000` 表示一个以毫秒为单位的时间戳。 ```sql SELECT * FROM monitor WHERE ts > 1667446797000; ``` 当处理时间精度为非默认类型的 Unix 时间值时,你需要使用 `::` 语法来指定时间的类型。 这样可以确保数据库正确地识别时间的类型。 例如 `1667446797` 表示一个以秒为单位的时间戳,不是 `ts` 列默认的毫秒时间戳。 你需要使用 `::TimestampSecond` 语法来指定它的类型为 `TimestampSecond` 来告知数据库 `1667446797` 应该被视为以秒为单位的时间戳。 ```sql SELECT * FROM monitor WHERE ts > 1667446797::TimestampSecond; ``` 请参考[数据类型](/reference/sql/data-types.md#日期和时间类型) 获取更多时间类型。 对于标准的 `RFC3339` 或 `ISO8601` 字符串,由于其具备明确的精度,你可以直接在过滤条件中使用它们: ```sql SELECT * FROM monitor WHERE ts > '2022-07-25 10:32:16.408'; ``` 你还可以使用时间函数来过滤数据。 例如,使用 `now()` 函数和 `INTERVAL` 关键字来获取最近 5 分钟的数据: ```sql SELECT * FROM monitor WHERE ts >= now() - '5 minutes'::INTERVAL; ``` 请参考 [Functions](/reference/sql/functions/overview.md) 获取更多时间函数信息。 ### 时区 GreptimeDB 的 SQL 客户端会根据本地时区解释不带时区信息的字符串时间戳。 例如,当客户端时区为 `+08:00` 时,下面的两个查询是相同的: ```sql SELECT * FROM monitor WHERE ts > '2022-07-25 10:32:16.408'; SELECT * FROM monitor WHERE ts > '2022-07-25 10:32:16.408+08:00'; ``` 查询结果中的时间戳列值会根据客户端时区格式化。 例如,下面的代码展示了相同的 `ts` 值在客户端时区 `UTC` 和 `+08:00` 下的结果: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2023-12-31 16:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2024-01-01 00:00:00 | 0.5 | 0.1 | +-----------+---------------------+------+--------+ ``` ### 函数 GreptimeDB 提供了丰富的内置函数和聚合函数,为数据分析应用开发。其特点包括: + Apache Datafusion 查询引擎中继承的函数,包括一组符合 Postgres 命名方式和行为的日期/时间函数。 + JSON、位置信息等特殊数据类型的操作函数。 + 高级全文匹配能力。 查看 [函数列表](/reference/sql/functions/overview.md)。 ## 排序 GreptimeDB 不保证返回数据的顺序。你需要使用 `ORDER BY` 子句来对返回的数据进行排序。 例如,在时间序列场景中通常使用时间索引列作为排序键: ```sql -- ascending order by ts SELECT * FROM monitor ORDER BY ts ASC; ``` ```sql -- descending order by ts SELECT * FROM monitor ORDER BY ts DESC; ``` ## `CASE` 表达式 你可以使用 `CASE` 表达式在查询中执行条件逻辑。 例如,下面的查询根据 `cpu` 字段的值返回 CPU 的状态: ```sql SELECT host, ts, CASE WHEN cpu > 0.5 THEN 'high' WHEN cpu > 0.3 THEN 'medium' ELSE 'low' END AS cpu_status FROM monitor; ``` 结果如下: ```sql +-----------+---------------------+------------+ | host | ts | cpu_status | +-----------+---------------------+------------+ | 127.0.0.1 | 2022-11-03 03:39:57 | low | | 127.0.0.1 | 2022-11-03 03:39:58 | medium | | 127.0.0.2 | 2022-11-03 03:39:58 | low | +-----------+---------------------+------------+ 3 rows in set (0.01 sec) ``` 更多信息请参考 [CASE](/reference/sql/case.md)。 ## 按标签聚合数据 你可以使用 `GROUP BY` 语句将具有相同值的行进行分组汇总,例如查询 `idc` 列中的所有不同值的内存均值: ```sql SELECT host, avg(cpu) FROM monitor GROUP BY host; ``` ```sql +-----------+------------------+ | host | AVG(monitor.cpu) | +-----------+------------------+ | 127.0.0.2 | 0.2 | | 127.0.0.1 | 0.3 | +-----------+------------------+ 2 rows in set (0.00 sec) ``` 请参考 [GROUP BY](/reference/sql/group_by.md) 获取更多相关信息。 ### 查询时间线中的最新数据 你可以通过组合使用 `DISTINCT ON` 和 `ORDER BY` 来查询每条时间线的最新数据点,例如: ```sql SELECT DISTINCT ON (host) * FROM monitor ORDER BY host, ts DESC; ``` ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2022-11-03 03:39:58 | 0.5 | 0.2 | | 127.0.0.2 | 2022-11-03 03:39:58 | 0.2 | 0.3 | +-----------+---------------------+------+--------+ 2 rows in set (0.00 sec) ``` ## 按时间窗口聚合数据 GreptimeDB 支持 [Range Query](/reference/sql/range.md) 来按时间窗口聚合数据。 假设我们有以下数据在 [`monitor` 表](/user-guide/deployments-administration/manage-data/basic-table-operations.md#创建表) 中: ```sql +-----------+---------------------+------+--------+ | host | ts | cpu | memory | +-----------+---------------------+------+--------+ | 127.0.0.1 | 2023-12-13 02:05:41 | 0.5 | 0.2 | | 127.0.0.1 | 2023-12-13 02:05:46 | NULL | NULL | | 127.0.0.1 | 2023-12-13 02:05:51 | 0.4 | 0.3 | | 127.0.0.2 | 2023-12-13 02:05:41 | 0.3 | 0.1 | | 127.0.0.2 | 2023-12-13 02:05:46 | NULL | NULL | | 127.0.0.2 | 2023-12-13 02:05:51 | 0.2 | 0.4 | +-----------+---------------------+------+--------+ ``` 下面的查询返回 10 秒内的平均 CPU 使用率,并且每 5 秒计算一次: ```sql SELECT ts, host, avg(cpu) RANGE '10s' FILL LINEAR FROM monitor ALIGN '5s' TO '2023-12-01T00:00:00' BY (host) ORDER BY ts ASC; ``` 1. `avg(cpu) RANGE '10s' FILL LINEAR` 是一个 Range 表达式。`RANGE '10s'` 指定了聚合的时间范围为 10s,`FILL LINEAR` 指定了如果某个点没有数据,使用 `LINEAR` 方法来填充。 2. `ALIGN '5s'` 指定了查询的步频为 5s。 3. `TO '2023-12-01T00:00:00` 指定了原始对齐时间。默认值为 Unix 时间 0。 4. `BY (host)` 指定了聚合的键。如果省略 `BY` 关键字,那么默认使用数据表的主键作为聚合键。 5. `ORDER BY ts ASC` 指定了结果集的排序方法。如果不指定排序方法,结果集的顺序是不确定的。 查询结果如下: ```sql +---------------------+-----------+----------------------------------------+ | ts | host | AVG(monitor.cpu) RANGE 10s FILL LINEAR | +---------------------+-----------+----------------------------------------+ | 2023-12-13 02:05:35 | 127.0.0.1 | 0.5 | | 2023-12-13 02:05:40 | 127.0.0.1 | 0.5 | | 2023-12-13 02:05:45 | 127.0.0.1 | 0.4 | | 2023-12-13 02:05:50 | 127.0.0.1 | 0.4 | | 2023-12-13 02:05:35 | 127.0.0.2 | 0.3 | | 2023-12-13 02:05:40 | 127.0.0.2 | 0.3 | | 2023-12-13 02:05:45 | 127.0.0.2 | 0.2 | | 2023-12-13 02:05:50 | 127.0.0.2 | 0.2 | +---------------------+-----------+----------------------------------------+ ``` ### 时间范围窗口 将初始时间范围窗口在时间序列中向前和向后移动,就生成了所有时间范围窗口。 在上面的例子中,初始对齐时间被设置为 `2023-12-01T00:00:00`,这也是初始时间窗口的结束时间。 `RANGE` 选项和初始对齐时间定义了初始时间范围窗口,它从 `初始对齐时间` 开始,到 `初始对齐时间 + RANGE` 结束。 `ALIGN` 选项定义了查询的步频,决定了从初始时间窗口到其他时间窗口的计算步频。 例如,使用初始对齐时间 `2023-12-01T00:00:00` 和 `ALIGN '5s'`,时间窗口的对齐时间为 `2023-11-30T23:59:55`、`2023-12-01T00:00:00`、`2023-12-01T00:00:05`、`2023-12-01T00:00:10` 等。 这些时间窗口是左闭右开区间,满足条件 `[对齐时间, 对齐时间 + 范围)`。 下方的图片可以帮助你更直观的理解时间范围窗口: 当查询的步频大于时间范围窗口时,数据将只会被计算在一个时间范围窗口中。 ![align > range](/align_greater_than_range.png) 当查询的步频小于时间范围窗口时,数据将会被计算在多个时间范围窗口中。 ![align < range](/align_less_than_range.png) ### 对齐到特定时间戳 对齐时间默认基于当前 SQL 客户端会话的时区。 你可以将初始对齐时间设置为任何你想要的时间戳。例如,使用 `NOW` 将对齐到当前时间: ```sql SELECT ts, host, avg(cpu) RANGE '1w' FROM monitor ALIGN '1d' TO NOW BY (host); ``` 或者使用 `ISO 8601` 时间戳将对齐到指定时间: ```sql SELECT ts, host, avg(cpu) RANGE '1w' FROM monitor ALIGN '1d' TO '2023-12-01T00:00:00+08:00' BY (host); ``` ### 填充空值 `FILL` 选项可以用来填充数据中的空值。 例如上面的例子使用了 `LINEAR` 方法来填充空值。 该选项也支持其他填充空值的方法,例如 `PREV` 和常量值 `X`,更多信息请参考 [FILL OPTION](/reference/sql/range.md#fill-option)。 ### 语法 请参考 [Range Query](/reference/sql/range.md) 获取更多信息。 ## 表名约束 如果你的表名包含特殊字符或大写字母,需要将表名用反引号括起来。 有关示例,请参阅表创建表文档中的[表名约束](/user-guide/deployments-administration/manage-data/basic-table-operations.md#表名约束)部分。 ## HTTP API 在 HTTP 请求中使用 `POST` 方法来查询数据: ```shell curl -X POST \ -H 'authorization: Basic {{authorization if exists}}' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'sql=select * from monitor' \ http://localhost:4000/v1/sql?db=public ``` 结果如下: ```json { "code": 0, "output": [ { "records": { "schema": { "column_schemas": [ { "name": "host", "data_type": "String" }, { "name": "ts", "data_type": "TimestampMillisecond" }, { "name": "cpu", "data_type": "Float64" }, { "name": "memory", "data_type": "Float64" } ] }, "rows": [ ["127.0.0.1", 1667446797450, 0.1, 0.4], ["127.0.0.1", 1667446798450, 0.5, 0.2], ["127.0.0.2", 1667446798450, 0.2, 0.3] ] } } ], "execution_time_ms": 0 } ``` 请参考 [API 文档](/user-guide/protocols/http.md#post-sql-语句)获取更详细的 HTTP 请求的内容。 --- ## 视图 在 SQL 中,视图(View)是基于 SQL 语句的结果集的虚拟表。 它包含与真实的表一样的行和列。 每次查询视图时,都会运行该视图的查询。 在以下情况下,我们可以使用视图: * 简化复杂查询,避免每次查询都重复编写和发送复杂语句。 * 对特定用户开放读取权限,限制一些列和行的读取,保证数据安全和隔离。 可以使用 `CREATE VIEW` 语句创建视图。 ## 视图示例 ```sql CREATE VIEW cpu_monitor AS SELECT cpu, host, ts FROM monitor; ``` 这个视图的名称是 `cpu_monitor`,在 `AS` 之后的查询语句是用于呈现数据的 SQL 语句。查询视图: ```sql SELECT * FROM cpu_monitor; ``` 结果示例: ```sql +------+-----------+---------------------+ | cpu | host | ts | +------+-----------+---------------------+ | 0.5 | 127.0.0.1 | 2023-12-13 02:05:41 | | 0.3 | 127.0.0.1 | 2023-12-13 02:05:46 | | 0.4 | 127.0.0.1 | 2023-12-13 02:05:51 | | 0.3 | 127.0.0.2 | 2023-12-13 02:05:41 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:46 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:51 | +------+-----------+---------------------+ ``` 通过 `WHERE` 查询视图: ```sql SELECT * FROM cpu_monitor WHERE host = '127.0.0.2'; ``` 结果示例: ```sql +------+-----------+---------------------+ | cpu | host | ts | +------+-----------+---------------------+ | 0.3 | 127.0.0.2 | 2023-12-13 02:05:41 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:46 | | 0.2 | 127.0.0.2 | 2023-12-13 02:05:51 | +------+-----------+---------------------+ ``` 创建一个从两个表联合查询数据的视图: ```sql CREATE VIEW app_cpu_monitor AS SELECT cpu, latency, host, ts FROM monitor LEFT JOIN app_monitor ON monitor.host = app_monitor.host AND monitor.ts = app_monitor.ts ``` 然后可以像查询一个单表数据一样查询这个视图: ```sql SELECT * FROM app_cpu_monitor WHERE host = 'host1' ``` ## 更新视图 使用 `CREATE OR REPLACE VIEW` 来更新视图,如果视图不存在,则会创建: ```sql CREATE OR REPLACE VIEW memory_monitor AS SELECT memory, host, ts FROM monitor; ``` ## 显示视图定义 通过 `SHOW CREATE VIEW view_name` 语句来显示创建视图的 `CREATE VIEW` 语句: ```sql SHOW CREATE VIEW cpu_monitor; ``` ```sql +-------------+--------------------------------------------------------------+ | View | Create View | +-------------+--------------------------------------------------------------+ | cpu_monitor | CREATE VIEW cpu_monitor AS SELECT cpu, host, ts FROM monitor | +-------------+--------------------------------------------------------------+ ``` ## 列出视图 使用 `SHOW VIEWS` 语句查找所有视图: ```sql > SHOW VIEWS; +----------------+ | Views | +----------------+ | cpu_monitor | | memory_monitor | +----------------+ ``` 当然,像 `SHOW TABLES` 一样,它也支持 `LIKE` 和 `WHERE`: ```sql > SHOW VIEWS like 'cpu%'; +-------------+ | Views | +-------------+ | cpu_monitor | +-------------+ 1 row in set (0.02 sec) > SHOW VIEWS WHERE Views = 'memory_monitor'; +----------------+ | Views | +----------------+ | memory_monitor | +----------------+ ``` ## 删除视图 使用 `DROP VIEW` 语句删除视图: ```sql DROP VIEW cpu_monitor; ``` 如果希望在视图不存在时不报错,可以使用: ```sql DROP VIEW IF EXISTS test; ``` --- ## 时区 你可以在客户端会话中指定时区以方便地管理时间数据。 客户端会话中指定的时区仅应用在客户端向服务器发送请求时, 不影响存储在 GreptimeDB 服务器中的时间数据。 GreptimeDB 在数据写入或查询时,会根据指定的时区将时间值从字符串表示转换为日期时间,或转换回来。 ## 在客户端中指定时区 默认情况下,所有客户端使用[默认时区配置](/user-guide/deployments-administration/configuration.md#默认时区配置),即 UTC。 你也可以在每个客户端会话中指定时区, 这将覆盖默认的时区配置。 ### MySQL 客户端 - **命令行**:有关通过 MySQL 命令行客户端配置时区的内容,请参阅 MySQL 协议文档中的[时区部分](/user-guide/protocols/mysql.md#时区)。 - **MySQL driver**:如果你使用的是 Java 或 Go 中的 MySQL driver,请查看 SQL 工具文档的[时区部分](/reference/sql-tools.md#时区)。 ### PostgreSQL 客户端 要配置 PostgreSQL 客户端的时区,请参阅 PostgreSQL 协议文档中的[时区部分](/user-guide/protocols/postgresql.md#时区)。 ### HTTP API 使用 HTTP API 时,你可以通过 header 参数指定时区。有关更多信息,请参阅 [HTTP API 文档](/user-guide/protocols/http.md#时区)。 ### Dashboard Dashboard 将使用本地时区作为默认时区值。您可以在 settings 菜单中更改它。 ### 其他客户端 对于其他客户端,你可以更改 GreptimeDB 的[默认时区配置](/user-guide/deployments-administration/configuration.md#默认时区配置)。 ## 时区对 SQL 语句的影响 客户端中的时区设置会影响数据的写入和查询。 ### 写入数据 客户端中设置的时区会影响数据的写入。有关更多信息,请参阅[写入数据](/user-guide/ingest-data/for-iot/sql.md#时区)。 此外,表 schema 中的默认写入的时间戳值也会受到客户端时区的影响,影响方式与数据写入相同。 ### 查询数据 时区设置也会影响数据的查询。 有关详细信息,请参阅[查询数据](/user-guide/query-data/sql.md#时区)。 --- ## Trace 数据模型 :::warning 本章内容目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: 在本节,我们主要描述 Trace 数据如何转换成 GreptimeDB 的表结构。 我们复用了 Pipeline 的概念来标记数据模型的版本,因此注意在 Trace 数据中暂时只能 使用内置的 Pipeline。 ## 数据模型版本机制 GreptimeDB 本身的数据类型和相关功能在持续演化。为了实现向后兼容,我们使用 Pipeline 的名称来作为数据模型的版本。目前可用的 Pipeline 包括: - `greptime_trace_v1` 在使用 OTLP/HTTP 协议写入数据时,HTTP 头是必须设置的 `x-greptime-pipeline-name: greptime_trace_v1`. 在未来我们可能引入新的 Pipeline 名称,即数据模型版本。但已有的版本会持续保持维护。 新的 Pipeline 可能与老版本不兼容,倒是需要创建新的数据表来使用。 ## 数据模型 `greptime_trace_v1` 数据模型是非常直观的。默认情况下,Trace 数据存储在名为 `opentelemetry_traces` 的表中。你可以通过在 OTLP/HTTP 请求中指定 `x-greptime-trace-table-name` 请求头来自定义表名。 - 所有常见的 [OpenTelemetry Trace](https://opentelemetry.io/docs/concepts/signals/traces/) 数据字段都被映射为 GreptimeDB 的列。 - `service_name` 从 `resource_attributes["service.name"]` 中提取,并用作 **Tag**(**主键**的一部分)。 - `timestamp` 是 Span 的开始时间,用作 **时间索引**(Time Index)。 - `duration_nano` 列由 `end_time - start_time` 生成。 - 所有的属性字段被打平为列,按照 `[span|resource|scope]_attributes.[attribute_key]` 的命名方式生成名称。 - 注意:`resource_attributes.service.name` 被排除在打平之外,因为它已经存储在 `service_name` 列中。 - 如果属性的值是复合类型,如 `Array` 或 `Kvlist`,它将被存储为 GreptimeDB 的 `JSON` 类型。 - 其他复合类型字段 `span_links` 和 `span_events` 将被存储为 `JSON` 类型。 在插入第一条数据时,表将被创建。并且当数据中涉及新的字段时,表的结构会自动变更增加列。 以下是一个使用 OpenTelemetry Django 埋点生成的表结构: ``` timestamp | 2025-05-07 10:03:29.657544 timestamp_end | 2025-05-07 10:03:29.661714 duration_nano | 4169970 trace_id | fb60d19aa36fdcb7d14a71ca0b9b42ae span_id | 49806a2671f2ddcb span_kind | SPAN_KIND_SERVER span_name | POST todos/ span_status_code | STATUS_CODE_UNSET span_status_message | trace_state | scope_name | opentelemetry.instrumentation.django scope_version | 0.51b0 service_name | myproject span_attributes.http.request.method | POST span_attributes.url.full | span_attributes.server.address | django:8000 span_attributes.network.peer.address | span_attributes.server.port | 8000 span_attributes.network.peer.port | span_attributes.http.response.status_code | 201 span_attributes.network.protocol.version | 1.1 resource_attributes.telemetry.sdk.language | python resource_attributes.telemetry.sdk.name | opentelemetry resource_attributes.telemetry.sdk.version | 1.30.0 span_events | [] span_links | [] parent_span_id | eccc18b6fc210f31 span_attributes.db.system | span_attributes.db.name | span_attributes.db.statement | span_attributes.url.scheme | http span_attributes.url.path | /todos/ span_attributes.client.address | 10.89.0.5 span_attributes.client.port | 44302 span_attributes.user_agent.original | python-requests/2.32.3 span_attributes.http.route | todos/ ``` 可以通过执行 `show create table opentelemetry_traces` 来查看表建表语句: ``` Table | opentelemetry_traces Create Table | CREATE TABLE IF NOT EXISTS "opentelemetry_traces" ( + | "timestamp" TIMESTAMP(9) NOT NULL, + | "timestamp_end" TIMESTAMP(9) NULL, + | "duration_nano" BIGINT UNSIGNED NULL, + | "trace_id" STRING NULL SKIPPING INDEX WITH(granularity = '10240', type = 'BLOOM'), + | "span_id" STRING NULL, + | "span_kind" STRING NULL, + | "span_name" STRING NULL, + | "span_status_code" STRING NULL, + | "span_status_message" STRING NULL, + | "trace_state" STRING NULL, + | "scope_name" STRING NULL, + | "scope_version" STRING NULL, + | "service_name" STRING NULL SKIPPING INDEX WITH(granularity = '10240', type = 'BLOOM'),+ | "span_attributes.http.request.method" STRING NULL, + | "span_attributes.url.full" STRING NULL, + | "span_attributes.server.address" STRING NULL, + | "span_attributes.network.peer.address" STRING NULL, + | "span_attributes.server.port" BIGINT NULL, + | "span_attributes.network.peer.port" BIGINT NULL, + | "span_attributes.http.response.status_code" BIGINT NULL, + | "span_attributes.network.protocol.version" STRING NULL, + | "resource_attributes.telemetry.sdk.language" STRING NULL, + | "resource_attributes.telemetry.sdk.name" STRING NULL, + | "resource_attributes.telemetry.sdk.version" STRING NULL, + | "span_events" JSON NULL, + | "span_links" JSON NULL, + | "parent_span_id" STRING NULL, + | "span_attributes.db.system" STRING NULL, + | "span_attributes.db.name" STRING NULL, + | "span_attributes.db.statement" STRING NULL, + | "span_attributes.url.scheme" STRING NULL, + | "span_attributes.url.path" STRING NULL, + | "span_attributes.client.address" STRING NULL, + | "span_attributes.client.port" BIGINT NULL, + | "span_attributes.user_agent.original" STRING NULL, + | "span_attributes.http.route" STRING NULL, + | TIME INDEX ("timestamp"), + | PRIMARY KEY ("service_name") + | ) + | PARTITION ON COLUMNS ("trace_id") ( + | trace_id < '1', + | trace_id >= 'f', + | trace_id >= '1' AND trace_id < '2', + | trace_id >= '2' AND trace_id < '3', + | trace_id >= '3' AND trace_id < '4', + | trace_id >= '4' AND trace_id < '5', + | trace_id >= '5' AND trace_id < '6', + | trace_id >= '6' AND trace_id < '7', + | trace_id >= '7' AND trace_id < '8', + | trace_id >= '8' AND trace_id < '9', + | trace_id >= '9' AND trace_id < 'a', + | trace_id >= 'a' AND trace_id < 'b', + | trace_id >= 'b' AND trace_id < 'c', + | trace_id >= 'c' AND trace_id < 'd', + | trace_id >= 'd' AND trace_id < 'e', + | trace_id >= 'e' AND trace_id < 'f' + | ) + | ENGINE=mito + | WITH( + | append_mode = 'true', + | table_data_model = 'greptime_trace_v1' + | ) ``` ### 分区规则 Trace 表包含了默认的 [分区规 则](/user-guide/deployments-administration/manage-data/table-sharding.md#partition),在 `trace_id` 列上根据首个字符的取值划分区间。 这个规则默认将引入 16 个分区,适合在 3-5 个 datanode 的部署规模下使用。 如果数据量和部署规模更大,需要自定义分区规则,可以拷贝这个建表语句,并更新 `PARTITION ON` 这部分来设置更细致的分区规则,并在写入数据之前创建这个表。 ### 索引 我们默认使用对 `service_name` 和 `trace_id` 两个常用字段使用[跳数索 引](/user-guide/manage-data/data-index.md#skipping-index),满足常见的查询场景。 实际使用中,用户可能希望对一些特定的属性列增加索引,这可以通过[alter table](/reference/sql/alter.md#create-an-index-for-a-column)语句来实现。不同于分 区规则,索引可以增量添加而不用重新建表。 ### Append-only 模式 通过此接口创建的表,默认为[Append-only 模 式](/user-guide/deployments-administration/performance-tuning/design-table.md#何时使用-append-only-表)。 ### TTL 可以对 Trace 表应用 [过期时间规则](/reference/sql/alter.md#alter-table-options)。 ## 辅助表 当你写入 Trace 数据时,GreptimeDB 会自动创建两个辅助表,以便于搜索服务和操作。这些表通过在主 Trace 表名后追加 `_services` 和 `_operations` 来命名。 默认情况下,这些表被命名为 `opentelemetry_traces_services` 和 `opentelemetry_traces_operations`。如果你通过 `x-greptime-trace-table-name` HTTP 头部自定义了主 Trace 表名,辅助表也会相应地命名(例如 `_services` 和 `_operations`)。 ### 服务表 (`opentelemetry_traces_services`) 该表存储 Trace 数据中发现的唯一服务名称列表。 - **列**: - `timestamp`: 所有条目都使用一个固定的时间戳 (2100-01-01 00:00:00)。 - `service_name`: 服务名称 (Tag)。 ### 操作表 (`opentelemetry_traces_operations`) 该表存储 Trace 数据中发现的唯一操作(服务、Span 名称和 Span 类型)列表。 - **列**: - `timestamp`: 所有条目都使用一个固定的时间戳 (2100-01-01 00:00:00)。 - `service_name`: 服务名称 (Tag)。 - `span_name`: Span 名称 (Tag)。 - `span_kind`: Span 类型 (Tag)。 --- ## 扩展 Trace 数据 :::warning 本章内容目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: 本章主要介绍如何从 Trace 数据中生成衍生数据。 ## 从 Trace 生成聚合指标数据 每个 Span 中都包含 `duration_nano` 字段代表其处理时间,在这个例子里,我们将创建 [Flow](/user-guide/flow-computation/overview.md) 任务来生成延迟的指标数据。 这里我们使用 OpenTelemetry Django 埋点数据作为源数据,不过因为使用的都是通用字段, 所以并不影响例子的解读。 ### 创建 Sink 表 首先,我们创建一个 Flow 中的物化视图,Sink 表。对于延迟数据,我们使用 [uddsketch](https://arxiv.org/abs/2004.08604) 结构来快速生成特定百分为的延迟数据。 ```sql CREATE TABLE "django_http_request_latency" ( "span_name" STRING NULL, "latency_sketch" BINARY, "time_window" TIMESTAMP time index, PRIMARY KEY ("span_name") ); ``` 表中包含三个关键列: - `span_name`: Span 的名称或类型 - `latency_sketch`: uddsketch 数据 - `time_window`: 时间窗口 ### 创建 Flow 下一步我们创建用于计算 uddsketch 数据的 Flow 任务。该任务以 30s 为时间窗口。这里 例子里我们过滤了 `scope_name` 字段,在实际的场景里这是可选的。 注意:在本示例中,我们使用默认表名 `opentelemetry_traces` 作为源 trace 表。如果你的表名已自定义,请相应地替换。 ```sql CREATE FLOW django_http_request_latency_flow SINK TO django_http_request_latency EXPIRE AFTER '30m' COMMENT 'Aggregate latency using uddsketch' AS SELECT span_name, uddsketch_state(128, 0.01, "duration_nano") AS "latency_sketch", date_bin('30 seconds'::INTERVAL, "timestamp") as "time_window", FROM opentelemetry_traces WHERE scope_name = 'opentelemetry.instrumentation.django' GROUP BY span_name, time_window; ``` ### 查询指标 当 Trace 数据写入进来时,sink 表中将有数据生成。我们可以用 SQL 语句来查询 p90 分 为的延迟: ```sql SELECT span_name, time_window, uddsketch_calc(0.90, "latency_sketch") AS p90 FROM django_http_request_latency ORDER BY time_window DESC LIMIT 20; ``` 我们将获得类似的结果: ``` span_name | time_window | p90 ---------------------+----------------------------+-------------------- GET todos/ | 2025-05-09 02:38:00.000000 | 4034758.586053441 POST todos/ | 2025-05-09 02:38:00.000000 | 22988738.680499777 PUT todos// | 2025-05-09 02:38:00.000000 | 5338559.200101535 GET todos/ | 2025-05-09 02:37:30.000000 | 4199425.807196321 POST todos/ | 2025-05-09 02:37:30.000000 | 15104466.164886404 PUT todos// | 2025-05-09 02:37:30.000000 | 16693072.385310777 GET todos/ | 2025-05-09 02:37:00.000000 | 4370813.453648573 POST todos/ | 2025-05-09 02:37:00.000000 | 30417369.407361753 PUT todos// | 2025-05-09 02:37:00.000000 | 14512192.224492861 GET todos/ | 2025-05-09 02:36:30.000000 | 3578495.53232116 POST todos/ | 2025-05-09 02:36:30.000000 | 15409606.895490168 PUT todos// | 2025-05-09 02:36:30.000000 | 15409606.895490168 GET todos/ | 2025-05-09 02:36:00.000000 | 3507634.2346514342 POST todos/ | 2025-05-09 02:36:00.000000 | 45377987.991290994 PUT todos// | 2025-05-09 02:36:00.000000 | 14512192.224492861 GET todos/ | 2025-05-09 02:35:30.000000 | 3237945.86410019 POST todos/ | 2025-05-09 02:35:30.000000 | 15409606.895490168 PUT todos// | 2025-05-09 02:35:30.000000 | 13131130.769316385 GET todos/ | 2025-05-09 02:35:00.000000 | 3173828.124217018 POST todos/ | 2025-05-09 02:35:00.000000 | 14512192.224492861 (20 rows) ``` --- ## Traces :::warning 本章内容目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: GreptimeDB 0.14 中加入了 Trace 数据的原生支持。本节内容我们将介绍 Trace 数据读写, 和数据建模等高级主题。 - [写入与查询](./read-write.md) - [GreptimeDB 中的 Trace 数据建模](./data-model.md) - [扩展 Trace 数据](./extend-trace.md) --- ## 写入与查询 :::warning 本章内容目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: 本节我们将从 Trace 数据的写入和查询开始使用 GreptimeDB. GreptimeDB 并未为 Trace 数据引入新的协议,而是尽可能使用以后的广泛接受的协议。 ## 写入 GreptimeDB 使用 OpenTelemetry 的 OTLP/HTTP 协议作为主要的 Trace 数据写入协议。 Trace 也是 OpenTelemetry 中最广为接受的子协议,包含了良好的生态。 ### OpenTelemetry SDK 如果你在应用中使用了 OpenTelemetry 的 SDK/API 库,你可以直接配置一个 OTLP/HTTP 的导出模块来将 trace 数据写入 GreptimeDB。 在我们的 [OpenTelemetry 协议文档 里](/user-guide/ingest-data/for-observability/opentelemetry.md) 介绍了关于这部分 接口的使用,包含相应的写入路径和配置项。 ### OpenTelemetry Collector [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) 是一个厂商中 立的用于收集和处理 OpenTelemetry 数据的服务。本文我们将介绍如何使用 OpenTelemetry Collector 将 traces 数据写入到 GreptimeDB。 #### 启动 OpenTelemetry Collector 你可以使用如下命令来快速启动一个 OpenTelemetry Collector 实例,此时 collector 会监听 `4317`(gRPC) 和 `4318`(HTTP) 端口: ```shell docker run --rm \ --network host \ -p 4317:4317 \ -p 4318:4318 \ -v $(pwd)/config.yaml:/etc/otelcol-contrib/config.yaml \ otel/opentelemetry-collector-contrib:0.123.0 ``` 其中 `config.yaml` 文件内容如下: ```yaml receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp: endpoint: "http://greptimedb:4000/v1/otlp" # GreptimeDB 的 OTLP 路径 headers: x-greptime-pipeline-name: "greptime_trace_v1" #authorization: "Basic " tls: insecure: true service: pipelines: traces: receivers: [otlp] exporters: [otlphttp] ``` #### 将 Trace 数据写入到 OpenTelemetry Collector 你可以给应用配置相应的 exporter 来将 traces 数据写入到 OpenTelemetry Collector。 比如你可以使用环境变量 `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` 来配置 exporter 的 endpoint: ```shell export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://localhost:4318/v1/otlp/v1/traces" ``` 此处为了方便,我们可使用工具 [`telemetrygen`](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/telemetrygen) 来快速生成 traces 数据并写入到 OpenTelemetry Collector 中,更多细节可参考 [OpenTelemetry Collector 官方文 档](https://opentelemetry.io/docs/collector/quick-start/)。 我们可以用如下命令安装 `telemetrygen`(请确保你已经安装了 Go): ```shell go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest ``` 然后我们就可以使用如下命令来生成 traces 数据并写入到 OpenTelemetry Collector 中: ```shell telemetrygen traces --otlp-insecure --traces 3 ``` 上面这条命令将生成 3 条 traces 数据,并通过 gRPC 协议写入到 OpenTelemetry Collector 中。 ### 认证 GreptimeDB 的 OTEL 端点支持 Basic 认证。详情请参考 [鉴权](/user-guide/protocols/http.md#鉴权) 文档。 ### GreptimeDB Pipeline 在 OTLP 接口中,我们要求 HTTP 头 `x-greptime-pipeline-name` 作为必选参数。在这里 我们复用了日志接口中 Pipeline 的概念作为数据转化的机制。但是注意在 Trace 接口中 我们目前仅支持内置的 `greptime_trace_v1`,自定义的 Pipeline 暂不支持。 ### Append-only 模式 通过此接口创建的表,默认为[Append-only 模 式](/user-guide/deployments-administration/performance-tuning/design-table.md#何时使用-append-only-表). ## 查询 GreptimeDB 提供了两种 Trace 数据的查询接口,分别是 Jaeger API 兼容接口和 GreptimeDB 原生的 SQL 查询接口,后者可以运行在 HTTP, MySQL 或者 Postgres 等协议 上。 ### Jaeger GreptimeDB 内置的 Jaeger 兼容层使得用户可以直接复用市面上的 Jaeger 生态工具,例 如 Grafana 的 Jaeger 数据源。 我们在 [Jaeger 协议文档](/user-guide/query-data/jaeger.md)里对此做了具体描述。 ### SQL Trace 数据也可以通过 SQL 查询。默认 Trace 数据会写入 `opentelemetry_traces` 表中, 这个表名也可以在写入时通过 `x-greptime-trace-table-name` 来指定。通过 SQL 查询: ```sql SELECT * FROM public.opentelemetry_traces \G ``` 输出的例子如下: ``` *************************** 1. row *************************** timestamp: 2025-05-07 10:03:29.657544 timestamp_end: 2025-05-07 10:03:29.661714 duration_nano: 4169970 parent_span_id: eccc18b6fc210f31 trace_id: fb60d19aa36fdcb7d14a71ca0b9b42ae span_id: 49806a2671f2ddcb span_kind: SPAN_KIND_SERVER span_name: POST todos/ span_status_code: STATUS_CODE_UNSET span_status_message: trace_state: scope_name: opentelemetry.instrumentation.django scope_version: 0.51b0 service_name: myproject span_attributes.http.request.method: POST span_attributes.url.full: span_events: [] span_links: [] ... ``` 在下一节[数据模型](./data-model.md) 中我们会对这个表结构做详细介绍。 --- ## 向量数据类型 ## 概述 在人工智能领域,向量是一种重要的数据类型,用于表示数据集中的特征或者样本。向量可以用于许多机器学习和深度学习算法中,如推荐系统、自然语言处理和图像识别。引入向量类型后,GreptimeDB 可以更有效地支持这些 AI 应用,提供强大的向量存储和计算能力。 ## 基本介绍 在 GreptimeDB 中,向量表示为固定维度的 Float32(32 位浮点数)数组。创建向量类型列时,必须指定向量的维度,并且维度在定义后不能更改。 ## 定义向量类型列 在 SQL 中,可以通过以下语法来定义包含向量类型的表。需要注意的是,维度 `` 必须是一个正整数,用于定义向量的长度。 ```sql CREATE TABLE ( ... VECTOR() ); ``` 例如,定义一个具有维度 3 的向量类型列的表: ```sql CREATE TABLE vecs ( ts TIMESTAMP TIME INDEX, vec_col VECTOR(3) ); ``` ## 向量写入 在 GreptimeDB 中,你可以通过多种方式将向量数据写入数据库。最简单的方法是使用字符串形式,并通过隐式转换将其存储为向量。字符串需要用方括号 `[]` 包围。以下是使用隐式转换的 SQL 示例: ```sql INSERT INTO () VALUES ('[, , ...]'), ('[, , ...]'), ... ('[, , ...]'); ``` 例如,插入 3 个三维向量: ```sql INSERT INTO vecs (ts, vec_col) VALUES ('2024-11-18 00:00:01', '[1.0, 2.0, 3.0]'), ('2024-11-18 00:00:02', '[4.0, 5.0, 6.0]'), ('2024-11-18 00:00:03', '[7.0, 8.0, 9.0]'); ``` 如果你希望更明确地控制数据转换,可以使用 `parse_vec` 函数来显式地解析字符串为向量: ```sql INSERT INTO vecs (ts, vec_col) VALUES ('2024-11-18 00:00:01', parse_vec('[1.0, 2.0, 3.0]')), ('2024-11-18 00:00:02', parse_vec('[4.0, 5.0, 6.0]')), ('2024-11-18 00:00:03', parse_vec('[7.0, 8.0, 9.0]')); ``` ## 向量计算 GreptimeDB 支持多种向量函数,用于计算向量之间的相似度,包括 `vec_l2sq_distance`、`vec_cos_distance` 和 `vec_dot_product`。这些函数在 AI 应用中用于搜索最接近的内容。 可以使用以下 SQL 格式执行向量计算: ```sql SELECT (, ) FROM ; ``` 例如,若要查找与给定向量 `[5.0, 5.0, 5.0]` 具有最小平方欧几里得距离的向量,并显示它们之间的距离,可以使用如下查询: ```sql SELECT vec_to_string(vec_col), vec_l2sq_distance(vec_col, '[5.0, 5.0, 5.0]') AS distance FROM vecs ORDER BY distance; ``` 执行此查询后,您将得到类似以下的结果: ``` +-----------------------------+----------+ | vec_to_string(vecs.vec_col) | distance | +-----------------------------+----------+ | [4,5,6] | 2 | | [1,2,3] | 29 | | [7,8,9] | 29 | +-----------------------------+----------+ 3 rows in set (0.01 sec) ``` 通过这种方式,GreptimeDB 可以帮助你快速识别和查找相似的数据向量,为 AI 应用提供强大的支持。 更多关于向量计算函数的信息,请参阅[向量函数参考文档](/reference/sql/functions/vector.md)。 --- ## Region Balancer 该插件用于均衡 Datanode 上的 Region 写入负载,通过指定的窗口大小和负载阈值来避免频繁的 Region 迁移。可通过添加以下配置至 Metasrv 开启 Region Rebalancer 功能。 ```toml [[plugins]] [plugins.region_balancer] window_size = "45s" window_stability_threshold = 2 min_load_threshold = "10MB" tick_interval = "45s" ``` ## 配置项说明 - `window_size`: string - **说明**: 滑动窗口的时间跨度,用于计算区域负载的短期平均值。窗口期内的负载变化会被平滑,减轻短期突增对负载均衡的影响。 - **单位**: 时间(支持格式:`"45s"` 表示 45 秒)。 - **建议**: 根据集群负载波动情况配置,较大的窗口会使负载均衡响应更平稳。 - `window_stability_threshold`: integer - **说明**: 连续多少个窗口必须满足触发条件后,才会进行迁移操作。该阈值用于防止频繁的平衡操作,只在持续不均衡的情况下进行 Region 迁移。 - **建议**: 较大的值会延迟再平衡的触发,适用于负载波动较大的系统;值为 2 表示需要至少两个连续窗口符合条件。 - `min_load_threshold`: string - **说明**: 触发 Region 迁移的最小写负载阈值(每秒字节数)。当节点的负载低于该值时,将不会触发迁移。 - **单位**: 字节(例如,`"10MB"` 表示 10 MiB)。 - **建议**: 设置为合理的最小值,防止小负载情况触发迁移。值可以根据系统实际流量进行调整。 - `tick_interval`: string - **说明**: 平衡器的运行间隔时间,控制负载均衡任务的触发频率。 - **单位**: 时间(例如,"45s" 表示 45 秒)。 - **建议**: 根据系统的响应速度和负载变化频率设置。较短的间隔可以更快响应负载变化,但可能增加系统开销。 --- ## 管理控制台 GreptimeDB 企业版管理控制台是标准 GreptimeDB 仪表板的增强版本,为企业用户提供更全面的集群可观测性与运维能力。 ## 集群概览 **Overview** 页面展示集群整体运行状态和资源使用情况。 - **Service Overview**:CPU、内存、存储使用率;数据写入速率;各协议请求速率。 - **Storage Overview**:数据库数、表数、区域数;Manifest、WAL、Index 文件大小。 - **Cluster**:节点类型;节点运行状态与资源使用率。 ![Overview](/enterprise-console-overview.png) ## 运维操作 **Region Management** 提供 Region 级别的运维能力。 - **Datanodes 视角**:查看各数据节点及 Region 详情,包括 Region ID、所属表、存储大小、WAL/Manifest/Index 占用、行数。 - **Tables 视角**:按表查看 Region 分布,支持展开查看 Region 信息。 - **Region 维护**:支持 Flush 与 Compact。 - **Region 迁移**:将 Region 从一个节点迁移到另一个节点,支持超时配置和实时迁移状态展示。 ![Region Management - Datanodes](/enterprise-console-region-datanodes.png) ![Region Management - Tables](/enterprise-console-region-tables.png) ## 数据管理 **Data Management** 页面提供 SQL/PromQL 查询、数据写入、日志查询、日志管道、链路追踪和 Flow 管理等功能。这些功能与开源版 Dashboard 和 Cloud Dashboard 保持一致,此处不再展开说明。 ## 监控功能 **Monitoring** 页面提供全方位的指标与日志监控。 ### 指标监控(Metrics) 提供多个分组的监控指标,包括 Overview、Ingestion、Queries、Resources、Frontend Requests、Frontend to Datanode、Mito Engine、OpenDAL、Metasrv 和 Flownode,覆盖集群运行状态、请求速率、延迟、资源使用等关键数据。 ![Metrics](/enterprise-console-monitor-metrics.png) ### 实例日志搜索(Instance Logs) 支持按角色、实例、日志级别、时间范围和关键词筛选集群日志,结果可导出为 JSON。 ![Instance Logs](/enterprise-console-instance-logs.png) ### 慢查询分析(Slow Query) 展示执行时间较长的 SQL/PromQL 查询,支持查看耗时、语句详情,并可使用 **Explain Query** 分析执行计划。 ![Slow Query](/enterprise-console-slow-query.png) --- ## LDAP 鉴权 除了 GreptimeDB OSS 中内置的 [Static User Provider](/user-guide/deployments-administration/authentication/static.md), GreptimeDB Enterprise 还提供了连接到外部 LDAP 服务器进行身份验证的功能。 ## 配置 与 [PostgreSQL 中的 LDAP 机制相似](https://www.postgresql.org/docs/current/auth-ldap.html),在 GreptimeDB 中,LDAP 鉴权也分为两种模式:"simple bind" 和 "search bind"。 在 "simple bind" 模式下,GreptimeDB 会构造一个格式为 `{prefix}{username}{suffix}` 的 "DN"(distinguished name) ,并使用客户端传来的密码向 LDAP 服务发起”绑定 (bind)“。绑定的结果就是鉴权的结果。一个典型配置是,`prefix` 参数指定 `cn=`, `suffix` 用于指定 DN 的其余部分。`username` 将会被替换为客户端发来的用户名。 以下一个 LDAP user provider "simple bind" 模式的配置文件示例: ```toml # LDAP 服务地址。 server = "127.0.0.1" # LDAP 服务端口。 port = 636 # 设置为 "ldap" 以使用 LDAP scheme,"ldaps" 以使用 LDAPS。 # GreptimeDB 和 LDAP 服务之间的连接一开始时是未加密的。连接建立后升级到 TLS。这是 LDAPv3 的 "StartTLS" 标准。 scheme = "ldaps" # LDAP 鉴权模式。`bind = "simple"` 和 `bind = "search"` 只能选择其一。 [auth_mode] # 以下配置仅在 simple bind 模式下使用: bind = "simple" # 当进行 simple bind 鉴权时,用于构造绑定 DN 的前缀。 prefix = "cn=" # 当进行 simple bind 鉴权时,用于构造绑定 DN 的后缀。 suffix = ",dc=example,dc=com" ``` 在 "search bind" 模式中,GreptimeDB 首先会使用配置文件中设置的固定用户名和密码(`bind_dn` 和 `bind_passwd`)尝试绑定到 LDAP 目录。然后 GreptimeDB 会在 LDAP 目录中搜索尝试登录到数据库的用户。搜索将在 `base_dn` 下的子树中进行,由 `search_filter` 过滤,并尝试对 `search_attribute` 中指定的属性进行精确匹配。一旦在搜索中找到用户,GreptimeDB 会以此用户重新绑定到目录,使用客户端指定的密码,以验证登录是否正确。这种方法允许用户对象在 LDAP 目录中的位置更加灵活,但会导致向 LDAP 服务器发出两个额外的请求。 以下 toml 片段展示了 GreptimeDB LDAP user provider "search bind" 模式的配置文件示例。在上面的 "simple bind" 模式配置文件中显示的 `server`、`port` 和 `scheme` 的公共部分被省略了: ```toml [auth_mode] # 以下配置仅在 search bind 模式下使用: bind = "search" # 进行 search bind 鉴权时,开始搜索用户的根 DN。 base_dn = "ou=people,dc=example,dc=com" # 进行 search bind 鉴权时,首先进行绑定的用户 DN。 bind_dn = "cn=admin,dc=example,dc=com" # 进行 search bind 鉴权时,首先进行绑定的用户密码。 bind_passwd = "secret" # 进行 search bind 鉴权时,用于匹配的用户属性。 # 如果未指定属性,则将使用 uid 属性。 search_attribute = "cn" # 进行 search bind 鉴权时,使用的搜索过滤器。 # "$username" 将被替换为客户端传来的用户名。 # 这允许比 search_attribute 更灵活的用户搜索。 search_filter = "(cn=$username)" ``` ## 在 GreptimeDB 中使用 LDAP User Provider 要使用 LDAP User Provider,首先参照上文配置你的 LDAP 鉴权模式,然后在启动 GreptimeDB 时使用 `--user-provider` 参数,将其设置为 `ldap_user_provider:`。例如,如果你有一个配置文件是 `/home/greptimedb/ldap.toml`,你可以使用以下命令启动一个 standalone GreptimeDB: ```shell greptime standalone start --user-provider=ldap_user_provider:/home/greptimedb/ldap.toml ``` 现在你就可以使用你的 LDAP 用户账户创建一个连接到 GreptimeDB 了。 :::tip 注意 如果你使用 MySQL CLI 连接到配置了 LDAP User Provider 的 GreptimeDB,你需要在 MySQL CLI 中指定 `--enable-cleartext-plugin`。 ::: --- ## 备份 ## 备份元数据 GreptimeDB 集群的元数据存储可以存储在 etcd 或者关系数据库中。对于重要的集群,建议使用云厂商提供的关系数据库服务(rds)并开启定期备份功能。 请参考[元数据导出与导入工具](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-meta-data.md) 了解更多细节。 ## 备份数据库 由于对象存储一般会存储多个副本,如果 GreptimeDB 的数据存储在对象存储上,则通常无需再额外备份数据库。你也可以考虑开启对象存储的多版本特性,以避免出现误操作导致的数据丢失。 你还可以使用 GreptimeDB 的 `COPY DATABASE` 功能来创建备份。 请参考[数据导出和导入工具](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data.md)文档了解更多信息。 --- ## 部署具有 Datanode 组的 GreptimeDB 集群 在本指南中,你将学习如何在 Kubernetes 上部署具有 datanode 组的 GreptimeDB 集群,该组由多个 datanode 实例组成。 :::tip NOTE 此功能仅适用于企业版。请勿使用开源镜像启用此功能。如果你想使用此功能,请联系[我们](https://greptime.cn/contactus)。 ::: ## 先决条件 - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.18.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [GreptimeDB Operator](https://github.com/GrepTimeTeam/greptimedb-operator) >= v0.3.0 ## 升级 operator 安装 GreptimeDB Operator,将镜像版本设置为大于或等于 `v0.3.0`。 有关升级 operator 的详细说明,请参阅 [GreptimeDB Operator 管理](/user-guide/deployments-administration/deploy-on-kubernetes/greptimedb-operator-management.md#升级)指南。 ## Datanode 组配置 在企业版中,你可以配置 **datanode 组**来将读写工作负载分离到不同的组中。 datanode 接受 `workload_types` 字段来区分其工作负载类型。支持的类型有 **`hybrid`**、**`query`** 和 **`ingest`**: * **`hybrid`** 是默认值,作为 `query` 和 `ingest` 的超集,允许 datanode 处理两种工作负载。 * **`query`** 为读负载优化,datanode 只处理读负载。 * **`ingest`** 为写负载优化,datanode 只处理写负载。 虽然 `hybrid` 很方便,但在同一个 datanode 上同时进行读写操作可能会相互干扰,例如,一个大查询可能占用过多资源,从而影响在线写入。为了获得最佳性能,建议将读写工作负载分离到不同的 datanode 组中。 在配置 datanode 组时,确保每个组都包含 `name` 字段。以下 `values.yaml` 示例展示了如何定义单独的 datanode 组: ```yaml danodata: enabled: false datanodeGroups: - name: write replicas: 1 config: | workload_types = ["ingest"] template: main: resources: requests: cpu: '4' memory: 8Gi storage: fs: storageClassName: ${storageClassName} storageSize: 100Gi - name: read replicas: 1 config: | workload_types = ["query"] template: main: resources: limits: cpu: '8' memory: 16Gi meta: replicas: 1 backendStorage: etcd: endpoints: - "etcd.etcd-cluster.svc.cluster.local:2379" frontend: replicas: 1 ``` 有关为 Metasrv 配置替代元数据存储后端的指导,请参阅[元数据存储配置](/user-guide/deployments-administration/manage-metadata/configuration.md)文档。 你可以使用以下命令应用上述配置: ``` helm upgrade --install ${release-name} greptime/greptimedb-cluster --namespace ${namespace} -f values.yaml ``` ## 校验安装 检查 Pod 的状态: ```bash kubectl get pods -n ${namespace} NAME READY STATUS RESTARTS AGE ${release-name}-datanode-read-0 1/1 Running 0 30s ${release-name}-datanode-write-0 1/1 Running 0 30s ${release-name}-flownode-0 1/1 Running 0 60s ${release-name}-frontend-774c76cffc-znvrw 1/1 Running 0 30s ${release-name}-meta-58977b7897-8k2sf 1/1 Running 0 90s ``` ## 后续步骤 - 为了获得最佳性能,建议[配置 frontend 组](/user-guide/deployments-administration/deploy-on-kubernetes/configure-frontend-groups.md),这确保读写流量的完全分离,实现最大隔离。 - 为你的表添加读副本,请参阅[读副本](/enterprise/read-replicas/overview.md)。 --- ## GreptimeDB 企业版部署指南 ## 环境准备 - [Docker](https://docs.docker.com/get-started/get-docker/) >= v23.0.0 - [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) >= v1.21.0 - [Helm](https://helm.sh/docs/intro/install/) >= v3.0.0 - [kubernetes](https://kubernetes.io/) >= 1.21 ## 前言 GreptimeDB 企业版部署包括以下组件: 1. GreptimeDB Operator:用于和 Kubernetes 集群交互。 2. KV 存储:用于存储数据库元数据信息(支持云服务或自建),推荐使用云服务中的 RDS,例如 AWS RDS PostgreSQL。可选以下存储设施: - PostgreSQL - MySQL - ETCD 3. GreptimeDB 数据库集群,包含以下组件: - Meta:数据库集群元数据信息管理组件 - Datanode:数据节点 - Frontend:入口和协议解析节点 - Flownode(可选): 流计算节点 - Vector Sidecar:指标采集 agent - GreptimeDB Standalone: 集群自监控存储节点 4. GreptimeDB Enterprise Dashboard 5. Kafka(可选): 为 GreptimeDB 提供 Remote WAL 6. MinIO(可选): 为 GreptimeDB 提供对象存储,推荐使用云服务中的对象存储(例如:AWS S3) 其中打`*`的为可选安装: | Pod 组件名称 | 副本数量 | CPU (Core) | 内存 (GB) | 磁盘 (Gi) | |---------------------------------|------|------------|---------|---------| | ETCD`*` | 3 | 2 | 4 | 10 | | GreptimeDB Operator | 1 | 1 | 1 | | | Meta | | | | | | Datanode | | | | | | Frontend | | | | | | Flownode`*` | | | | | | Vector Sidecar | | | | | | GreptimeDB Standalone | 1 | 4 | 8 | | | GreptimeDB Enterprise Dashboard | 1 | | | | | Kafka`*` | 3 | | | | | MinIO`*` | 4 | | | | ## 部署 GreptimeDB Operator 参考 [GreptimeDB Operator 的管理文档](/user-guide/deployments-administration/deploy-on-kubernetes/greptimedb-operator-management.md)获取详细的安装步骤。 ## 部署 ETCD (可选) 参考 [管理 ETCD](/user-guide/deployments-administration/manage-metadata/manage-etcd.md)获取详细的安装步骤。 ## 部署 Kafka (可选) 参考 [部署 Kafka 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-kafka.md)获取详细的安装步骤。 ## 部署 MinIO (可选) 参考 [部署 MinIO 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-minio.md)获取详细的安装步骤。 ## 部署 GreptimeDB 基础设施测试 参考 [部署 GreptimeDB 基础设施测试](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-infra-test.md) 获取详细的安装步骤,将测试结果告诉 Greptimeteam。 ## 安装及启动 GreptimeDB ### 获取 GreptimeDB 企业版镜像 GreptimeDB 企业版以 docker 镜像发布。我们为每位客户提供了一个单独的、托管在阿里云上的私有 docker 仓库,你可以使用 docker pull 命令直接拉取,或在 helm chart 中配置。 你需要在 helm chart 的 `values.yaml` 文件中配置镜像信息以获得专属的 GreptimeDB 企业版,例如: ```yaml customImageRegistry: enabled: true # -- pull secret 名称,可自定义,需要和 `image.pullSecrets` 保持一致 secretName: greptimedb-custom-image-pull-secret registry: username: password: image: registry: repository: tag: pullSecrets: - greptimedb-custom-image-pull-secret ``` 上述配置中, `customImageRegistry` 中的 `registry`、`username` 和 `password` 用于创建 k8s 的 pull secret, `image` 中的 `registry`、`repository` 和 `tag` 用于指定 GreptimeDB 企业版镜像, 因此 `customImageRegistry.secretName` 和 `image.pullSecrets` 需要保持一致以保证拉取镜像时能够找到正确的认证信息。 请联系 Greptime 工作人员获取上述配置项的具体值。 Greptime 工作人员在首次交付给你 GreptimeDB 企业版时,会通过邮件或其他方式告知你镜像仓库地址和用户名密码。请妥善保存,并切勿分享给外部人员! ### 配置管理 以下为有助于帮助配置的工具和文档: - 工具: https://enterprise-wizard.greptime.com/ - 文档: [common-helm-chart-configurations](/user-guide/deployments-administration/deploy-on-kubernetes/common-helm-chart-configurations.md) 在安装之前,你需要创建一个文件来配置 GreptimeDB 集群,请根据你的 Kubernetes 环境调整,以下是 `greptimedb-cluster-values.yaml` 的参考配置: ```yaml customImageRegistry: enabled: true # -- pull secret 名称,可自定义,需要和 `image.pullSecrets` 保持一致 secretName: greptimedb-custom-image-pull-secret registry: username: password: image: registry: repository: tag: pullSecrets: - greptimedb-custom-image-pull-secret additionalLabels: {} initializer: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: greptime/greptimedb-initializer tag: "v0.6.0" # -- Meta 配置 meta: # -- Meta 副本数 replicas: 2 backendStorage: # 可选 # KV 存储配置,本配置连接到 ETCD etcd: endpoints: ["etcd.etcd-cluster.svc.cluster.local:2379"] # 以下是一个使用 PostgreSQL 作为 KV 存储的示例 # postgresql: # host: "postgres.default.svc.cluster.local" # port: 5432 # database: "metasrv" # table: "greptime_metakv" # electionLockID: 1 # credentials: # secretName: "meta-postgresql-credentials" # username: "root" # password: "root" # 以下是一个使用 MySQL 作为 KV 存储的示例 # mysql: # host: "mysql.default.svc.cluster.local" # port: 3306 # database: "metasrv" # table: "greptime_metakv" # electionLockID: 1 # credentials: # secretName: "meta-mysql-credentials" # username: "root" # password: "root" rbac: create: true podTemplate: serviceAccount: create: true main: # Meta 资源配置 resources: requests: cpu: '2' memory: 4Gi limits: cpu: '2' memory: 4Gi affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: app.greptime.io/component: greptimedb-meta topologyKey: kubernetes.io/hostname weight: 1 # -- Datanode 配置 datanode: # -- Datanode 副本数量 replicas: 3 # -- Datanode 配置 configData: |- [[region_engine]] [region_engine.mito] write_cache_size = "20G" write_cache_ttl = "7d" podTemplate: # serviceAccount: # # 是否创建 service account # create: false # # 添加 service account 注释 # annotations: {} main: # -- Datanode 资源设置 resources: requests: cpu: '8' memory: 16Gi limits: cpu: '8' memory: 16Gi affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: app.greptime.io/component: greptimedb-datanode topologyKey: kubernetes.io/hostname weight: 1 # -- Datanode 本地磁盘配置 storage: storageClassName: null # -- 本地磁盘大小 storageSize: 100Gi # -- Storage retain policy for datanode persistent volume storageRetainPolicy: Retain # -- Frontend 配置 frontend: # -- Frontend 副本数 replicas: 3 podTemplate: main: # Frontend 资源配置 resources: requests: cpu: '8' memory: 16Gi limits: cpu: '8' memory: 16Gi affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: app.greptime.io/component: greptimedb-frontend topologyKey: kubernetes.io/hostname weight: 1 # -- Flownode 配置 flownode: # -- 是否部署 flownode enabled: false # -- Flownode 副本数 replicas: 1 podTemplate: main: resources: requests: cpu: '8' memory: 16Gi limits: cpu: '8' memory: 16Gi # -- 数据库自监控配置 monitoring: # -- 打开自监控 enabled: true # -- 监控数据的默认保留时间 ttl: 30d standalone: base: # serviceAccountName: "greptimedb-datanode" imagePullSecrets: - name: "greptimedb-custom-image-pull-secret" main: # 自监控资源配置 resources: requests: cpu: '4' memory: 8Gi limits: cpu: '4' memory: 8Gi # 自监控 standalone 存储位置,可按需打开存放至对象存储 # objectStorage: # cache: # cacheCapacity: "50GiB" # s3: # secretName: "storage-credentials" # bucket: "greptimedb-bucket" # region: "ap-southeast-1" # root: "greptimedb-monitor-data" # endpoint: "http://minio.minio:9000" # 自监控本地磁盘大小 datanodeStorage: fs: storageClassName: null storageSize: 100Gi # sidecar vector 配置 vector: registry: greptime-registry.cn-hangzhou.cr.aliyuncs.com repository: timberio/vector tag: "0.49.0-debian" # sidecar vector 资源配置 resources: requests: cpu: '1' memory: "1Gi" limits: cpu: '1' memory: "1Gi" # 对象存储相关配置,按需打开 # 使用 MinIO # objectStorage: # cache: # cacheCapacity: "50GiB" # s3: # bucket: "greptimedb-bucket" # region: "ap-southeast-1" # root: "greptimedb-data" # endpoint: "http://minio.minio:9000" # 打开企业版用户和权限配置 auth: enabled: true useBuiltIn: true mountPath: "/etc/greptimedb/auth" fileName: "passwd" users: # 默认的 admin 用户名,按需修改 - username: "superuser" # 初始化 admin 账户的密码,按需修改 password: "1fa44bbc-5ded-42bd-a3f1-c3621affce63" permission: "admin" # Remote WAL相关配置,按需打开 # remoteWal: # enabled: true # kafka: # brokerEndpoints: # - "kafka-broker-0.kafka-broker-headless.kafka.svc.cluster.local:9092" # - "kafka-broker-1.kafka-broker-headless.kafka.svc.cluster.local:9092" # - "kafka-broker-2.kafka-broker-headless.kafka.svc.cluster.local:9092" ``` ### 启动 GreptimeDB 在 `greptimedb` 命名空间中安装 GreptimeDB 集群: ```bash helm upgrade --install greptimedb \ --create-namespace \ oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/greptimedb-cluster \ -n greptimedb --values greptimedb-cluster-values.yaml ``` 验证 GreptimeDB 安装: ```bash kubectl get pod -n greptimedb ```
预期输出 ```bash NAME READY STATUS RESTARTS AGE greptimedb-datanode-0 2/2 Running 0 2m33s greptimedb-datanode-1 2/2 Running 0 2m33s greptimedb-datanode-2 2/2 Running 0 2m33s greptimedb-frontend-74999c79cc-pzj8w 2/2 Running 0 17s greptimedb-frontend-74999c79cc-rm2fb 2/2 Running 0 17s greptimedb-frontend-74999c79cc-zbtdg 2/2 Running 0 17s greptimedb-meta-56dc894867-jpt5c 2/2 Running 0 4m29s greptimedb-meta-56dc894867-tpw4c 2/2 Running 0 4m29s greptimedb-meta-56dc894867-wmh1t 2/2 Running 0 4m29s greptimedb-monitor-standalone-0 1/1 Running 0 4m42s ```
## 部署 Enterprise Dashboard ### 配置管理 在安装之前,你需要创建一个文件 `dashboard-values.yaml` 来配置 dashboard,以下是配置示例: ```yaml replicaCount: 1 image: # 请咨询 Greptime 工作人员获取 repository: tag: pullPolicy: IfNotPresent imagePullSecrets: - name: greptimedb-custom-image-pull-secret nameOverride: "" fullnameOverride: "" config: | servicePort: 19095 logLevel: info enableLicenseManager: true enableUserAuthentication: true backendStore: type: sqlite sqlite: dataDir: /data provisionedInstances: - name: greptimedb namespace: greptimedb type: cluster settings: basic: url: http://greptimedb-frontend.greptimedb.svc.cluster.local:4000 meta_url: http://greptimedb-meta.greptimedb.svc.cluster.local:4000 monitoring: greptimedb: url: http://greptimedb-monitor-standalone.greptimedb.svc.cluster.local:4000 license: secret_name: greptimedb-license secret_namespace: greptimedb servicePort: 19095 serviceAccount: create: true annotations: {} name: "" podAnnotations: {} podSecurityContext: {} # fsGroup: 2000 securityContext: {} service: type: ClusterIP port: 19095 annotations: {} # dashboard 资源配置 resources: requests: cpu: '1' memory: 1Gi limits: cpu: '1' memory: 1Gi nodeSelector: {} tolerations: [] affinity: {} ``` ### 安装 ```bash helm upgrade --install greptimedb-enterprise-dashboard \ oci://greptime-registry.cn-hangzhou.cr.aliyuncs.com/charts/greptimedb-enterprise-dashboard \ -n greptimedb \ --values dashboard-values.yaml ``` 验证 Enterprise Dashboard 安装: ```bash kubectl get pod -n greptimedb | grep enterprise-dashboard ```
预期输出 ```bash greptimedb-enterprise-dashboard-67f498d6f9-n89z5 1/1 Running 0 27s ```
```bash kubectl get svc -n greptimedb | grep enterprise-dashboard ```
预期输出 ```bash greptimedb-enterprise-dashboard ClusterIP 10.96.80.175 19095/TCP 89s ```
### 登录 访问 dashboard service 的 19095 端口进行登录 ![Enterprise Dashboard Login](/enterprise-dashboard-login.png) 使用数据库部署配置中的 `auth.users[0].username` 和 `auth.users[0].password` 登录。有关更多控制台操作的参考[文档](/enterprise/console-ui.md)。 --- ## 在 Kubernetes 上部署 GreptimeDB(Deploy-on-kubernetes) GreptimeDB 企业版在 Kubernetes 上的部署流程与开源版基本一致,本章节将重点介绍企业版特有的部署配置和功能。 ## 安装 要了解如何通过 Helm Chart 启动 GreptimeDB 企业版,请前往[安装 GreptimeDB](./installation.md) 页面。 ## 升级 请前往[升级 GreptimeDB](./upgrade.md) 页面了解如何升级 GreptimeDB。 --- ## 升级 ## 直接升级 单独升级 GreptimeDB 企业版的镜像非常简单,只需要在 helm chart 中修改 `tag` 后重启即可。 ## 不使用 GreptimeDB Operator 升级集群 在不使用 GreptimeDB Operator 升级集群时,在操作各组件之前(例如,滚动升级 Datanode 节点),必须手动开启 Metasrv 的运维模式。升级完成后,需等待所有组件状态恢复健康,再关闭 Metasrv 的运维模式。在开启 Metasrv 运维模式后,集群中的 Auto Balancing(如启用)以及 Region Failover(如启用)机制将暂停触发,直至运维模式关闭。 请参考[管理运维模式](/user-guide/deployments-administration/maintenance/maintenance-mode.md#管理维护模式)了解如何开启和关闭运维模式。 --- ## 基于双活互备的 DR 解决方案 在 GreptimeDB 的“双活互备”架构中,通常部署两个节点(例如节点 A 与节点 B): - 两个节点都对外提供完整服务能力。 - 两个节点互为主从,角色是对等的,不存在长期固定的单主节点。 - 写入采用双向异步复制,任一节点接收到写请求后都会异步复制到对端节点。 - GreptimeDB 的架构防止了循环复制的问题。 - 查询在各自节点本地执行,不需要跨节点合并查询结果。 该模式的目标是:在不引入第三个计算节点或管理节点的前提下,以较低架构复杂度获得跨节点容灾能力。 ## 架构与读写路径 ### 写入路径 1. 客户端将写请求发送到节点 A(或节点 B)。 2. 发起节点本地落盘,写请求视为成功(返回给客户端)。 3. 发起节点将写请求异步复制到对端节点。 - 若累积的未复制成功的写请求过多(具体数值可配置),发起节点可暂停客户端写入,以达到 RPO 和 RTO 的目标。 ### 查询路径 - 客户端连接哪个节点,就在该节点本地执行查询。 - 不依赖双节点实时查询合并。 - 只要任一节点可用,查询链路就可以继续提供服务。 - 由于异步复制的特性,我们在此架构中可获得数据的最终一致性(eventually consistency)。 ## RPO 与 RTO ### RPO RPO 可通过不同的配置来达到不同的效果。 核心的配置是节点预留给待复制的写入请求的空间大小。 若该空间大小为 `0`(字节),则异步复制退化为同步复制,RPO 为 0。 配置为其他值时,RPO 的值可根据写入请求的大小和速度动态计算。 ### RTO RTO 的值和节点切换方式有关,不同的节点切换方法和配置可获得不同的 RTO 目标。 见下文“故障切换实现方式”部分。 ## 故障切换实现方式 为了保持我们的双活互备架构的最低需求,我们没有要求第三个节点或第三个服务来处理 GreptimeDB 的故障转移。一般来说,有几种方法可以处理故障转移: - 通过一个 LoadBalancer。如果你可以额外腾出另一个节点来部署一个 LoadBalancer 如 [HAProxy](https://www.haproxy.org/),或者你有其他 LoadBalance 服务,我们推荐这种方式。 - 通过客户端 SDK 的故障转移机制。例如,如果你使用 MySQL Connector/j,你可以通过在连接 URL 中设置多个主机和端口来配置故障转移(参见其[文档](https://dev.mysql.com/doc/connector-j/en/connector-j-config-failover.html) )。PostgreSQL 的驱动程序[也有相同的机制](https://jdbc.postgresql.org/documentation/use/#connection-fail-over) 。这是处理故障转移最简单的方法,但并不是每个客户端 SDK 都支持这种故障转移机制。 - 内部的 endpoint 更新机制。如果你可以检测到节点的故障,那么就可以在你的代码中更新 GreptimeDB 的 endpoint。 :::tip NOTE 请参考 "[解决方案比较](/user-guide/deployments-administration/disaster-recovery/overview.md#解决方案比较)" 来比较不同灾难恢复解决方案的 RPO 和 RTO。 ::: ## 总结 GreptimeDB 双活互备 DR 方案的核心是: - 两节点互为主从、双向异步复制写入。 - 查询在各自节点本地执行。 - 通过外部故障切换机制保障业务在单节点故障时快速恢复。 在该模式下,架构简单、RPO 和 RTO 目标明确且可配置。 该解决方案比较适合用在中小规模的业务场景中。 --- ## 灾难恢复(Disaster-recovery) 作为分布式数据库,GreptimeDB 提供了不同的灾难恢复(DR)解决方案。 请参考 GreptimeDB OSS 文档中的[灾难恢复概述](/user-guide/deployments-administration/disaster-recovery/overview.md)了解 Greptime 提供的所有灾难恢复解决方案。本章节仅介绍在 GreptimeDB Enterprise 中提供的解决方案。 - [基于双活互备的 DR 解决方案](./dr-solution-based-on-active-active-failover.md) --- ## 审计日志 数据库的审计日志记录了对数据库执行的操作。审计日志有助于监控用户活动,检测可疑操作,并确保组织内外的合规性。本文档提供了 GreptimeDB 中审计日志的概述以及如何配置它。 ## 概述 一条在 GreptimeDB 上执行的语句(SQL 或 PromQL)会被记录在审计日志中(当然,前提是已经将其配置为需要被审计)。以下是审计日志中的一条示例记录: ```json { "time": "2024-11-05T06:13:19.903713Z", "user": "greptime_user", "source": "Mysql", "class": "Ddl", "command": "Create", "object_type": "Database", "object_names": [ "audit_test" ], "statement": "CREATE DATABASE audit_test" } ``` 正如您所见,一条审计日志的记录被格式化为 JSON 字符串。它包含以下字段: - `time`: 语句执行的时间。格式为带有 UTC 时区的 ISO 8601 日期和时间的字符串。 - `user`: 发送该请求的用户。 - `source`: 请求的来源,也即用于连接到 GreptimeDB 的协议。 - `class`: 语句的类别,如 "Read"、"Write" 或 "DDL" 等。 - `command`: 语句的命令,如 "Select"、"Insert" 或 "Create" 等。 - `object_type`: 语句操作的对象的类型,如 "Database"、"Table" 或 "Flow" 等。 - `object_names`: 语句操作的对象的名称。 - `statement`: 语句本身。 ## 配置 审计日志作为 GreptimeDB 的插件提供。要启用并配置它,请将以下 TOML 添加到 GreptimeDB 配置文件中: ```toml [[plugins]] # 将审计日志插件添加到 GreptimeDB 中。 [plugins.audit_log] # 是否启用审计日志,默认为 true。 enable = true # 存储审计日志文件的目录。默认为 "./greptimedb_data/logs/"。 dir = "./greptimedb_data/logs/" # 允许审计的语句的来源。此选项作为过滤器:如果语句不来自这些配置的来源之一,则不会记录在审计日志中。 # 多个来源用逗号(",")分隔。 # 所有可配置的来源是 "Http"、"Mysql" 和 "Postgres"。 # 一个特殊的 "all"(默认值)表示所有来源。 sources = "all" # 允许审计的语句的类别。此选项作为过滤器:如果语句的类别不匹配这些配置的值之一,则不会记录在审计日志中。 # 多个类别用逗号(",")分隔。 # 所有可配置的类别是 "Read"、"Write"、"Admin"、"DDL" 和 "Misc"。 # 一个特殊的 "all" 表示所有类别。默认值为 "DDL" 和 "Admin"。 classes = "ddl,admin" # 允许审计的语句的命令。此选项作为过滤器:如果语句的命令不匹配这些配置的值之一,则不会记录在审计日志中。 # 多个命令用逗号(",")分隔。 # 所有可配置的命令是 "Promql"、"Select"、"Copy"、"Insert"、"Delete"、"Create"、"Alter"、"Truncate"、"Drop"、"Admin" 和 "Misc"。 # 一个特殊的 "all"(默认值)表示所有命令。 commands = "all" # 允许审计的对象类型。此选项作为过滤器:如果语句的目标对象不匹配这些配置的值之一,则不会记录在审计日志中。 # 多个对象类型用逗号(",")分隔。 # 所有可配置的对象类型是 "Database"、"Table"、"View"、"Flow"、"Index" 和 "Misc"。 # 一个特殊的 "all"(默认值)表示所有对象类型。 object_types = "all" # 保留的审计日志文件的最大数量。默认为 30。 # 审计日志每天生成一个新的。 max_log_files = 30 ``` ## 注意 如果没有正确配置的话,审计日志可能会非常庞大。例如,在业务繁忙的 GreptimeDB 中,将 "`all`" 设置给所有的 `sources`,`classes`, `commands` 和 `object_types` 会记录在 GreptimeDB 上执行的所有语句,导致一个非常大的审计日志文件。这可能会轻易地耗尽磁盘空间。因此,强烈建议合理地配置审计日志插件以避免这种情况。 --- ## 检查 GreptimeDB 状态(Monitoring) 请参考[开源 GreptimeDB 文档](/user-guide/deployments-administration/monitoring/check-db-status.md)了解如何检查 GreptimeDB 的健康状态。 --- ## 运维关键日志(Monitoring) GreptimeDB 在运行过程中,会将一些关键的操作以及预期外的错误信息输出到日志中。 你可以通过这些日志了解 GreptimeDB 的运行情况,以及排查错误出现的原因。 ## GreptimeDB 运维日志 请参考 GreptimeDB OSS 文档中的[重要日志](/user-guide/deployments-administration/monitoring/key-logs.md)部分。 ## License 过期 对于 GreptimeDB 的企业版,建议监控 license 的到期日志以确保不间断使用企业版功能。 企业版的 license 过期时,metasrv 会打印如下 warning 日志, 这时需要及时联系 Greptime 获取新的 license ```bash License is expired at xxx, please contact your GreptimeDB vendor to renew it ``` --- ## 关键指标监控 监控的关键指标包括 CPU、内存、磁盘 I/O 和网络带宽的使用情况。 ## 告警指标 告警系统各公司一般都有自己使用的,配置方法可能各不相同,因此本文档不列举具体的告警配置方式,只列出部分需要关注的指标,可以基于这些指标配置一个是否长时间(超过数分钟)处于不正常数值的告警。你可以根据实际情况设置告警的水位。 | 指标 | 含义 | 参考规则 | | --- | --- | --- | | `sum(process_resident_memory_bytes{}) by (instance, pod)` | 进程的内存占用 | 占用率持续大于阈值 | | `sum(rate(process_cpu_seconds_total{}[$__rate_interval]) * 1000) by (instance, pod)` | 进程的 CPU 暂用,CPU 显示的是 millicore | 利用率持续大于阈值 | | `sum by(instance, pod) (greptime_mito_write_stall_total{instance=~"$datanode"})` | datanode 积压的写入请求数量 | 持续 n 分钟大于 0 | | `sum(rate(greptime_table_operator_ingest_rows{instance=~"$frontend"}[$__rate_interval]))` | 当前每秒写入的行数 | 持续 n 分钟跌 0(或低于阈值) | | `greptime_mito_compaction_failure_total` | compaction 失败 | 最近新增大于 0 | | `greptime_mito_flush_failure_total` | flush 失败 | 最近新增大于 0 | | `sum by(instance, pod, path, method, code) (rate(greptime_servers_http_requests_elapsed_count{path!~"/health\|/metrics"}[$__rate_interval]))` | HTTP 请求数和返回的响应码 | 响应码 200 的请求数量持续 n 分钟低于阈值或者响应码非 200 的请求数量持续 n 分钟大于正常阈值 | | `sum by (instance, pod) (rate(greptime_mito_write_rows_total{instance=~"$datanode"}[$__rate_interval]))` | 存储引擎写入行数 | 持续 n 分钟低于正常阈值 | Pod 维度还建议配置磁盘告警,当磁盘水位超过某个阈值后进行告警。 此外,也可以根据运维[关键日志](key-logs.md)中所列举的错误日志中的关键字监控以下事件: - Region 续租失败 - Region failover --- ## 监控(Monitoring) 有效的数据库管理很大程度上依赖于监控。 你可以使用以下方法监控 GreptimeDB: --- ## 部署与管理 在阅读本文档之前, 推荐先阅读 GreptimeDB 开源数据库版本的[部署与管理文档](/user-guide/deployments-administration/overview.md), 其文档中涵盖了所有功能企业版同样支持。 下面章节描述的是企业版专属功能: ## 配置与部署 - [在 Kubernetes 上部署 GreptimeDB 企业版](./deploy-on-kubernetes/overview.md): 了解如何获取专用的 GreptimeDB 企业版镜像。 - [LDAP 鉴权](authentication.md): 为 GreptimeDB 企业版提供增强的认证能力。 ## 监控 [监控](./monitoring/overview.md) 章节描述了企业版中所支持的特定指标和日志。 ## 灾难恢复 [灾难恢复](./disaster-recovery/overview.md)提供了确保 GreptimeDB 企业版数据持久性和可用性的策略和最佳实践。 --- ## 聚合查询 ## 指标聚合 在 GreptimeDB 中,指标聚合用于对数值字段进行统计计算,例如求和、平均值、最大值、最小值等。 | Aggregation | 实现情况 | Description | | ----------- | -------- | ------------------------------ | | sum | | 聚合用于计算数值字段的总和。 | | avg | | 聚合用于计算数值字段的平均值。 | | max | | 聚合用于计算数值字段的最大值。 | | min | | 聚合用于计算数值字段的最小值。 | | count | ✅ | 聚合用于计算文档的数量。 | ## 桶聚合 在 GreptimeDB 中,桶聚合用于对文档进行分组,例如按时间、种类等字段进行分桶。 | Aggregation | 实现情况 | Description | | -------------- | -------- | -------------------------------- | | date_histogram | | 聚合用于对时间字段进行分桶。 | | terms | | 聚合用于对指定字段的值进行分组。 | --- ## GreptimeDB Elasticsearch 兼容性概述 # 概述 GreptimeDB 的 Elasticsearch 兼容层旨在提供与 Elasticsearch 的在一定程度上的兼容性,以便用户能够相对轻松地将现有的 Elasticsearch 应用程序迁移到 GreptimeDB。 但是,GreptimeDB 并不完全兼容 Elasticsearch 的所有功能和特性。在某些情况下,用户可能需要对其应用程序进行调整和修改,以便在 GreptimeDB 中实现相同的功能。 ## 原理 本质上 GreptimeDB 是接收 Elasticsearch 的 QueryDSL 语法,并将其转换为 GreptimeDB 的查询语法,并且按照 Elasticsearch API 格式来返回数据。从而实现与 Elasticsearch 的兼容性。 ## API 支持列表 | API | Method | Description | | ------------------------------ | ------ | ------------ | | /\{table_name\}/\_search | POST | 执行搜索查询 | | /\{table_name\}/\_async_search | POST | 执行搜索查询 | | /\_resolve/index/\{schema_name\} | POST | 索引文档 | | /\{table_name\}/\_field_caps | GET | 获取字段信息 | ## 查询支持列表 | Query | Description | | ------------ | ------------ | | match | 匹配查询 | | match_phrase | 短语匹配 | | match_all | 匹配所有 | | term | 精确匹配 | | prefix | 前缀匹配 | | range | 范围查询 | | exists | 字段存在查询 | | bool | 复合查询 | | aggregation | 聚合查询 | ## 聚合支持列表 | Aggregation | 实现情况 | Description | | -------------- | -------- | ----------- | | avg | | 平均值 | | sum | | 求和 | | min | | 最小值 | | max | | 最大值 | | count | ✅ | 计数 | | date_histogram | ✅ | 日期直方图 | | histogram | | 直方图 | | terms | | 词条聚合 | ## 使用 Kibana 查询 GreptimeDB 如需了解更多信息,请联系我们。 --- ## 查询 由于 GreptimeDB 和 Elasticsearch 的设计的目的有多不同,有众多的功能无法兼容,我们尽可能地提供了相应的替代方案。在各个具体的接口中,我们会说明 GreptimeDB 的实现方式和 Elasticsearch 的区别。 :::tip 所有与 boost 分数相关的功能都不支持。 不会自动增加并维护 `_id` 字段。如需使用,需在原始数据中包含该字段。 不支持使用 @timestamp 作为时间字段。 不允许在同一个请求中同时包含 query 和 aggregation ::: ## 查询语法 ### match 在 GreptimeDB 中,`match` 查询用于匹配文本字段中的一个或多个词。 不支持 analyzer,auto_generate_synonyms_phrase_query,fuzziness,max_expansions,prefix_length, fuzzy_transpositions,fuzzy_rewrite,lenient,operator,minimum_should_match,zero_terms_query。 ### match_phrase 在 GreptimeDB 中,`match_phrase` 查询用于匹配文本字段中的一个短语。会根据查询的数据类型来生成不同的查询,当数据类型为文本时,他会转化为 like 查询。 当数据类型为其他类型时,他会转化为相应的等值查询。 不支持 analyzer,auto_generate_synonyms_phrase_query,fuzziness,max_expansions,prefix_length, fuzzy_transpositions,fuzzy_rewrite,lenient,operator,minimum_should_match,zero_terms_query。 ### match_all 在 GreptimeDB 中,`match_all` 查询用于匹配所有文档。 ### term 在 GreptimeDB 中,`term` 查询用于匹配文本字段中的一个精确值。主要将查询转化为等值查询。 目前不支持 case_insensitive ### prefix 在 GreptimeDB 中,`prefix` 查询用于匹配文本字段中的一个前缀。主要将查询转为为一个 like 查询。 比如你查询以 `yi` 开头的文本,实际会转化为 `LIKE 'yi%'` 的形式。 不支持 rewrite,case_insensitive ### range 在 GreptimeDB 中,`range` 查询用于匹配文本字段中的一个范围。主要将查询转化为大于等于和小于等于的条件。 目前不支持 format,relation,time_zone,boost ### exists 在 GreptimeDB 中,`exists` 查询用于匹配文本字段中存在的值。主要将查询转化为是否存在的条件。 ### bool 在 GreptimeDB 中,`bool` 查询用于匹配多个查询条件。主要将查询转化为 AND 和 OR 的组合条件。 --- ## 企业版 GreptimeDB Enterprise 是专为满足企业特定需求而设计的强大时序数据库解决方案。 除了开源版 GreptimeDB 中提供的所有功能外, Enterprise 版还提供更多增强功能,帮助企业优化数据效率并显著降低成本,使企业能够使用时序数据做出更智能、更快速的决策。 解决方案包括: - **将数据库部署在你的云中 - Bring Your Own Cloud(BYOC**: 利用你自己的云基础设施来托管 GreptimeDB,提供广泛的定制和灵活性以满足你的业务需求。此服务包括对你的云资源的全面管理和强大的安全措施,以保护你的基础设施。 - **全托管的独立云**: Greptime 团队提供完全托管的专用云环境,确保最佳性能、增强的安全性和卓越的可靠性,以满足你的企业需求。 - **[边云一体解决方案](https://greptime.com/product/carcloud)**: 用于管理从边缘设备到云的时序数据,实现整个基础设施的实时分析和洞察的全面解决方案。 - 针对物联网 (IoT)、可观测等行业的特定解决方案。 ## 功能介绍 GreptimeDB Enterprise 支持开源版中的所有功能, 你可以阅读[用户指南](/user-guide/overview.md)文档以获取开源版的所有功能详情。 有关开源版和企业版之间的功能对比,请参考官网的[价格页面](https://greptime.cn/pricing)或[联系我们](https://greptime.cn/contactus)。 GreptimeDB Enterprise 包括以下高级功能, 详情描述在本章节的文档中: - [基于双活互备的 DR 解决方案](./deployments-administration/disaster-recovery/overview.md):通过高级灾难恢复解决方案确保服务不中断和数据保护。 - [部署 GreptimeDB](./deployments-administration/overview.md):设置认证信息及其他关键配置后,将 GreptimeDB 部署在 Kubernetes 上并监控关键指标。 - [审计日志](./deployments-administration/monitoring/audit-logging.md):记录数据库用户行为的日志。 - [自动分区平衡](./autopilot/region-balancer.md):通过分区监控和迁移在 datanode 之间自动平衡负载。 - [Elasticsearch 查询兼容性](./elasticsearch-compatible/overview.md):在 Kibana 中以 GreptimeDB 作为后端。 - [Greptime 企业版管理控制台](./console-ui.md):加强版本的管理界面,提供更多的集群管理和监控功能。 - [读副本](./read-replicas/overview.md):专门运行复杂的查询操作的 datanode,避免影响实时写入。 - [Trigger](./trigger.md):定时查询和检测预配置的规则,可触发外部 webhook,兼容 Prometheus AlertManager。 - [内置用户管理](./user.md):内置 RBAC 和细粒度 ACL,确保数据安全和隔离。 - Flow 的可靠性功能。 ## 发布说明 - [25.05](./release-notes/release-25_05.md) - [24.11](./release-notes/release-24_11.md) --- ## 管理读副本 本文介绍如何在 GreptimeDB 企业版中管理读副本,包括在表与 Region 级别添加/移除读副本、使用 `SHOW REGION` 查看副本分布,以及放置约束与性能最佳实践建议。 :::warning 警告 读副本(Follower Region)依赖[对象存储](/user-guide/deployments-administration/configuration.md#storage-options)(例如 AWS S3)。 由于 Follower Region 可能被调度到不同的 Datanode,它们必须通过对象存储共享 Region 数据;不支持仅使用本地存储的集群。 在允许查询从 Follower Region 读取之前,请确保在 Metasrv 和所有 Datanode 上启用 [GC](/user-guide/deployments-administration/manage-data/gc.md)。只有在启用 GC 时,才支持从 Follower Region 读取。 ::: ## 为表添加读副本 添加读副本只需一条 SQL: ```sql ADMIN ADD_TABLE_FOLLOWER() ``` 每个 Region 的 Follower 节点会基于 Datanode 的工作负载类型进行分配。**为获得最佳性能,强烈建议先[配置 Datanode 分组](/enterprise/deployments-administration/deploy-on-kubernetes/configure-datanode-groups.md),将读与写工作负载分别放置在不同的 Datanode 组中。** 该函数的参数: - `table_name`:需要添加读副本的表名。 示例步骤: 先启动一个包含 3 个 Datanode 的企业集群,然后建表: ```sql CREATE TABLE foo ( ts TIMESTAMP TIME INDEX, i INT PRIMARY KEY, s STRING, ) PARTITION ON COLUMNS ('i') ( i <= 0, i > 0, ); ``` 使用 `SHOW REGION` 查看当前 Region 分布: ```sql SHOW REGION FROM foo; +-------+---------------+------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511105 | 1 | Yes | +-------+---------------+------+--------+ ``` 上述结果表明在 Datanode `0` 与 `1` 上各有一个写副本 Region。 接着添加读副本: ```sql ADMIN ADD_TABLE_FOLLOWER('foo'); ``` 再次查看 Region 分布: ```sql SHOW REGION FROM foo; +-------+---------------+------------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511104 | 4294967296 | No | | foo | 4398046511105 | 1 | Yes | | foo | 4398046511105 | 4294967297 | No | +-------+---------------+------------+--------+ ``` 现在可以看到读副本已经分配到 Peer `4294967296` 与 `4294967297` 上。 ## 从表移除读副本 移除读副本同样只需一条 SQL: ```sql ADMIN REMOVE_TABLE_FOLLOWER() ``` 该函数参数: - `table_name`:要移除读副本的表名。 该命令会从每个 Region 中移除**最近添加的**一个读副本。 示例,执行前: ```sql SHOW REGION FROM foo; +-------+---------------+------------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511104 | 4294967296 | No | | foo | 4398046511104 | 4294967297 | No | | foo | 4398046511105 | 1 | Yes | | foo | 4398046511105 | 4294967296 | No | | foo | 4398046511105 | 4294967297 | No | +-------+---------------+------------+--------+ ``` 此时 Region `4398046511104` 与 `4398046511105` 各有两个读副本在 `4294967296`、`4294967297` 节点上。 执行: ```sql ADMIN REMOVE_TABLE_FOLLOWER('foo'); +------------------------------------+ | ADMIN REMOVE_TABLE_FOLLOWER('foo') | +------------------------------------+ | 0 | +------------------------------------+ ``` 每个 Region 最近添加的读副本被移除: - Region `4398046511104`:移除了 `4294967297` 节点上的读副本 - Region `4398046511105`:移除了 `4294967296` 节点上的读副本 结果: ```sql SHOW REGION FROM foo; +-------+---------------+------------+--------+ | Table | Region | Peer | Leader | +-------+---------------+------------+--------+ | foo | 4398046511104 | 0 | Yes | | foo | 4398046511104 | 4294967296 | No | | foo | 4398046511105 | 1 | Yes | | foo | 4398046511105 | 4294967297 | No | +-------+---------------+------------+--------+ ``` ## 为 Region 添加读副本 ```sql ADMIN ADD_REGION_FOLLOWER(, ) ``` 参数说明: - `region_id`:需要添加读副本的 Region ID。 - `datanode_id`:要承载该读副本的 Datanode ID。 同一 Datanode 上不能同时承载同一 Region 的写副本与读副本;且每个 Datanode 对同一 Region 仅能承载一个读副本。 示例: ```sql -- 在 Datanode 2 上为 Region 4398046511104 添加一个读副本 ADMIN ADD_REGION_FOLLOWER(4398046511104, 2); ``` 若目标 Datanode 已存在该 Region 的读副本,或该 Datanode 已存在该 Region 的写副本,则命令会被拒绝。 ## 从 Region 移除读副本 ```sql ADMIN REMOVE_REGION_FOLLOWER(, ) ``` 参数说明: - `region_id`:需要移除读副本的 Region ID。 - `datanode_id`:要移除的读副本所在的 Datanode ID。 示例: ```sql -- 从 Datanode 2 上移除 Region 4398046511104 的读副本 ADMIN REMOVE_REGION_FOLLOWER(4398046511104, 2); ``` ## 下一步 * [从读副本查询](/enterprise/read-replicas/query-read-replicas.md) --- ## GreptimeDB 只读副本概述 # 概述 *读副本 (Read Replica)* 是 GreptimeDB 企业集群版中的一项重要功能,旨在提升系统的整体读写性能与可扩展性。 :::warning 注意 读副本(Follower Region)依赖[对象存储](/user-guide/deployments-administration/configuration.md#storage-options)(例如 AWS S3)。 由于 Follower Region 可能被调度到不同的 Datanode,它们必须通过对象存储共享 Region 数据;不支持仅使用本地存储的集群。 在允许查询从 Follower Region 读取之前,请确保在 Metasrv 和所有 Datanode 上启用 [GC](/user-guide/deployments-administration/manage-data/gc.md)。只有在启用 GC 时,才支持从 Follower Region 读取。 ::: 在读副本机制中,客户端将数据写入写副本 (Leader Region),随后由 Leader Region 将数据同步到 Follower Region。Follower Region 作为 Leader Region 的只读副本。通过[配置 Datanode 组](/enterprise/deployments-administration/deploy-on-kubernetes/configure-datanode-groups.md),可以将 Leader Region 与 Follower Region 分别部署在不同的 Datanode 节点上,读写请求能够有效隔离,避免资源争用,从而获得更平滑的读写体验: ## 原理 GreptimeDB 企业集群版基于存算分离架构,使副本间的数据同步几乎零成本;同时,读副本也能以极低延迟读取到最新写入的数据。下面分别介绍数据同步与数据读取机制。 ### 数据同步 在 GreptimeDB 中,计算与存储解耦,所有数据以 SST 文件的形式存放在对象存储中。因此,Leader Region 与 Follower Region 之间无需复制 SST 文件本体,只需同步其元信息即可。元信息相比 SST 文件体量小得多,因而同步开销极低。一旦元信息同步完成,读副本便“拥有”相同的 SST 文件,从而可以读取数据: ![read-replica-data-sync](/read-replica-data-sync.png) 在实现上,SST 文件的元信息持久化在一个特殊的 manifest 文件中(同样位于对象存储)。每个 manifest 文件都有唯一的版本号。Leader Region 与 Follower Region 之间的同步,本质上就是同步这个版本号——一个简单的整数,开销极小。Follower Region 获得版本号后即可从对象存储拉取对应的 manifest 文件,从而获得 Leader Region 生成的 SST 元信息。 manifest 版本号通过 Region 与 Metasrv 之间的心跳进行同步:Leader Region 在发往 Metasrv 的心跳中携带版本号,Metasrv 在回复 Follower Region 的心跳中将其下发: ![read-replica-heartbeat](/read-replica-heartbeat.png) 可以看出,若仅依赖 SST 文件层面的同步,读副本读到新写入数据的延迟约为 Leader Region 与 Follower Region 分别到 Metasrv 的心跳间隔之和。以默认 3 秒心跳为例,读副本通常只能读到 3–6 秒前已写入并 flush 至对象存储的数据。对于对数据“新鲜度”要求不高的场景已足够,但若需要近实时读取,还需配合下述机制。 ### 数据读取 最新写入的数据首先保存在 Leader Region 的 memtable 中。为了读到这些最新数据,Follower Region 需要向 Leader Region 请求 memtable 数据,并与自身通过前述同步机制获得的 SST 数据合并,从而向客户端提供包含最新写入的完整结果集: Follower Region 通过内部 gRPC 接口从 Leader Region 获取 memtable 数据。该过程会给 Leader Region 带来一定读负载,但由于 memtable 位于内存且大小受限,通常影响可控。 ## 下一步 * [管理读副本](/enterprise/read-replicas/manage-read-replicas.md) * [从读副本查询](/enterprise/read-replicas/query-read-replicas.md) --- ## 从读副本查询 GreptimeDB 允许从**读副本 (Follower Region)** 读取数据,从而降低写副本 (Leader Region) 的负载并提升查询伸缩性。你可以通过 **SQL** 与 **HTTP** 两种方式设置读优先策略。 :::warning 警告 读副本(Follower Region)依赖[对象存储](/user-guide/deployments-administration/configuration.md#storage-options)(例如 AWS S3)。 由于 Follower Region 可能被调度到不同的 Datanode,它们必须通过对象存储共享 Region 数据;不支持仅使用本地存储的集群。 在允许查询从 Follower Region 读取之前,请确保在 Metasrv 和所有 Datanode 上启用 [GC](/user-guide/deployments-administration/manage-data/gc.md)。只有在启用 GC 时,才支持从 Follower Region 读取。 ::: ## 读优先策略 `READ_PREFERENCE` 支持如下取值: - `leader`:始终从写副本读取。 - `follower`:仅从读副本读取;若不存在读副本,则查询失败。 - `follower_preferred`:优先从读副本读取;若不可用则回退到写副本。 ## SQL 协议 在 SQL 会话中设置读优先: ```sql SET READ_PREFERENCE = 'follower'; ``` --- ## HTTP 协议 在 HTTP 请求中通过请求头指定 `X-Greptime-Read-Preference`: ```bash curl -X POST \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "X-Greptime-Read-Preference: follower" \ -d "sql=select * from monitoring" \ http://localhost:4000/v1/sql ``` --- ## 示例:从读副本读取 在从读副本读取之前,需要先为表添加读副本。参见[副本管理](/enterprise/read-replicas/manage-read-replicas.md)。 向示例表插入数据: ```sql INSERT INTO foo (ts, i, s) VALUES (1, -1, 's1'), (2, 0, 's2'), (3, 1, 's3'); ``` 设置从读副本读取: ```sql SET READ_PREFERENCE = 'follower'; ``` 查询数据: ```sql SELECT * FROM foo ORDER BY ts; +----------------------------+------+------+ | ts | i | s | +----------------------------+------+------+ | 1970-01-01 00:00:00.001000 | -1 | s1 | | 1970-01-01 00:00:00.002000 | 0 | s2 | | 1970-01-01 00:00:00.003000 | 1 | s3 | +----------------------------+------+------+ ``` --- ## 验证是否从读副本读取 可以使用 `EXPLAIN ANALYZE` 进行验证: ```sql EXPLAIN ANALYZE SELECT * FROM foo ORDER BY ts; ``` - 当输出中的 `other_ranges` 大于 0 时,表示查询涉及了读副本。 - 若使用 `VERBOSE` 选项,将看到类似如下的详细信息: ```plaintext extension_ranges: [LeaderMemtableRange{leader: Peer { id: 1, addr: "192.168.50.189:14101" }, num_rows: 2, time_range: (1::Millisecond, 2::Millisecond) ... ``` 如果仅从写副本读取,上述 `extension_ranges` 段不会出现。 --- ## GreptimeDB 企业版 24.11 我们很高兴向大家介绍 GreptimeDB 企业版的 24.11 版本。 ## 特性亮点 ### Region Rebalance 为了增强 GreptimeDB 的弹性,Region Rebalance 功能允许在数据节点之间灵活地重新分配 Region,无论是否由手动或动态触发。 这一前瞻性的措施带来了多个关键优势,包括均衡工作负载、优化资源利用,并确保在计划 维护期间无缝运行。 ### GreptimeDB 企业版管理控制台 我们带来了首个版本的 GreptimeDB 企业版管理控制台的用户界面。 此版本提供了一系列功能,包括: - 慢查询分析与调试 - 详细的集群拓扑信息 - 实时查看集群指标和日志 ### LDAP User Provider 将您自己的 LDAP 用户数据库与 GreptimeDB 企业版进行连接。我们实现了灵活的配置选项 支持,无论是简单的还是复杂的认证机制。 ### 审计日志 提供日志以跟踪数据库中的查询操作,并记录以下信息: - 查询类型:读取、写入、DDL 或其他 - 命令:SELECT、INSERT 等 - 对象类型:操作的目标对象,例如表、数据库等 ### GreptimeDB 开源版特性 本版本基于 GreptimeDB 开源版 v0.10。开源基础引入了一些新功能: - 向量数据类型支持用于相似性搜索 - 二级索引更新:用户现在可以在任何列上创建二级索引 - 添加了表选项以更新 TTL、压缩参数和全文索引设置 - JSON 数据类型和函数的支持 - Loki Remote Write 的早期支持 - 更多地理空间的通用函数(UDF)包括空间关系与测量、S2 索引等。 请参阅[这里](https://docs.greptime.com/release-notes/release-0-10-0)以获取完整的 变更日志。 --- ## GreptimeDB 企业版 25.05 我们很高兴向大家介绍 GreptimeDB 企业版的 25.05 版本。 ## 特性亮点 ### Elasticsearch 兼容层 此为 GreptimeDB Enterprise 中的 Elasticsearch 兼容层,这层允许用户将 GreptimeDB 配置为 Kibana 界面的后端,进行日志的搜索、聚合和大盘构建。 本次发布支持的查询: - match - match_all - multi_match - term - terms - prefix - wildcard - regexp - range - exists - bool ### 读副本 为了更好地支持分析型查询和其他高代价的查询,本版本中我们设计了专门的查询节点。这 类节点将专门执行查询,因此在使用时可以将资源尽可能使用而不用担心影响数据的在线写 入。 得益于我们的存算分离架构,增加专门的读节点并不是非常大的架构重构。一种新的 datanode 角色将承担这种任务。由于数据存储在对象存储上,在创建读节点时不会产生由 datanode 向新节点的数据拷贝,创建的过程成本很低。用户在发送查询时可以指定查询是 否要运行在读副本上。 ### 触发器 GreptimeDB 的触发器定期检查用户配置的规则,如果满足条件就将触发下游的 webhook。 当前发布的是触发器的首个版本,我们设计的目标也是让它可以和 Prometheus AlertManager 一起工作。注意这不是关系型数据库中的触发器。 ```sql CREATE TRIGGER IF NOT EXISTS cpu_monitor ON (SELECT host AS host_label, cpu, memory FROM machine_monitor WHERE cpu > 1) EVERY '5 minute'::INTERVAL LABELS (severity = 'warning') ANNOTATIONS (summary = 'CPU utilization is too high', link = 'http://...') NOTIFY( WEBHOOK alert_manager URL 'http://127.0.0.1:9093' WITH (timeout="1m") ); ``` ### Flow Reliability Flow 增加了可靠性功能: - 任务迁移:在多个 flow 节点之间调度任务,可以保持负载均衡或高可用。 ## GreptimeDB 开源版特性 本版本基于 GreptimeDB 开源版 v0.14。 --- ## GreptimeDB 企业版 25.11 我们很高兴向大家介绍 GreptimeDB 企业版的 25.11 版本。 ## 特性亮点 ### 批量写入 批量写入是我们在企业版中引入的一种新的写入链路,这套机制适用于高吞吐的数据写入、 导入场景。根据我们的测试,新的写入链路可以带来高达 5 倍的吞吐量加速。 在这个版本中,我们先为 Prometheus remote write 路径添加了批量写入的支持,其余更 多的协议支持将陆续加入到 25.11 后续的功能版本。 使用批量写入并不需要用户调整客户端 API 。 ### Triggers 的功能完善 Trigger 功能在 25.11 版本进行了功能的补齐,包含支持类似 Prometheus 的 `for` 和 `keep_firing_for` 等触发状态管理机制。 [通过 Trigger 文档了解更多](../trigger.md). ## 来自 GreptimeDB 开源版本的更新 此版本基于 GreptimeDB 开源版 v1.0.0. --- ## Trigger Trigger 允许用户基于 SQL 语句定义触发规则,GreptimeDB 根据这些触发规则进行周期性 计算,当满足条件后对外发出通知。 ## 关键特性 - **SQL 原生**:用 SQL 定义触发规则,复用 GreptimeDB 内置函数,无需额外学习成本 - **多阶段状态管理**:内置 pending / firing / inactive 状态机,防止抖动和重复 通知 - **丰富的上下文**:自定义 labels 和 annotations,并自动注入查询结果字段,便于精 准定位根因 - **生态友好**:告警负载完全兼容 Prometheus Alertmanager,可直接使用其分组、抑制、 静默和路由功能 ## 快速入门示例 本节通过端到端示例展示如何监控系统负载(`load1`),当负载超过阈值时触发告警。 在本示例中你将: - 创建指标表:建立 `load1` 表存储主机负载指标 - 定义 Trigger:通过 SQL 设定触发条件,配置 labels、annotations 及通知方式 - 模拟数据写入:依次注入正常与异常的负载数据,激活告警逻辑 - 观察状态变化:实时查看告警实例从 pending → firing → inactive 的完整生命周期 ### 1. 创建数据表 使用 MySQL 客户端连接 GreptimeDB,并创建 `load1` 表: ```sql CREATE TABLE `load1` ( host STRING, load1 FLOAT32, ts TIMESTAMP TIME INDEX ) WITH ('append_mode'='true'); ``` ### 2. 创建 Trigger 使用 MySQL 客户端连接 GreptimeDB,并创建 `load1_monitor` Trigger: ```sql CREATE TRIGGER IF NOT EXISTS `load1_monitor` ON ( SELECT host AS label_host, avg(load1) AS avg_load1, max(ts) AS ts FROM public.load1 WHERE ts >= NOW() - '1 minutes'::INTERVAL GROUP BY host HAVING avg(load1) > 10 ) EVERY '1 minutes'::INTERVAL FOR '3 minutes'::INTERVAL KEEP FIRING FOR '3 minutes'::INTERVAL LABELS (severity=warning) ANNOTATIONS (comment='Your computer is smoking, should take a break.') NOTIFY( WEBHOOK alert_manager URL 'http://localhost:9093' WITH (timeout='1m') ); ``` 该 Trigger 每分钟运行一次,计算过去 60 秒内每台主机的平均负载,并为每个满足 `avg(load1) > 10` 的主机生成告警实例。 关键参数说明: - **FOR**:指定条件需要持续多久才会进入 firing 状态 - **KEEP FIRING FOR**:指定条件不再满足后,告警实例在 firing 状态保持多久 详见 [Trigger 语法](/reference/sql/trigger-syntax.md)。 ### 3. 查看 Trigger 状态 #### 列出所有 Trigger ```sql SHOW TRIGGERS; ``` 输出: ```text +---------------+ | Triggers | +---------------+ | load1_monitor | +---------------+ ``` #### 查看创建语句 ```sql SHOW CREATE TRIGGER `load1_monitor`\G ``` 输出: ```text *************************** 1. row *************************** Trigger: load1_monitor Create Trigger: CREATE TRIGGER IF NOT EXISTS `load1_monitor` ON (SELECT host AS label_host, avg(load1) AS avg_load1 ...) EVERY '1 minutes'::INTERVAL FOR '3 minutes'::INTERVAL KEEP FIRING FOR '3 minutes'::INTERVAL LABELS (severity = 'warning') ANNOTATIONS (comment = 'Your computer is smoking, should take a break.') NOTIFY( WEBHOOK `alert_manager` URL `http://localhost:9093` WITH (timeout = '1m'), ) ``` #### 查看 Trigger 详情 ```sql SELECT * FROM information_schema.triggers\G ``` 输出: ```text *************************** 1. row *************************** trigger_name: load1_monitor trigger_id: 1024 raw_sql: (SELECT host AS label_host, avg(load1) AS avg_load1, ...) interval: 60 labels: {"severity":"warning"} annotations: {"comment":"Your computer is smoking, should take a break."} for: 180 keep_firing_for: 180 channels: [{"channel_type":{"Webhook":{"opts":{"timeout":"1m"}, ...}] flownode_id: 0 ``` 关于更多字段说明,参见 [Triggers](/reference/sql/information-schema/triggers)。 #### 查看告警实例 ```sql SELECT * FROM information_schema.alerts; ``` 如果尚未写入数据,将返回空结果。 关于更多字段说明,参见 [Alerts](/reference/sql/information-schema/alerts)。 ### 4. 写入数据并观察告警状态 下面的脚本模拟数据写入:先写入 1 分钟正常值,再写入 6 分钟的高值触发告警,随后 恢复到正常值。 ```bash #!/usr/bin/env bash MYSQL="mysql -h 127.0.0.1 -P 4002" insert_normal() { $MYSQL -e "INSERT INTO load1 (host, load1, ts) VALUES ('newyork1', 1.2, now()), ('newyork2', 1.1, now()), ('newyork3', 1.3, now());" } insert_high() { $MYSQL -e "INSERT INTO load1 (host, load1, ts) VALUES ('newyork1', 1.2, now()), ('newyork2', 12.1, now()), ('newyork3', 11.5, now());" } # 第一分钟:正常数据 for i in {1..4}; do insert_normal; sleep 15; done # 接下来 6 分钟:高负载 for i in {1..24}; do insert_high; sleep 15; done # 之后:恢复正常 while true; do insert_normal; sleep 15; done ``` #### 状态变迁 在另一个终端中查询告警状态: **阶段 1:无告警** ```sql SELECT * FROM information_schema.alerts\G ``` 输出: ``` Empty set ``` **阶段 2:pending**(条件首次满足,未达 `FOR` 时长) ```sql SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts; ``` ```text +------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+ | trigger_id | labels | active_at | fired_at | resolved_at | +------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+ | 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | NULL | NULL | | 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | NULL | NULL | +------------+-----------------------------------------------------------------------+----------------------------+----------+-------------+ ``` **阶段 3:firing**(满足 `FOR`,开始发送通知) ```sql SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts; ``` ```text +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+ | trigger_id | labels | active_at | fired_at | resolved_at | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+ | 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | NULL | | 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | NULL | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+-------------+ ``` **阶段 4:inactive**(条件不满足 + KEEP FIRING FOR 期满,发送恢复通知) ```sql SELECT trigger_id, labels, active_at, fired_at, resolved_at FROM information_schema.alerts; ``` ```text +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+ | trigger_id | labels | active_at | fired_at | resolved_at | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+ | 1024 | {"alert_name":"load1_monitor","host":"newyork3","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | 2025-12-29 12:05:20.991750 | | 1024 | {"alert_name":"load1_monitor","host":"newyork2","severity":"warning"} | 2025-12-29 11:58:20.992670 | 2025-12-29 12:02:20.991713 | 2025-12-29 12:05:20.991750 | +------------+-----------------------------------------------------------------------+----------------------------+----------------------------+----------------------------+ ``` ### 5. 集成 Alertmanager(可选) 如果已部署 Prometheus Alertmanager,GreptimeDB 会自动将 firing 和 inactive 状态 的告警推送过去。 每次评估后,Trigger 会将查询结果中的字段注入 labels 和 annotations。本示例中, `host` 会作为 label,`avg_load1` 会作为 annotation。这些字段会传递到 Alertmanager, 并可在通知模板中使用。 由于 payload 与 Alertmanager 兼容,你可以直接复用其分组、抑制、静默和路由能力, 无需适配器。 ## 参考资料 - [Trigger 语法](/reference/sql/trigger-syntax.md): 与 `TRIGGER` 相关的 SQL 语句的语法细节 - [INFORMATION_SCHEMA.TRIGGERS](/reference/sql/information-schema/triggers): 关于 `Trigger` 元数据的视图 - [INFORMATION_SCHEMA.ALERTS](/reference/sql/information-schema/alerts): 关于告警实例元数据的视图 --- ## 内置用户管理 GreptimeDB 企业版提供了由 Metasrv 支持的内置用户与权限系统。它支持 基于角色的访问控制 (RBAC) 和细粒度访问控制列表 (ACL),用于保障数据 安全与隔离。 ## 主要特性 - **内置用户管理**:用户账号和权限存储在 Metasrv 中,确保整个集群中的 管理保持一致。 - **基于角色的访问控制 (RBAC)**:为用户分配全局权限,控制 `SELECT`、 `INSERT`、`CREATE TABLE` 等操作。 - **细粒度 ACL**:使用精确匹配或正则表达式控制特定数据库内的表级访问。 - **动态管理**:通过 HTTP API 动态管理用户,无需重启服务器。 - **初始账号导入**:支持在启动时从密码文件导入初始账号。 ## 配置说明 本节介绍如何启用企业版用户 Provider 并执行基础的用户管理操作。 ### 1. 启用用户 Provider 要使用企业版用户与权限系统,需要在接收客户端请求的组件中启用 `greptime_ee_user_provider`。在单机模式中,请在 standalone server 上配置; 在集群模式中,请在每个 frontend 节点上配置。 用户 Provider 的取值如下: ```text greptime_ee_user_provider: ``` 密码文件是可选的,仅用于初始账号导入。若要在不导入用户的情况下启用 Provider,请使用 `greptime_ee_user_provider:`。配置解析器要求保留末尾的 冒号 `:`。 **Standalone 命令行:** ```shell ./greptime standalone start \ --user-provider=greptime_ee_user_provider:/path/to/passwords.txt ``` **Standalone 配置文件:** ```toml user_provider = "greptime_ee_user_provider:/path/to/passwords.txt" ``` ```shell ./greptime standalone start \ -c /path/to/standalone.toml ``` **Frontend 命令行:** ```shell ./greptime frontend start \ --metasrv-addrs=127.0.0.1:3002 \ --user-provider=greptime_ee_user_provider:/path/to/passwords.txt ``` **Frontend 配置文件:** ```toml user_provider = "greptime_ee_user_provider:/path/to/passwords.txt" [meta_client] metasrv_addrs = ["127.0.0.1:3002"] ``` 然后使用配置文件启动 frontend: ```shell ./greptime frontend start \ -c /path/to/frontend.toml ``` ### 2. 初始账号导入(可选) 密码文件使用以下格式: `[:]=` 可用角色: - `admin`:拥有完整权限,包括用户管理权限。 - `readonly`(或 `ro`):只读访问权限 (`SqlSelect`)。 - `writeonly`(或 `wo`):只写访问权限,例如 `SqlInsert`、`TableCreate`。 - `readwrite`(或 `rw`):同时拥有读写访问权限(默认)。 `passwords.txt` 示例: ```text # username[:role]=password superuser:admin=strong_password alice:ro=alice_pwd bob:rw=bob_pwd ``` 默认情况下,导入的用户会获得 `public` 数据库的完整访问权限 (`AclType::All`)。 导入的账号只会创建一次。如果后续启动时发现某个导入用户已经存在,则会跳过 该用户。之后你可以通过 UI 修改这些导入的用户。 ## 权限与 ACL ### 全局权限 权限包括以下操作: | 权限 | 描述 | | :--- | :--- | | `TableCreate` | 创建新表 | | `TableAlter` | 修改已有表 | | `TableDrop` | 删除表 | | `SqlSelect` | 执行 `SELECT` 查询 | | `SqlInsert` | 执行 `INSERT` 操作 | | `SqlDelete` | 执行 `DELETE` 操作 | | `FlowCreate` | 创建 flow | | `FlowDrop` | 删除 flow | | `DatabaseCreate` | 创建数据库 | | `DatabaseAlter` | 修改数据库 | | `DatabaseDrop` | 删除数据库 | | `Admin` | 完整管理权限 | | `TriggerCreate` | 创建触发器 | | `TriggerDrop` | 删除触发器 | | `TriggerAlter` | 修改触发器 | #### 预定义角色权限 使用密码文件导入账号时,预定义角色会映射到以下权限组合: | 角色 | 权限 | | :--- | :--- | | `admin` | 所有权限 | | `readonly` / `ro` | `SqlSelect` | | `writeonly` / `wo` | `SqlInsert`, `SqlDelete`, `TableCreate`, `TableAlter`, `TableDrop`, `FlowCreate`, `FlowDrop`, `TriggerCreate`, `TriggerDrop`, `TriggerAlter`, `DatabaseCreate`, `DatabaseAlter`, `DatabaseDrop` | | `readwrite` / `rw` | `readonly` + `writeonly` 权限 | ### 访问控制列表 (ACL) ACL 在数据库内提供表级安全控制。每条 ACL 都限定在某个数据库中,并控制 用户可以访问该数据库中的哪些表。 `all` ACL 授予对该数据库中所有表的访问权限。当用户需要读取或写入该 数据库中当前和未来的所有表时,可以使用该 ACL;实际访问能力仍受用户全局 权限的约束。 `match` ACL 通过精确表名授予对单个表的访问权限。当用户只应访问某个特定表, 且不应自动获得对其他相似表名的访问权限时,可以使用该 ACL。 `regex` ACL 授予对表名匹配正则表达式的表的访问权限。当表名遵循某种命名规则、 需要按组管理时,可以使用该 ACL。例如,`mem_.*` 匹配以 `mem_` 开头的表名, `.*_metrics` 匹配以 `_metrics` 结尾的表名,`sensor_[0-9]+` 匹配 `sensor_1`、`sensor_2024` 等表名。Regex ACL 会在配置的数据库内对表名 进行匹配,因此请尽量使用明确的模式,避免授予超出预期的表访问权限。 ## 校验规则 ### 用户名 用户名必须: - 以字母开头(`a-z` 或 `A-Z`) - 仅包含字母、数字和下划线 - 匹配 `[a-zA-Z][a-zA-Z0-9_]*` 模式 ### 密码 密码校验规则取决于用户的创建或更新方式: - 导入账号的密码不能为空。 - 通过 UI 创建或更新的密码长度必须为 6 到 64 个字符。 ## Enterprise Dashboard 中的用户管理 启用 `greptime_ee_user_provider` 后,GreptimeDB 和 Enterprise Dashboard 都要求 用户使用账号登录。下图展示了 Enterprise Dashboard 的登录页面: 你可以使用自动创建的 admin 账号,或使用导入文件中定义的账号登录。 只有拥有 `Admin` 权限的账号才能看到数据库管理菜单。非 admin 账号只能访问 查询页面,体验与开源版 dashboard 类似。 以 admin 用户登录后,点击左下角的 `User Management`,即可进入用户管理页面: 该页面会列出所有当前用户。你可以在此页面执行以下操作: 1. 创建用户 2. 更新已有用户 3. 删除用户 下图展示了创建用户的表单: 在该表单中,你可以配置: 1. 用户名 2. 密码 3. 账号是否拥有 `Admin` 权限。非 admin 用户会被授予 `readwrite` 权限。 4. 账号的 ACL 列表 ACL 表单包含两个页签。你可以选择精确的表,也可以选择整个数据库来授予 全库访问权限,或者使用正则表达式为一组表授予访问权限。下图展示了正则表达式 表单: ## 参考 - **管理员账号**:系统首次启动时,如果默认 `admin` 账号尚不存在, GreptimeDB 企业版会自动创建该账号。 - 如果设置了环境变量 `GREPTIME_ENTERPRISE_ADMIN_PASSWORD`,则使用该变量的 值作为密码。 - 如果未设置该环境变量,则生成一个随机 UUID 作为密码。 - **查看自动生成的密码**:如果生成了随机密码,你可以在 GreptimeDB 日志文件中 找到它。搜索类似如下的消息: ```text Created admin user with auto-generated password ``` - **重置管理员密码**:你可以使用 CLI 重置 `admin` 密码,无需手动编辑 KV 存储。 该命令从 Metasrv 配置文件中读取后端存储设置,并支持标准的 `GREPTIMEDB_METASRV__...` 环境变量覆盖。 ```shell ./greptime-ee cli user admin-password \ --new-password \ --config-file /path/to/metasrv.toml ``` 此命令必须在 Metasrv 实例上执行。`--config-file` 应指向你的 Metasrv(或 standalone)部署所使用的同一 Metasrv 配置文件,以便 CLI 能够定位正确的后端 存储(etcd、MySQL 或 PostgreSQL)。 - **持久化**:用户信息会持久化在 Metasrv 的 KV 存储中,因此集群中的所有 frontend 节点都可以访问这些用户信息。 - **Admin 保护**:内置的 `admin` 用户不能通过 API 删除。 --- ## GreptimeDB 表引擎 ## 概述 GreptimeDB 提供多种专业的表引擎(Table Engine),每种引擎都针对特定工作负载和使用场景进行了优化设计。本文档全面介绍了这些引擎,并提供了何时使用每种引擎的指导。 ### Mito 引擎 Mito 是 GreptimeDB 的默认`存储引擎`,负责高效存储和管理数据库数据。基于 [LSMT][1](日志结构合并树)架构构建,Mito 已针对时间序列数据工作负载进行了广泛优化。 该引擎的架构包括预写日志(WAL)以确保持久性、Memtable 在内存中高效组织数据以及基于时间窗口压缩策略(TWCS)的高效压缩策略。这种设计使 Mito 能够处理高吞吐量的写入操作,同时保持出色的查询性能。 Mito 无缝集成了各种对象存储解决方案,包括 S3、GCS 和 Azure Blob Storage,无需额外插件即可提供原生支持。它在对象存储之上实现了分层缓存系统,优化了任何规模时间序列数据的存储成本和访问速度。 [1]: https://en.wikipedia.org/wiki/Log-structured_merge-tree ### Metric 引擎 顾名思义,Metric 引擎旨在高效处理指标数据。它专门处理可观测性负载中典型的海量小表的场景。 Metric 引擎的关键创新在于使用合成宽物理表来存储来自众多小表的数据。这种方法能够跨表高效重用列和元数据,显著减少存储开销,同时提高列式压缩效率。在 Metric 引擎下,表成为轻量级逻辑结构,非常适合云原生可观测场景,这些场景中通常存在数千个小型指标表。 Metric 引擎构建在 Mito 引擎之上,这意味着其数据实际上存储在 Mito 引擎中。这种架构利用了 Mito 强大的存储能力,同时为指标数据管理添加了专门的优化。 ### File 引擎 File 引擎是 GreptimeDB 中专为处理基于文件的数据源而设计的专用存储引擎。它允许 GreptimeDB 直接查询和处理存储在外部文件中的数据,无需数据导入或转换。 该引擎支持数据分析工作流中常用的各种文件格式,实现与现有数据管道的无缝集成。通过将外部文件视为虚拟表,File 引擎提供了对基于文件的数据的 SQL 查询能力,同时保持了 GreptimeDB 查询引擎的性能优化。 当数据已经以文件格式存在时,File 引擎特别有用,允许用户分析这些数据,同时分析存储在其他 GreptimeDB 引擎中的时间序列数据。这一功能使 GreptimeDB 成为更加多功能的统一分析平台,能够处理多样化的数据源。 ## 引擎选择指南 ### 何时使用各种引擎 - **Mito 引擎**:作为默认存储引擎,Mito 适用于大多数通用时间序列工作负载。当你需要平衡写入吞吐量、查询性能和存储效率时,它是一个极佳的选择。对于需要持久存储并具有良好全面性能特性的应用程序,请使用 Mito。 - **Metric 引擎**:当处理涉及数千个具有相似列结构的小表的可观测性和指标监控场景时,选择 Metric 引擎。该引擎在云原生监控环境中表现出色,可以减少存储开销并提高查询性能,特别适合指标数据为主的场景。 - **File 引擎**:当你需要查询已存在于外部文件中的数据而无需将其导入数据库时,选择 File 引擎。这对于数据探索、一次性分析任务或与现有基于文件的数据管道集成时非常理想。 ### 在 SQL 中指定引擎类型 在 GreptimeDB 中创建表时,您可以通过 CREATE TABLE 语句中的 `ENGINE` 子句指定要使用的引擎。有关语法和选项的更详细信息,请参阅 [CREATE TABLE](/reference/sql/create.md#create-table) 文档。 --- ## 关于 GreptimeDB 版本号 GreptimeDB 遵循 [语义化版本控制](https://semver.org/) 方案: 1.2.3 其中: - 1 是主版本号 - 2 是次版本号 - 3 是修订号 ## 主版本号 (1) 主版本号表示软件生命周期中的一个重要里程碑,通常引入广泛的变化。 - 特点:包括主要的架构更新、重大新功能或系统大修。 - 影响:通常不向后兼容,用户或开发人员需要进行调整。 - 示例:主要的 API 重新设计、基础架构的重大变化或引入新的核心模块。 ## 次版本号 (2) 次版本号侧重于功能增强和小改进,旨在完善现有系统。 - 特点:添加新功能、小更新或界面改进。 - 影响:虽然它在同一主版本内努力保持向后兼容,但偶尔也可能会出现小的破坏性更改。 - 示例:引入可选功能、更新用户界面或扩展配置选项并对现有行为进行轻微调整。 ## 修订号 (3) 修订号用于修补或小幅改进,解决特定问题。 - 特点:专注于错误修复、安全更新或性能优化。 - 影响:不引入新功能或改变系统的整体行为。 - 示例:修复已知错误、解决安全漏洞或提高系统稳定性。 --- ## Datanode `greptime datanode` 命令提供了用于管理和基准测试 datanode 实例的子命令。 ## start 启动 datanode 服务。 ### 选项 你可以通过以下命令列出所有选项: ``` greptime datanode start --help ``` | 选项 | 描述 | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | Datanode 的配置文件 | | `--data-home` | 数据库存储 home 目录 | | `--env-prefix ` | 配置的环境变量前缀,默认为`GREPTIMEDB_DATANODE` | | `--http-addr ` | HTTP 服务器地址 | | `--http-timeout ` | HTTP 超时设置,单位秒 | | `--metasrv-addrs ` | Metasrv 服务器列表,用逗号或者空格隔开 | | `--node-id ` | 节点 ID | | `--rpc-bind-addr ` | gRPC 服务绑定地址址 | | `--rpc-server-addr ` | 该地址用于来自主机外部的连接和通信。如果留空或未设置,服务器将自动使用主机上第一个网络接口的 IP 地址,其端口号与 `rpc_bind_addr` 中指定的相同; | | `--wal-dir ` | WAL 目录 | 所有的 `addr` 类选项都是 `ip:port` 形式的字符串。 ### 示例 #### 使用配置启动服务 使用自定义配置启动 Datanode 实例: ```sh greptime datanode start -c config/datanode.example.toml ``` 使用命令行参数启动 Datanode,指定 gRPC 服务地址、MySQL 服务地址、Metasrv 地址和该 Datanode 的 ID: ```sh greptime datanode start --rpc-bind-addr=0.0.0.0:4001 --mysql-addr=0.0.0.0:4002 --metasrv-addrs=0.0.0.0:3002 --node-id=1 ``` `datanode.example.toml` 配置文件来自 `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` 仓库的 `config` 目录。你可以在那里找到更多示例配置文件。`-c` 选项指定配置文件,更多信息请参考 [Configuration](/user-guide/deployments-administration/configuration.md)。 ## objbench `objbench` 子命令是一个用于测量对象存储上特定文件读写性能的基准测试工具。这对于诊断性能问题和测试存储层性能非常有用。 ### 选项 | 选项 | 描述 | | --------------------- | ------------------------------------------------------------------------------------------------------- | | `--config ` | datanode 配置文件路径(TOML 格式) | | `--source ` | 对象存储中的源 SST 文件路径(例如 `data/greptime/public/1024/1024_0000000000/metadata/.parquet`) | | `-v`/`--verbose` | 启用详细输出 | | `--pprof-file ` | pprof 火焰图的输出文件路径(启用性能分析)。生成 SVG 格式的火焰图文件 | ### 示例 #### 基础基准测试 测量特定文件的读写性能: ```sh greptime datanode objbench --config ./datanode.toml --source data/greptime/public/1024/1024_0000000000/metadata/8fb41bc7-a106-4b9e-879b-392da799f958.parquet ``` #### 带性能分析的基准测试 测量性能并生成用于性能分析的火焰图: ```sh greptime datanode objbench --config ./datanode.toml --source data/greptime/public/1024/1024_0000000000/metadata/8fb41bc7-a106-4b9e-879b-392da799f958.parquet --pprof-file=./flamegraph.svg ``` 这将生成一个 SVG 格式的火焰图,可以在 Web 浏览器中打开进行性能分析。 ## scanbench `scanbench` 子命令用于直接从存储层对 region 扫描进行基准测试。 ### 选项 | 选项 | 描述 | | ------------------------------------ | --------------------------------------------------------------------------------------------------------- | | `--config ` | datanode/standalone 配置文件路径(TOML 格式)。 | | `--region-id ` | Region ID 支持两种格式:``(例如 `4398046511104`)或 `:`(例如 `1024:0`)。 | | `--table-dir ` | 打开 region 时使用的表目录(例如 `greptime/public/1024`)。 | | `--scanner ` | 扫描策略,默认 `seq`。 | | `--scan-config ` | 用于微调扫描请求的 JSON 文件。 | | `--parallelism ` | 模拟扫描并行度,默认 `1`。 | | `--iterations ` | 基准测试迭代次数,默认 `1`。 | | `--path-type ` | Region 路径类型,默认 `bare`。 | | `--enable-wal` | 打开 region 时启用 WAL 回放,默认关闭。 | | `--pprof-file ` | pprof 火焰图输出路径(仅 Unix)。 | | `--pprof-after-warmup` | 在首轮迭代(warmup)后再开始 pprof。需要与 `--pprof-file` 一起使用,默认关闭。 | | `-v`/`--verbose` | 启用详细输出。 | ### `scan-config` JSON ```json { "projection_names": ["host", "cpu"], "filters": ["host = 'web-1'", "cpu > 80"], "series_row_selector": "last_row" } ``` 说明: - 所有字段均为可选。 - `projection`(列索引)与 `projection_names`(列名)二选一。 - `projection_names` 采用精确匹配(区分大小写)。 - `filters` 应为 SQL 表达式(而非完整 SQL 语句)。 - `series_row_selector` 当前仅支持 `last_row`。 ### 示例 #### 默认顺序扫描 ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir greptime/public/1024 ``` #### 使用并行度的无序扫描 ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir greptime/public/1024 --scanner unordered --parallelism 8 --iterations 5 ``` #### 扫描 metric engine 数据目录的 series 扫描 ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir data/greptime/public/1024 --parallelism 16 --scan-config ./scanconfig.json --scanner series --path-type data --iterations 10 ``` `scanconfig.json` 示例: ```json { "projection_names": ["greptime_timestamp", "greptime_value", "az", "hostname", "region", "__tsid"], "filters": [ "mode = 'idle'", "region = 'us-west-2'", "greptime_timestamp >= 1742550540001", "greptime_timestamp <= 1742552400000", "__table_id = 1182" ] } ``` #### warmup 后开始性能分析 ```sh greptime datanode scanbench --config ./datanode.toml --region-id 1024:0 --table-dir greptime/public/1024 --iterations 5 --pprof-file ./scanbench.svg --pprof-after-warmup ``` --- ## Flownode ## 子命令选项 你可以通过以下命令列出所有选项: ``` greptime flownode start --help ``` | Option | Description | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | Flownode 的配置文件 | | `--env-prefix ` | 配置的环境变量前缀,默认为`GREPTIMEDB_FLOWNODE` | | `--metasrv-addrs ...` | etasrv 服务器列表,用逗号或者空格隔开 | | `--node-id ` | 节点 ID | | `--rpc-bind-addr ` | gRPC 服务绑定地址 | | `--rpc-server-addr ` | 该地址用于来自主机外部的连接和通信。如果留空或未设置,服务器将自动使用主机上第一个网络接口的 IP 地址,其端口号与 `rpc_bind_addr` 中指定的相同; | :::note 如果在启用了 Frontend 认证的集群中单独部署 Flownode,请为 Frontend 配置 internal gRPC 地址。 你可以通过 Frontend 的 `internal_grpc` 配置项,或者 `--internal-grpc-bind-addr` 和 `--internal-grpc-server-addr` 命令行选项来配置。 Flownode 会使用从 Metasrv 发现的 Frontend 地址发起连接,且不会携带认证信息。因此,它应访问 Frontend 的 internal gRPC 服务,而不是需要认证的公开 gRPC 服务。 ::: 所有的 `addr` 类选项都是 `ip:port` 形式的字符串。 ## Examples ### 使用配置启动服务 使用自定义配置启动 Flownode 实例: ```sh greptime flownode start -c config/flownode.example.toml ``` 使用命令行参数启动 Flownode,指定 gRPC 服务地址、Metasrv 地址: ```sh greptime flownode start --node-id=0 --rpc-bind-addr=127.0.0.1:6800 --metasrv-addrs=127.0.0.1:3002 ``` `flownode.example.toml` 配置文件来自 `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` 仓库的 `config` 目录。你可以在那里找到更多示例配置文件。`-c` 选项指定配置文件,更多信息请参考 [Configuration](/user-guide/deployments-administration/configuration.md)。 --- ## Frontend ## 子命令选项 你可以通过以下命令列出所有选项: ``` greptime frontend start --help ``` | Option | Description | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | Frontend 的配置文件 | | `--disable-dashboard` | 禁用 dashboard http 服务,默认是 `false` | | `--env-prefix ` | 配置的环境变量前缀,默认为`GREPTIMEDB_FRONTEND` | | `--rpc-bind-addr ` | gRPC 服务绑定地址 | | `--rpc-server-addr ` | 该地址用于来自主机外部的连接和通信。如果留空或未设置,服务器将自动使用主机上第一个网络接口的 IP 地址,其端口号与 `rpc_bind_addr` 中指定的相同; | | `--http-timeout ` | HTTP 请求超时时间(秒) | | `--influxdb-enable` | 是否启用 InfluxDB 协议 | | `--metasrv-addrs ` | Metasrv 服务器列表,用逗号或者空格隔开 | | `--mysql-addr ` | MySQL 服务器地址 | | `--postgres-addr ` | Postgres 服务器地址 | | `--tls-cert-path ` | TLS 公钥文件路径 | | `--tls-key-path ` | TLS 私钥文件路径 | | `--tls-mode ` | TLS 模式 | | `--user-provider ` | 您可以参考 [authentication](/user-guide/deployments-administration/authentication/overview.md) | 所有的 `addr` 类选项都是 `ip:port` 形式的字符串。 ## Examples ### 使用配置启动服务 使用自定义配置启动 Frontend 实例: ```sh greptime frontend start -c config/frontend.example.toml ``` 使用命令行参数启动 Frontend,指定 Metasrv 地址: ```sh greptime frontend start --metasrv-addrs=0.0.0.0:3002 ``` `frontend.example.toml` 配置文件来自 `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` 仓库的 `config` 目录。你可以在那里找到更多示例配置文件。`-c` 选项指定配置文件,更多信息请参考 [Configuration](/user-guide/deployments-administration/configuration.md)。 --- ## Metasrv ## 子命令选项 你可以通过以下命令列出所有选项: ``` greptime metasrv start --help ``` | Option | Description | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `-c`/`--config-file` | Metasrv 的配置文件 | | `--enable-region-failover` | 是否启用 Region 自动容灾,默认是 `false`。开启条件请参考:[Region 自动容灾](/user-guide/deployments-administration/manage-data/region-failover.md) | | `--env-prefix ` | 配置的环境变量前缀,默认为`GREPTIMEDB_METASRV` | | `--rpc-bind-addr ` | gRPC 服务绑定地址 | | `--rpc-server-addr ` | 该地址用于来自主机外部的连接和通信。如果留空或未设置,服务器将自动使用主机上第一个网络接口的 IP 地址,其端口号与 `rpc_bind_addr` 中指定的相同; | | `--http-addr ` | HTTP 服务器地址 | | `--http-timeout ` | HTTP 请求超时时间(秒) | | `--selector ` | 您可以参考 [selector-type](/contributor-guide/metasrv/selector.md#selector-type) | | `--store-addrs ` | 逗号或空格分隔的键值存储服务器(默认是 etcd)地址,用于存储元数据 | 所有的 `addr` 类选项都是 `ip:port` 形式的字符串。 ## 示例 ### 使用配置启动服务 使用自定义配置启动 Metasrv 实例: ```sh greptime metasrv start -c config/metasrv.example.toml ``` `metasrv.example.toml` 配置文件来自 `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` 仓库的 `config` 目录。你可以在那里找到更多示例配置文件。`-c` 选项指定配置文件,更多信息请参考 [Configuration](/user-guide/deployments-administration/configuration.md)。 --- ## GreptimeDB 命令行概述 # 概述 `greptime` 命令行工具可以启动、停止、或传递配置项给 GreptimeDB。 ## 安装命令行工具 Greptime 命令行工具与 GreptimeDB 二进制文件捆绑在一起。 如果你按照[快速安装 GreptimeDB](/getting-started/installation/overview.md)文档中所述使用二进制文件启动的 GreptimeDB,可以在 GreptimeDB 的当前目录中执行 `./greptime` 命令。 为了方便起见,如果你希望使用 `greptime` 而不是 `./greptime` 来运行命令, 可以将命令行工具的二进制文件移动到系统的 `bin` 目录,或者将二进制文件的路径添加到 `PATH` 环境变量中。 如果你是在 Kubernetes 中部署的 GreptimeDB,可以通过 frontend pod 访问 greptime 命令行工具。使用以下命令进入 pod: ```sh kubectl exec -it -n -- /bin/bash ``` 进入 pod 后,可以运行 `greptime help` 查看所有可用命令。 ## 选项 `help` 命令列出了 `greptime` 所有可用的命令和选项。 ```sh $ greptime help Usage: greptime [OPTIONS] Commands: datanode Start datanode service frontend Start frontend service metasrv Start metasrv service standalone Run greptimedb as a standalone service cli Execute the cli tools for greptimedb help Print this message or the help of the given subcommand(s) Options: --log-dir --log-level -h, --help Print help -V, --version Print version ``` ### 全局选项 | Option | Description | | ------------------------- | ----------------------------------------- | | `-h`/`--help` | 打印帮助信息 | | `-V`/`--version` | 打印版本信息 | | `--log-dir ` | 日志目录,默认是 `./greptimedb_data/logs` | | `--log-level ` | 日志级别,默认是 `info` | ### 子命令 - [Metasrv](/reference/command-lines/metasrv.md) - [Datanode](/reference/command-lines/datanode.md) - [Flownode](/reference/command-lines/flownode.md) - [Frontend](/reference/command-lines/frontend.md) - [Standalone](/reference/command-lines/standalone.md) ### 升级 GreptimeDB 版本 请参考具体的[升级步骤](/user-guide/deployments-administration/upgrade.md) --- ## Standalone ## 子命令选项 你可以通过以下命令列出所有选项: ``` greptime standalone start --help ``` | Option | Description | | --------------------------------- | ------------------------------------------------- | | `-c`/`--config-file` | Standalone 的配置文件 | | `--env-prefix ` | 配置的环境变量前缀,默认为`GREPTIMEDB_STANDALONE` | | `--http-addr ` | HTTP 服务器地址 | | `--influxdb-enable` | 是否启用 InfluxDB 协议 | | `--mysql-addr ` | MySQL 服务器地址 | | `--postgres-addr ` | Postgres 服务器地址 | | `--rpc-bind-addr ` | gRPC 服务绑定地址 | 所有的 `addr` 类选项都是 `ip:port` 形式的字符串。 ## 示例 ### 使用配置启动服务 使用自定义配置启动 Standalone 实例: ```sh greptime --log-dir=greptimedb_data/logs --log-level=info standalone start -c config/standalone.example.toml ``` `standalone.example.toml` 配置文件来自 `[GreptimeDB](https://github.com/GreptimeTeam/greptimedb/)` 仓库的 `config` 目录。你可以在那里找到更多示例配置文件。`-c` 选项指定配置文件,更多信息请参考 [Configuration](/user-guide/deployments-administration/configuration.md)。 --- ## 数据导出和导入 数据导出和导入工具提供了备份和恢复 GreptimeDB 数据库的功能。这些工具可以处理表结构和数据,允许进行完整的备份或选择性的备份和恢复操作。 ## 导出工具 ### 命令语法 ```bash greptime cli data export [OPTIONS] ``` ### 选项 | 选项 | 是否必需 | 默认值 | 描述 | | ------------------------- | -------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--addr` | 是 | - | 要连接的 GreptimeDB 数据库地址 | | `--output-dir` | 是 | - | 存储导出数据的目录。**重要提示**:此路径位于**远程服务器的文件系统**上,而非本地机器。如需在本地获取文件,建议配置远程存储(S3/OSS/GCS/Azure Blob)导出数据,同时使用 `--ddl-local-dir` 将 SQL 文件保存到本地。 | | `--database` | 否 | 所有数据库 | 要导出的数据库名称 | | `--db-parallelism, -j` | 否 | 1 | 并行导出的数据库数量。例如,有 20 个数据库且 `db-parallelism` 设置为 4 时,将同时导出 4 个数据库。(别名:`--export-jobs`) | | `--table-parallelism` | 否 | 4 | 单个数据库内并行导出的表数量。例如,数据库包含 30 个表且 `table-parallelism` 设置为 8 时,将同时导出 8 个表。 | | `--max-retry` | 否 | 3 | 每个任务的最大重试次数 | | `--target, -t` | 否 | all | 导出目标(schema/data/all) | | `--start-time` | 否 | - | 数据导出的开始时间范围 | | `--end-time` | 否 | - | 数据导出的结束时间范围 | | `--auth-basic` | 否 | - | 使用 `:` 格式 | | `--timeout` | 否 | 0 | 对 DB 进行一次调用的超时时间,默认为 0 代表永不超时(例如 `30s`, `10min 20s`) | | `--proxy` | 否 | - | 代理服务器地址,如设置该参数,将覆盖系统代理。如果未设置 `--proxy` 和 `--no-proxy`,则默认使用系统代理 | | `--no-proxy` | 否 | - | 禁用代理服务器,如设置该参数,将完全不使用代理 | | `--s3` | 否 | - | 是否导出数据到 Amazon S3 | | `--ddl-local-dir` | 否 | - | 当同时设置了 `ddl_local_dir` 和远程存储(如 S3/OSS/GCS/Azure Blob)时,SQL 文件将导出至本地目录,而数据将导出到远程存储。注意:`ddl_local_dir` 只导出 SQL 文件至**本地文件系统**,适用于导出客户端无法直接访问远程存储的情况。如果未设置 `ddl_local_dir`,则 SQL 和数据都将导出至远程存储 | | `--s3-bucket` | 是\* | - | 当设置了 `--s3` 时,必须指定 S3 的 bucket 名称 | | `--s3-root` | 是\* | - | 当设置了 `--s3` 时,必须指定导出在 bucket 中的根路径 | | `--s3-endpoint` | 否\* | - | 当设置了 `--s3` 时,需指定 S3 的 endpoint | | `--s3-access-key-id` | 是\* | - | 当设置了 `--s3` 时,需指定 S3 的 Access Key ID | | `--s3-secret-access-key` | 是\* | - | 当设置了 `--s3` 时,需指定 S3 的 Secret Access Key | | `--s3-region` | 是\* | - | 当设置了 `--s3` 时,需指定 S3 的区域(Region) | | `--oss` | 否 | - | 是否导出数据到阿里云 OSS | | `--oss-bucket` | 是\* | - | 当设置了 `--oss` 时,需指定 OSS 的 bucket 名称 | | `--oss-endpoint` | 否\* | - | 当设置了 `--oss` 时,需指定 OSS 的 endpoint | | `--oss-access-key-id` | 是\* | - | 当设置了 `--oss` 时,需指定 OSS 的 Access Key ID | | `--oss-access-key-secret` | 是\* | - | 当设置了 `--oss` 时,需指定 OSS 的 Access Key Secret | | `--gcs` | 否 | - | 是否导出数据到 Google Cloud Storage (GCS) | | `--gcs-bucket` | 是\* | - | 当设置了 `--gcs` 时,必须指定 GCS 的 bucket 名称 | | `--gcs-root` | 是\* | - | 当设置了 `--gcs` 时,必须指定导出在 bucket 中的根路径 | | `--gcs-scope` | 否 | - | GCS 服务范围 | | `--gcs-credential` | 否 | - | GCS 凭证内容 | | `--gcs-endpoint` | 否 | - | GCS 端点 URL | | `--azblob` | 否 | - | 是否导出数据到 Azure Blob Storage | | `--azblob-container` | 是\* | - | 当设置了 `--azblob` 时,必须指定 Azure Blob 的容器名称 | | `--azblob-root` | 是\* | - | 当设置了 `--azblob` 时,必须指定导出在容器中的根路径 | | `--azblob-account-name` | 是\* | - | 当设置了 `--azblob` 时,必须指定 Azure Blob 的账户名称 | | `--azblob-account-key` | 否 | - | Azure Blob 账户密钥 | | `--azblob-endpoint` | 否 | - | Azure Blob 端点 URL | | `--azblob-sas-token` | 否 | - | Azure Blob SAS 令牌 | ### 导出目标 - `schema`: 仅导出表结构(`SHOW CREATE TABLE`) - `data`: 仅导出表数据(`COPY DATABASE TO`) - `all`: 导出表结构和数据(默认) ## 导入工具 ### 命令语法 ```bash greptime cli data import [OPTIONS] ``` ### 选项 | 选项 | 是否必需 | 默认值 | 描述 | | ------------------------ | -------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `--addr` | 是 | - | 要连接的 GreptimeDB 数据库地址 | | `--input-dir` | 是 | - | 包含备份数据的目录 | | `--database` | 否 | 所有数据库 | 要导入的数据库名称 | | `--db-parallelism, -j` | 否 | 1 | 并行导入的数据库数量。例如,有 20 个数据库且 `db-parallelism` 设置为 4 时,将同时导入 4 个数据库。(别名:`--import-jobs`) | | `--max-retry` | 否 | 3 | 每个任务的最大重试次数 | | `--target, -t` | 否 | all | 导入目标(schema/data/all) | | `--auth-basic` | 否 | - | 使用 `:` 格式 | ### 导入目标 - `schema`: 仅导入表结构 - `data`: 仅导入表数据 - `all`: 导入表结构和数据(默认) --- ## 元数据交互 `greptime cli meta` 命令可以用于与 GreptimeDB 集群的元数据进行交互。 ## 公共选项 | 选项 | 描述 | 默认值 | 值 | | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ----------------------------------------------------- | | `--store-addrs ...` | 元数据存储服务地址。可以是 etcd、postgres 或 mysql。 对于 postgres 存储,格式为:`"password=password dbname=postgres user=postgres host=localhost port=5432"`。 对于 etcd 存储,格式为:`"127.0.0.1:2379"`。 对于 mysql 存储,格式为:`"mysql://user:password@ip:port/dbname"` | - | - | | `--max-txn-ops ` | 单个事务中操作的最大数量。仅在使用 [etcd-store] 时使用 | 128 | - | | `--backend ` | 元数据存储后端类型 | etcd-store | etcd-store, memory-store, postgres-store, mysql-store | | `--store-key-prefix ` | 元数据存储前缀缀 | - | - | | `--meta-table-name ` | 元数据存储的表名。元数据存储后端为 [postgres-store] 或 [mysql-store] 时使用 | greptime_metakv | - | ## 获取键值对 ### 命令语法 ```bash greptime cli meta get key [OPTIONS] [KEY] ``` ### 选项 | 选项 | 描述 | 默认值 | | ----------------- | ----------------------------------------------------------------------- | ------ | | `--prefix` | 是否执行前缀查询。如果为 true,则返回所有键值对,其中键以给定的前缀开头 | false | | `--limit ` | 返回的最大键值对数量。如果为 0,则返回所有键值对 | 0 | ## 获取表元数据 ### 命令语法 ```bash greptime cli meta get table [OPTIONS] ``` ### 选项 | 选项 | 描述 | 默认值 | | ------------------------------- | ---------------------- | -------- | | `--table-id ` | 通过表 ID 获取表元数据 | - | | `--table-name ` | 通过表名获取表元数据 | - | | `--schema-name ` | 所属数据库的名称 | public | | `--catalog-name ` | 所属 catalog 的名称 | greptime | | `--pretty` | 美化输出 | - | ## 写入键值对 ### 命令语法 ```bash greptime cli meta put key [OPTIONS] [KEY] ``` ### 选项 | 选项 | 描述 | 默认值 | | --------------- | ------------------------------------ | ------ | | `--value-stdin` | 从标准输入读取要写入的值 | - | | `--no-validate` | 写入前跳过元数据校验 | false | :::note `--value-stdin` 为必填项。 ::: ## 写入表元数据 ### 写入表信息 #### 命令语法 ```bash greptime cli meta put table info [OPTIONS] ``` #### 选项 | 选项 | 描述 | 默认值 | | ------------------------------- | ----------------------------------------------------- | -------- | | `--table-id ` | 通过表 ID 选择表 | - | | `--table-name ` | 通过表名选择表 | - | | `--schema-name ` | 所属数据库的名称 | public | | `--catalog-name ` | 所属 catalog 的名称 | greptime | | `--value-stdin` | 从标准输入读取 JSON 编码的 `TableInfoValue`(必填) | - | ### 写入表路由 #### 命令语法 ```bash greptime cli meta put table route [OPTIONS] ``` #### 选项 | 选项 | 描述 | 默认值 | | ------------------------------- | ------------------------------------------------------ | -------- | | `--table-id ` | 通过表 ID 选择表 | - | | `--table-name ` | 通过表名选择表 | - | | `--schema-name ` | 所属数据库的名称 | public | | `--catalog-name ` | 所属 catalog 的名称 | greptime | | `--value-stdin` | 从标准输入读取 JSON 编码的 `TableRouteValue`(必填) | - | ## 删除键值对 ### 命令语法 ```bash greptime cli meta del key [OPTIONS] [KEY] ``` ### 选项 | Option | 描述 | 默认值 | | ---------- | -------------------------- | ------ | | `--prefix` | 删除具有给定前缀的键值对。 | false | ## 删除表元数据 ### 命令语法 ```bash greptime cli meta del table [OPTIONS] ``` #### 选项 | Option | 描述 | 默认值 | | ------------------------------- | ---------------------- | -------- | | `--table-id ` | 通过表 ID 获取表元数据 | - | | `--table-name ` | 通过表名获取表元数据 | - | | `--schema-name ` | 表所属数据库的名称 | public | | `--catalog-name ` | 表所属 catalog 的名称 | greptime | ## 示例 ### 获取单个键值对 ```bash greptime cli meta get key --store-addrs=$ENDPOINT \ --backend=postgres-store \ __table_name/greptime/public/metric_table_2 ``` 输出: ```json __table_name/greptime/public/metric_table_2 {"table_id":1059} ``` ### 获取所有具有给定前缀的键值对 输出: ```bash greptime cli meta get key --prefix \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ __table_name/greptime/public ``` ```json __table_name/greptime/public/greptime_physical_table {"table_id":1057} __table_name/greptime/public/metric_table_1 {"table_id":1058} __table_name/greptime/public/metric_table_2 {"table_id":1059} ``` ### 通过表 ID 获取表元数据 ```bash greptime cli meta get table --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store ``` 输出: ```json __table_info/1059 { "table_info": { "ident": { "table_id": 1059, "version": 0 }, "name": "metric_table_2", "desc": null, "catalog_name": "greptime", "schema_name": "public", "meta": { "schema": { "column_schemas": [ { "name": "app", "data_type": { "String": null }, "is_nullable": true, "is_time_index": false, "default_constraint": null, "metadata": {} }, ... ], "timestamp_index": 2, "version": 0 }, "primary_key_indices": [ 0, ... ], "value_indices": [ 3 ], "engine": "metric", "next_column_id": 8, "region_numbers": [ 0, ... ], "options": { "write_buffer_size": null, "ttl": null, "skip_wal": false, "extra_options": { "on_physical_table": "greptime_physical_table" } }, "created_on": "2025-06-17T14:53:14.639207075Z", "partition_key_indices": [] }, "table_type": "Base" }, "version": 0 } __table_route/1059 { "type": "logical", "physical_table_id": 1057, "region_ids": [ 4548370366464, 4548370366465, ... ] } ``` ### 通过表名获取表元数据 ```bash greptime cli meta get table --table-name=metric_table_2 \ --schema-name=public \ --store-addrs=$ENDPOINT \ --backend=postgres-store ``` 输出: 与上述命令的输出相同。 ### 写入表信息 ```bash cat table_info.json | greptime cli meta put table info \ --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --value-stdin ``` 输出: ```bash Table(1059) info updated ``` ### 写入表路由 ```bash cat table_route.json | greptime cli meta put table route \ --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --value-stdin ``` 输出: ```bash Table(1059) route updated ``` ## 删除不存在的键值对 ```bash greptime cli meta del key --store-addrs=$ENDPOINT \ --backend=postgres-store \ non_existent_key ``` 输出(返回删除的键值对数量): ```bash 0 ``` ## 删除键值对 ```bash greptime cli meta del key --store-addrs=$ENDPOINT \ --backend=postgres-store \ __table_name/greptime/public/metric_table_3 ``` 输出(返回删除的键值对数量): ```bash 1 ``` ## 删除表元数据 ```bash greptime cli meta del table --table-id=1059 \ --store-addrs=$ENDPOINT \ --backend=postgres-store ``` 输出: ```bash Table(1059) deleted ``` --- ## 元数据导出和导入 元数据导出和导入工具提供了备份和恢复 GreptimeDB 元信息的功能。这些工具允许进行元信息备份和恢复操作。 ## 导出工具 ### 命令语法 ```bash greptime cli meta snapshot save [OPTIONS] ``` ### 选项 #### 存储后端选项 | 选项 | 是否必需 | 默认值 | 描述 | | ------------------ | -------- | ----------------- | ------------------------------------------------------------------------------------------------------ | | --store-addrs | 是 | - | 要连接的元数据存储服务地址(支持 etcd、MySQL、PostgreSQL 和 RaftEngine),格式与 Metasrv 配置中的 store-addrs 一致。RaftEngine 使用 `raftengine:///path/to/metadata` 格式 | | --backend | 是 | - | 元数据存储后端类型,支持 `etcd-store`、`postgres-store`、`mysql-store`、`raft-engine-store` | | --store-key-prefix | 否 | "" | 元数据存储前缀,参考 Metasrv 配置 | | --meta-table-name | 否 | greptime_metakv | 当后端为 `postgres-store` 或 `mysql-store` 时,元数据存储的表名 | | --max-txn-ops | 否 | 128 | 最大事务操作数 | #### 文件选项 | 选项 | 是否必需 | 默认值 | 描述 | | ----------- | -------- | ----------------- | -------------------------------------------------- | | --file-name | 否 | metadata_snapshot | 元数据导出的文件名,会自动添加 `.metadata.fb` 后缀 | | --dir | 否 | "" | 存储导出数据的目录 | #### 对象存储选项 要使用对象存储来存储导出的元数据,请启用以下任一提供商并配置其连接参数: ##### S3 | 选项 | 是否必需 | 默认值 | 描述 | | ------------------------------ | -------- | ------ | ------------------------------------------- | | --s3 | 否 | false | 是否使用 S3 作为导出数据的存储介质 | | --s3-bucket | 否 | - | S3 桶名 | | --s3-root | 否 | - | S3 桶中的根路径 | | --s3-access-key-id | 否 | - | S3 访问密钥 ID | | --s3-secret-access-key | 否 | - | S3 访问密钥 | | --s3-region | 否 | - | S3 区域名称 | | --s3-endpoint | 否 | - | S3 端点 URL(可选,默认根据桶区域确定) | | --s3-enable-virtual-host-style | 否 | false | 为 S3 API 请求启用虚拟主机样式 | ##### OSS(阿里云) | 选项 | 是否必需 | 默认值 | 描述 | | ----------------------- | -------- | ------ | ---------------------------------- | | --oss | 否 | false | 是否使用 OSS 作为导出数据的存储介质 | | --oss-bucket | 否 | - | OSS 桶名 | | --oss-root | 否 | - | OSS 桶中的根路径 | | --oss-access-key-id | 否 | - | OSS 访问密钥 ID | | --oss-access-key-secret | 否 | - | OSS 访问密钥 | | --oss-endpoint | 否 | - | OSS 端点 URL | ##### GCS(谷歌云存储) | 选项 | 是否必需 | 默认值 | 描述 | | --------------------- | -------- | ------ | ---------------------------------- | | --gcs | 否 | false | 是否使用 GCS 作为导出数据的存储介质 | | --gcs-bucket | 否 | - | GCS 桶名 | | --gcs-root | 否 | - | GCS 桶中的根路径 | | --gcs-scope | 否 | - | GCS 服务范围 | | --gcs-credential | 否 | - | GCS 凭证内容 | | --gcs-endpoint | 否 | - | GCS 端点 URL | ##### Azure Blob 存储 | 选项 | 是否必需 | 默认值 | 描述 | | --------------------- | -------- | ------ | ---------------------------------------- | | --azblob | 否 | false | 是否使用 Azure Blob 作为导出数据的存储介质 | | --azblob-container | 否 | - | Azure Blob 容器名称 | | --azblob-root | 否 | - | 容器中的根路径 | | --azblob-account-name | 否 | - | Azure Blob 账户名称 | | --azblob-account-key | 否 | - | Azure Blob 账户密钥 | | --azblob-endpoint | 否 | - | Azure Blob 端点 URL | | --azblob-sas-token | 否 | - | Azure Blob SAS 令牌 | ## 导入工具 ### 命令语法 ```bash greptime cli meta snapshot restore [OPTIONS] ``` ### 选项 #### 存储后端选项 | 选项 | 是否必需 | 默认值 | 描述 | | ------------------ | -------- | --------------- | ------------------------------------------------------------------------------------------------------ | | --store-addrs | 是 | - | 要连接的元数据存储服务地址(支持 etcd、MySQL、PostgreSQL 和 RaftEngine),格式与 Metasrv 配置中的 store-addrs 一致。RaftEngine 使用 `raftengine:///path/to/metadata` 格式 | | --backend | 是 | - | 元数据存储后端类型,支持 `etcd-store`、`postgres-store`、`mysql-store`、`raft-engine-store` | | --store-key-prefix | 否 | "" | 元数据存储的 key 前缀,参考 Metasrv 配置 | | --meta-table-name | 否 | greptime_metakv | 当后端为 `postgres-store` 或 `mysql-store` 时,元数据存储的表名 | | --max-txn-ops | 否 | 128 | 最大事务操作数 | #### 文件选项 | 选项 | 是否必需 | 默认值 | 描述 | | ----------- | -------- | ----------------------------- | -------------------------------------------------------------------------------------- | | --file-name | 否 | metadata_snapshot.metadata.fb | 元数据导出的文件名 | | --dir | 否 | "." | 存储导出数据的目录 | | --force | 否 | false | 是否强制导入,当目标后端检测包含旧数据时,默认无法导入数据,若想强制导入则可开启此标志 | #### 对象存储选项 要使用对象存储来导入元数据,请启用以下任一提供商并配置其连接参数: ##### S3 | 选项 | 是否必需 | 默认值 | 描述 | | ------------------------------ | -------- | ------ | ------------------------------------------- | | --s3 | 否 | false | 是否使用 S3 作为导出数据的存储介质 | | --s3-bucket | 否 | - | S3 桶名 | | --s3-root | 否 | - | S3 桶中的根路径 | | --s3-access-key-id | 否 | - | S3 访问密钥 ID | | --s3-secret-access-key | 否 | - | S3 访问密钥 | | --s3-region | 否 | - | S3 区域名称 | | --s3-endpoint | 否 | - | S3 端点 URL(可选,默认根据桶区域确定) | | --s3-enable-virtual-host-style | 否 | false | 为 S3 API 请求启用虚拟主机样式 | ##### OSS(阿里云) | 选项 | 是否必需 | 默认值 | 描述 | | ----------------------- | -------- | ------ | ---------------------------------- | | --oss | 否 | false | 是否使用 OSS 作为导出数据的存储介质 | | --oss-bucket | 否 | - | OSS 桶名 | | --oss-root | 否 | - | OSS 桶中的根路径 | | --oss-access-key-id | 否 | - | OSS 访问密钥 ID | | --oss-access-key-secret | 否 | - | OSS 访问密钥 | | --oss-endpoint | 否 | - | OSS 端点 URL | ##### GCS(谷歌云存储) | 选项 | 是否必需 | 默认值 | 描述 | | --------------------- | -------- | ------ | ---------------------------------- | | --gcs | 否 | false | 是否使用 GCS 作为导出数据的存储介质 | | --gcs-bucket | 否 | - | GCS 桶名 | | --gcs-root | 否 | - | GCS 桶中的根路径 | | --gcs-scope | 否 | - | GCS 服务范围 | | --gcs-credential | 否 | - | GCS 凭证内容 | | --gcs-endpoint | 否 | - | GCS 端点 URL | ##### Azure Blob 存储 | 选项 | 是否必需 | 默认值 | 描述 | | --------------------- | -------- | ------ | ---------------------------------------- | | --azblob | 否 | false | 是否使用 Azure Blob 作为导出数据的存储介质 | | --azblob-container | 否 | - | Azure Blob 容器名称 | | --azblob-root | 否 | - | 容器中的根路径 | | --azblob-account-name | 否 | - | Azure Blob 账户名称 | | --azblob-account-key | 否 | - | Azure Blob 账户密钥 | | --azblob-endpoint | 否 | - | Azure Blob 端点 URL | | --azblob-sas-token | 否 | - | Azure Blob SAS 令牌 | ## 信息工具 信息工具允许您查看元数据快照的内容而无需恢复它。 ### 命令语法 ```bash greptime cli meta snapshot info [OPTIONS] ``` ### 选项 #### 文件选项 | 选项 | 是否必需 | 默认值 | 描述 | | ------------- | -------- | ----------------- | ---------------------- | | --file-name | 否 | metadata_snapshot | 要查看的元数据快照文件名 | | --dir | 否 | "." | 快照文件存储的目录 | | --inspect-key | 否 | "*" | 过滤元数据键的查询模式 | | --limit | 否 | - | 显示的最大条目数 | #### 对象存储选项 要检查存储在对象存储中的快照,请启用以下任一提供商并配置其连接参数: ##### S3 | 选项 | 是否必需 | 默认值 | 描述 | | ------------------------------ | -------- | ------ | --------------------------------------- | | --s3 | 否 | false | 是否使用 S3 作为快照的存储介质 | | --s3-bucket | 否 | - | S3 桶名 | | --s3-root | 否 | - | S3 桶中的根路径 | | --s3-access-key-id | 否 | - | S3 访问密钥 ID | | --s3-secret-access-key | 否 | - | S3 访问密钥 | | --s3-region | 否 | - | S3 区域名称 | | --s3-endpoint | 否 | - | S3 端点 URL(可选,默认根据桶区域确定) | | --s3-enable-virtual-host-style | 否 | false | 为 S3 API 请求启用虚拟主机样式 | ##### OSS(阿里云) | 选项 | 是否必需 | 默认值 | 描述 | | ----------------------- | -------- | ------ | ------------------------------ | | --oss | 否 | false | 是否使用 OSS 作为快照的存储介质 | | --oss-bucket | 否 | - | OSS 桶名 | | --oss-root | 否 | - | OSS 桶中的根路径 | | --oss-access-key-id | 否 | - | OSS 访问密钥 ID | | --oss-access-key-secret | 否 | - | OSS 访问密钥 | | --oss-endpoint | 否 | - | OSS 端点 URL | ##### GCS(谷歌云存储) | 选项 | 是否必需 | 默认值 | 描述 | | --------------------- | -------- | ------ | ------------------------------ | | --gcs | 否 | false | 是否使用 GCS 作为快照的存储介质 | | --gcs-bucket | 否 | - | GCS 桶名 | | --gcs-root | 否 | - | GCS 桶中的根路径 | | --gcs-scope | 否 | - | GCS 服务范围 | | --gcs-credential | 否 | - | GCS 凭证内容 | | --gcs-endpoint | 否 | - | GCS 端点 URL | ##### Azure Blob 存储 | 选项 | 是否必需 | 默认值 | 描述 | | --------------------- | -------- | ------ | ------------------------------------ | | --azblob | 否 | false | 是否使用 Azure Blob 作为快照的存储介质 | | --azblob-container | 否 | - | Azure Blob 容器名称 | | --azblob-root | 否 | - | 容器中的根路径 | | --azblob-account-name | 否 | - | Azure Blob 账户名称 | | --azblob-account-key | 否 | - | Azure Blob 账户密钥 | | --azblob-endpoint | 否 | - | Azure Blob 端点 URL | | --azblob-sas-token | 否 | - | Azure Blob SAS 令牌 | --- ## 逻辑表修复 `greptime cli meta repair logical-tables` 命令可以用于修复 GreptimeDB 集群的逻辑表。在某些情况下,逻辑表元数据可能与存储在元数据存储中的元数据不一致。此命令可用于修复逻辑表元数据。 :::tip 该工具需要连接到元数据存储和 Datanode。确保集群正在运行且工具可与 Datanode 通信。 ::: ## 命令语法 ```bash greptime cli meta repair logical-tables [OPTIONS] ``` ## 选项 | 选项 | 描述 | 默认值 | 值 | | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ----------------------------------------------------- | | `--store-addrs ...` | 元数据存储服务地址。可以是 etcd、postgres 或 mysql。 对于 postgres 存储,格式为:`"password=password dbname=postgres user=postgres host=localhost port=5432"`。 对于 etcd 存储,格式为:`"127.0.0.1:2379"`。 对于 mysql 存储,格式为:`"mysql://user:password@ip:port/dbname"` | - | - | | `--max-txn-ops ` | 单个事务中操作的最大数量。仅在使用 [etcd-store] 时使用 | 128 | - | | `--backend ` | 元数据存储后端类型 | etcd-store | etcd-store, memory-store, postgres-store, mysql-store | | `--store-key-prefix ` | 元数据存储前缀 | - | - | | `--meta-table-name ` | 元数据存储的表名。元数据存储后端为 [postgres-store] 或 [mysql-store] 时使用 | greptime_metakv | - | | `--table-names ` | 要修复的表名,用逗号分隔 | - | | `--table-ids ` | 要修复的表 ID,用逗号分隔 | - | | `--schema-name ` | 要修复的表所属数据库的名称 | public | | `--catalog-name ` | 要修复的表所属 catalog 的名称 | greptime | | `--fail-fast` | 如果任何修复操作失败,是否立即失败 | - | | `--client-timeout-secs ` | 客户端操作 Datanode 的超时时间 | 30 | | `--client-connect-timeout-secs ` | 客户端连接 Datanode 的超时时间 | 3 | ## 示例 ### 通过表名修复逻辑表 ```bash greptime cli meta repair logical-tables --store-addrs=$ENDPOINT \ --backend=postgres-store \ --table-names=metric_table_1,metric_table_2 \ --schema-name=public \ --catalog-name=greptime ``` 输出: ```bash 2025-06-20T08:31:43.904497Z INFO cli::metadata::repair: All alter table requests sent successfully for table: greptime.public.metric_table_1 2025-06-20T08:31:43.904499Z INFO cli::metadata::repair: All alter table requests sent successfully for table: greptime.public.metric_table_2 2025-06-20T08:31:43.904539Z INFO cli::metadata::repair: Repair logical tables result: 2 tables repaired, 0 tables skipped ``` --- ## 修复分区列 `greptime cli meta repair partition-column` 命令可用于修复 GreptimeDB 集群的分区列。 ## 何时使用此工具 在 [PR-6494](https://github.com/GreptimeTeam/greptimedb/pull/6494) 之前,表元数据中的分区列可能会引用到无效的列。例如,当在分区列之前向表中添加新列时,可能会导致分区列偏移。 如果你发现由于分区列错误导致读取或写入失败,可以使用此工具。该工具将扫描所有表的元数据,并将分区列设置为正确的列。 ## 命令语法 ```bash greptime cli meta repair partition-column [OPTIONS] ``` ## 选项 | 选项 | 描述 | 默认值 | 值 | | - | - | - | - | | `--store-addrs ` | 元数据的存储后端地址。可以是 etcd、postgres 或 mysql 之一。对于 postgres 存储,格式为:`"password=password dbname=postgres user=postgres host=localhost port=5432"`。对于 etcd 存储,格式为:`"127.0.0.1:2379"`。对于 mysql 存储,格式为:`"mysql://user:password@ip:port/dbname"` | | 字符串 | | `--backend ` | 元数据存储后端类型 | `etcd-store` | 以下其一:`etcd-store``memory-store``postgres-store``mysql-store` | | `--max-txn-ops ` | 事务中的最大操作数。仅在使用 `etcd-store` 时使用。 | `128` | 数字 | | `--store-key-prefix ` | 元数据存储的键前缀 | "" | 字符串 | | `--meta-table-name ` | RDS 中存储元数据的表名。仅在使用 `postgres-store` 或 `mysql-store` 时使用。 | `greptime_metakv` | 字符串 | | `--dry-run ` | 如果存在此选项,该工具将不会对表元数据进行任何更改。相反,它只会报告(通过向标准输出打印日志)无效的分区列。建议在第一次运行此工具时添加此选项,并手动验证结果。 | `false` | 以下其一:`true``false` | | `--update-limit ` | 该工具对表元数据执行更改的最大次数。此选项可用于逐步更新表元数据。 | 无限制 | 数字 | ## 示例 ```bash greptime cli meta repair partition-column \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --dry-run true \ --update-limit 1 ``` --- ## Glossary(术语表) 欢迎访问 GreptimeDB 技术术语库!本资源系统阐释了云原生开源时序数据库 GreptimeDB 的核心概念与关键技术术语,涵盖指标、日志及事件处理领域。通过本术语库,您将深入理解支撑 GreptimeDB 的创新架构与技术实现。 > 注:该排名顺序按照英文词汇首字母正序排列。 --- ## A ### Anomaly Detection (异常检测) 识别数据点、事件或观测值显著偏离常态的过程。在时序数据场景中,异常检测可辅助发现可能表征关键事件的非常规模式。 ### Append Only Table (Append Only 表) GreptimeDB 中针对写入密集型工作负载优化的表类型,数据仅插入而不更新或删除。这种设计显著提升写入和查询性能,特别适用于日志分析和时序数据场景。 --- ## C ### Cardinality (基数) 衡量数据库元素唯一性的指标,如数据列中唯一值的数量。高基数场景(尤其在时序数据中)将显著提升存储复杂度与资源需求。 ### Cloud-Native Design (云原生架构) 基于云计算框架构建弹性可扩展应用的架构方法论。GreptimeDB 的云原生设计支持从边缘计算节点到云端分布式集群的无缝扩展。 ### Columnar Storage (列式存储) 按列而非行组织数据表的存储格式。该格式显著提升分析型查询效率,是 GreptimeDB 实现高性价比的重要技术基础。 --- ## D ### Decoupled Compute and Storage Architecture (存算分离架构) 将计算资源与存储资源解耦管理的架构设计。该架构支持独立扩展与资源优化,实现工作负载管理的灵活性与高性能。 --- ## E ### Edge Database (边缘数据库) 部署在网络边缘侧(临近数据源或终端用户)的数据库系统,通过降低数据传输延迟实现实时数据处理。 ### Edge Deployment (边缘部署) 在临近数据源或终端用户的边缘节点部署服务的实践方案。GreptimeDB 支持边缘部署模式,可在资源受限环境下实现实时数据处理。 ### Event Management (事件管理) 对指标、日志、追踪等事件数据进行采集、组织与分析的系统化实践,是保障实时系统稳定运行的核心环节。 --- ## D ### Datanode (数据节点) GreptimeDB 分布式架构中负责数据存储和处理的核心组件。Datanode 处理数据摄入、存储管理、本地数据查询执行,并维护包含实际表数据的 region。可在集群中部署多个 datanode 以提供水平可扩展性、容错能力和分布式数据处理能力。 --- ## F ### Field (字段) GreptimeDB 数据模型中包含实际测量数据或日志内容的列类型。Field 存储数值、文本内容或其他数据指标,代表时序数据中的核心信息,与 Tag 和 Time Index 列相补构成完整的数据模型。 ### Flow Engine (流处理引擎) GreptimeDB 的实时流数据处理系统,支持对流式数据进行连续增量计算。Flow Engine 类似智能物化视图,当源表有新数据到达时自动更新结果表。以可配置间隔(默认一秒)处理数据,计算开销极小,特别适用于 ETL 流程、降采样、实时分析和持续聚合等场景。 ### Frontend (前端节点) GreptimeDB 分布式架构中的查询处理层,作为客户端连接的入口点。Frontend 节点处理 SQL 解析、查询规划、分布式查询协调和结果聚合。它们将查询路由到适当的 datanode,管理客户端会话,并为各种数据库接口(包括 MySQL、PostgreSQL 和 GreptimeDB 原生协议)提供协议兼容性。 --- ## G ### GreptimeCloud GreptimeDB 的全托管云服务,提供 serverless 自动扩展的数据库即服务(DBaaS)能力。GreptimeCloud 通过自动扩展、按量付费、企业级安全和无缝云边协同部署等特性消除运维开销,非常适合寻求无忧可观测性数据库解决方案的组织。 --- ## I ### IoT Cloud (物联网云平台) 专为物联网应用设计的云计算平台,提供海量设备数据存储、处理与连接管理能力。 ### IoT Database (物联网数据库) 针对物联网传感器高频时序数据优化的数据库系统。GreptimeDB 可高效处理物联网设备产生的大规模时序数据,提供弹性扩展能力。 ### IoT Observability (物联网可观测性) 通过指标、日志与事件数据对物联网设备及系统进行监控、分析与洞察的能力,确保物联网生态的可靠运行。 ### Interoperability (协议互操作性) 异构系统间无缝协作的能力。GreptimeDB 原生支持 SQL、InfluxDB、OpenTelemetry、Prometheus、Elasticsearch、Loki 等协议与 API,实现开箱即用的系统集成。 --- ## L ### Log Aggregation (日志聚合) 对一组日志执行计算以生成单个摘要统计数据,以供分析和故障排除,例如 SUM,COUNT 等。 ### Log Management (日志管理) 涵盖日志采集、存储、分析与可视化的全生命周期管理方案,是保障系统性能与安全的重要基础。 --- ## M ### Memory Leak (内存泄漏) 程序未能正确释放闲置内存导致的软件缺陷,长期运行可能引发系统性能下降或崩溃。 ### Metric Engine (指标引擎) GreptimeDB 中专门设计用于高效处理指标数据的存储引擎,特别适用于可观测性工作负载中常见的数千个小表场景。Metric Engine 使用合成的宽物理表来存储来自众多逻辑表的数据,实现高效的列和元数据重用,降低存储开销并增强列式压缩效果。基于 Mito Engine 构建,提供强大的存储能力。 ### Mito Engine (Mito 引擎) GreptimeDB 的默认存储引擎,基于日志结构合并树(LSM-Tree)架构,针对时序工作负载进行优化。Mito 具备预写日志(WAL)、内存表和时间窗口压缩策略(TWCS),能够处理高吞吐量写入同时保持出色的查询性能。原生集成对象存储解决方案(S3、GCS、Azure Blob)并实现分层缓存以优化存储成本和访问速度。 --- ## L ### LSM-Tree (日志结构合并树) GreptimeDB 存储引擎采用的数据结构,通过先将数据写入日志再定期合并为有序结构来优化写入性能。该设计特别适合高写入吞吐量的时序工作负载。 --- ## M ### Metasrv (元数据服务) GreptimeDB 分布式架构中的元数据管理服务,维护集群状态、表结构和 region 分布信息。Metasrv 协调集群操作,管理表的创建和修改,处理 region 分配和迁移,确保集群范围内的元数据一致性。它作为集群管理的中央控制平面,是所有元数据操作的权威数据源。 --- ## O ### Observability (可观测性) 通过系统外部输出推断内部状态的能力。GreptimeDB 作为可观测性基础设施,可通过指标、日志与事件数据实现系统性能监控与深度洞察。 ### OpenTelemetry 面向云原生应用的开源可观测性框架,提供遥测数据(追踪、指标、日志)的采集、处理与导出工具链。GreptimeDB 深度集成 OpenTelemetry 以强化数据可观测性。 --- ## P ### Pipeline (数据管道) GreptimeDB 中用于实时处理传入数据的强大解析和转换机制。Pipeline 由可配置的处理器组成,用于预处理原始数据;分发器用于将数据路由到不同管道;以及转换规则用于数据类型转换和表结构定义。支持多种输入格式和数据源(包括日志、Prometheus 指标和其他可观测性数据),提供广泛的处理能力,包括时间戳解析、正则匹配、字段提取和数据类型转换,实现可观测性数据的结构化存储和高效查询。 ### PromQL (Prometheus 查询语言) 专为 Prometheus 设计的时序数据查询语言。GreptimeDB 支持 PromQL 且兼容性接近 100%,支持用户执行复杂的时序数据分析操作并使用现有的 Prometheus 仪表盘和告警规则。 --- ## R ### Read Replica (读副本) GreptimeDB 企业版中的功能,通过创建额外的只读数据实例来提升查询性能和可扩展性。读副本将读取工作负载分布到多个实例上,减少主数据库的负载同时提供更快的查询响应。该功能支持数据访问点的地理分布,提升读取操作的高可用性,并在企业环境中实现读密集型工作负载的高效扩展。 ### Region (区域) GreptimeDB 架构中数据分布的基本单元。Region 包含表数据的子集,可分布在集群的不同节点上。每个 Region 管理自己的存储、索引和查询处理,实现水平扩展和容错能力。 ### Repartition (重分区) 通过合并已有分区并按新规则拆分分区来调整建表后的分区边界的过程。重分区用于更好地匹配当前数据分布、缓解热点,并减少冷小分区。 ### Rust 以前沿内存安全特性著称的系统级编程语言。GreptimeDB 采用 Rust 语言构建,为其高性能与高可靠性提供底层保障。 --- ## S ### Scalability (弹性扩展) 通过垂直扩展(提升单节点性能)或水平扩展(增加集群节点)应对数据量与查询负载增长的能力。GreptimeDB 的弹性扩展特性确保系统在业务增长时持续保持高性能。 ### SQL 关系型数据库的标准查询语言。GreptimeDB 支持使用 SQL 对指标、日志及事件数据进行高效查询。 ### Stream Processing (流式处理) 对到达的数据流进行连续实时处理的技术。在 GreptimeDB 中,流式处理通过 Flow Engine 实现,对流式时序数据执行增量计算。支持对 metrics、logs 和 events 进行即时过滤、计算和聚合,以最小延迟提供可操作的洞察。 --- ## T ### Tag (标签) GreptimeDB 数据模型中用于唯一标识时序数据的列类型。具有相同 Tag 值的行属于同一个时间序列,使 Tag 成为组织和查询可观测性数据的关键。Tag 通常用于存储元数据,如主机名、服务名或设备 ID,并在表架构中指定为 PRIMARY KEY 列。 ### Time Index (时间索引) GreptimeDB 表中的特殊时间戳列,作为时序数据的主要时间维度。每个 GreptimeDB 表都需要一个 Time Index 列来按时间顺序组织数据,实现基于时间的查询,支持高效的时序操作,如降采样和时间窗口聚合。 ### Time Series Database (时序数据库) 专为时间戳索引数据设计的数据库类型。GreptimeDB 作为云原生时序数据库,深度优化了对指标、日志及事件的分析查询性能。 ### Table Sharding (表分片) 将一张大表拆分为多个更小分区的技术。在 GreptimeDB 中,表分片有助于将负载分散到多个 region 上,并提升热点表或大表的吞吐能力。 --- ## T ### Trigger (触发器) GreptimeDB 企业版中的监控和告警功能,支持对时序数据条件进行自动化评估。Trigger 在指定间隔内持续监控表中的数据,执行基于 SQL 的规则来检查预定义的阈值或条件,并在满足条件时通过 webhook 发送通知。该功能与 Alertmanager 等告警系统集成,支持自定义标签和注释,特别适用于实时系统监控、性能告警和自动化事件响应。 --- ## U ### Unified Analysis (统一分析) 在单一平台集成多源异构数据分析的能力。GreptimeDB 通过兼容 SQL 与 PromQL 实现跨数据类型(指标/日志/事件)的统一查询分析。 ### Unified Observability (统一可观测性) 将 metrics、logs 和 traces 整合到单一系统中的数据库架构方法,消除数据孤岛并降低运维复杂性。GreptimeDB 通过将所有遥测数据类型视为带有时间戳的宽事件来实现统一可观测性,实现跨信号关联、简化数据管道和成本高效的可观测性基础设施。 --- ## W ### WAL (预写日志) GreptimeDB 用于确保数据持久性和一致性的日志机制。WAL 在数据变更应用到主存储之前记录所有变更,在系统故障时实现数据恢复。GreptimeDB 支持灵活的 WAL 选项,包括本地磁盘存储或 Kafka 等分布式服务。 ### Wide Events (宽事件) 可观测性 2.0 中的基础概念,将 metrics、logs 和 traces 融合为单一综合事件的上下文丰富、高维度遥测数据。宽事件捕获每次服务交互的广泛上下文信息,包括高基数字段(用户 ID、会话 ID)、业务逻辑数据、基础设施详情和请求元数据。GreptimeDB 原生支持将宽事件作为带时间戳的可观测性数据,支持复杂的多维度查询并解决系统行为分析中的 "unknown unknowns" 问题。 --- ## V ### Vector Processing (向量化处理) GreptimeDB 查询引擎采用的高性能数据处理技术,通过批量操作数据向量(数组)来提升查询性能。支持 SIMD 指令加速,显著提升大规模时序数据的分析速度。 ### Vehicle Data Collection (车载数据采集) 对车辆传感器读数、GPS 定位信息等数据进行采集的标准化流程,是现代车联网生态的核心组成部分。 ### Vehicle-Cloud Integrated TSDB (车云协同时序数据库) 专为车联网设计的时序数据库系统,支持车载终端与云端系统的协同工作,实现车联网数据的高效存储与实时分析。 --- *注:本术语表将持续更新,以反映 GreptimeDB 生态的最新功能演进与技术概念扩展。* --- --- ## gtctl [gtctl][1],g-t-control,是一个用于管理 GreptimeDB 集群的命令行工具。gtctl 是集成了 GreptimeDB 集群的多种操作的多合一 binary。 ## 安装 ### 一键安装 使用以下命令下载二进制文件: ```bash curl -fsSL https://raw.githubusercontent.com/greptimeteam/gtctl/develop/hack/install.sh | sh ``` 下载完成后,gtctl 将位于当前目录中。 你还可以从 AWS 中国区 S3 存储桶安装 gtctl: ```bash curl -fsSL https://downloads.greptime.cn/releases/scripts/gtctl/install.sh | sh -s -- -s aws ``` ### 通过 Homebrew 安装 在 macOS 上,可以通过 Homebrew 安装 gtctl: ```bash brew tap greptimeteam/greptime brew install gtctl ``` ### 从源代码构建 如果已经安装了 [Go][2],可以在该项目下运行 `make` 命令来构建 gtctl: ```bash make gtctl ``` 构建完成后,gtctl 将生成在 `./bin/` 目录下。如果想要安装 gtctl,可以运行 `install` 命令: ```bash # 构建的 gtctl 将安装在 /usr/local/bin 目录下 make install # 构建的 gtctl 将安装在自定义路径下 make install INSTALL_DIR= ``` ## 启用 gtctl 自动补全(可选) gtctl 支持多种不同的 shell 自动补全。 ### Bash 在 Bash 中,可以使用命令 `gtctl completion bash` 生成 gtctl 的自动补全脚本。将补全脚本引入到你的 shell 中可以启用 gtctl 的自动补全功能。 ```bash echo 'source <(gtctl completion bash)' >> ~/.bashrc ``` ### Zsh 在 Zsh 中,可以使用命令 `gtctl completion zsh` 生成 gtctl 的自动补全脚本。将补全脚本引入到你的 shell 中可以启用 gtctl 的自动补全功能。 ```bash mkdir -p $ZSH/completions && gtctl completion zsh > $ZSH/completions/_gtctl ``` ### Fish 在 Fish 中,可以使用命令 `gtctl completion fish` 生成 gtctl 的自动补全脚本。将补全脚本引入到你的 shell 中可以启用 gtctl 的自动补全功能。 ```bash gtctl completion fish | source ``` ## 快速入门 体验 GreptimeDB 集群的**最快**方法是使用 playground: ```bash gtctl playground ``` `playground` 命令将在你的环境中以**裸机**模式部署最小的 GreptimeDB 集群。 ## 部署 gtctl 支持两种部署模式:Kubernetes 和裸机模式(Bare-Metal)。 ### Kubernetes #### 先决条件 * 需要 Kubernetes 版本 1.18 或更高。 你可以使用 [kind][3] 创建自己的 Kubernetes 集群: ```bash kind create cluster ``` #### 创建 创建自己的 GreptimeDB 集群和 etcd 集群: ```bash gtctl cluster create mycluster -n default ``` 如果你想使用存储在中国区的 artifacts(charts 和镜像),你可以启用 `--use-greptime-cn-artifacts`: ```bash gtctl cluster create mycluster -n default --use-greptime-cn-artifacts ``` 创建完成后,整个 GreptimeDB 集群将在 default 命名空间中启动: ```bash # 获取集群。 gtctl cluster get mycluster -n default # 列出所有集群。 gtctl cluster list ``` 所有在 [charts][4] 中提供的用于 cluster、etcd 和 operator 的值都是可配置的,你可以使用 `--set` 进行配置。gtctl 还提供了一些常用的配置选项,你可以使用 `gtctl cluster create --help` 来查看它们。 ```bash # 将 cluster datanode 副本数配置为 5 gtctl cluster create mycluster --set cluster.datanode.replicas=5 # 两种配置 etcd 存储大小为 15Gi 的方式 gtctl cluster create mycluster --set etcd.storage.volumeSize=15Gi gtctl cluster create mycluster --etcd-storage-size 15Gi ``` #### 预运行 在集群创建过程中,gtctl 提供了 `--dry-run` 选项。如果用户使用 `--dry-run` 执行命令,gtctl 将输出清单的内容而不应用它们: ```bash gtctl cluster create mycluster -n default --dry-run ``` #### 连接 你可以使用 kubectl 的 `port-forward` 命令将前端请求转发到本地: ```bash kubectl port-forward svc/mycluster-frontend 4002:4002 > connections.out & ``` 使用 gtctl 的 `connect` 命令或你的 `mysql` 客户端连接到集群: ```bash gtctl cluster connect mycluster -p mysql mysql -h 127.0.0.1 -P 4002 ``` #### 扩缩容(实验性) 你可以使用以下命令来扩展(或缩小)集群的规模: ```bash # 将 datanode 扩展到 3 个副本。 gtctl cluster scale -n -c datanode --replicas 3 # 将 frontend 扩展到 5 个副本。 gtctl cluster scale -n -c frontend --replicas 5 ``` #### 删除 如果你想删除集群,可以执行以下操作: ```bash # 删除集群。 gtctl cluster delete mycluster -n default # 删除集群,包括 etcd 集群。 gtctl cluster delete mycluster -n default --tear-down-etcd ``` ### 裸机模式(Bare-Metal) #### 创建 你可以使用以下简单命令在裸机环境中部署 GreptimeDB 集群: ```bash gtctl cluster create mycluster --bare-metal ``` 它会在 `${HOME}/.gtctl` 中创建所有必要的元信息。 如果你想进行更多的配置,可以使用 yaml 格式的配置文件: ```bash gtctl cluster create mycluster --bare-metal --config ``` 你可以参考 [`examples/bare-metal`][5] 中提供的示例配置文件 `cluster.yaml` 和 `cluster-with-local-artifacts.yaml`。 #### 删除 由于裸机模式下的集群在前台运行,任何 `SIGINT` 和 `SIGTERM` 信号都会删除集群。例如,在键盘上按下 `Ctrl+C` 后集群将被删除。 删除操作还会删除位于 `${HOME}/.gtctl` 中的一个集群的元信息。如果启用了 `--retain-logs`(默认启用),集群的日志将保留。 ## 开发 Makefile 提供了许多有用的工具,你可以简单地运行 `make help` 来获取更多信息: * 编译项目 ```bash make ``` 然后 gtctl 会生成在 `./bin/` 目录下。 * 运行单元测试 ```bash make test ``` * 运行端到端测试 ```bash make e2e ``` [1]: [2]: [3]: [4]: [5]: --- ## HTTP API 端点列表 以下是 GreptimeDB 中各种 HTTP 路径及其用法的完整列表: ## 管理 API 未版本化的端点(不在 `/v1` 下)。用于健康检查、状态、指标等管理用途。 ### 健康检查 - **路径**: `/health` - **方法**: `GET`, `POST` - **描述**: 提供一个健康检查端点以验证服务器是否正在运行。 - **用法**: 访问此端点以检查服务器的健康状态。 请参考[检查 GreptimeDB 健康状态文档](/enterprise/deployments-administration/monitoring/check-db-status.md#查看-greptimedb-是否正常运行)获取示例。 ### 状态 - **路径**: `/status` - **方法**: `GET` - **描述**: 检索服务器的当前状态。 - **用法**: 使用此端点获取服务器状态信息。 请参考[检查 GreptimeDB 状态文档](/enterprise/deployments-administration/monitoring/check-db-status.md#查看-greptimedb-的部署状态)获取示例。 ### 指标 - **路径**: `/metrics` - **方法**: `GET` - **描述**: 暴露 Prometheus 指标以进行监控。 - **用法**: Prometheus 可以抓取此端点以收集指标数据。 示例如下: ```bash curl -X GET http://127.0.0.1:4000/metrics ``` 输出: ```text # HELP greptime_app_version app version # TYPE greptime_app_version gauge greptime_app_version{app="greptime-edge",short_version="main-b4bd34c5",version="0.12.0"} 1 # HELP greptime_catalog_catalog_count catalog catalog count # TYPE greptime_catalog_catalog_count gauge greptime_catalog_catalog_count 1 # HELP greptime_catalog_schema_count catalog schema count # TYPE greptime_catalog_schema_count gauge greptime_catalog_schema_count 3 # HELP greptime_flow_run_interval_ms flow run interval in ms # TYPE greptime_flow_run_interval_ms gauge greptime_flow_run_interval_ms 1000 # HELP greptime_meta_create_catalog meta create catalog # TYPE greptime_meta_create_catalog histogram greptime_meta_create_catalog_bucket{le="0.005"} 1 greptime_meta_create_catalog_bucket{le="0.01"} 1 greptime_meta_create_catalog_bucket{le="0.025"} 1 greptime_meta_create_catalog_bucket{le="0.05"} 1 greptime_meta_create_catalog_bucket{le="0.1"} 1 ... ``` ### 配置 - **路径**: `/config` - **方法**: `GET` - **描述**: 检索服务器的配置选项。 - **用法**: 访问此端点以获取配置详细信息。 示例如下: ```shell curl http://localhost:4000/config ``` 输出包含 GreptimeDB 服务器的配置信息。 ```toml enable_telemetry = true user_provider = "static_user_provider:file:user" init_regions_in_background = false init_regions_parallelism = 16 [http] addr = "127.0.0.1:4000" timeout = "30s" body_limit = "64MiB" is_strict_mode = false # ... ``` ### 仪表盘 - **路径**: `/dashboard` - **方法**: `GET`, `POST` - **描述**: 提供对服务器仪表盘界面的访问。 - **用法**: 访问这些端点以与基于 Web 的仪表盘进行交互。 此仪表盘与 GreptimeDB 服务器一起打包,并提供一个用户友好的界面与服务器进行交互。构建 GreptimeDB 时需要启用相应的编译标志。仪表盘的原始源代码在 https://github.com/GreptimeTeam/dashboard。 ### 日志级别 - **路径**: `/debug/log_level` - **方法**: `POST` - **描述**: 动态调整服务器的日志级别。 - **用法**: 发送日志级别更改请求到此端点。 有关更多信息,请参阅[如何文档](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-change-log-level-on-the-fly.md)。 ### 启用/禁用链路追踪 - **路径**: `/debug/enable_trace` - **方法**: `POST` - **描述**: 在运行时动态启用或禁用分布式链路追踪。 - **用法**: 发送 `true` 启用链路追踪,或发送 `false` 禁用链路追踪。 启用链路追踪示例: ```bash curl --data "true" http://127.0.0.1:4000/debug/enable_trace # 输出: trace enabled ``` 禁用链路追踪示例: ```bash curl --data "false" http://127.0.0.1:4000/debug/enable_trace # 输出: trace disabled ``` 有关链路追踪配置的更多信息,请参阅[链路追踪文档](/user-guide/deployments-administration/monitoring/tracing.md)。 ### 性能分析工具 - **基础路径**: `/debug/prof/` - **端点**: - `cpu` - `mem` - **方法**: `POST` 用于分析数据库节点。 - **描述**: 运行时 CPU 或内存使用情况分析。 - **用法**: - 有关 CPU 分析的详细指南,请参阅 [CPU 分析](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-profile-cpu.md)。 - 有关内存分析的详细指南,请参阅 [内存分析](https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-profile-memory.md)。 ## 查询端点 用于向 GreptimeDB 发送查询的各种查询 API。 ### SQL API - **路径**: `/v1/sql` - **方法**: `GET`, `POST` - **描述**: 执行 SQL 查询。 - **用法**: 在请求体中发送 SQL 语句。 有关 SQL API 的更多信息,请参阅用户指南中的 [HTTP API 文档](/user-guide/protocols/http.md#post-sql-statements)。 ### PromQL API - **路径**: `/v1/promql` - **方法**: `GET`, `POST` - **描述**: 执行 PromQL 查询以获取 Prometheus 兼容的指标,并以 GreptimeDB 的 JSON 格式返回数据。 - **用法**: 在请求体中发送 PromQL 语句。 有关 PromQL API 的更多信息,请参阅 [PromQL 文档](/user-guide/query-data/promql.md)。 ## 协议端点 与 GreptimeDB 兼容的各种协议的端点。如 InfluxDB、Prometheus、OpenTelemetry 等。 ### InfluxDB 兼容性 - **路径**: - `/v1/influxdb/write` - `/v1/influxdb/api/v2/write` - `/v1/influxdb/ping` - `/v1/influxdb/health` - **方法**: - `POST` 用于写入端点。 - `GET` 用于 ping 和健康检查端点。 - **描述**: 提供与 InfluxDB 兼容的数据写入和健康检查端点。 - **用法**: - 使用 InfluxDB 行协议写入数据。 - 使用 ping 和健康检查端点检查服务器状态。 有关 InfluxDB 协议的详细文档,请参阅[这里](/user-guide/protocols/influxdb-line-protocol.md)。 ### Prometheus 远程写入/读取 - **路径**: - `/v1/prometheus/write` - `/v1/prometheus/read` - **方法**: `POST` - **描述**: 支持 Prometheus 远程写入和读取 API。 - **用法**: - 使用 Prometheus 远程写入协议发送指标数据。 - 使用 Prometheus 远程读取协议读取指标数据。 ### Prometheus HTTP API - **基础路径**: `/v1/prometheus/api/v1` - **端点**: - `/format_query` - `/status/buildinfo` - `/query` - `/query_range` - `/labels` - `/series` - `/parse_query` - `/label/{label_name}/values` - **方法**: `GET`, `POST` - **描述**: 提供 Prometheus HTTP API 端点以查询和检索指标数据。 - **用法**: 使用这些端点以标准 Prometheus HTTP API 进行指标交互。 有关 Prometheus HTTP API 的更多信息,请参阅原始 Prometheus 文档 [Prometheus HTTP API](https://prometheus.io/docs/prometheus/latest/querying/api/)。 ### OpenTelemetry 协议 (OTLP) - **路径**: - `/v1/otlp/v1/metrics` - `/v1/otlp/v1/traces` - `/v1/otlp/v1/logs` - **方法**: `POST` - **描述**: 支持 OpenTelemetry 协议以写入 Metrics、Traces 和 Logs。 - **用法**: 将 OpenTelemetry 格式的数据发送到这些端点。 ### Loki 兼容性 - **路径**: `/v1/loki/api/v1/push` - **方法**: `POST` - **描述**: 以兼容 Loki 的 API 写入日志。 - **用法**: 将日志数据以 Loki 的格式发送到此端点。 ### OpenTSDB 协议 - **路径**: `/v1/opentsdb/api/put` - **方法**: `POST` - **描述**: 支持使用 OpenTSDB 协议写入数据。 - **用法**: 使用 OpenTSDB 的 JSON 格式写入时间序列数据。 ## 日志写入端点 - **路径**: - `/v1/ingest` - `/v1/pipelines/{pipeline_name}` - `/v1/pipelines/_dryrun` - **方法**: - `POST` 写入日志和添加 Pipeline。 - `DELETE` 用于删除 Pipeline。 - **描述**: 提供日志写入和 Pipeline 管理的端点。 - **用法**: - 通过 `/logs` 端点写入日志。 - 使用 `/pipelines` 端点管理日志 Pipeline。 有关日志写入和 Pipeline 管理的更多信息,请参阅[日志概述](/user-guide/logs/overview.md)。 --- ## 内置 Pipeline GreptimeDB 提供了常见日志格式的内置 Pipeline,允许你直接使用而无需创建新的 Pipeline。 请注意,内置 Pipeline 的名称以 "greptime_" 为前缀,不可编辑。 ## `greptime_identity` `greptime_identity` Pipeline 适用于写入 JSON 日志,并自动为 JSON 日志中的每个字段创建列。嵌套的 JSON 对象将自动展开为使用点符号的单独列。 - 嵌套对象会被自动展开(例如,`{"a": {"b": 1}}` 变成列 `a.b`) - 数组会被转换为 JSON 字符串 - 如果相同字段包含不同类型的数据,则会返回错误 - 值为 `null` 的字段将被忽略 - 如果没有手动指定,一个作为时间索引的额外列 `greptime_timestamp` 将被添加到表中,以指示日志写入的时间 ### 类型转换规则 - `string` -> `string` - `number` -> `int64` 或 `float64` - `boolean` -> `bool` - `null` -> 忽略 - `array` -> `string`(JSON 字符串格式) - `object` -> 自动展开为单独的列(参见[展开 JSON 对象](#展开-json-对象)) 例如,如果我们有以下 JSON 数据: ```json [ {"name": "Alice", "age": 20, "is_student": true, "score": 90.5,"object": {"a":1,"b":2}}, {"age": 21, "is_student": false, "score": 85.5, "company": "A" ,"whatever": null}, {"name": "Charlie", "age": 22, "is_student": true, "score": 95.5,"array":[1,2,3]} ] ``` 我们将合并每个批次的行结构以获得最终 schema。注意,嵌套对象会自动展开为单独的列(例如 `object.a`、`object.b`),数组会转换为 JSON 字符串。表 schema 如下所示: ```sql mysql> desc pipeline_logs; +--------------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+---------------------+------+------+---------+---------------+ | age | Int64 | | YES | | FIELD | | is_student | Boolean | | YES | | FIELD | | name | String | | YES | | FIELD | | object.a | Int64 | | YES | | FIELD | | object.b | Int64 | | YES | | FIELD | | score | Float64 | | YES | | FIELD | | company | String | | YES | | FIELD | | array | String | | YES | | FIELD | | greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | +--------------------+---------------------+------+------+---------+---------------+ 9 rows in set (0.00 sec) ``` 数据将存储在表中,如下所示: ```sql mysql> select * from pipeline_logs; +------+------------+---------+----------+----------+-------+---------+-----------+----------------------------+ | age | is_student | name | object.a | object.b | score | company | array | greptime_timestamp | +------+------------+---------+----------+----------+-------+---------+-----------+----------------------------+ | 22 | 1 | Charlie | NULL | NULL | 95.5 | NULL | [1,2,3] | 2024-10-18 09:35:48.333020 | | 21 | 0 | NULL | NULL | NULL | 85.5 | A | NULL | 2024-10-18 09:35:48.333020 | | 20 | 1 | Alice | 1 | 2 | 90.5 | NULL | NULL | 2024-10-18 09:35:48.333020 | +------+------------+---------+----------+----------+-------+---------+-----------+----------------------------+ 3 rows in set (0.01 sec) ``` ### 自定义时间索引列 每个 GreptimeDB 表中都必须有时间索引列。`greptime_identity` pipeline 不需要额外的 YAML 配置,如果你希望使用写入数据中自带的时间列(而不是日志数据到达服务端的时间戳)作为表的时间索引列,则需要通过参数进行指定。 假设这是一份待写入的日志数据: ```JSON [ {"action": "login", "ts": 1742814853} ] ``` 设置如下的 URL 参数来指定自定义时间索引列: ```shell curl -X "POST" "http://localhost:4000/v1/ingest?db=public&table=pipeline_logs&pipeline_name=greptime_identity&custom_time_index=ts;epoch;s" \ -H "Content-Type: application/json" \ -H "Authorization: Basic {{authentication}}" \ -d $'[{"action": "login", "ts": 1742814853}]' ``` 取决于数据的格式,`custom_time_index` 参数接受两种格式的配置值: - Unix 时间戳: `<字段名>;epoch;<精度>` - 该字段需要是整数或者字符串 - 精度为这四种选项之一: `s`, `ms`, `us`, or `ns`. - 时间戳字符串: `<字段名>;datestr;<字符串解析格式>` - 例如输入的时间字段值为 `2025-03-24 19:31:37+08:00`,则对应的字符串解析格式为 `%Y-%m-%d %H:%M:%S%:z` 通过上述配置,结果表就能正确使用输入字段作为时间索引列 ```sql DESC pipeline_logs; ``` ```sql +--------+-----------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+-----------------+------+------+---------+---------------+ | ts | TimestampSecond | PRI | NO | | TIMESTAMP | | action | String | | YES | | FIELD | +--------+-----------------+------+------+---------+---------------+ 2 rows in set (0.02 sec) ``` 假设时间变量名称为 `input_ts`,以下是一些使用 `custom_time_index` 的示例: - 1742814853: `custom_time_index=input_ts;epoch;s` - 1752749137000: `custom_time_index=input_ts;epoch;ms` - "2025-07-17T10:00:00+0800": `custom_time_index=input_ts;datestr;%Y-%m-%dT%H:%M:%S%z` - "2025-06-27T15:02:23.082253908Z": `custom_time_index=input_ts;datestr;%Y-%m-%dT%H:%M:%S%.9f%#z` ### 展开 JSON 对象 `greptime_identity` pipeline **自动展开**嵌套的 JSON 对象为单层结构。此行为始终启用,使用点符号(例如 `a.b.c`)为每个嵌套字段创建单独的列。 #### 控制展开深度 你可以使用 `x-greptime-pipeline-params` header 中的 `max_nested_levels` 参数来控制对象展开的深度。默认值为 10 层。 以下是一个示例请求: ```shell curl -X "POST" "http://localhost:4000/v1/ingest?db=&table=&pipeline_name=greptime_identity&version=" \ -H "Content-Type: application/x-ndjson" \ -H "Authorization: Basic {{authentication}}" \ -H "x-greptime-pipeline-params: max_nested_levels=5" \ -d "$" ``` 当达到最大嵌套级别时,任何剩余的嵌套结构都会被转换为 JSON 字符串并存储在单个列中。例如,当 `max_nested_levels=3` 时: ```JSON { "a": { "b": { "c": { "d": [1, 2, 3] } } }, "e": [ "foo", "bar" ], "f": { "g": { "h": 123, "i": "hello", "j": { "k": true } } } } ``` 将被展开为: ```json { "a.b.c": "{\"d\":[1,2,3]}", "e": "[\"foo\",\"bar\"]", "f.g.h": 123, "f.g.i": "hello", "f.g.j": "{\"k\":true}" } ``` 注意: - 任何级别的数组都会被转换为 JSON 字符串(例如,`"e"` 变成 `"[\"foo\",\"bar\"]"`) - 当达到嵌套级别限制时(此例中为第 3 层),剩余的嵌套对象会被转换为 JSON 字符串(例如 `"a.b.c"` 和 `"f.g.j"`) - 深度限制内的常规标量值以其原生类型存储(例如 `"f.g.h"` 为整数,`"f.g.i"` 为字符串) --- ## Pipeline 配置 Pipeline 是 GreptimeDB 中对 log 数据进行解析和转换的一种机制,由一个唯一的名称和一组配置规则组成,这些规则定义了如何对日志数据进行格式化、拆分和转换。目前我们支持 JSON(`application/json` 或者 `application/x-ndjson`,推荐后者)和纯文本(`text/plain`)格式的日志数据作为输入。 这些配置以 YAML 格式提供,使得 Pipeline 能够在日志写入过程中,根据设定的规则对数据进行处理,并将处理后的数据存储到数据库中,便于后续的结构化查询。 ## 输入格式 一般情况下,Pipeline 接收一组键值对形式的 map 作为 Pipeline 的输入。如下三种格式均可作为 Pipeline 的输入: ### JSON 格式 当请求的 Content-Type 为 `application/json` 时,请求的数据格式为标准的 JSON 格式。 ```json [ {"message": "hello world", "time": "2024-07-12T16:18:53.048"}, {"message": "hello greptime", "time": "2024-07-12T16:18:53.048"} ] ``` ### NDJSON 格式 当请求的 Content-Type 为 `application/x-ndjson` 时,每行数据会被视为一条独立的标准 JSON 对象。 ```json {"message": "hello world", "time": "2024-07-12T16:18:53.048"} {"message": "hello greptime", "time": "2024-07-12T16:18:53.048"} ``` ### 纯文本格式 当请求的 Content-Type 为 `text/plain` 时,每行数据会被视为一条独立的对象。并且会将整行数据视为一个字符串,存储在一个只包含 `message` 字段的 map 对象中 ``` hello world 2024-07-12T16:18:53.048 hello greptime 2024-07-12T16:18:53.048 ``` 上述的纯文本格式数据会被转换为如下的等价形式: ```json {"message": "hello world 2024-07-12T16:18:53.048"} {"message": "hello greptime 2024-07-12T16:18:53.048"} ``` 也就是说,当输入内容为纯文本格式时,需要在编写 `Processor` 和 `Transform` 的过程中,使用 `message` 来指代每行数据的内容。 ## 整体结构 Pipeline 由四部分组成:Processors、Dispatcher、Transform 和 Table suffix。 Processors 对数据进行预处理。 Dispatcher 可以将 pipeline 执行上下文转发到不同的后续 pipeline 上。 Transform 决定最终保存在数据库中的数据类型和表结构。 Table suffix 支持将数据保存到不同的表中。 - Version 用于指定 pipeline 配置的格式。虽然它是可选的,但是我们强烈建议使用 version 2 来编写新配置。更多详情请参考这个[章节](#版本-2-中的-transform)。 - Processor 用于对 log 数据进行预处理,例如解析时间字段,替换字段等。 - Dispatcher(可选) 用于将执行上下文转发到另一个 pipeline,同一个输入批次的数据可以基于特定的值被不同的 pipeline 进行处理。 - Transform(可选) 用于对数据进行格式转换,例如将字符串类型转换为数字类型,并且指定数据库表中列的索引信息。 - Table suffix(可选) 用于将数据存储到不同的表中,以便后续使用。 一个包含 Processor 和 Transform 的简单配置示例如下: ```yaml version: 2 processors: - urlencoding: fields: - string_field_a - string_field_b method: decode ignore_missing: true dispatcher: field: type rules: - value: http table_suffix: _http pipeline: http - value: db table_suffix: _db transform: - fields: - string_field_a - string_field_b type: string # 写入的数据必须包含 timestamp 字段 - fields: - reqTimeSec, req_time_sec # epoch 是特殊字段类型,必须指定精度 type: epoch, ms index: timestamp table_suffix: _${string_field_a} ``` 从 `v0.15` 开始, GreptimeDB 引入了一个新的文件格式版本。 其主要的差别在于 Transform 的处理逻辑。 请参考[下述章节](#版本-2-中的-transform)查看更多细节。 ## Processor Processor 用于对 log 数据进行预处理,其配置位于 YAML 文件中的 `processors` 字段下。 Pipeline 会按照多个 Processor 的顺序依次加工数据,每个 Processor 都依赖于上一个 Processor 处理的结果。 Processor 由一个 name 和多个配置组成,不同类型的 Processor 配置有不同的字段。 我们目前内置了以下几种 Processor: - `date`: 解析格式化的时间字符串字段,例如 `2024-07-12T16:18:53.048`。 - `epoch`: 解析数字时间戳字段,例如 `1720772378893`。 - `decolorize`: 移除日志数据中的 ANSI 颜色代码。 - `dissect`: 对 log 数据字段进行拆分。 - `gsub`: 对 log 数据字段进行替换。 - `join`: 对 log 中的 array 类型字段进行合并。 - `letter`: 对 log 数据字段进行字母转换。 - `regex`: 对 log 数据字段进行正则匹配。 - `urlencoding`: 对 log 数据字段进行 URL 编解码。 - `csv`: 对 log 数据字段进行 CSV 解析。 - `json_path`: 从 JSON 数据中提取字段。(**已废弃**,请使用 `vrl` ) - `json_parse`: 将一个字段解析成 JSON 对象。 - `simple_extract`: 使用简单的 key 从 JSON 数据中提取字段。 - `digest`: 提取日志消息模板。 - `select`: 从 pipeline 执行上下文中保留或移除字段。 - `vrl`: 使用 pipeline 上下文执行 [vrl](https://vector.dev/docs/reference/vrl/) 脚本。 - `filter`: 过滤不需要写入的行数据。 ### Processor 的输入和输出 大多数 Processor 接收一个 `field` 或者 `fields` 参数(一个串行处理的 `field` 列表)作为输入数据。 Processor 会产出一个或者多个输出数据。 对于那些只产出一个输出数据的 processor,输出的数据会替换上下文中原始 key 所关联的数据。 下述的示例中,在 `letter` processor 之后,一个大写版本的字符串会被保存在 `message` 字段中。 ```yaml processors: - letter: fields: - message method: upper ``` 我们可以将输出数据保存到另一个字段中,使得原有的字段不变。 下述的示例中,我们依然使用 `message` 字段作为 `letter` processor 的输入,但是将输出保存到一个名为 `upper_message` 的新字段中。 ```yaml processors: - letter: fields: - key: message rename_to: upper_message method: upper ``` 这个重命名的语法有一种便捷的书写方式:通过 `,` 将两个字段分割即可。 以下是一个示例: ```yaml processors: - letter: fields: - message, upper_message method: upper ``` 重命名主要有两个场景: 1. 保持原字段不变,使得它可以被多个 processor 使用,或者作为原始记录被保存到数据库中。 2. 统一命名。例如为了一致性,将驼峰命名法的变量重命名为蛇形命名法。 ### `date` `date` Processor 用于解析时间字段。示例配置如下: ```yaml processors: - date: fields: - time formats: - '%Y-%m-%d %H:%M:%S%.3f' ignore_missing: true timezone: 'Asia/Shanghai' ``` 如上所示,`date` Processor 的配置包含以下字段: - `fields`: 需要解析的时间字段名列表。 - `formats`: 时间格式化字符串,支持多个时间格式化字符串。按照提供的顺序尝试解析,直到解析成功。你可以在[这里](https://docs.rs/chrono/latest/chrono/format/strftime/index.html)找到格式化的语法说明。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 - `timezone`:时区。使用[tz_database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) 中的时区标识符来指定时区。默认为 `UTC`。 ### `epoch` `epoch` Processor 用于解析时间戳字段,示例配置如下: ```yaml processors: - epoch: fields: - reqTimeSec resolution: millisecond ignore_missing: true ``` 如上所示,`epoch` Processor 的配置包含以下字段: - `fields`: 需要解析的时间戳字段名列表。 - `resolution`: 时间戳精度,支持 `s`, `sec` , `second` , `ms`, `millisecond`, `milli`, `us`, `microsecond`, `micro`, `ns`, `nanosecond`, `nano`。默认为 `ms`。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 ### `decolorize` `decolorize` Processor 用于移除日志数据中的 ANSI 颜色代码。示例配置如下: ```yaml processors: - decolorize: fields: - message ``` 如上所示,`decolorize` Processor 的配置包含以下字段: - `fields`: 需要移除颜色代码的字段名列表。 ### `dissect` `dissect` Processor 用于对 log 数据字段进行拆分,示例配置如下: ```yaml processors: - dissect: fields: - message patterns: - '%{key1} %{key2}' ignore_missing: true append_separator: '-' ``` 如上所示,`dissect` Processor 的配置包含以下字段: - `fields`: 需要拆分的字段名列表。不支持字段重命名。 - `patterns`: 拆分的 dissect 模式。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 - `append_separator`: 对于多个追加到一起的字段,指定连接符。默认是一个空字符串。 #### Dissect 模式 和 Logstash 的 Dissect 模式类似,Dissect 模式由 `%{key}` 组成,其中 `%{key}` 为一个字段名。例如: ``` "%{key1} %{key2} %{+key3} %{+key4/2} %{key5->} %{?key6}" ``` #### Dissect 修饰符 Dissect 模式支持以下修饰符: | 修饰符 | 说明 | 示例 | | ----------- | ---------------------------------------- | --------------------- | | `+` | 将两个或多个字段追加到一起 | `%{+key} %{+key}` | | `+` 和 `/n` | 按照指定的顺序将两个或多个字段追加到一起 | `%{+key/2} %{+key/1}` | | `->` | 忽略右侧的任何重复字符 | `%{key1->} %{key2->}` | | `?` | 忽略匹配的值 | `%{?key}` | #### `dissect` 示例 例如,对于以下 log 数据: ``` "key1 key2 key3 key4 key5 key6" ``` 使用以下 Dissect 模式: ``` "%{key1} %{key2} %{+key3} %{+key3/2} %{key5->} %{?key6}" ``` 将得到以下结果: ``` { "key1": "key1", "key2": "key2", "key3": "key3 key4", "key5": "key5" } ``` ### `gsub` `gsub` Processor 用于对 log 数据字段进行替换,示例配置如下: ```yaml processors: - gsub: fields: - message pattern: 'old' replacement: 'new' ignore_missing: true ``` 如上所示,`gsub` Processor 的配置包含以下字段: - `fields`: 需要替换的字段名列表。 - `pattern`: 需要替换的字符串。支持正则表达式。 - `replacement`: 替换后的字符串。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 ### `join` `join` Processor 用于对 log 中的 Array 类型字段进行合并,示例配置如下: ```yaml processors: - join: fields: - message separator: ',' ignore_missing: true ``` 如上所示,`join` Processor 的配置包含以下字段: - `fields`: 需要合并的字段名列表。注意,这里每行字段的值需要是 Array 类型,每行字段会单独合并自己数组内的值,所有行的字段不会合并到一起。 - `separator`: 合并后的分隔符。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 #### `join` 示例 例如,对于以下 log 数据: ```json { "message": ["a", "b", "c"] } ``` 使用以下配置: ```yaml processors: - join: fields: - message separator: ',' ``` 将得到以下结果: ```json { "message": "a,b,c" } ``` ### `letter` `letter` Processor 用于对 log 数据字段进行字母转换,示例配置如下: ```yaml processors: - letter: fields: - message method: upper ignore_missing: true ``` 如上所示,`letter` Processor 的配置包含以下字段: - `fields`: 需要转换的字段名列表。 - `method`: 转换方法,支持 `upper`, `lower` ,`capital`。默认为 `lower`。注意 `capital` 只会将第一个字母转换为大写。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 ### `regex` `regex` Processor 用于对 log 数据字段进行正则匹配,示例配置如下: ```yaml processors: - regex: fields: - message patterns: - ':(?[0-9])' ignore_missing: true ``` 如上所示,`regex` Processor 的配置包含以下字段: - `fields`: 需要匹配的字段名列表。如果重命名了字段,重命名后的字段名将与 `pattern` 中的命名捕获组名进行拼接。 - `pattern`: 要进行匹配的正则表达式,需要使用命名捕获组才可以从对应字段中取出对应数据。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 #### regex 命名捕获组的规则 `regex` Processor 支持使用 `(?...)` 的语法来命名捕获组,最终将数据处理为这种形式: ```json { "_": "" } ``` 例如 `regex` Processor 中 field 填写的字段名为 `message`,对应的内容为 `"[ERROR] error message"`, 你可以将 pattern 设置为 `\[(?[A-Z]+)\] (?.+)`, 最终数据会被处理为: ```json { "message_level": "ERROR", "message_content": "error message" } ``` ### `urlencoding` `urlencoding` Processor 用于对 log 数据字段进行 URL 编码,示例配置如下: ```yaml processors: - urlencoding: fields: - string_field_a - string_field_b method: decode ignore_missing: true ``` 如上所示,`urlencoding` Processor 的配置包含以下字段: - `fields`: 需要编码的字段名列表。 - `method`: 编码方法,支持 `encode`, `decode`。默认为 `encode`。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 ### `csv` `csv` Processor 用于对 log 数据中没有携带 header 的 CSV 类型字段解析,示例配置如下: ```yaml processors: - csv: fields: - message separator: ',' quote: '"' trim: true ignore_missing: true ``` 如上所示,`csv` Processor 的配置包含以下字段: - `fields`: 需要解析的字段名列表。 - `separator`: 分隔符。 - `quote`: 引号。 - `trim`: 是否去除空格。默认为 `false`。 - `ignore_missing`: 忽略字段不存在的情况。默认为 `false`。如果字段不存在,并且此配置为 false,则会抛出异常。 ### `json_path`(废弃) :::danger 废弃特性 增加 vrl processor 后,`json_path` 处理器的使用场景已经大大减少。 如果你需要从 JSON 数据中提取字段,建议使用 `vrl` 处理器来实现更灵活的处理。 我们计划在未来的版本中废弃 `json_path` 处理器。 ::: `json_path` 处理器用于从 JSON 数据中提取字段。以下是一个配置示例: ```yaml processors: - json_path: fields: - complex_object json_path: "$.shop.orders[?(@.active)].id" ignore_missing: true result_index: 1 ``` 在上述示例中,`json_path` processor 的配置包括以下字段: - `fields`:要提取的字段名称列表。 - `json_path`:要提取的 JSON 路径。 - `ignore_missing`:忽略字段缺失的情况。默认为 `false`。如果字段缺失且此配置设置为 `false`,将抛出异常。 - `result_index`:指定提取数组中要用作结果值的下标。默认情况下,包含所有值。Processor 提取的结果值是包含 path 中所有值的数组。如果指定了索引,将使用提取数组中对应的下标的值作为最终结果。 #### JSON 路径语法 JSON 路径语法基于 [jsonpath-rust](https://github.com/besok/jsonpath-rust) 库。 在此阶段,我们仅推荐使用一些简单的字段提取操作,以便将嵌套字段提取到顶层。 #### `json_path` 示例 例如,给定以下日志数据: ```json { "product_object": { "hello": "world" }, "product_array": [ "hello", "world" ], "complex_object": { "shop": { "orders": [ { "id": 1, "active": true }, { "id": 2 }, { "id": 3 }, { "id": 4, "active": true } ] } } } ``` 使用以下配置: ```yaml processors: - json_path: fields: - product_object, object_target json_path: "$.hello" result_index: 0 - json_path: fields: - product_array, array_target json_path: "$.[1]" result_index: 0 - json_path: fields: - complex_object, complex_target_1 json_path: "$.shop.orders[?(@.active)].id" - json_path: fields: - complex_target_1, complex_target_2 json_path: "$.[1]" result_index: 0 - json_path: fields: - complex_object, complex_target_3 json_path: "$.shop.orders[?(@.active)].id" result_index: 1 transform: - fields: - object_target - array_target type: string - fields: - complex_target_3 - complex_target_2 type: uint32 - fields: - complex_target_1 type: json ``` 结果将是: ```json { "object_target": "world", "array_target": "world", "complex_target_3": 4, "complex_target_2": 4, "complex_target_1": [1, 4] } ``` ### `json_parse` `json_parse`,如其名字所示,将一个字符串解析成一个 JSON 对象。以下是一份示例配置: ```yaml processors: - json_parse: fields: - complex_object, target_field ignore_missing: true ``` 在上述示例中,`json_parse` 处理器的配置包含以下字段: - `fields`:对于每个字段,第一个 key 表示输入字符串中的 key,第二个 key 表示输出的 key 名称。如果不填写第二个 key,则默认使用第一个 key 名作为输出名,也就是替换第一个 key 中的值。上面的示例表示解析 `complex_object` 并将输出放入 `target_field` 中。 - `ignore_missing`:忽略字段不存在的情况。默认为 `false`。如果字段不存在且此配置为 `false`,将抛出异常。 #### `json_parse` example 例如,给定以下日志数据: ```json { "product_object": "{\"hello\":\"world\"}", } ``` 使用以下配置: ```yaml processors: - json_parse: fields: - product_object ``` 结果将是: ```json { "product_object": { "hello": "world" } } ``` ### `simple_extract` 虽然 `json_path` 处理器能够使用复杂表达式从 JSON 对象中提取字段,但它相对较慢且成本较高。`simple_extract` 处理器提供了一种简单的方法,仅使用键名来提取字段。以下是示例配置: ```yaml processors: - simple_extract: fields: - complex_object, target_field key: "shop.name" ignore_missing: true ``` 在上述示例中,`simple_extract` 处理器的配置包含以下字段: - `fields`:对于每个字段,第一个键表示上下文中的输入 JSON 对象,第二个键表示输出键名。上面的示例表示从 `complex_object` 中提取数据并将输出放入 `target_field` 中。 - `key`:提取键,使用 `x.x` 格式,每个 `.` 表示一个新的嵌套层。 - `ignore_missing`:忽略字段不存在的情况。默认为 `false`。如果字段不存在且此配置为 `false`,将抛出异常。 #### `simple_extract` 示例 例如,给定以下日志数据: ```json { "product_object": { "hello": "world" }, "product_array": [ "hello", "world" ], "complex_object": { "shop": { "name": "some_shop_name" } } } ``` 使用以下配置: ```yaml processors: - simple_extract: fields: - complex_object, shop_name key: "shop.name" transform: - fields: - shop_name type: string ``` 结果将是: ```json { "shop_name": "some_shop_name" } ``` ### `digest` `digest` 处理器用于从日志内容中提取日志模板,它通过识别并移除可变内容(如数字、UUID、IP 地址、引号中的内容和括号中的文本等)来实现。提取出的模板可用于日志的分类和分析。配置示例如下: ```yaml processors: - digest: fields: - message presets: - numbers - uuid - ip - quoted - bracketed regex: - "foobar" ignore_missing: true ``` 在上述示例中,`digest` 处理器的配置包含以下字段: - `fields`:要进行摘要处理的字段名列表。处理后的结果将存储在带有 `_digest` 后缀的新字段中。 - `presets`:要移除的预设模式列表。支持以下模式: - `numbers`:匹配数字序列 - `uuid`:匹配 UUID 字符串,如 `123e4567-e89b-12d3-a456-426614174000` - `ip`:匹配 IPv4/IPv6 地址(可选带端口号) - `quoted`:匹配单引号/双引号内的文本(包括各种 Unicode 引号) - `bracketed`:匹配各种类型括号内的文本(包括各种 Unicode 括号) - `regex`:要移除的自定义正则表达式列表 - `ignore_missing`:是否忽略字段不存在的情况。默认为 `false`。如果字段不存在且此配置为 `false`,将抛出异常。 #### `digest` 示例 例如,给定以下日志数据: ```json { "message": "User 'john.doe' from [192.168.1.1] accessed resource 12345 with UUID 123e4567-e89b-12d3-a456-426614174000" } ``` 使用以下配置: ```yaml processors: - digest: fields: - message presets: - numbers - uuid - ip - quoted - bracketed ``` 结果将是: ```json { "message": "User 'john.doe' from [192.168.1.1] accessed resource 12345 with UUID 123e4567-e89b-12d3-a456-426614174000", "message_digest": "User from accessed resource with UUID " } ``` 提取的模板可用于对相似的日志消息进行分组或分析日志模式,即使可变内容不同。例如,以下所有日志消息都会生成相同的模板: - `User 'alice' from [10.0.0.1] accessed resource 54321 with UUID 987fbc97-4bed-5078-9141-2791ba07c9f3` - `User 'bob' from [2001:0db8::1] accessed resource 98765 with UUID 550e8400-e29b-41d4-a716-446655440000` ### `select` `select` 处理器用于从 pipeline 执行上下文中保留或者移除字段。 从 `v0.15` 开始,我们引入了[`自动 transform`](#自动-transform)用来简化配置。 `自动 transform`会尝试将 pipeline 执行上下文中所有的字段都保存下来。 `select` 处理器在这里能选择上下文中的字段并保留或者移除,在`自动 transform`模式下即反映了最终的表结构。 `select` 处理器的选项非常简单: - `type` (可选) - `include` (默认): 只保留选中的字段列表 - `exclude`: 从当前的上下文中移除选中的字段列表 - `fields`: 选择的字段列表 以下是一个简单的示例: ```YAML processors: - dissect: fields: - message patterns: - "%{+ts} %{+ts} %{http_status_code} %{content}" - date: fields: - ts formats: - "%Y-%m-%d %H:%M:%S%.3f" - select: fields: - http_status_code - ts ``` 通过 `dissect` 和 `date` 处理器之后,现在上下文中有四个字段: `ts`,`http_status_code`,`content` 和最初的 `message`。 在没有 `select` 处理器的情况下,四个字段都会被保存下来。 `select` 处理器在这里选择了 `http_status_code` 和 `ts` 两个字段来保存(默认 `include` 行为),等效于从 pipeline 执行上下文中删除了 `content` 和 `message` 字段,使得最终只有 `http_status_code` 和 `ts` 这两个字段被保存到数据库中。 上述的示例也可以用以下 `select` 处理器配置来达成效果: ```YAML - select: type: exclude fields: - content - message ``` ### `vrl` :::warning 实验性特性 此实验性功能可能存在预期外的行为,其功能未来可能发生变化。 ::: `vrl` 处理器使用 pipeline 上下文作为环境来运行 vrl 编程脚本。 相比于简单的处理器,它功能更加强大,允许你编写编程代码来此操作上下文中的变量;不过执行 vrl 脚本会消耗更多的资源。 更多的 vrl 语言介绍和使用,请参考[官方网站](https://vector.dev/docs/reference/vrl/)。 `vrl` 处理器目前只有一个配置项,就是 `source`(源码)。以下是一个示例: ```YAML processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - vrl: source: | .from_source = "channel_2" cond, err = .id1 > .id2 if (cond) { .from_source = "channel_1" } del(.id1) del(.id2) . ``` 这份配置使用 `|` 在 YAML 中开启一个多行的文本。随后即可编写整个脚本。 在使用 `vrl` 处理器时,有一些需要注意的点: 1. 整个脚本必须以一个单独的 `.` 行作为结尾,表示将整个上下文作为脚本的返回值。 2. vrl 脚本的返回值中不能包含任何的 `regex` 类型的变量。在脚本的过程中可以使用这种类型,但是在返回之前需要 `del`(删除) 掉。 3. 由于 pipeline 的类型和 vrl 的类型之前存在转换,经过 vrl 处理的类型会变成最大的容量类型,即 `i64`, `u64` 和 `Timestamp::nanoseconds`。 ### `filter` `filter` 处理器用于根据指定条件筛选数据行,从而移除不需要的数据。 以下是一个简单的 `filter` 处理器配置: ```YAML processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" - filter: field: name mode: simple match_op: in case_insensitive: true targets: - John - Wick transform: - field: name type: string - field: time type: time index: timestamp ``` `filter` 处理器在这里会检查 pipeline 上下文中的 `name` 变量的值。 如果它的值和 targets 列表 `['John', 'Wick']` 中的任意值匹配,则认为条件判断成功。 这条输入数据的处理将会被中止,不会被持久化到数据库中。 `filter` 处理器接受以下参数: 1. `field`(或者 `fields`):用于比较的上下文变量,可以是一个或者多个;任意一个满足条件即会触发过滤。 2. `mode`(可选):默认为 `simple`,即为简单字符串匹配。这个字段是为了将来对 `filter` 处理器的功能进行扩展。 3. `match_op`(可选):如果 mode 是 `simple`,这个选项可以设置为 `in` 或者 `not_in`,意为检查目标列表是否包含变量。默认为 `in`。 4. `case_insensitive`(可选):默认为 `true`. 5. `targets`: 用于比较的目标列表。 ## Transform Transform 用于对 log 数据进行转换,并且指定在数据库表中列的索引信息。其配置位于 YAML 文件中的 `transform` 字段下。 从 `v0.15` 开始,GreptimeDB 引入了版本 2 格式和自动 transform,可以大幅简化配置。具体详情见下。 Transform 由一个或多个配置组成,每个配置包含以下字段: - `fields`: 需要转换的字段名列表 - `type`: 指定在数据库中的数据类型 - `index`(可选): 索引类型 - `tag`(可选): 设置列为 tag - `on_failure`(可选): 转换失败时的处理方式 - `default`(可选): 默认值 ### 版本 2 中的 Transform 在最初的 pipeline 版本中,你需要在 transform 中手动指定所有的字段,来将它们持久化到数据库中。 如果一个字段没有在 transform 中被指定,那么它将会被丢弃。 当字段的数量不断增加时,配置将会变得繁琐、容易出错。 从 `v0.15` 开始,GreptimeDB 引入了一种新的 transform 模式,使得编写 pipeline 配置变得更加简单。 你只需要在 transform 指定需要设置索引和数据类型转换的字段即可;其他 pipeline 上下文中的字段将会被 pipeline 引擎自动转换并保存。 配合 `select` 处理器,我们可以决定什么字段会被最终保留在数据库中。 但是这无法兼容已经存在的 pipeline 配置文件。 如果你已经在 pipeline 配置中使用了 `dissect` 或者 `regex` 处理器,那么在升级数据库版本后,原始的日志文本,因为还留存于 pipeline 上下文中,会被立刻写入到数据库中。 因此,GreptimeDB pipeline 引入了 `version` 字段来执行要使用的 transform 版本,就像 Docker Compose 文件的版本号字段一样。 以下是一个示例: ```YAML version: 2 processors: - date: field: input_str formats: - "%Y-%m-%dT%H:%M:%S%.3fZ" transform: - field: input_str, ts type: time, ms index: timestamp ``` 只需要在配置文件的开头加上 `version: 2`,pipeline 引擎就会以新的 transform 模式来处理数据: 1. 顺序执行所有配置的 transform 规则。 2. 将 pipeline 上下文中的所有字段保存到最终的结果表中 注意: - Transform 规则**必须设置一个时间索引列**。 - 版本 2 中的 transform 规则执行会将原始字段从 pipeline 上下文中移除,故你无法在 transform 规则对同一个字段引用多次 ### 自动 transform 在版本 2 中 transform 的配置编写已经进行了大幅的简化。 即使如此,在某些场景下,我们仍然希望能够结合处理器的处理能力与 `greptime_identity` 的自动字段保存能力,从而无需编写任何转换代码,即可让 pipeline 引擎自动推导并保存字段。 现在自定义 pipeline 支持了这点。 如果 pipeline 配置中没有 transform 模块,pipeline 引擎将会尝试为上下文中的变量自动推导数据类型,并将它们持久化到数据库中,就像 `greptime_identity` 一样。 当在 GreptimeDB 中创建表时,必须指定一个时间索引列。在这个场景中,pipeline 引擎会尝试从上下文中寻找一个 `timestamp` 类型的字段,并将其设置成时间索引列。`timestamp` 类型的字段是 `date` 或者 `epoch` processor 的产物。所以在 processors 声明中,必须存在一个 `date` 或者 `epoch` processor。同时,只允许存在一个 `timestamp` 类型的字段,多个 `timestamp` 字段的情况下会因无法判断在哪一列上设置时间索引而报错。 例如,以下 pipeline 配置现在是有效的。 ```YAML version: 2 processors: - dissect: fields: - message patterns: - '%{ip_address} - %{username} [%{timestamp}] "%{http_method} %{request_line} %{protocol}" %{status_code} %{response_size}' ignore_missing: true - date: fields: - timestamp formats: - "%d/%b/%Y:%H:%M:%S %z" ``` 其产生的表结构如下: ``` mysql> desc auto_trans; +---------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------+---------------------+------+------+---------+---------------+ | timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP | | host | String | | YES | | FIELD | | http_method | String | | YES | | FIELD | | ip_address | String | | YES | | FIELD | | message | String | | YES | | FIELD | | protocol | String | | YES | | FIELD | | request_line | String | | YES | | FIELD | | response_size | String | | YES | | FIELD | | service | String | | YES | | FIELD | | source_type | String | | YES | | FIELD | | status_code | String | | YES | | FIELD | | username | String | | YES | | FIELD | +---------------+---------------------+------+------+---------+---------------+ 12 rows in set (0.03 sec) ``` 可以看到所有的字段都被保存下来了,包括原始的 `message` 字段。注意所有的字段都被保存成 `String` 类型,`timestamp` 字段自动被设置成时间索引列。 ### `fields` 字段 每个字段名都是一个字符串。 在 transform 中 `fields` 也可以使用重命名,语法参考[这里](#processor-的输入和输出)。 字段的最终命名会被作为数据库表中的列的名字。 ### `type` 字段 GreptimeDB 目前内置了以下几种转换类型: - `int8`, `int16`, `int32`, `int64`: 整数类型。 - `uint8`, `uint16`, `uint32`, `uint64`: 无符号整数类型。 - `float32`, `float64`: 浮点数类型。 - `string`: 字符串类型。 - `time`: 时间类型。将被转换为 GreptimeDB `timestamp(9)` 类型。 - `epoch`: 时间戳类型。将被转换为 GreptimeDB `timestamp(n)` 类型。n 为时间戳精度,n 的值视 epoch 精度而定。当精度为 `s` 时,n 为 0;当精度为 `ms` 时,n 为 3;当精度为 `us` 时,n 为 6;当精度为 `ns` 时,n 为 9。 如果字段在转换过程中获得了非法值,Pipeline 将会抛出异常。例如将一个字符串 `abc` 转换为整数时,由于该字符串不是一个合法的整数,Pipeline 将会抛出异常。 ### `index` 字段 `Pipeline` 会将处理后的数据写入到 GreptimeDB 自动创建的数据表中。为了提高查询效率,GreptimeDB 会为表中的某些列创建索引。`index` 字段用于指定哪些字段需要被索引。关于 GreptimeDB 的索引类型,请参考[数据索引](/user-guide/manage-data/data-index.md)文档。 GreptimeDB 支持以下四种字段的索引类型: - `timestamp`: 用于指定某列是时间索引列 - `inverted`: 用于指定某列使用 inverted 类型的索引(倒排索引) - `fulltext`: 用于指定某列使用 fulltext 类型的索引(全文索引),该列需要是字符串类型 - `skipping`: 用于指定某列使用 skipping 类型的索引(跳数索引),该列需要是字符串类型 不提供 `index` 字段时,GreptimeDB 将不会在该字段上建立索引。 在 GreptimeDB 中,一张表里必须包含一个 `timestamp` 类型的列作为该表的时间索引列,因此一个 Pipeline 有且只有一个时间索引列。 #### 时间戳列 通过 `index: timestamp` 指定哪个字段是时间索引列,写法请参考下方的 [Transform 示例](#transform-示例)。 #### Inverted 索引 通过 `index: inverted` 指定在哪个列上建立倒排索引,写法请参考下方的 [Transform 示例](#transform-示例)。 #### Fulltext 索引 通过 `index: fulltext` 指定在哪个列上建立全文索引,该索引可大大提升 [日志搜索](/user-guide/logs/fulltext-search.md) 的性能,写法请参考下方的 [Transform 示例](#transform-示例)。 #### Skipping 索引 通过 `index: skipping` 指定在哪个列上建立跳数索引,该索引只需少量存储空间的索引文件即可以加速在高基数列上的查询,写法请参考下方的 [Transform 示例](#transform-示例)。 ### `tag` 字段 `Pipeline` 支持手动指定 tag 列。关于 tag 列的更多信息,请参考[数据模型](/user-guide/concepts/data-model.md)文档。写法请参考下方的 [Transform 示例](#transform-示例)。 ### `on_failure` 字段 `on_failure` 字段用于指定转换失败时的处理方式,支持以下几种方式: - `ignore`: 忽略转换失败的字段,不写入数据库。 - `default`: 写入默认值。默认值由 `default` 字段指定。 ### `default` 字段 `default` 字段用于指定转换失败时的默认值。 ### Transform 示例 例如,对于以下 log 数据: ```json { "num_field_a": "3", "string_field_a": "john", "string_field_b": "It was snowing when he was born.", "time_field_a": 1625760000 } ``` 使用以下配置: ```yaml transform: - fields: - string_field_a, name type: string index: skipping tag: true - fields: - num_field_a, age type: int32 index: inverted - fields: - string_field_b, description type: string index: fulltext - fields: - time_field_a, born_time type: epoch, s index: timestamp ``` 将得到以下结果: ``` { "name": "john", "age": 3, "description": "It was snowing when he was born.", "born_time": 2021-07-08 16:00:00 } ``` ## Dispatcher Dispatcher 允许用户将数据路由到其他 Pipeline 上。这是为了应对当多种日志类型共享 单一来源且需要存储在不同结构的单独表中。 配置例子如下: ```yaml dispatcher: field: type rules: - value: http table_suffix: _http pipeline: http - value: db table_suffix: _db ``` Dispatcher 在 processor 之后执行。当匹配到相应的规则时,下一个 pipeline 将被执行。 你可以指定路由数据所依据的字段名 `field`,并指定路由规则 `rules`。假如 `field` 字段匹配到规则中的 `value`,数据将被路由到 `pipeline`。如果规则中没有指定 `pipeline`,将会根据当前的数据结构推断表结构。在上面的例子里,如果用户输入的数据 中 `type` 字段的值为 `http`,我们将把数据路由给名为 `http` 的 pipeline 执行。如 果 `type` 字段的值为 `db`,我们将用当前数据的结构作为表结构存储。 写入的目标表名由 `table_suffix` 指定,并直接追加到请求输入的 `table` 参数后面。 如果你想要使用下划线 `_` 这样的分隔符,需要显式写进 `table_suffix` 里。例 如,请求的表名叫做 `applogs`,当匹配到上面例子中的 `http` 规则时,最终的表 名叫做 `applogs_http`。 如果没有规则匹配到,数据将执行当前 pipeline 中定一个 transform 规则。 ## Table suffix :::warning 实验性特性 此实验性功能可能存在预期外的行为,其功能未来可能发生变化。 ::: 在一些场景下,你可能需要将写入的日志数据基于输入的字段值保存到不同表上。 比如你可能希望按照产生的应用名将日志保存到不同的表上,在表名上添加这个应用名的后缀。 一个配置示例如下: ```yaml table_suffix: _${app_name} ``` 语法非常简单: 使用 `${}` 来引用 pipeline 执行上下文中的变量。 该变量可以是输入数据中直接存在的,也可以是前序处理流程中产生的。 变量替换完成之后,整个字符串会被添加到输入的表名后。 注意: 1. 引用的变量必须是一个整数或者字符串类型的数据 2. 如果在执行过程中遇到任何错误(例如变量不存在或者无效数据类型),输入的表名会被作为最终表名 下面举一个例子。以下是输入数据: ```JSON [ {"type": "db"}, {"type": "http"}, {"t": "test"} ] ``` 输入的表名为 `persist_app`,pipeline 配置如下: ```YAML table_suffix: _${type} ``` 这三行输入数据会被写入到三张不同的表中: 1. `persist_app_db` 2. `persist_app_http` 3. `persist_app`, 因为输入的数据中并没有 `type` 字段,所以使用了默认的表名 --- ## 写入日志的 API 在写入日志之前,请先阅读 [Pipeline 配置](/user-guide/logs/use-custom-pipelines.md#上传-pipeline)完成配置的设定和上传。 ## HTTP API 你可以使用以下命令通过 HTTP 接口写入日志: ```shell curl -X "POST" "http://localhost:4000/v1/ingest?db=&table=&pipeline_name=&version=&skip_error=" \ -H "Content-Type: application/x-ndjson" \ -H "Authorization: Basic {{authentication}}" \ -d "$" ``` ### 请求参数 此接口接受以下参数: - `db`:数据库名称。 - `table`:表名称。 - `pipeline_name`:[Pipeline](./pipeline-config.md) 名称。 - `version`:Pipeline 版本号。可选,默认使用最新版本。 - `skip_error`:写入日志时是否跳过错误。可选,默认为 `false`。当设置为 `true` 时,GreptimeDB 会跳过遇到错误的单条日志项并继续处理剩余的日志,不会因为一条日志项的错误导致整个请求失败。 ### `Content-Type` 和 Body 数据格式 GreptimeDB 使用 `Content-Type` header 来决定如何解码请求体内容。目前我们支持以下两种格式: - `application/json`: 包括普通的 JSON 格式和 NDJSON 格式。 - `application/x-ndjson`: 指定 NDJSON 格式,会尝试先分割行再进行解析,可以达到精确的错误检查。 - `text/plain`: 通过换行符分割的多行日志文本行。 #### `application/json` 和 `application/x-ndjson` 格式 以下是一份 JSON 格式请求体内容的示例: ```JSON [ {"message":"127.0.0.1 - - [25/May/2024:20:16:37 +0000] \"GET /index.html HTTP/1.1\" 200 612 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\""}, {"message":"192.168.1.1 - - [25/May/2024:20:17:37 +0000] \"POST /api/login HTTP/1.1\" 200 1784 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36\""}, {"message":"10.0.0.1 - - [25/May/2024:20:18:37 +0000] \"GET /images/logo.png HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0\""}, {"message":"172.16.0.1 - - [25/May/2024:20:19:37 +0000] \"GET /contact HTTP/1.1\" 404 162 \"-\" \"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1\""} ] ``` 请注意整个 JSON 是一个数组(包含多行日志)。每个 JSON 对象代表即将要被 Pipeline 引擎处理的一行日志。 JSON 对象中的 key 名,也就是这里的 `message`,会被用作 Pipeline processor 处理时的 field 名称。比如: ```yaml processors: - dissect: fields: # `message` 是 JSON 对象中的 key 名 - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true # pipeline 文件的剩余部分在这里省略 ``` 我们也可以将这个请求体内容改写成 NDJSON 的格式,如下所示: ```JSON {"message":"127.0.0.1 - - [25/May/2024:20:16:37 +0000] \"GET /index.html HTTP/1.1\" 200 612 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\""} {"message":"192.168.1.1 - - [25/May/2024:20:17:37 +0000] \"POST /api/login HTTP/1.1\" 200 1784 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36\""} {"message":"10.0.0.1 - - [25/May/2024:20:18:37 +0000] \"GET /images/logo.png HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0\""} {"message":"172.16.0.1 - - [25/May/2024:20:19:37 +0000] \"GET /contact HTTP/1.1\" 404 162 \"-\" \"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1\""} ``` 注意到最外层的数组符被消去了,现在每个 JSON 对象通过换行符分割而不是 `,`。 #### `text/plain` 格式 纯文本日志在整个生态系统中被广泛应用。GreptimeDB 同样支持日志数据以 `text/plain` 格式进行输入,使得我们可以直接从日志产生源进行写入。 以下是一份和上述样例请求体内容等价的文本请求示例: ```plain 127.0.0.1 - - [25/May/2024:20:16:37 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" 192.168.1.1 - - [25/May/2024:20:17:37 +0000] "POST /api/login HTTP/1.1" 200 1784 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36" 10.0.0.1 - - [25/May/2024:20:18:37 +0000] "GET /images/logo.png HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0" 172.16.0.1 - - [25/May/2024:20:19:37 +0000] "GET /contact HTTP/1.1" 404 162 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1" ``` 仅需要将 `Content-Type` header 设置成 `text/plain`,即可将纯文本请求发送到 GreptimeDB。 主要注意的是,和 JSON 格式自带 key 名可以被 Pipeline processor 识别和处理不同,`text/plain` 格式直接将整行文本输入到 Pipeline engine。在这种情况下我们可以使用 `message` 来指代整行输入文本,例如: ```yaml processors: - dissect: fields: # 使用 `message` 作为 field 名称 - message patterns: - '%{ip_address} - - [%{timestamp}] "%{http_method} %{request_line}" %{status_code} %{response_size} "-" "%{user_agent}"' ignore_missing: true # pipeline 文件的剩余部分在这里省略 ``` 对于 `text/plain` 格式的输入,推荐首先使用 `dissect` 或者 `regex` processor 将整行文本分割成不同的字段,以便进行后续的处理。 ## 设置表选项 写入日志的表选项需要在 pipeline 中配置。 从 `v0.15` 开始,pipeline 引擎可以识别特定的变量名称,并且通过这些变量对应的值设置相应的建表选项。 通过与 `vrl` 处理器的结合,现在可以非常轻易地通过输入的数据在 pipeline 的执行过程中设置建表选项。 以下是支持的表选项变量名: - `greptime_auto_create_table` - `greptime_ttl` - `greptime_append_mode` - `greptime_merge_mode` - `greptime_physical_table` - `greptime_skip_wal` 请前往[表选项](/reference/sql/create.md#表选项)文档了解每一个选项的详细含义。 以下是 pipeline 特有的变量: - `greptime_table_suffix`: 在给定的目标表后增加后缀 以如下 pipeline 文件为例 ```YAML processors: - date: field: time formats: - "%Y-%m-%d %H:%M:%S%.3f" ignore_missing: true - vrl: source: | .greptime_table_suffix, err = "_" + .id .greptime_ttl = "1d" . ``` 在这份 vrl 脚本中,我们将表后缀变量设置为输入字段中的 `id`(通过一个下划线连接),然后将 ttl 设置成 `1d`。 然后我们使用如下数据执行写入。 ```JSON { "id": "2436", "time": "2024-05-25 20:16:37.217" } ``` 假设给定的表名为 `d_table`,那么最终的表名就会按照预期被设置成 `d_table_2436`。这个表同样的 ttl 同样会被设置成 1 天。 ## 示例 请参考[快速开始](/user-guide/logs/quick-start.md)和[使用自定义 pipeline 中的](/user-guide/logs/use-custom-pipelines.md#使用-pipeline-写入日志)写入日志部分的文档。 --- ## ADMIN `ADMIN` 语句用于运行管理函数: ```sql ADMIN function(arg1, arg2, ...) ``` ## 管理函数 GreptimeDB 提供了一些管理函数来管理数据库和数据: * `flush_table(table_name)` 根据表名将表的 Memtable 刷新到 SST 文件中。 * `flush_region(region_id)` 根据 Region ID 将 Region 的 Memtable 刷新到 SST 文件中。通过 [PARTITIONS](./information-schema/partitions.md) 表查找 Region ID。 * `compact_table(table_name, [type], [options])` 为表启动一个 compaction 任务,详细信息请阅读 [compaction](/user-guide/deployments-administration/manage-data/compaction.md#严格窗口压缩策略swcs和手动压缩)。 * `compact_region(region_id)` 为 Region 启动一个 compaction 任务。 * `migrate_region(region_id, from_peer, to_peer, [timeout])` 在 Datanode 之间迁移 Region,请阅读 [Region Migration](/user-guide/deployments-administration/manage-data/region-migration.md)。 * `procedure_state(procedure_id)` 根据 ID 查询 Procedure 状态。 * `flush_flow(flow_name)` 将 Flow 的输出刷新到目标接收表。 * `reconcile_table(table_name)` 修复指定表的元数据不一致问题,详细信息请阅读 [table reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md)。 * `reconcile_database(database_name)` 修复指定数据库中所有表的元数据不一致问题,详细信息请阅读 [table reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md)。 * `reconcile_catalog()` 修复整个集群中所有表的元数据不一致问题,详细信息请阅读 [table reconciliation](/user-guide/deployments-administration/maintenance/table-reconciliation.md)。 * `gc_table(table_name, [full_file_listing])` 对对象存储中已删除表的孤立 SST 文件进行垃圾回收,返回已处理的 Region 数量。可选参数 `full_file_listing`(默认为 `false`),设为 `true` 时启用全量文件扫描模式。 * `gc_regions(region_id1, ..., region_idN, [full_file_listing])` 根据 Region ID 对对象存储中指定 Region 的孤立 SST 文件进行垃圾回收,返回已处理的 Region 数量。可选参数 `full_file_listing`(默认为 `false`),设为 `true` 时启用全量文件扫描模式。 例如: ```sql -- 刷新表 test -- admin flush_table("test"); -- 为表 test 启动 compaction 任务,默认并行度为 1 -- admin compact_table("test"); -- 启动常规 compaction,并行度设置为 2 -- admin compact_table("test", "regular", "parallelism=2"); -- 启动 SWCS compaction,使用默认时间窗口,并行度设置为 2 -- admin compact_table("test", "swcs", "parallelism=2"); -- 启动 SWCS compaction,自定义时间窗口和并行度 -- admin compact_table("test", "swcs", "window=1800,parallelism=2"); -- 对已删除的表进行垃圾回收 -- admin gc_table("test"); -- 对已删除的表进行垃圾回收(启用全量文件扫描)-- admin gc_table("test", true); -- 对指定 Region 进行垃圾回收 -- admin gc_regions(1, 2, 3); -- 对指定 Region 进行垃圾回收(启用全量文件扫描)-- admin gc_regions(1, 2, 3, true); ``` --- ## ALTER `ALTER` 可以用来修改数据库的设置,表的设置或表的元数据,包括: * 修改数据库选项 * 添加/删除/修改列 * 设置/取消列默认值 * 重命名表 * 修改表选项 ## ALTER DATABASE `ALTER DATABASE` 语句可以用来修改数据库的选项。 ### 语法 ```sql ALTER DATABASE db [SET = [, ...] | UNSET [, ...] ] ``` 当前支持修改以下数据库选项: - `ttl`: 数据库中数据的默认保留时间。过期的数据会被异步删除。 - 如果之前未设置 ttl,通过 `ALTER` 设置新的 ttl 后,超过保留时间的数据将被删除。 - 如果之前已设置过 ttl,通过 `ALTER` 修改 ttl 后,新的保留时间将立即生效,超过新保留时间的数据将被删除。 - 如果之前已设置过 ttl,通过 `ALTER` 取消 ttl 设置后,新增的数据将不会被删除,但已被删除的数据无法恢复。 - `compaction.twcs.time_window`: TWCS 压缩策略的时间窗口参数。值应该是一个[时间长度字符串](/reference/time-durations.md)。对此选项的修改会立即影响所有没有明确设置压缩选项的表。 - `compaction.twcs.max_output_file_size`: TWCS 压缩策略的最大允许输出文件大小。对此选项的修改会立即影响所有没有明确设置压缩选项的表。 - `compaction.twcs.trigger_file_num`: 触发压缩的特定时间窗口中的文件数。对此选项的修改会立即影响所有没有明确设置压缩选项的表。 ### 示例 #### 修改数据库中数据的默认保留时间 修改数据库中数据的默认保留时间为 1 天: ```sql ALTER DATABASE db SET 'ttl'='1d'; ``` 取消数据库中数据的默认保留时间设置: ```sql ALTER DATABASE db UNSET 'ttl'; ``` #### 修改数据库的压缩选项 数据库级别的压缩选项在压缩调度时动态解析。当您修改这些选项时,更改会立即影响数据库中所有没有明确设置压缩选项的表,类似于 TTL 的工作方式。 修改数据库的压缩时间窗口: ```sql ALTER DATABASE db SET 'compaction.twcs.time_window'='2h'; ``` 修改压缩的最大输出文件大小: ```sql ALTER DATABASE db SET 'compaction.twcs.max_output_file_size'='500MB'; ``` 修改触发压缩的文件数: ```sql ALTER DATABASE db SET 'compaction.twcs.trigger_file_num'='8'; ``` 取消压缩选项: ```sql ALTER DATABASE db UNSET 'compaction.twcs.time_window'; ``` ## ALTER TABLE ## 语法 ```sql ALTER TABLE [db.]table [ADD COLUMN name1 type1 [options], ADD COLUMN name2 type2 [options], ... | DROP COLUMN name | MODIFY COLUMN name type | MODIFY COLUMN name SET DEFAULT value | MODIFY COLUMN name DROP DEFAULT | MODIFY COLUMN name SET FULLTEXT INDEX [WITH ] | MODIFY COLUMN name UNSET FULLTEXT INDEX | SPLIT PARTITION () INTO () | MERGE PARTITION () | RENAME name | SET = [, ...] ] ``` ### 增加列 在表中增加新列: ```sql ALTER TABLE monitor ADD COLUMN load_15 double; ``` 列的定义和 [CREATE](./create.md) 中的定义方式一样。 我们可以在表中同时增加多个列: ```sql ALTER TABLE monitor ADD COLUMN disk_usage double, ADD COLUMN disk_free double; ``` 我们可以设置新列的位置。比如放在第一位: ```sql ALTER TABLE monitor ADD COLUMN load_15 double FIRST; ``` 或者放在某个已有列之后: ```sql ALTER TABLE monitor ADD COLUMN load_15 double AFTER memory; ``` 增加一个带默认值的 Tag 列(加入 Primary key 约束): ```sql ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY; ``` ### 移除列 从表中移除列: ```sql ALTER TABLE monitor DROP COLUMN load_15; ``` 后续的所有查询立刻不能获取到被移除的列。 ### 修改列类型 修改列的数据类型 ```sql ALTER TABLE monitor MODIFY COLUMN load_15 STRING; ``` 被修改的列不能是 tag 列(primary key)或 time index 列,同时该列必须允许空值 `NULL` 存在来保证数据能够安全地进行转换(转换失败时返回 `NULL`)。 ### 设置列默认值 为现有列设置默认值: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 SET DEFAULT 0.0; ``` 设置字符串默认值: ```sql ALTER TABLE monitor MODIFY COLUMN `status` SET DEFAULT 'active'; ``` 默认值将在插入新行时使用,当该列没有显式提供值时。 移除列的默认值: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 DROP DEFAULT; ``` 删除默认值后,该列将使用 `NULL` 作为默认值。数据库只允许对可为空的列删除默认值。 ### 修改表的参数 `ALTER TABLE` 语句也可以用来更改表的选项。 当前支持修改以下表选项: - `ttl`: 表数据的保留时间。 - `append_mode`: 表是否为 append-only。你可以将其从 `false` 更改为 `true`,但之后不能再改回 `false`。 - `compaction.twcs.time_window`: TWCS compaction 策略的时间窗口,其值是一个[时间范围字符段](/reference/time-durations.md)。 - `compaction.twcs.max_output_file_size`: TWCS compaction 策略的最大允许输出文件大小。 - `compaction.twcs.trigger_file_num`: 某个窗口内触发 compaction 的最小文件数量阈值。 - `sst_format`: 表的 SST 格式。值可以是 `flat` 或 `primary_key`。表支持双向格式转换:`primary_key` 转换为 `flat`,以及 `flat` 转换为 `primary_key`。 ```sql ALTER TABLE monitor SET 'ttl'='1d'; ALTER TABLE monitor SET 'append_mode'='true'; ALTER TABLE monitor SET 'compaction.twcs.time_window'='2h'; ALTER TABLE monitor SET 'compaction.twcs.max_output_file_size'='500MB'; ALTER TABLE monitor SET 'compaction.twcs.trigger_file_num'='8'; ALTER TABLE monitor SET 'sst_format'='flat'; ALTER TABLE monitor SET 'sst_format'='primary_key'; ``` ### 移除表参数 ```sql ALTER TABLE monitor UNSET 'ttl'; ``` ### 分区拆分与合并 使用 `SPLIT PARTITION` 将一个分区拆分为多个分区: ```sql ALTER TABLE sensor_readings SPLIT PARTITION ( device_id < 100 ) INTO ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ); ``` 使用 `MERGE PARTITION` 将多个分区合并为一个分区。以下示例将两个分区合并为一个覆盖 `device_id < 100` 的分区: ```sql ALTER TABLE sensor_readings MERGE PARTITION ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ); ``` 你可以在语句末尾附加 DDL 选项以控制执行行为: ```sql ALTER TABLE sensor_readings SPLIT PARTITION ( device_id < 100 ) INTO ( device_id < 100 AND area < 'South', device_id < 100 AND area >= 'South' ) WITH ( TIMEOUT = '5m', WAIT = false ); ``` 当 `WAIT = false` 时,语句会返回 `procedure_id`,可通过 `ADMIN procedure_state(procedure_id)` 查询状态(参见 [ADMIN](/reference/sql/admin.md))。 `TIMEOUT` 用于控制整个操作的超时时间,无论 `WAIT` 是否为 `true` 都会生效。 :::caution 注意 重分区相关操作仅支持在分布式集群中执行。 必须开启共享对象存储和 GC,并确保所有 datanode 都能访问同一对象存储后再执行这些语句。 ::: ### 创建列的索引 在列上启用倒排索引: ```sql ALTER TABLE monitor MODIFY COLUMN host SET INVERTED INDEX; ``` 启用列的全文索引: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 SET FULLTEXT INDEX WITH (analyzer = 'English', case_sensitive = 'false', backend = 'bloom'); ``` 在启用列的全文索引时,可以使用 `FULLTEXT INDEX WITH` 指定以下选项: - `analyzer`:设置全文索引的分析器语言。支持的值为 `English` 和 `Chinese`。默认为 `English`。 - `case_sensitive`:设置全文索引是否区分大小写。支持的值为 `true` 和 `false`。默认为 `false`。 - `backend`:设置全文索引的后端实现。支持的值为 `bloom` 和 `tantivy`。默认为 `bloom`。 - `granularity`:(适用于 `bloom` 后端)每个过滤器覆盖的数据块大小。粒度越小,过滤效果越好,但索引大小会增加。默认为 `10240`。 - `false_positive_rate`:(适用于 `bloom` 后端)错误识别块的概率。该值越低,准确性越高(过滤效果越好),但索引大小会增加。该值为介于 `0` 和 `1` 之间的浮点数。默认为 `0.01`。 更多关于全文索引配置和性能对比的信息,请参考[全文索引配置指南](/user-guide/manage-data/data-index.md#全文索引)。 与 `CREATE TABLE` 一样,可以不带 `WITH` 选项,全部使用默认值。 启用列上的跳数索引: ```sql ALTER TABLE monitor MODIFY COLUMN host SET SKIPPING INDEX WITH(granularity = 1024, type = 'BLOOM'); ``` 跳数索引的有效选项包括: * `type`: 索引类型,目前仅支持 `BLOOM` 即布隆过滤器。 * `granularity`: (适用于 `BLOOM` 类型)每个过滤器覆盖的数据块大小。粒度越小,过滤效果越好,但索引大小会增加。默认为 `10240`。 * `false_positive_rate`: (适用于 `BLOOM` 类型)错误识别块的概率。该值越低,准确性越高(过滤效果越好),但索引大小会增加。该值为介于 `0` 和 `1` 之间的浮点数。默认为 `0.01`。 ### 移除列的索引 语法如下: ```sql ALTER TABLE [table] MODIFY COLUMN [column] UNSET [INVERTED | SKIPPING | FULLTEXT] INDEX; ``` 例如,移除倒排索引: ```sql ALTER TABLE monitor_pk MODIFY COLUMN host UNSET INVERTED INDEX; ``` 移除跳数索引: ```sql ALTER TABLE monitor_pk MODIFY COLUMN host UNSET SKIPPING INDEX; ``` 移除全文索引: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 UNSET FULLTEXT INDEX; ``` 修改列的全文索引选项时,列的数据类型必须是字符串类型。 当列的全文索引未开启过时,可以启用全文索引,并设置 `analyzer` 和 `case_sensitive` 选项;当列的全文索引选项已经启用时,可以关闭全文索引,**但不能修改选项,跳数索引也是如此**。 ### 重命名表 ```sql ALTER TABLE monitor RENAME monitor_new; ``` 该命令只是重命名表,不会修改表中的数据。 --- ## CASE CASE 语句类似于编程语言中的 IF-THEN-ELSE 结构,允许你在查询中执行条件逻辑, 它使你能够根据条件返回特定值,从而使数据检索和操作更加动态。 ## 语法 ```sql CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 ... ELSE result END ``` - `condition1`,`condition2`,...:表达式的判断条件。 - `result1`,`result2`,...:满足相应条件时要返回的值。 - `result`:当没有条件满足时要返回的值(可选)。 ## 示例 `CASE` 语句可以在各种子句中使用,例如 `SELECT`,`WHERE`,`ORDER BY` 和 `GROUP BY`。 ### 在 `SELECT` 中使用 `CASE` 在 `SELECT` 子句中,你可以使用 `CASE` 语句根据条件创建新列。 请参阅查询数据指南中的[示例](/user-guide/query-data/sql.md#case)。 你还可以将 `CASE` 与 `SUM` 等函数一起使用,以有条件地聚合数据。 例如,你可以计算状态码为 200 和 404 的日志总数: ```sql SELECT SUM(CASE WHEN status_code = '200' THEN 1 ELSE 0 END) AS status_200_count, SUM(CASE WHEN status_code = '404' THEN 1 ELSE 0 END) AS status_404_count FROM nginx_logs; ``` ### 在 `WHERE` 中使用 `CASE` 在 `WHERE` 子句中,你可以根据条件过滤行。 例如,以下查询根据 `ts` 条件从 `monitor` 表中检索数据: ```sql SELECT * FROM monitor WHERE host = CASE WHEN ts > '2023-12-13 02:05:46' THEN '127.0.0.1' ELSE '127.0.0.2' END; ``` ### 在 `GROUP BY` 中使用 `CASE` `CASE` 语句可以在 `GROUP BY` 子句中使用,以根据特定条件对数据进行分类。 例如,以下查询按 `host` 列分组,并将 `cpu` 列分类为三类:'high','medium' 和 'low': ```sql SELECT host, COUNT(*) AS count, CASE WHEN cpu > 0.5 THEN 'high' WHEN cpu > 0.3 THEN 'medium' ELSE 'low' END AS cpu_status FROM monitor GROUP BY host, cpu_status; ``` ### 在 `ORDER BY` 中使用 `CASE` 根据 GreptimeDB 的[数据模型](/user-guide/concepts/data-model.md), `Tag` 列拥有索引,可以在 `ORDER BY` 子句中使用以提高查询性能。 假如 `nginx_logs` 表中的 `status_code` 和 `http_method` 列是存储字符串值的 `Tag` 列, 你可以利用 `CASE` 语句根据这些列对数据进行排序,如下所示: ```sql SELECT * FROM nginx_logs ORDER BY CASE WHEN status_code IS NOT NULL THEN status_code ELSE http_method END; ``` --- ## CAST `CAST` 用于将一个数据类型的表达式转换为另一个数据类型。 ## Syntax ```sql CAST (expression AS data_type) ``` ## 参数 - expression: 需要类型转换的表达式。 - data_type: 需要被转换为的数据类型。 # 示例 将字符串转换为 `INT` 类型: ```sql SELECT CAST('123' AS INT) ; ``` ```sql +-------------+ | Utf8("123") | +-------------+ | 123 | +-------------+ ``` --- ## COMMENT `COMMENT` 语句用于为表、列和流添加或删除注释。注释提供的描述可以帮助记录数据库对象的用途和使用方法。 ## COMMENT ON TABLE `COMMENT ON TABLE` 用于为表添加或删除注释。 ### 语法 ```sql COMMENT ON TABLE table_name IS { 'comment' | NULL } ``` - `table_name`: 要添加注释的表名。 - `'comment'`: 包含注释文本的字符串。 - `NULL`: 删除表的现有注释。 ### 示例 为表添加注释: ```sql COMMENT ON TABLE system_metrics IS 'System monitoring metrics collected every minute'; ``` 删除表的注释: ```sql COMMENT ON TABLE system_metrics IS NULL; ``` 使用 `SHOW CREATE TABLE` 查看表注释: ```sql SHOW CREATE TABLE system_metrics; ``` 也可以通过查询 `INFORMATION_SCHEMA.TABLES` 表的 `table_comment` 列来查看注释。 ## COMMENT ON COLUMN `COMMENT ON COLUMN` 用于为表的特定列添加或删除注释。 ### 语法 ```sql COMMENT ON COLUMN table_name.column_name IS { 'comment' | NULL } ``` - `table_name`: 包含该列的表名。 - `column_name`: 要添加注释的列名。 - `'comment'`: 包含注释文本的字符串。 - `NULL`: 删除列的现有注释。 ### 示例 为列添加注释: ```sql COMMENT ON COLUMN system_metrics.cpu_usage IS 'CPU usage percentage (0-100)'; ``` 为多个列添加注释: ```sql COMMENT ON COLUMN system_metrics.memory_usage IS 'Memory usage in bytes'; COMMENT ON COLUMN system_metrics.disk_usage IS 'Disk usage percentage'; ``` 删除列的注释: ```sql COMMENT ON COLUMN system_metrics.cpu_usage IS NULL; ``` 使用 `SHOW CREATE TABLE` 查看列注释: ```sql SHOW CREATE TABLE system_metrics; ``` 也可以通过查询 `INFORMATION_SCHEMA.COLUMNS` 表的 `column_comment` 列来查看列注释。 ## COMMENT ON FLOW `COMMENT ON FLOW` 用于为流添加或删除注释。 ### 语法 ```sql COMMENT ON FLOW flow_name IS { 'comment' | NULL } ``` - `flow_name`: 要添加注释的流名称。 - `'comment'`: 包含注释文本的字符串。 - `NULL`: 删除流的现有注释。 ### 示例 为流添加注释: ```sql COMMENT ON FLOW temperature_monitoring IS 'Monitors temperature sensors and alerts on high values'; ``` 删除流的注释: ```sql COMMENT ON FLOW temperature_monitoring IS NULL; ``` 使用 `SHOW CREATE FLOW` 查看流注释: ```sql SHOW CREATE FLOW temperature_monitoring; ``` 也可以通过查询 `INFORMATION_SCHEMA.FLOWS` 表的 `comment` 列来查看流注释。 ## 注意事项 - 注释作为元数据存储,不会影响表、列或流的行为或性能。 - 可以通过发出新的 `COMMENT ON` 语句来更新注释。 - 将注释设置为 `NULL` 会删除现有注释,如果注释不存在也不会产生错误。 - 注释对于记录数据库对象的用途特别有用,特别是在协作环境中。 --- ## ANSI Compatibility GreptimeDB 支持的 SQL 是 ANSI SQL 的子集,并且拥有一些特有的扩展。一些主要的不兼容和扩展描述如下: 1. 建表 * 支持特有的 `TIME INDEX` 约束,详细请参考[数据模型](/user-guide/concepts/data-model.md)和 [CREATE](./create.md) 建表语法一节。 * 目前仅支持 `PRIMARY KEY` 约束,不支持其他类型的约束,也不支持外键。 * GreptimeDB 是原生的分布式数据库,因此分布式表的建表语句支持分区规则,也请参考[CREATE](./create.md) 建表语法一节。 2. 插入新数据:与 ANSI SQL 语法一致,但是强制要求提供 `TIME INDEX` 列值(或默认值)。 3. 更新:不支持 `UPDATE` 语法,但是在 `INSERT` 的时候,如果主键和 `TIME INDEX` 对应的列值一样,那么后续插入的行将覆盖以前写入的行,从而变相实现更新。 * 从 0.8 开始,GreptimeDB 支持 [append 模式](/reference/sql/create.md#创建-Append-Only-表),创建时指定`append_mode = "true"` 选项的表将保留重复的数据行。 * GreptimeDB 支持 [merge 模式](/reference/sql/create.md#create-an-append-only-table),该模式使用 `merge_mode="last_non_null"` 选项创建表,允许部分更新字段。 4. 查询:查询语法兼容 ANSI SQL,存在部分功能差异和缺失 * 从 v0.9.0 开始支持[视图](/user-guide/query-data/view.md)。 * TQL 语法扩展:TQL 子命令支持在 SQL 中执行 PromQL,详细请参考 [TQL](./tql.md) 一节。 * [Range Query](/reference/sql/range.md#range-query) 支持按照指定窗口来查询和聚合时序数据。 5. 删除数据:语法与 ANSI SQL 基本一致。 6. 他项: * 标识符,如表名,列名等,约束与 ANSI SQL 类似,大小写敏感,遇到特殊字符或者大写需要用双引号括起来。 * GreptimeDB 针对不同方言做了优化,比如用 MySQL 客户端或者 PostgreSQL 客户端连接到数据库时,允许使用特定 SQL 方言的标识符规则,比如在 MySQL 中可以用反引号 `` ` ``,而在 PostgreSQL 中还是标准的双引号 `"`。 --- ## COPY ## COPY TABLE ### COPY TO `COPY TO` 被用来将表的内容导出到文件中,其语法如下: ```sql COPY tbl TO '/xxx/xxx/output.parquet' WITH (FORMAT = 'parquet'); ``` 命令以 `COPY` 关键字开始,后面跟着要导出数据的表名(本例中为 `tbl`)。 `TO` 指定导出数据的文件路径和名称(本例中为 `/xxx/xxx/output.parquet`)。 :::tip NOTE 导出的文件会生成在执行该查询的 GreptimeDB 服务端节点上,而不是发起 SQL 的客户端机器上。请确保路径在服务端可访问且可写,或使用 `CONNECTION` 导出到 S3、GCS、Azure Blob Storage 等云存储服务。 ::: 例如,可以使用自定义时间戳和日期格式导出数据到 CSV 或 JSON 文件: ```sql COPY tbl TO '/path/to/file.csv' WITH ( FORMAT = 'csv', TIMESTAMP_FORMAT = '%Y/%m/%d %H:%M:%S', DATE_FORMAT = '%Y-%m-%d' ); ``` ```sql COPY tbl TO '/path/to/file.json' WITH ( FORMAT = 'json', TIMESTAMP_FORMAT = '%Y/%m/%d %H:%M:%S', DATE_FORMAT = '%Y-%m-%d' ); ``` 也可以将数据导出为压缩的 CSV 或 JSON 文件: ```sql COPY tbl TO '/path/to/file.csv.gz' WITH ( FORMAT = 'csv', compression_type = 'gzip' ); ``` :::tip NOTE 使用压缩时,请确保文件扩展名与压缩类型匹配:gzip 使用 `.gz`,zstd 使用 `.zst`,bzip2 使用 `.bz2`,xz 使用 `.xz`。 ::: #### `WITH` 选项 `WITH` 可以添加一些选项,比如文件的 `FORMAT` 用来指定导出文件的格式。本例中的格式为 Parquet,它是一种用于大数据处理的列式存储格式。Parquet 为大数据分析高效地压缩和编码列式数据。 | 选项 | 描述 | 是否必需 | |---|---|---| | `FORMAT` | 目标文件格式,例如 JSON, CSV, Parquet | **是** | | `START_TIME`/`END_TIME`| 需要导出数据的时间范围,时间范围为左闭右开 | 可选 | | `compression_type` | 导出文件的压缩算法。支持的值:`gzip`、`zstd`、`bzip2`、`xz`。仅支持 CSV 和 JSON 格式。 | 可选 | | `TIMESTAMP_FORMAT` | 导出 CSV 或 JSON 格式时自定义时间戳列的格式。使用 [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) 格式说明符(例如 `'%Y-%m-%d %H:%M:%S'`)。支持 CSV 和 JSON 格式。 | 可选 | | `DATE_FORMAT` | 导出 CSV 或 JSON 格式时自定义日期列的格式。使用 [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) 格式说明符(例如 `'%Y-%m-%d'`)。支持 CSV 和 JSON 格式。 | 可选 | | `TIME_FORMAT` | 导出 CSV 或 JSON 格式时自定义时间列的格式。使用 [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) 格式说明符(例如 `'%H:%M:%S'`)。支持 CSV 和 JSON 格式。 | 可选 | #### `CONNECTION` 选项 `COPY TO` 支持导出数据到云存储上。详情请参考 [连接 S3](#连接-s3)、[连接 GCS](#连接-gcs) 或 [连接 Azure Blob Storage](#连接-azure-blob-storage)。 ### COPY FROM `COPY FROM` 被用来将文件中的数据导入到表中,其语法如下: ```sql COPY [.] FROM { '/[]' } [ [ WITH ] ( [ FORMAT = { 'CSV' | 'JSON' | 'PARQUET' | 'ORC' } ] [ PATTERN = '' ] ) ] [LIMIT NUM] ``` 命令以 `COPY` 关键字开始,后面跟着要导入数据的表名。 #### `WITH` 选项 `FORMAT` 指定导入文件的格式,本例中为 Parquet。 选项 `PATTERN` 允许使用通配符(如 *)指定匹配某种模式的多个输入文件。例如,你可以使用以下语法导入目录(必须是绝对路径)"/path/to/folder" 中文件名包含 `parquet` 的所有文件: ```sql COPY tbl FROM '/path/to/folder/' WITH (FORMAT = 'parquet', PATTERN = '.*parquet.*'); ``` 例如,如果你只有一个文件需要导入,可以使用下方的语法: ```sql COPY tbl FROM '/path/to/folder/xxx.parquet' WITH (FORMAT = 'parquet'); ``` 也可以从压缩的 CSV 或 JSON 文件导入数据: ```sql COPY tbl FROM '/path/to/file.csv.gz' WITH ( FORMAT = 'csv', compression_type = 'gzip' ); ``` | 选项 | 描述 | 是否必需 | |---|---|---| | `FORMAT` | 目标文件格式,例如 JSON, CSV, Parquet, ORC | **是** | | `PATTERN` | 使用正则匹配文件,例如 `*_today.parquet` | 可选 | | `compression_type` | 导入文件的压缩算法。支持的值:`gzip`、`zstd`、`bzip2`、`xz`。仅支持 CSV 和 JSON 格式。 | 可选 | :::tip NOTE CSV 文件必须带有 header,包含表的列名。 ::: #### Connection 选项 `COPY FROM` 同样支持从云存储上导入数据。详情请参考 [连接 S3](#连接-s3)、[连接 GCS](#连接-gcs) 或 [连接 Azure Blob Storage](#连接-azure-blob-storage)。 #### LIMIT 选项 可以通过 `LIMIT` 手动限制一次插入的最大行数。 ### 连接 S3 你可以从 S3 导入/导出数据 ```sql -- COPY FROM COPY tbl FROM '' WITH (FORMAT = 'parquet') CONNECTION(REGION = 'us-west-2'); -- COPY TO COPY tbl TO '' WITH (FORMAT = 'parquet') CONNECTION(REGION = 'us-west-2'); ``` #### URL 注意:你应该使用 `S3://bucket/key-name` 指定文件。下方的例子展示了正确的格式: ``` S3://my-bucket/data.parquet ``` 另一种方式是使用 Virtual-hosted–style(`ENABLE_VIRTUAL_HOST_STYLE` 需要设置成 `true`),例如: ``` https://bucket-name.s3.region-code.amazonaws.com/key-name ``` :::tip NOTE 可以在 S3 控制台上点击 `Copy S3 URI` 或者 `COPY URL` 直接获取对应的 URL/HTTP 前缀或者完整路径。 ::: #### 选项 你可以设置这些 **CONNECTION** 选项: | 选项 | 描述 | 是否必需 | |---|---|---| | `REGION` | AWS region 名称,例如 `us-west-2` | **是** | | `ENDPOINT` | The bucket endpoint,例如 `s3.us-west-2.amazonaws.com` | 可选 | | `ACCESS_KEY_ID` | 用于连接 AWS S3 兼容的对象存储的访问密钥 ID | 可选 | | `SECRET_ACCESS_KEY` | 用于连接 AWS S3 兼容的对象存储的秘密访问密钥 | 可选 | | `ENABLE_VIRTUAL_HOST_STYLE` | 如果你使用 virtual hosting 的方式来定位 bucket,将该选项设置为 "true" | 可选 | | `SESSION_TOKEN` | 用于连接 AWS S3 服务的临时凭证。 | 可选 | ### 连接 GCS 你可以从 Google Cloud Storage (GCS) 导入/导出数据: ```sql -- COPY FROM COPY tbl FROM 'gcs:///' WITH (FORMAT = 'parquet') CONNECTION(SCOPE = 'https://www.googleapis.com/auth/devstorage.read_write'); -- COPY TO COPY tbl TO 'gcs:///' WITH (FORMAT = 'parquet') CONNECTION(SCOPE = 'https://www.googleapis.com/auth/devstorage.read_write'); ``` #### URL 使用 `gcs://bucket/path` 指定文件或目录,例如: ``` gcs://my-bucket/data.parquet ``` #### 选项 | 选项 | 描述 | 是否必需 | |---|---|---| | `SCOPE` | GCS 访问范围,例如 `https://www.googleapis.com/auth/devstorage.read_write` | 可选 | | `CREDENTIAL` | JSON 格式的服务账号凭证内容 | 可选 | | `ENDPOINT` | GCS 服务的 Endpoint | 可选 | ### 连接 Azure Blob Storage 你可以从 Azure Blob Storage 导入/导出数据: ```sql -- COPY FROM COPY tbl FROM 'azblob:///' WITH (FORMAT = 'parquet') CONNECTION(ACCOUNT_NAME = 'my-account', ACCOUNT_KEY = 'my-key'); -- COPY TO COPY tbl TO 'azblob:///' WITH (FORMAT = 'parquet') CONNECTION(ACCOUNT_NAME = 'my-account', ACCOUNT_KEY = 'my-key'); ``` #### URL 使用 `azblob://container/path` 指定文件或目录,例如: ``` azblob://my-container/data.parquet ``` #### 选项 | 选项 | 描述 | 是否必需 | |---|---|---| | `ACCOUNT_NAME` | Azure 存储账号名称 | 可选 | | `ACCOUNT_KEY` | Azure 存储账号密钥 | 可选 | | `ENDPOINT` | Azure Blob Storage 服务的 Endpoint | 可选 | | `SAS_TOKEN` | Azure Blob Storage 的共享访问签名(SAS)令牌 | 可选 | ## COPY 查询结果 你可以使用 `COPY` 语句将查询结果导出到文件中。语法如下: ```sql COPY () TO '' WITH (FORMAT = { 'CSV' | 'JSON' | 'PARQUET' }); ``` | 选项 | 描述 | 是否必需 | |---|---|---| | `QUERY` | 要执行的 SQL SELECT 语句 | **是** | | `PATH` | 输出文件的路径 | **是** | | `FORMAT` | 输出文件格式:'CSV'、'JSON' 或 'PARQUET' | **是** | | `compression_type` | 导出文件的压缩算法。支持的值:`gzip`、`zstd`、`bzip2`、`xz`。仅支持 CSV 和 JSON 格式。 | 可选 | | `TIMESTAMP_FORMAT` | 导出 CSV 或 JSON 格式时自定义时间戳列的格式。使用 [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) 格式说明符。支持 CSV 和 JSON 格式。 | 可选 | | `DATE_FORMAT` | 导出 CSV 或 JSON 格式时自定义日期列的格式。使用 [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) 格式说明符。支持 CSV 和 JSON 格式。 | 可选 | | `TIME_FORMAT` | 导出 CSV 或 JSON 格式时自定义时间列的格式。使用 [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) 格式说明符。支持 CSV 和 JSON 格式。 | 可选 | ### PostgreSQL `COPY ... TO STDOUT` 当你通过 PostgreSQL 协议连接时,可以使用 `COPY () TO STDOUT` 将查询结果流式传输到客户端。这在你希望由 PostgreSQL 客户端(例如 `psql`)处理输出,而不是在 GreptimeDB 服务端写文件时很有用。选项部分同时支持 PostgreSQL 兼容的 `WITH (...)` 和直接使用 `(...)` 两种写法。 ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO STDOUT; COPY (SELECT * FROM tbl WHERE host = 'host1') TO STDOUT WITH (FORMAT csv); COPY (SELECT * FROM tbl WHERE host = 'host1') TO STDOUT (FORMAT binary); ``` - `FORMAT` 支持 PostgreSQL 文本格式(省略时默认使用)、`csv` 和 `binary`。 - `COPY ... TO STDOUT` 仅在 PostgreSQL 协议下支持导出查询结果,也就是 `COPY ()`。 例如,在 `psql` 中可以使用 `\copy` 将流式结果保存到客户端本地文件: ```sql \copy (SELECT * FROM tbl WHERE host = 'host1') TO '/tmp/file.csv' WITH (FORMAT csv) ``` 例如,以下语句将查询结果导出到 CSV 文件中: ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.csv' WITH (FORMAT = 'csv'); ``` 也可以将查询结果导出为压缩文件: ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.json.gz' WITH ( FORMAT = 'json', compression_type = 'gzip' ); ``` 也可以在导出到 CSV 或 JSON 时指定自定义日期和时间格式: ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.csv' WITH ( FORMAT = 'csv', TIMESTAMP_FORMAT = '%m-%d-%Y %H:%M:%S', DATE_FORMAT = '%Y/%m/%d' ); ``` ```sql COPY (SELECT * FROM tbl WHERE host = 'host1') TO '/path/to/file.json' WITH ( FORMAT = 'json', TIMESTAMP_FORMAT = '%m-%d-%Y %H:%M:%S', DATE_FORMAT = '%Y/%m/%d' ); ``` ## COPY DATABASE `COPY` 语句除可以导入/导出表之外,也可以导入/导出指定的数据库,其语法如下: ```sql COPY DATABASE [TO | FROM] '' WITH ( FORMAT = { 'CSV' | 'JSON' | 'PARQUET' } START_TIME = "", END_TIME = "", PARALLELISM = ) [CONNECTION( REGION = "", ENDPOINT = "", ACCESS_KEY_ID = "", SECRET_ACCESS_KEY = "", ENABLE_VIRTUAL_HOST_STYLE = "[true | false]", )] ``` | 选项 | 描述 | 是否必需 | |---|---|---| | `FORMAT` | 目标文件格式,例如 JSON, CSV, Parquet | **是** | | `START_TIME`/`END_TIME`| 需要导出数据的时间范围,时间范围为左闭右开 | 可选 | | `PARALLELISM` | 并行处理的表数量。例如,数据库包含 30 个表且 `PARALLELISM` 设置为 8 时,将同时处理 8 个表。默认值为 CPU 核心总数,最小值为 1。 | 可选 | > - 当导入/导出表时,`` 参数必须以 `/` 结尾; > - COPY DATABASE 同样可以通过 `CONNECTION` 参数将数据导入/导出的路径指向 S3、GCS、Azure Blob Storage 等对象存储 ### 示例 ```sql -- 将 public 数据库中所有数据导出到 /tmp/export/ 目录下 COPY DATABASE public TO '/tmp/export/' WITH (FORMAT='parquet'); -- 使用 4 个并行操作导出所有表数据 COPY DATABASE public TO '/tmp/export/' WITH (FORMAT='parquet', PARALLELISM=4); -- 将 public 数据库中时间范围在 2022-04-11 08:00:00 到 2022-04-11 09:00:00 之间的数据导出到 /tmp/export/ 目录下 COPY DATABASE public TO '/tmp/export/' WITH (FORMAT='parquet', START_TIME='2022-04-11 08:00:00', END_TIME='2022-04-11 09:00:00'); -- 从 /tmp/export/ 目录恢复 public 数据库的数据 COPY DATABASE public FROM '/tmp/export/' WITH (FORMAT='parquet'); -- 使用 8 个并行操作导入数据 COPY DATABASE public FROM '/tmp/export/' WITH (FORMAT='parquet', PARALLELISM=8); ``` ## Windows 平台上的路径 请注意,在 Windows 平台上执行 `COPY`/`COPY DATABASE` 语句时,请使用 `/` 代替 `` 中的 `\`,如 `C:/some_dir/output.parquet`。 ```sql -- 下列语句将会报错 COPY tbl TO 'C:\xxx\xxx\output.parquet' WITH (FORMAT = 'parquet'); -- 下列语句能够正常执行 COPY tbl TO 'C:/xxx/xxx/output.parquet' WITH (FORMAT = 'parquet'); ``` --- ## CREATE `CREATE` 用于创建新的数据库或者表。 ## CREATE DATABASE ### Syntax 创建新数据库: ```sql CREATE DATABASE [IF NOT EXISTS] db_name [WITH ] ``` 如果 `db_name` 数据库已经存在,`CREATE` 语句的行为如下: - 不会创建新的数据库。 - 当 `IF NOT EXISTS` 子句被指定时,不会返回错误。 - 否则,返回错误。 数据库也可以通过使用 `WITH` 关键字配置与 `CREATE TABLE` 语句类似的选项。数据库支持以下选项: - `ttl` - 数据库中所有表的数据存活时间(不能设置为 `instant`) - `memtable.type` - 内存表类型(`time_series`、`partition_tree`) - `append_mode` - 数据库中的表是否为仅追加模式(`true`/`false`) - `merge_mode` - 合并重复行的策略(`last_row`、`last_non_null`) - `skip_wal` - 是否为数据库中的表禁用预写日志(`'true'`/`'false'`) - `sst_format` - 数据库中表的 SST(Sorted String Table)文件格式(`flat`、`primary_key`) - `compaction.*` - 压缩相关设置(如 `compaction.type`、`compaction.twcs.time_window`) 阅读更多关于[表选项](#表选项)的信息。 :::note 重要的行为差异 数据库选项的行为有所不同: - **TTL 和 Compaction 选项**(`ttl`、`compaction.*`):这些选项具有**持续影响**。没有指定这些值的表会持续继承数据库级别的值。更改数据库 TTL 或 compaction 选项会立即影响所有没有明确自行设置这些选项的表。 - **其他选项**(`memtable.type`、`append_mode`、`merge_mode`、`skip_wal`、`sst_format`):这些选项充当**模板变量**,仅在创建新表时应用。更改这些数据库级别的选项不会影响已存在的表——它们仅作为新创建表的默认值。 ::: 在创建表时,如果未提供相应的表选项,将使用在数据库级别配置的选项或者默认值。 ### 示例 创建名为 `test` 的数据库: ```sql CREATE DATABASE test; ``` ```sql Query OK, 1 row affected (0.05 sec) ``` 使用 `IF NOT EXISTS` 再次创建: ```sql CREATE DATABASE IF NOT EXISTS test; ``` 创建一个具有 7 天 `TTL`(数据存活时间)的数据库,也就是该数据库中的所有表如果没有单独设置 TTL 选项,都将继承此选项值。 ```sql CREATE DATABASE test WITH (ttl='7d'); ``` 创建一个带有多个选项的数据库,包括仅追加模式和自定义内存表类型: ```sql CREATE DATABASE test WITH ( ttl='30d', 'memtable.type'='partition_tree', 'append_mode'='true' ); ``` 创建一个禁用预写日志并设置自定义合并模式的数据库: ```sql CREATE DATABASE test WITH ( 'skip_wal'='true', 'merge_mode'='last_non_null' ); ``` 创建一个指定 SST 文件格式的数据库: ```sql CREATE DATABASE test WITH ('sst_format'='flat'); ``` ## CREATE TABLE ### Syntax 在 `db` 或当前数据库中创建新表: ```sql CREATE TABLE [IF NOT EXISTS] [db.]table_name ( column1 type1 [NULL | NOT NULL] [DEFAULT expr1] [TIME INDEX] [PRIMARY KEY] [indexes] [COMMENT comment1], column2 type2 [NULL | NOT NULL] [DEFAULT expr2] [TIME INDEX] [PRIMARY KEY] [indexes] [COMMENT comment2], ... [TIME INDEX (column)], [PRIMARY KEY(column1, column2, ...)], ) [ PARTITION ON COLUMNS(column1, column2, ...) ( , ... ) ] ENGINE = engine WITH([TTL | storage | ...] = expr, ...) ``` 表 schema 由 `ENGINE` 之前的括号指定,表 schema 是列的定义和表的约束。 列定义包括列名称和数据类型,以及可选的 `NULL`、`NOT NULL`、`DEFAULT` 等。 关于 `engine` 选项和表引擎的选择,请阅读[表引擎](/reference/about-greptimedb-engines.md)介绍。 ### 表约束 表约束包括以下内容: - `TIME INDEX` 指定时间索引列,每个表只能有一个时间索引列。它表示 GreptimeDB 的 [数据模型](/user-guide/concepts/data-model.md) 中的 `Timestamp` 类型。 - `PRIMARY KEY` 指定表的主键列,它表示 GreptimeDB 的 [数据模型](/user-guide/concepts/data-model.md) 中的 `Tag` 类型。它不能包含时间索引列,但是它总是隐式地将时间索引列添加到键的末尾。 - 其他列是 GreptimeDB 的 [数据模型](/user-guide/concepts/data-model.md) 中的 `Field` 类型。 :::tip 注意 `CREATE` 语句中指定的 `PRIMARY KEY` **不是** 传统关系数据库中的主键。 实际上,传统关系数据库中的 `PRIMARY KEY` 相当于 GreptimeDB 中的 `PRIMARY KEY` 和 `TIME INDEX` 的组合。 换句话说,`PRIMARY KEY` 和 `TIME INDEX` 一起构成了 GreptimeDB 中行的唯一标识符。 ::: 如果表已经存在且创建表时指定了 `IF NOT EXISTS`,`CREATE` 语句不会返回错误;否则返回错误。 #### 索引 GreptimeDB 提供了丰富的索引实现来加速查询,请在[索引](/user-guide/manage-data/data-index.md)章节查看更多信息。 ### 表选项 用户可以使用 `WITH` 添加表选项。有效的选项包括以下内容: | 选项 | 描述 | 值 | | ------------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ttl` | 表数据的存储时间 | 一个时间范围字符串,例如 `'60m'`, `'1h'` 代表 1 小时, `'14d'` 代表 14 天等。支持的时间单位有:`s` / `m` / `h` / `d` | | `storage` | 自定义表的存储引擎,存储引擎提供商的名字 | 字符串,类似 `S3`、`Gcs` 等。必须在 `[[storage.providers]]` 列表里配置,参考 [configuration](/user-guide/deployments-administration/configuration.md#存储引擎提供商)。 | | `compaction.type` | Compaction 策略 | 字符串值。只支持 `twcs`。你可以阅读这篇[文章](https://cassandra.apache.org/doc/latest/cassandra/managing/operating/compaction/twcs.html)来了解 `twcs` compaction 策略 | | `compaction.twcs.trigger_file_num` | 某个窗口内触发 compaction 的最小文件数量阈值 | 字符串值,如 '8'。只在 `compaction.type` 为 `twcs` 时可用 | | `compaction.twcs.time_window` | Compaction 时间窗口 | 字符串值,如 '1d' 表示 1 天。该表会根据时间戳将数据分区到不同的时间窗口中。只在 `compaction.type` 为 `twcs` 时可用 | | `compaction.twcs.max_output_file_size` | TWCS compaction 的最大输出文件大小 | 字符串值,如 '1GB'、'512MB'。设置 TWCS compaction 产生的文件的最大大小。只在 `compaction.type` 为 `twcs` 时可用 | | `memtable.type` | memtable 的类型 | 字符串值,支持 `time_series`,`partition_tree` | | `append_mode` | 该表是否时 append-only 的 | 字符串值。默认值为 'false',根据 'merge_mode' 按主键和时间戳删除重复行。设置为 'true' 可以开启 append 模式和创建 append-only 表,保留所有重复的行 | | `merge_mode` | 合并重复行的策略 | 字符串值。只有当 `append_mode` 为 'false' 时可用。默认值为 `last_row`,保留相同主键和时间戳的最后一行。设置为 `last_non_null` 则保留相同主键和时间戳的最后一个非空字段。 | | `sst_format` | SST 文件的格式 | 字符串值,支持 `primary_key`,`flat`。默认为 `flat`。`flat` 格式建议用于具有高基数主键的表。 | | `comment` | 表级注释 | 字符串值。 | | `index.type` | Index 类型 | **仅用于 metric engine** 字符串值,支持 `none`, `skipping`. | | `skip_wal` | 是否关闭表的预写日志 | 字符串类型。当设置为 `'true'` 时表的写入数据将不会持久化到预写日志,可以避免存储磨损同时提升写入吞吐。但是当进程重启时,尚未 flush 的数据会丢失。请仅在数据源本身可以确保可靠性的情况下使用此功能。 | #### 创建指定 TTL 的表 例如,创建一个存储数据 TTL(Time-To-Live) 为七天的表: ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with(ttl='7d'); ``` `ttl` 值是一个字符串,支持以下类型的值: - [时间范围字符串](/reference/time-durations.md),如 `1hour 12min 5s`。 - `forever`, `NULL`, `0s` (或任何长度为 0 的时间范围,如 `0d`)或空字符串 `''`,表示数据永远不会被删除。 - `instant`, 注意数据库的 TTL 不能设置为 `instant`。`instant` 表示数据在插入时立即删除,如果你想将输入发送到流任务而不保存它,可以使用 `instant`,请参阅[流管理文档](/user-guide/flow-computation/manage-flow.md#manage-flows)了解更多细节。 - 未设置,可以使用 `ALTER TABLE UNSET 'ttl'` 来取消表的 `ttl` 设置,这样表将继承数据库的 `ttl` 策略(如果有的话)。 如果一张表有自己的 TTL 策略,那么它将使用该 TTL 策略。否则,数据库的 TTL 策略将被应用到表上。 比如说,如果表的 TTL 设置为 `forever`,那么无论数据库的 TTL 是什么,数据都不会被删除。但是如果你取消表的 TTL 设置: ```sql ALTER TABLE UNSET 'ttl'; ``` 那么数据库的 TTL 将会被应用到表上。 请注意表和数据库的默认 TTL 策略都是未设置,也就是没有设置 TTL,代表着数据永远不会删除。 #### 创建自定义存储的表 或者创建一个表单独将数据存储在 Google Cloud Storage 服务上: ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with(ttl='7d', storage="Gcs"); ``` #### 创建自定义 compaction 参数的表 创建带自定义 twcs compaction 参数的表。这个表会尝试根据数据的时间戳将数据按 1 天的时间窗口分区,并会在最新时间窗口内的文件超过 8 个时合并该窗口的文件 ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with( 'compaction.type'='twcs', 'compaction.twcs.time_window'='1d', 'compaction.twcs.trigger_file_num'='8', 'compaction.twcs.max_output_file_size'='1GB' ); ``` #### 创建 Append-Only 表 创建一个 append-only 表来关闭去重 ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10, ) with('append_mode'='true'); ``` #### 创建带有 merge 模式的表 创建一个带有 `last_row` merge 模式的表,这是默认的 merge 模式。 ```sql create table if not exists metrics( host string, ts timestamp, cpu double, memory double, TIME INDEX (ts), PRIMARY KEY(host) ) with('merge_mode'='last_row'); ``` 在 `last_row` 模式下,表会通过保留最新的行来合并具有相同主键和时间戳的行。 ```sql INSERT INTO metrics VALUES ('host1', 0, 0, NULL), ('host2', 1, NULL, 1); INSERT INTO metrics VALUES ('host1', 0, NULL, 10), ('host2', 1, 11, NULL); SELECT * from metrics ORDER BY host, ts; +-------+-------------------------+------+--------+ | host | ts | cpu | memory | +-------+-------------------------+------+--------+ | host1 | 1970-01-01T00:00:00 | | 10.0 | | host2 | 1970-01-01T00:00:00.001 | 11.0 | | +-------+-------------------------+------+--------+ ``` 创建带有 `last_non_null` merge 模式的表。 ```sql create table if not exists metrics( host string, ts timestamp, cpu double, memory double, TIME INDEX (ts), PRIMARY KEY(host) ) with('merge_mode'='last_non_null'); ``` 在 `last_non_null` 模式下,表会通过保留每个字段的最新非 NULL 值来合并具有相同主键和时间戳的行。 ```sql INSERT INTO metrics VALUES ('host1', 0, 0, NULL), ('host2', 1, NULL, 1); INSERT INTO metrics VALUES ('host1', 0, NULL, 10), ('host2', 1, 11, NULL); SELECT * from metrics ORDER BY host, ts; +-------+-------------------------+------+--------+ | host | ts | cpu | memory | +-------+-------------------------+------+--------+ | host1 | 1970-01-01T00:00:00 | 0.0 | 10.0 | | host2 | 1970-01-01T00:00:00.001 | 11.0 | 1.0 | +-------+-------------------------+------+--------+ ``` #### 创建禁用 WAL 的表 创建一个禁用 WAL 的表。请注意,当 WAL 被禁用时,进程重启后尚未 flush 的数据将会丢失。 ```sql CREATE TABLE IF NOT EXISTS temperatures( ts TIMESTAMP TIME INDEX, temperature DOUBLE DEFAULT 10 ) with('skip_wal'='true'); ``` #### 创建 metric engine 的物理表 metric engine 使用合成物理宽表来存储大量的小表数据,实现重用相同列和元数据的效果。详情请参考 [metric engine 文档](/contributor-guide/datanode/metric-engine)和[表引擎](/reference/about-greptimedb-engines.md)介绍。 创建一个使用 metric engine 的物理表。 ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, TIME INDEX (greptime_timestamp), ) engine = metric with ( "physical_metric_table" = "", ); ``` #### 创建一个带有跳数索引的物理表 默认情况下,metric engine 不会为列创建索引。你可以通过设置 `index.type` 为 `skipping` 来设置索引类型。 创建一个带有跳数索引的物理表。所有自动添加的列都将应用跳数索引。 ```sql CREATE TABLE greptime_physical_table ( greptime_timestamp TIMESTAMP(3) NOT NULL, greptime_value DOUBLE NULL, TIME INDEX (greptime_timestamp), ) engine = metric with ( "physical_metric_table" = "", "index.type" = "skipping", ); ``` #### 创建指定 SST 格式的表 创建一个使用 `flat` SST 格式的表。 ```sql CREATE TABLE IF NOT EXISTS metrics( host string, ts timestamp, cpu double, memory double, TIME INDEX (ts), PRIMARY KEY(host) ) with('sst_format'='flat'); ``` `flat` 格式针对高基数主键进行了优化,是新建表的默认 SST 格式。 ### 列选项 GreptimeDB 支持以下列选项: | 选项 | 描述 | | ----------------- | -------------------------------------------------------- | | NULL | 列值可以为 `null` | | NOT NULL | 列值不能为 `null` | | DEFAULT `expr` | 该列的默认值是 `expr`,其类型必须是该列的类型 | | COMMENT `comment` | 列注释,必须为字符串类型 | | FULLTEXT INDEX | 创建全文索引,可以加速全文搜索操作。仅适用于字符串类型列 | | SKIPPING INDEX | 创建跳数索引,可以加速查询稀疏数据。 | | INVERTED INDEX | 创建倒排索引,可以加速查询稠密数据。 | 表约束 `TIME INDEX` 和 `PRIMARY KEY` 也可以通过列选项设置,但是它们只能在列定义中指定一次,在多个列选项中指定 `PRIMARY KEY` 会报错: ```sql CREATE TABLE system_metrics ( host STRING PRIMARY KEY, idc STRING PRIMARY KEY, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), TIME INDEX(ts) ); ``` 会得到报错: ```sql Illegal primary keys definition: not allowed to inline multiple primary keys in columns options ``` 正确的做法是使用 `PRIMARY KEY()` 来指定多个列作为主键: ```sql CREATE TABLE system_metrics ( host STRING, idc STRING, cpu_util DOUBLE, memory_util DOUBLE, disk_util DOUBLE, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(host, idc), ); ``` ```sql Query OK, 0 rows affected (0.01 sec) ``` #### `INDEX` 列选项 更多关于索引配置、性能对比和使用指南的信息,请参考[索引](/user-guide/manage-data/data-index.md)章节。 ### Region 分区规则 请参考 [分区](/contributor-guide/frontend/table-sharding.md#partition) 章节。 ## CREATE EXTERNAL TABLE ### Syntax 在 `db` 或当前数据库中创建新的文件外部表: ```sql CREATE EXTERNAL TABLE [IF NOT EXISTS] [db.]table_name [ ( column1 type1 [NULL | NOT NULL] [DEFAULT expr1] [TIME INDEX] [PRIMARY KEY] [COMMENT comment1], column2 type2 [NULL | NOT NULL] [DEFAULT expr2] [TIME INDEX] [PRIMARY KEY] [COMMENT comment2], ... [TIME INDEX (column)], [PRIMARY KEY(column1, column2, ...)] ) ] WITH ( LOCATION = url, FORMAT = { 'CSV' | 'JSON' | 'PARQUET' | 'ORC' } [,PATTERN = regex_pattern ] [,REGION = region ] [,ENDPOINT = uri ] [,ACCESS_KEY_ID = key_id ] [,SECRET_ACCESS_KEY = access_key ] [,ENABLE_VIRTUAL HOST_STYLE = { TRUE | FALSE }] [,SESSION_TOKEN = token ] ... ) ``` ### 表选项 | 选项 | 描述 | 是否必需 | | ---------- | ------------------------------------------------------------------ | -------- | | `LOCATION` | 外部表的位置,例如 `s3://[]`, `//[]` | **是** | | `FORMAT` | 目标文件的格式,例如 JSON,CSV,Parquet, ORC | **是** | | `PATTERN` | 使用正则来匹配文件,例如 `*_today.parquet` | 可选 | #### S3 | 选项 | 描述 | 是否必需 | | --------------------------- | --------------------------------------------------------------- | -------- | | `REGION` | AWS region 名称,例如 us-east-1 | **是** | | `ENDPOINT` | The bucket endpoint | 可选 | | `ACCESS_KEY_ID` | 用于连接 AWS S3 兼容对象存储的访问密钥 ID | 可选 | | `SECRET_ACCESS_KEY` | 用于连接 AWS S3 兼容对象存储的秘密访问密钥 | 可选 | | `ENABLE_VIRTUAL HOST_STYLE` | 如果你想要使用 virtual hosting 来定位 bucket,将其设置为 `true` | 可选 | | `SESSION_TOKEN` | 用于连接 AWS S3 服务的临时凭证 | 可选 | ### 时间索引列 在利用 `CREATE EXTERNAL TABLE` 语句创建外部表时,要求使用 `TIME INDEX` 约束来指定一个时间索引列。 ### 示例 你可以在创建外部表时不带有列定义,列定义将会被自动推断: ```sql CREATE EXTERNAL TABLE IF NOT EXISTS city WITH (location='/var/data/city.csv',format='csv'); ``` 在这个例子中,我们没有明确定义表的列,为满足外边表必须指定**时间索引列**的要求,`CREATE EXTERNAL TABLE` 语句会依据下述规则推断出时间索引列: 1. 如果可以从文件元数据中推断出时间索引列,那么就用该列作为时间索引列。 2. 如果存在名为 `greptime_timestamp` 的列(该列的类型必须为 `TIMESTAMP`,否则将抛出错误),那么就用该列作为时间索引列。 3. 否则,将自动创建名为 `greptime_timestamp` 的列作为时间索引列,并添加 `DEFAULT '1970-01-01 00:00:00+0000'` 约束。 或者带有列定义: ```sql CREATE EXTERNAL TABLE city ( host string, ts timestamp, cpu float64 default 0, memory float64, TIME INDEX (ts), PRIMARY KEY(host) ) WITH (location='/var/data/city.csv', format='csv'); ``` 在这个例子中,我们明确定义了 `ts` 列作为时间索引列。如果在文件中没有适合的时间索引列,你也可以创建一个占位符列,并添加 `DEFAULT expr` 约束。 ## 创建 Flow ```sql CREATE [OR REPLACE] FLOW [ IF NOT EXISTS ] SINK TO [ EXPIRE AFTER ] [ COMMENT '' ] AS ; ``` 对于 `CREATE FLOW`,`AS` 后面的查询既可以是常规 Flow 查询,也可以是 TQL 查询。GreptimeDB 现在还支持一种严格受限的 TQL CTE 写法,用来让 Flow 定义更清晰: ```sql CREATE FLOW calc_rate_cte SINK TO rate_reqs EVAL INTERVAL '1m' AS WITH rate_data (ts, req_rate, host, job, instance) AS ( TQL EVAL (now() - '1m'::interval, now(), '30s') rate(http_requests_total{job="my_service"}[1m]) AS req_rate ) SELECT * FROM rate_data; ``` 在 `CREATE FLOW` 中使用 `WITH` 时,当前仅支持一种刻意保持简单的形式: - 只能有一个 CTE,并且该 CTE 必须包含 `TQL EVAL`。 - 外层查询必须严格是 `SELECT * FROM `。 - 不支持额外的列投影、过滤、JOIN、排序,也不支持再混入其他 SQL CTE。 - 如果 CTE 名称使用了引号,那么外层 `SELECT` 里也要用相同的带引号名称引用它。 用于创建或更新 Flow 任务,请阅读[Flow 管理文档](/user-guide/flow-computation/manage-flow.md#创建-flow)。 ## 创建 View ```sql CREATE [OR REPLACE] VIEW [ IF NOT EXISTS ] AS select_statement ``` 用于创建或更新视图,请阅读[视图用户指南](/user-guide/query-data/view.md#视图)。 ## 创建 Trigger 请参考 [CREATE TRIGGER](/reference/sql/trigger-syntax.md#create-trigger) 文档。 --- ## 数据类型 SQL 数据类型定义了列可以存储的数据类型。当您运行 `DESC TABLE` 命令时,你可以看到每列的数据类型。 ## 字符串和二进制数据类型 | 类型名称 | 描述 | 大小 | | -------- | ------------------------------------------------------- | ------------------- | | `String` | UTF-8 编码的字符串。最多可容纳 2,147,483,647 字节的数据 | 字符串的长度 | | `Binary` | 变长二进制值。最多可容纳 2,147,483,647 字节的数据 | 数据的长度 + 2 字节 | `String` 和 `Binary` 的最大容量取决于它们的编码方式以及存储引擎如何处理它们。例如,`String` 值被编码为 UTF-8,如果所有字符的长度为 3 个字节,该字段最多可以存储 715,827,882 个字符。对于 `Binary` 类型,它们最多可以存储 2,147,483,647 字节。 ## 数值数据类型 | 类型名称 | 描述 | 大小 | | --------- | ------------------------------------------ | ------ | | `Int8` | -128 ~ 127 | 1 字节 | | `Int16` | -32768 ~ 32767 | 2 字节 | | `Int32` | -2147483648 ~ 2147483647 | 4 字节 | | `Int64` | -9223372036854775808 ~ 9223372036854775807 | 8 字节 | | `UInt8` | 0 ~ 255 | 1 字节 | | `UInt16` | 0 ~ 65535 | 2 字节 | | `UInt32` | 0 ~ 4294967295 | 4 字节 | | `UInt64` | 0 ~ 18446744073709551615 | 8 字节 | | `Float32` | 32 位 IEEE 754 浮点数 | 4 字节 | | `Float64` | 双精度 IEEE 754 浮点数 | 8 字节 | :::tip 注意 这里的描述指的是 GreptimeDB 原生类型信息,这些类型都是以 位(bits) 为单位的。但是,在使用 SQL 时,请遵循 PostgreSQL 和 MySQL 的惯例,其中 `INT2`、`INT4`、`INT8`、`FLOAT4` 和 `FLOAT8` 等类型都是以 字节(bytes) 为单位定义的。 例如,在 SQL 语句中,`INT8` 实际上对应 `BigInt`(8 个字节,64 位)。 ::: ## Decimal 类型 GreptimeDB 支持 `decimal` 类型,这是一种定点类型,表示为 `decimal(precision, scale)`,其中 `precision` 是总位数,`scale` 是小数部分的位数。例如,`123.45` 的总位数为 5,小数位数为 2。 - `precision` 可以在 [1, 38] 范围内。 - `scale` 可以在 [0, precision] 范围内。 如果未指定总位数和比例,则默认的十进制数是 `decimal(38, 10)`。 ```sql CREATE TABLE decimals( d DECIMAL(3, 2), ts TIMESTAMP TIME INDEX, ); INSERT INTO decimals VALUES ('0.1',1000), ('0.2',2000); SELECT * FROM decimals; ``` ```sql +------+---------------------+ | d | ts | +------+---------------------+ | 0.10 | 1970-01-01T00:00:01 | | 0.20 | 1970-01-01T00:00:02 | +------+---------------------+ ``` ## 日期和时间类型 | 类型名称 | 描述 | 大小 | | ---------------------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `TimestampSecond` | 64 位时间戳值,精度为秒,范围:`[-262144-01-01 00:00:00, +262143-12-31 23:59:59]` | 8 字节 | | `TimestampMillisecond` | 64 位时间戳值,毫秒精度,范围:`[-262144-01-01 00:00:00.000, +262143-12-31 23:59:59.999]` | 8 字节 | | `TimestampMicroSecond` | 64 位时间戳值,微秒精度,范围:`[-262144-01-01 00:00:00.000000, +262143-12-31 23:59:59.999999]` | 8 字节 | | `TimestampNanosecond` | 64 位时间戳值,纳秒精度,范围: `[1677-09-21 00:12:43.145225, 2262-04-11 23:47:16.854775807]` | 8 字节 | | `Interval` | 时间间隔 | 对于 `YearMonth`, 使用 4 字节,对于 `DayTime`, 使用 8 字节,对于 `MonthDayNano`, 使用 16 字节 | :::tip 注意 使用 MySQL/PostgreSQL 协议写入时间戳字符串字面量时,值的范围限制为 '0001-01-01 00:00:00' 到 '9999-12-31 23:59:59'。 ::: ### Interval 类型详解 `Interval` 类型用于需要跟踪和操作时间间隔的场景。它的编写语法如下: ``` QUANTITY UNIT [QUANTITY UNIT...] ``` * `QUANTITY`:是一个数字(可能有符号), * `UNIT`:时间单位,可以是 `microsecond`(微秒)、`millisecond`(毫秒)、`second`(秒)、`minute`(分钟)、`hour`(小时)、`day`(天)、`week`(周)、`month`(月)、`year`(年)、`decade`(十年)、`century`(世纪)或这些单位的缩写或复数形式; 不同的时间单位将会被计算合并,每个单位的符号决定它是增加还是减少总间隔。例如,“1 年 -2 个月”导致净间隔为 10 个月。 遗憾的是,GreptimeDB 暂时还不支持以 [ISO 8601 时间间隔](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals)格式编写间隔,例如 `P3Y3M700DT133H17M36.789S` 等。但它支持以这种格式输出。 让我们来看一些例子: ```sql SELECT '2 years 15 months 100 weeks 99 hours 123456789 milliseconds'::INTERVAL; ``` ```sql +---------------------------------------------------------------------+ | Utf8("2 years 15 months 100 weeks 99 hours 123456789 milliseconds") | +---------------------------------------------------------------------+ | P3Y3M700DT133H17M36.789S | +---------------------------------------------------------------------+ ``` 55 分钟前: ```sql SELECT '-1 hour 5 minute'::INTERVAL; ``` ```sql +--------------------------+ | Utf8("-1 hour 5 minute") | +--------------------------+ | P0Y0M0DT0H-55M0S | +--------------------------+ ``` 1 小时 5 分钟前: ```sql SELECT '-1 hour -5 minute'::INTERVAL; ``` ```sql +---------------------------+ | Utf8("-1 hour -5 minute") | +---------------------------+ | P0Y0M0DT-1H-5M0S | +---------------------------+ ``` 当然,你可以通过算术运算来操作时间间隔。 获取 5 分钟前的时间: ```sql SELECT now() - '5 minute'::INTERVAL; ``` ```sql +----------------------------------------------+ | now() - IntervalMonthDayNano("300000000000") | +----------------------------------------------+ | 2024-06-24 21:24:05.012306 | +----------------------------------------------+ ``` GreptimeDB 还支持类似 `3y2mon4h` 这样不包含空格的简写形式: ```sql SELECT '3y2mon4h'::INTERVAL; ``` ``` +---------------------------------------------------------+ | IntervalMonthDayNano("3010670175542044842954670112768") | +---------------------------------------------------------+ | P3Y2M0DT4H0M0S | +---------------------------------------------------------+ ``` 同样也支持符号数: ```sql SELECT '-1h5m'::INTERVAL; ``` ``` +----------------------------------------------+ | IntervalMonthDayNano("18446740773709551616") | +----------------------------------------------+ | P0Y0M0DT0H-55M0S | +----------------------------------------------+ ``` 支持的缩写包括: | 缩写 | 全称 | | ------ | ------------ | | y | years | | mon | months | | w | weeks | | d | days | | h | hours | | m | minutes | | s | seconds | | millis | milliseconds | | ms | milliseconds | | us | microseconds | | ns | nanoseconds | #### INTERVAL 关键字 在上述示例中,我们使用了 `cast` 类型转换操作 `'{quantity unit}'::INTERVAL` 来演示 interval 类型。实际上,interval 类型也可以使用 `INTERVAL` 关键字支持的语法,不过不同数据库方言之间的行为有所差异: 1. 在 MySQL 中,语法为 `INTERVAL {quantity} {unit}`,其中 `quantity` 可以是数字或字符串,具体取决于上下文。例如: ```sql mysql> SELECT INTERVAL 1 YEAR; +--------------------------------------------------------------------------------------+ | IntervalMonthDayNano("IntervalMonthDayNano { months: 12, days: 0, nanoseconds: 0 }") | +--------------------------------------------------------------------------------------+ | P1Y0M0DT0H0M0S | +--------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) mysql> SELECT INTERVAL '1 YEAR 2' MONTH; +--------------------------------------------------------------------------------------+ | IntervalMonthDayNano("IntervalMonthDayNano { months: 14, days: 0, nanoseconds: 0 }") | +--------------------------------------------------------------------------------------+ | P1Y2M0DT0H0M0S | +--------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) ``` 2. 在 PostgreSQL 和默认的 GreptimeDB 方言中,语法为 `INTERVAL '{quantity unit}'`,即 INTERVAL 关键字后跟 interval 字符串: ```sql public=> SELECT INTERVAL '1 year'; IntervalMonthDayNano("IntervalMonthDayNano { months: 12, days: 0, nanoseconds: 0 }") -------------------------------------------------------------------------------------- 1 year (1 row) public=> SELECT INTERVAL '1 year 2 month'; IntervalMonthDayNano("IntervalMonthDayNano { months: 14, days: 0, nanoseconds: 0 }") -------------------------------------------------------------------------------------- 1 year 2 mons (1 row) ``` ## JSON 类型(实验功能) :::warning JSON 类型目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: GreptimeDB 支持 JSON 类型,允许用户存储和查询 JSON 格式的数据。JSON 类型非常灵活,可以存储各种形式的结构化或非结构化数据,适合日志记录、分析和半结构化数据存储等场景。 ```sql CREATE TABLE json_data( my_json JSON, ts TIMESTAMP TIME INDEX ); INSERT INTO json_data VALUES ('{"key1": "value1", "key2": 10}', 1000), ('{"name": "GreptimeDB", "open_source": true}', 2000); SELECT * FROM json_data; ``` 输出: ``` +------------------------------------------+---------------------+ | my_json | ts | +------------------------------------------+---------------------+ | {"key1":"value1","key2":10} | 1970-01-01 00:00:01 | | {"name":"GreptimeDB","open_source":true} | 1970-01-01 00:00:02 | +------------------------------------------+---------------------+ ``` ### 查询 JSON 数据 您可以直接查询 JSON 数据,也可以使用 GreptimeDB 提供的 [JSON 函数](./functions/overview.md#json-functions) 提取特定字段。以下是一个示例: ```sql SELECT json_get_string(my_json, '$.name') as name FROM json_data; ``` 输出: ``` +---------------------------------------------------+ | name | +---------------------------------------------------+ | NULL | | GreptimeDB | +---------------------------------------------------+ ``` ## 布尔类型 | 类型名称 | 描述 | 大小 | | --------- | ------ | ------ | | `Boolean` | 布尔值 | 1 字节 | 在 SQL 语句中使用 `TRUE` 或 `FALSE` 表示布尔值。例如: ```sql CREATE TABLE bools( b BOOLEAN, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, ); ``` ```sql INSERT INTO bools(b, ts) VALUES (TRUE, '2024-01-01 00:00:00'), (FALSE, '2024-01-01 00:00:01'); ``` ## 与 MySQL 和 PostgreSQL 兼容的数据类型 ### 类型别名 对于从 MySQL 或 PostgreSQL 迁移到 GreptimeDB 的用户,GreptimeDB 支持以下类型别名。 | SQL 类型别名 | Native 数据类型 | | --------------------------------------------------------------- | ---------------------- | | `Text`, `TinyText`, `MediumText`, `LongText`, `Varchar`, `Char` | `String` | | `Varbinary` | `Binary` | | `TinyInt` | `Int8` | | `SmallInt`, `Int2` | `Int16` | | `Int`, `Int4` | `Int32` | | `BigInt`, `Int8` | `Int64` | | `UnsignedTinyInt` | `UInt8` | | `UnsignedSmallInt` | `UInt16` | | `UnsignedInt` | `UInt32` | | `UnsignedBigInt` | `UInt64` | | `Float`, `Float4` | `Float32` | | `Double`, `Float8` | `Float64` | | `Timestamp_s`, `Timestamp_sec`, `Timestamp(0)` | `TimestampSecond` | | `Timestamp`, `Timestamp_ms`, `Timestamp(3)` | `TimestampMillisecond` | | `Timestamp_us`, `Timestamp(6)` | `TimestampMicroSecond` | | `Timestamp_ns`, `Timestamp(9)` | `TimestampNanosecond` | :::warning 注意 类型别名 `Int2`、`Int4`、`Int8`、`Float4` 和 `Float8` 遵循 PostgreSQL 和 MySQL 的约定,这些标识符表示类型中的**字节**数(而非位数)。 具体来说: - `Int2` = 2 字节 = `SmallInt`(16 位) - `Int4` = 4 字节 = `Int`(32 位) - `Int8` = 8 字节 = `BigInt`(64 位) - `Float4` = 4 字节 = `Float`(32 位) - `Float8` = 8 字节 = `Double`(64 位) 注意:GreptimeDB 的原生类型名称(如 `UInt8`、`Int32`、`Int64`)表示**位**数,而 SQL 类型别名 `Int2`、`Int4` 和 `Int8` 遵循 PostgreSQL/MySQL 约定表示**字节**数。例如,原生类型 `Int8` 是 8 **位**整数(`TinyInt`, 1 字节),而 SQL 别名 `INT8` 映射到 8 **字节**整数(`BigInt`,64 位)。 ::: 在创建表时也可以使用这些别名类型。 例如,使用 `Varchar` 代替 `String`,使用 `Double` 代替 `Float64`,使用 `Timestamp(0)` 代替 `TimestampSecond`。 ```sql CREATE TABLE alias_types ( s TEXT, i Double, ts0 Timestamp(0) DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(s) ); ``` ### 日期和时间类型 除了在 GreptimeDB 中用作默认时间类型的 `Timestamp` 类型之外 GreptimeDB 还支持与 MySQL 和 PostgreSQL 兼容的 `Date` 和 `DateTime` 类型。 | 类型名称 | 描述 | 大小 | | ---------- | -------------------------------------------------- | ------ | | `Date` | 32 位日期值,表示自 UNIX Epoch 以来的天数 | 4 字节 | | `DateTime` | 64 位毫秒精度的间戳,等同于 `TimestampMicrosecond` | 8 字节 | ## 示例 ### 创建表 ```sql CREATE TABLE data_types ( s STRING, vbi BINARY, b BOOLEAN, tint INT8, sint INT16, i INT32, bint INT64, utint UINT8, usint UINT16, ui UINT32, ubint UINT64, f FLOAT32, d FLOAT64, dm DECIMAL(3, 2), dt DATE, dtt DATETIME, ts0 TIMESTAMPSECOND, ts3 TIMESTAMPMILLISECOND, ts6 TIMESTAMPMICROSECOND, ts9 TIMESTAMPNANOSECOND DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(s)); ``` ### 描述表结构 ```sh DESC TABLE data_types; ``` ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | s | String | PRI | YES | | TAG | | vbi | Binary | | YES | | FIELD | | b | Boolean | | YES | | FIELD | | tint | Int8 | | YES | | FIELD | | sint | Int16 | | YES | | FIELD | | i | Int32 | | YES | | FIELD | | bint | Int64 | | YES | | FIELD | | utint | UInt8 | | YES | | FIELD | | usint | UInt16 | | YES | | FIELD | | ui | UInt32 | | YES | | FIELD | | ubint | UInt64 | | YES | | FIELD | | f | Float32 | | YES | | FIELD | | d | Float64 | | YES | | FIELD | | dm | Decimal(3, 2) | | YES | | FIELD | | dt | Date | | YES | | FIELD | | dtt | TimestampMicrosecond | | YES | | FIELD | | ts0 | TimestampSecond | | YES | | FIELD | | ts3 | TimestampMillisecond | | YES | | FIELD | | ts6 | TimestampMicrosecond | | YES | | FIELD | | ts9 | TimestampNanosecond | PRI | NO | current_timestamp() | TIMESTAMP | +--------+----------------------+------+------+---------------------+---------------+ ``` --- ## DELETE `DELETE` 用于从表中删除行数据。 ## Syntax ```sql DELETE FROM [db.]table WHERE expr ``` 上述命令从表 `[db.]table` 中删除满足 `expr` 的行。被删除的行会立刻被标记,后续的查询立刻不能获取到这些行数据。 ## 示例 例如,有一个带有主键 `host` 的表: ```sql CREATE TABLE monitor ( host STRING, ts TIMESTAMP, cpu DOUBLE DEFAULT 0, memory DOUBLE, TIME INDEX (ts), PRIMARY KEY(host)) ; ``` 删除 host 为 `host1` 以及时间戳为 `1655276557000` 的行: ```sql DELETE FROM monitor WHERE host = 'host1' and ts = 1655276557000; ``` --- ## DESCRIBE TABLE `DESCRIBE [TABLE] [db.]table` 描述了 `db` 或当前使用的数据库中的表结构。 ## 示例 描述表 `monitor`: ```sql DESCRIBE TABLE monitor; ``` 或者 ```sql DESCRIBE monitor; ``` ```sql ```sql +--------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | | cpu | Float64 | | YES | 0 | FIELD | | memory | Float64 | | YES | | FIELD | +--------+----------------------+------+------+---------------------+---------------+ 4 rows in set (0.00 sec) ``` 结果中展示相应的表结构: * `Column`: 列名 * `Type`: 列类型 * `Key`: `PRI` 表示该列在 `PRIMARY KEY` 约束里。 * `Null`: `YES` 表示可以为空,否则为 `NO` * `Default`: 列的默认值 * `Semantic Type`:该列的语义类型,对应数据模型中的 `TAG`、`FIELD` 或 `TIMESTAMP`。 --- ## DISTINCT `SELECT DISTINCT` 用于从一组数据中选择唯一值,从查询的输出中返回唯一值,其基本语法如下: ```sql SELECT DISTINCT idc FROM system_metrics; ``` `SELECT DISTINCT` 可以与 filter 结合使用: ```sql SELECT DISTINCT idc, host FROM system_metrics WHERE host != 'host2'; ``` `SELECT DISTINCT` 是 GreptimeDB SQL 中一个简单但功能强大的命令,它允许用户将数据压缩成唯一值的综合。它可以用于一个或多个列,使其在数据分析和报告中非常灵活。使用 `SELECT DISTINCT` 是获取表中存储的数据类型概述的好方法。 --- ## DROP ## DROP DATABASE `DROP DATABASE` 用于删除数据库,它删除数据库的目录项并删除包含数据的目录。 :::danger 危险操作 `DROP DATABASE` 无法撤消。请谨慎使用! ::: ### 语法 ```sql DROP DATABASE [ IF EXISTS ] db_name ``` - `IF EXISTS`: 如果数据库不存在,则不抛出错误。 - `db_name`: 要删除的数据库的名称。 ### 示例 删除名为 `test` 的数据库: ```sql DROP DATABASE test; ``` ## DROP TABLE `DROP TABLE` 从数据库中删除表,它将删除该表的表定义和所有表数据、索引、规则和约束。 :::danger 危险操作 `DROP TABLE` 无法撤消。请谨慎使用! ::: ### 语法 ```sql DROP TABLE [ IF EXISTS ] table_name ``` - `IF EXISTS`: 如果表不存在,则不抛出错误。 - `table_name`: 要删除的表的名称。 ### 示例 删除 `monitor` 表: ```sql DROP TABLE monitor; ``` ## DROP FLOW ```sql DROP FLOW [ IF EXISTS ] flow_name; ``` - `IF EXISTS`: 如果流不存在,则不抛出错误。 - `flow_name`: 要删除的流的名称。 ```sql DROP FLOW IF EXISTS test_flow; ``` ``` Query OK, 0 rows affected (0.00 sec) ``` ## DROP VIEW ```sql DROP VIEW [ IF EXISTS ] view_name; ``` - `IF EXISTS`: 如果视图不存在,则不抛出错误。 - `view_name`: 要删除的视图的名称。 ```sql DROP VIEW IF EXISTS test_view; ``` ``` Query OK, 0 rows affected (0.00 sec) ``` ## DROP TRIGGER 请参考 [Trigger 语法](/reference/sql/trigger-syntax.md#drop-trigger)文档。 --- ## EXPLAIN `EXPLAIN` 用于提供语句的执行计划。 ## Syntax ```sql EXPLAIN [ANALYZE] [VERBOSE] SELECT ... ``` `ANALYZE` 子句将执行语句并测量每个计划节点花费的时间以及输出的总行数等。 `VERBOSE` 子句可以进一步提供执行计划时详细的信息。 ## 示例 Explain 以下的查询: ```sql EXPLAIN SELECT * FROM monitor where host='host1'\G ``` 样例输出: ```sql *************************** 1. row *************************** plan_type: logical_plan plan: MergeScan [is_placeholder=false] *************************** 2. row *************************** plan_type: physical_plan plan: MergeScanExec: peers=[4612794875904(1074, 0), ] ``` `plan_type` 列指示了是 `logical_plan` 还是 `physical_plan`,`plan` 列详细说明了执行计划。 `MergeScan` 计划负责合并多个 region 的查询结果。物理计划 `MergeScanExec` 中的 `peers` 数组包含了将要扫描的 region 的 ID。 使用 `ANALYZE` 解释执行计划: ```sql EXPLAIN ANALYZE SELECT * FROM monitor where host='host1'\G ``` 样例输出: ```sql *************************** 1. row *************************** stage: 0 node: 0 plan: MergeScanExec: peers=[4612794875904(1074, 0), ] metrics=[output_rows: 0, greptime_exec_read_cost: 0, finish_time: 3301415, first_consume_time: 3299166, ready_time: 3104209, ] *************************** 2. row *************************** stage: 1 node: 0 plan: SeqScan: region=4612794875904(1074, 0), partition_count=0 (0 memtable ranges, 0 file 0 ranges) metrics=[output_rows: 0, mem_used: 0, build_parts_cost: 1, build_reader_cost: 1, elapsed_await: 1, elapsed_poll: 21250, scan_cost: 1, yield_cost: 1, ] *************************** 3. row *************************** stage: NULL node: NULL plan: Total rows: 0 ``` `EXPLAIN ANALYZE` 语句提供了每个执行阶段的指标。`SeqScan` 计划会扫描一个 region 的数据。 获取查询执行更详细的信息: ```sql EXPLAIN ANALYZE VERBOSE SELECT * FROM monitor where host='host1'; ``` 样例输出: ```sql *************************** 1. row *************************** stage: 0 node: 0 plan: MergeScanExec: peers=[4612794875904(1074, 0), ] metrics=[output_rows: 0, greptime_exec_read_cost: 0, finish_time: 3479084, first_consume_time: 3476000, ready_time: 3209041, ] *************************** 2. row *************************** stage: 1 node: 0 plan: SeqScan: region=4612794875904(1074, 0), partition_count=0 (0 memtable ranges, 0 file 0 ranges), projection=["host", "ts", "cpu", "memory"], filters=[host = Utf8("host1")], metrics_per_partition: [[partition=0, {prepare_scan_cost=579.75µs, build_reader_cost=0ns, scan_cost=0ns, convert_cost=0ns, yield_cost=0ns, total_cost=789.708µs, num_rows=0, num_batches=0, num_mem_ranges=0, num_file_ranges=0, build_parts_cost=0ns, rg_total=0, rg_fulltext_filtered=0, rg_inverted_filtered=0, rg_minmax_filtered=0, rg_bloom_filtered=0, rows_before_filter=0, rows_fulltext_filtered=0, rows_inverted_filtered=0, rows_bloom_filtered=0, rows_precise_filtered=0, num_sst_record_batches=0, num_sst_batches=0, num_sst_rows=0, first_poll=785.041µs}]] metrics=[output_rows: 0, mem_used: 0, build_parts_cost: 1, build_reader_cost: 1, elapsed_await: 1, elapsed_poll: 17208, scan_cost: 1, yield_cost: 1, ] *************************** 3. row *************************** stage: NULL node: NULL plan: Total rows: 0 ``` `EXPLAIN ANALYZE VERBOSE` 语句会展示计划执行阶段更详细的指标信息。 --- ## 异常检测函数 GreptimeDB 提供三个统计异常评分**窗口函数**,为窗口中的每一行计算异常分数。 使用时必须带 `OVER` 子句。 :::tip 窗口内有效(非 NULL)数据点不够时返回 `NULL`。 分数 `0.0` 表示正常;分数越大,异常程度越高。 如果离散度(stddev / MAD / IQR)为零,而当前值又偏离中心,则返回 `+inf`——统计意义上的"无穷异常"。 ::: ## `anomaly_score_zscore` 基于 Z-Score 的异常评分。 **公式:** `|x − mean| / stddev` **最少有效样本数:** 2(使用总体标准差,即除以 n) ```sql anomaly_score_zscore(value) OVER (window_spec) ``` **参数:** - **value**:数值列或表达式。 **返回类型:** `DOUBLE` **退化情况:** | 条件 | 结果 | |---|---| | 窗口内有效点少于 2 | `NULL` | | `stddev = 0` 且 `value = mean` | `0.0` | | `stddev = 0` 且 `value ≠ mean` | `+inf` | | 正常情况 | 有限正数 `DOUBLE` | **示例:** ```sql SELECT ts, val, anomaly_score_zscore(val) OVER ( ORDER BY ts ROWS BETWEEN 4 PRECEDING AND CURRENT ROW ) AS zscore FROM metrics ORDER BY ts; ``` ## `anomaly_score_mad` 基于中位绝对偏差(MAD)的异常评分。 MAD 对极端离群值不敏感,比 Z-Score 更稳健。 **公式:** `|x − median| / (MAD × 1.4826)` 其中 1.4826 是正态分布一致性常数,保证在正态假设下 MAD 评分与 Z-Score 渐近等价。 **最少有效样本数:** 3(≤ 2 个样本时 MAD 几乎总为 0,会产生虚假的 `+inf`) ```sql anomaly_score_mad(value) OVER (window_spec) ``` **参数:** - **value**:数值列或表达式。 **返回类型:** `DOUBLE` **退化情况:** | 条件 | 结果 | |---|---| | 窗口内有效点少于 3 | `NULL` | | `MAD = 0` 且 `value = median` | `0.0` | | `MAD = 0` 且 `value ≠ median` | `+inf` | | 正常情况 | 有限正数 `DOUBLE` | **示例:** ```sql SELECT ts, val, anomaly_score_mad(val) OVER ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS mad_score FROM metrics ORDER BY host, ts; ``` ## `anomaly_score_iqr` 基于四分位距(IQR / Tukey Fences)的异常评分。 分数反映当前值超出下围栏(`Q1 − k × IQR`)或上围栏(`Q3 + k × IQR`)多远; 在围栏以内的值分数为 `0.0`。 **公式:** - 若 `value < Q1 − k × IQR`:score = `(Q1 − k × IQR − value) / IQR` - 若 `value > Q3 + k × IQR`:score = `(value − Q3 − k × IQR) / IQR` - 否则:score = `0.0` **最少有效样本数:** 3(线性插值下 Q1 ≠ Q3 至少需要 3 个点) ```sql anomaly_score_iqr(value, k) OVER (window_spec) ``` **参数:** - **value**:数值列或表达式。 - **k**:围栏倍数,非负 `DOUBLE`(`1.5` 为标准 Tukey 围栏,`3.0` 为远端围栏)。`k < 0` 时返回 `NULL`。 **返回类型:** `DOUBLE` **退化情况:** | 条件 | 结果 | |---|---| | 窗口内有效点少于 3 | `NULL` | | `IQR = 0` 且值在围栏内 | `0.0` | | `IQR = 0` 且值在围栏外 | `+inf` | | 正常情况 | 有限非负 `DOUBLE` | **示例:** ```sql SELECT ts, val, anomaly_score_iqr(val, 1.5) OVER ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS iqr_score FROM metrics ORDER BY host, ts; ``` ## 完整示例 建表、写入带离群点的时序数据,然后用三个异常函数同时打分。 ```sql CREATE TABLE sensor_data ( host STRING, val DOUBLE, ts TIMESTAMP TIME INDEX, PRIMARY KEY (host) ); INSERT INTO sensor_data VALUES ('web-1', 10.0, '2025-01-01 00:00:00'), ('web-1', 11.0, '2025-01-01 00:01:00'), ('web-1', 10.5, '2025-01-01 00:02:00'), ('web-1', 10.8, '2025-01-01 00:03:00'), ('web-1', 80.0, '2025-01-01 00:04:00'), -- 离群点 ('web-1', 10.3, '2025-01-01 00:05:00'), ('web-1', 11.2, '2025-01-01 00:06:00'); ``` 用命名窗口让三个函数共享同一窗口,ROUND 取两位小数方便阅读: ```sql SELECT ts, val, ROUND(anomaly_score_zscore(val) OVER w, 2) AS zscore, ROUND(anomaly_score_mad(val) OVER w, 2) AS mad, ROUND(anomaly_score_iqr(val, 1.5) OVER w, 2) AS iqr FROM sensor_data WINDOW w AS ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) ORDER BY ts; ``` 输出如下,`val = 80.0` 那行三个分数都远高于其他行: ``` +---------------------+------+--------+--------+-------+ | ts | val | zscore | mad | iqr | +---------------------+------+--------+--------+-------+ | 2025-01-01 00:00:00 | 10 | NULL | NULL | NULL | | 2025-01-01 00:01:00 | 11 | 1 | NULL | NULL | | 2025-01-01 00:02:00 | 10.5 | 0 | 0 | 0 | | 2025-01-01 00:03:00 | 10.8 | 0.6 | 0.4 | 0 | | 2025-01-01 00:04:00 | 80 | 2 | 155.58 | 136.5 | | 2025-01-01 00:05:00 | 10.3 | 0.46 | 0.67 | 0 | | 2025-01-01 00:06:00 | 11.2 | 0.38 | 0.67 | 0 | +---------------------+------+--------+--------+-------+ ``` ### 过滤异常行 用子查询只留分数超过阈值的行: ```sql SELECT * FROM ( SELECT host, ts, val, ROUND(anomaly_score_mad(val) OVER ( PARTITION BY host ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ), 2) AS mad FROM sensor_data ) WHERE mad > 3.0 ORDER BY host, ts; ``` 输出: ``` +-------+---------------------+------+--------+ | host | ts | val | mad | +-------+---------------------+------+--------+ | web-1 | 2025-01-01 00:04:00 | 80 | 155.58 | +-------+---------------------+------+--------+ ``` --- ## 近似函数 本页面列出了 GreptimeDB 中的近似函数,这些函数用于近似数据分析。 :::warning 下述的近似函数目前仍处于实验阶段,可能会在未来的版本中发生变化。 ::: ## 近似去重计数 (HLL) 这里使用了 [HyperLogLog](https://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf) (HLL) 算法来计算一组值的近似去重计数。它在内存使用和速度方面提供了高效的性能。GreptimeDB 提供了三个函数来处理 HLL 算法,具体描述如下: :::warning 由于算法的近似性质,结果可能不完全精确,但通常非常接近实际的去重计数。HyperLogLog 算法的相对标准误差约为 1.04/√m,其中 m 是算法中使用的寄存器数量。GreptimeDB 默认使用 16384 个寄存器,这使得相对标准误差约为 0.008125(即 0.8125%)。 ::: ### `hll` `hll(value)` 从给定列创建二进制的 HyperLogLog 状态。`value` 可以是你希望计算近似去重计数的任何列。它返回 HLL 状态的二进制表示,可以存储在表中或用于进一步计算。有关如何结合其他函数使用此函数计算近似去重计数的完整示例,请参阅 [完整使用示例](#完整使用示例)。 ### `hll_merge` `hll_merge(hll_state)` 将多个 HyperLogLog 状态合并为一个。当你需要合并多个 HLL 计算结果时,例如聚合来自不同时间窗口或来源的数据时,这非常有用。`hll_state` 参数是由 [`hll`](#hll) 创建的 HLL 状态的二进制表示。合并后的状态可用于计算所有合并状态的近似去重计数。有关如何结合其他函数使用此函数计算近似去重计数的完整示例,请参阅 [完整使用示例](#完整使用示例)。 ### `hll_count` `hll_count(hll_state)` 从 HyperLogLog 状态中计算得到近似去重计数的结果。此函数接受由 `hll` 创建或由 `hll_merge` 合并的 HLL 状态,并返回近似的去重值计数。有关如何结合其他函数使用此函数计算近似去重计数的完整示例,请参阅 [完整使用示例](#完整使用示例)。 ### 完整使用示例 此示例演示了如何组合使用这些函数来计算近似的去重的用户 ID 的数量。 首先创建用于存储用户访问日志的基础表 `access_log`,以及用于在 10 秒时间窗口内存储 HyperLogLog 状态的 `access_log_10s` 表。请注意,`state` 列的类型为 `BINARY`,它将以二进制格式存储 HyperLogLog 状态。 ```sql CREATE TABLE access_log ( `url` STRING, user_id BIGINT, ts TIMESTAMP TIME INDEX, PRIMARY KEY (`url`, `user_id`) ); CREATE TABLE access_log_10s ( `url` STRING, time_window timestamp time INDEX, state BINARY, PRIMARY KEY (`url`) ); ``` 将一些示例数据插入到 `access_log` 中: ```sql INSERT INTO access_log VALUES ("/dashboard", 1, "2025-03-04 00:00:00"), ("/dashboard", 1, "2025-03-04 00:00:01"), ("/dashboard", 2, "2025-03-04 00:00:05"), ("/dashboard", 2, "2025-03-04 00:00:10"), ("/dashboard", 2, "2025-03-04 00:00:13"), ("/dashboard", 4, "2025-03-04 00:00:15"), ("/not_found", 1, "2025-03-04 00:00:10"), ("/not_found", 3, "2025-03-04 00:00:11"), ("/not_found", 4, "2025-03-04 00:00:12"); ``` 现在我们可以使用 `hll` 函数为 `user_id` 列创建 10 秒时间窗口的 HyperLogLog 状态。输出将是 HLL 状态的二进制表示,其中包含计算后续近似去重计数所需的信息。`date_bin` 函数用于将数据分组到 10 秒的时间窗口中。因此,此 `INSERT INTO` 语句将为 `access_log` 表中每个 10 秒时间窗口创建 HyperLogLog 状态,并将其插入到 `access_log_10s` 表中: ```sql -- 使用 10 秒窗口查询来计算 HyperLogLog 状态: INSERT INTO access_log_10s SELECT `url`, date_bin("10s" :: INTERVAL, ts) AS time_window, hll(`user_id`) AS state FROM access_log GROUP BY `url`, time_window; -- 结果类似: -- Query OK, 3 rows affected (0.05 sec) ``` 然后我们可以使用 `hll_count` 函数从 HyperLogLog 状态(即 `state` 列)中检索近似去重计数。例如,要获取每个 10 秒时间窗口的用户访问近似去重计数,我们可以运行以下查询: ```sql -- 使用 `hll_count` 查询 `access_log_10s` 中的近似数据,请注意对于小型数据集,结果可能不是很准确。 SELECT `url`, `time_window`, hll_count(state) FROM access_log_10s; -- 结果如下: -- +------------+---------------------+---------------------------------+ -- | url | time_window | hll_count(access_log_10s.state) | -- +------------+---------------------+---------------------------------+ -- | /dashboard | 2025-03-04 00:00:00 | 2 | -- | /dashboard | 2025-03-04 00:00:10 | 2 | -- | /not_found | 2025-03-04 00:00:10 | 3 | -- +------------+---------------------+---------------------------------+ ``` 此外,我们可以通过使用 `hll_merge` 合并 HyperLogLog 状态,将 10 秒的数据聚合到 1 分钟级别。这使我们能够计算更大时间窗口的近似去重计数,这对于分析随时间变化的趋势非常有用。以下查询演示了如何实现: ```sql -- 使用 `hll_merge` 合并 HyperLogLog 状态,将 10 秒的数据聚合到 1 分钟级别。 SELECT `url`, date_bin('1 minute' :: INTERVAL, `time_window`) AS time_window_1m, hll_count(hll_merge(state)) as uv_per_min FROM access_log_10s GROUP BY `url`, date_bin('1 minute' :: INTERVAL, `time_window`); -- 结果如下: -- +------------+---------------------+------------+ -- | url | time_window_1m | uv_per_min | -- +------------+---------------------+------------+ -- | /dashboard | 2025-03-04 00:00:00 | 3 | -- | /not_found | 2025-03-04 00:00:00 | 3 | -- +------------+---------------------+------------+ ``` 请注意 `hll_merge` 函数如何用于合并 `access_log_10s` 表中的 HyperLogLog 状态,然后 `hll_count` 函数用于计算每个 1 分钟时间窗口的近似去重计数。如果只使用 `hll_merge` 而不使用 `hll_count`,结果将只是合并后的 HyperLogLog 状态的不可读二进制表示,这对于分析没有太大用处。因此,我们使用 `hll_count` 从合并后的状态中计算得到近似去重计数。 以下流程图说明了 HyperLogLog 函数的上述用法。首先,原始事件数据按时间窗口和 URL 分组,然后使用 `hll` 函数为每个时间窗口和 URL 创建一个 HyperLogLog 状态,接着使用 `hll_count` 函数检索每个时间窗口和 URL 的近似去重计数。最后,使用 `hll_merge` 函数合并每个 URL 的 HyperLogLog 状态,然后再次使用 `hll_count` 函数检索 1 分钟时间窗口的近似去重计数。 ![HLL 用例流程图](/hll.svg) ## 近似分位数(UDDSketch) 使用 [UDDSketch](https://arxiv.org/abs/2004.08604) 算法提供了三个函数用于近似分位数计算。 :::warning UDDSketch 算法旨在提供具有可调误差率的近似分位数,这有助于实现高效的内存使用和快速计算。结果可能并非完全精确,但通常非常接近实际分位数。 ::: ### `uddsketch_state` `uddsketch_state` 函数用于从给定列创建二进制格式的 UDDSketch 状态。它接受三个参数: - `bucket_num`:用于记录分位数信息的桶数量。关于如何确定该值,请参阅[如何确定桶数量和误差率](#如何确定桶数量和误差率)。 - `error_rate`:分位数计算所需的误差率。 - `value`:用于计算分位数的列。 例如,对于下述表 `percentile_base`,我们可以为 `value` 列创建一个 `uddsketch_state`,其中桶数量为 128,误差率为 0.01 (1%)。输出将是 UDDSketch 状态的二进制表示,其中包含后续计算近似分位数所需的信息。 该输出的二进制状态可被视为 `value` 列中值的直方图,后续可使用 `uddsketch_merge` 进行合并,或使用 `uddsketch_calc` 计算分位数。有关如何结合使用这些函数来计算近似分位数的完整示例,请参阅[UDDSketch 完整使用示例](#uddsketch-完整使用示例)。 ### `uddsketch_merge` `uddsketch_merge` 函数用于将多个 UDDSketch 状态合并为一个。它接受三个参数: - `bucket_num`:用于记录分位数信息的桶数量。关于如何确定该值,请参阅[如何确定桶数量和误差率](#如何确定桶数量和误差率)。 - `error_rate`:分位数计算所需的误差率。 - `udd_state`:由 `uddsketch_state` 创建的 UDDSketch 状态的二进制表示。 当你需要合并来自不同时间窗口或来源的结果时,此函数非常有用。请注意,`bucket_num` 和 `error_rate` 必须与创建原始状态时使用的参数匹配,否则合并将失败。 例如,如果你有来自不同时间窗口的多个 UDDSketch 状态,你可以将它们合并为一个状态,以计算所有数据的整体分位数。该输出的二进制状态随后可用于使用 `uddsketch_calc` 计算分位数。有关如何结合使用这些函数来计算近似分位数的完整示例,请参阅[UDDSketch 完整使用示例](#uddsketch-完整使用示例)。 ### `uddsketch_calc` `uddsketch_calc` 函数用于从 UDDSketch 状态计算近似分位数。它接受两个参数: - `quantile`:一个介于 0 和 1 之间的值,表示要计算的目标分位数,例如,0.99 代表第 99 百分位数。 - `udd_state`:由 `uddsketch_state` 创建或由 `uddsketch_merge` 合并的 UDDSketch 状态的二进制表示。 有关如何结合使用这些函数来计算近似分位数的完整示例,请参阅[UDDSketch 完整使用示例](#uddsketch-完整使用示例)。 ### 如何确定桶数量和误差率 `bucket_num` 参数设置了 UDDSketch 算法可使用的内部容器的最大数量,直接控制其内存占用。可以将其视为跟踪不同值范围的物理存储容量。更大的 `bucket_num` 允许 UddSketch 状态更准确地表示更宽的数据动态范围(即最大值和最小值之间更大的比率)。如果此限制对于你的数据而言过小,UddSketch 状态将被迫合并非常高或非常低的值,从而降低其准确性。对于大多数用例,`bucket_num` 的推荐值为 128,这在准确性和内存使用之间提供了良好的平衡。 `error_rate` 定义了分位数计算所需的精度。它保证任何计算出的分位数(例如 p99)都在真实值的某个*相对*百分比范围内。例如,`error_rate` 为 `0.01` 确保结果在实际值的 1% 以内。较小的 `error_rate` 提供更高的准确性,因为它强制 UDDSketch 算法使用更细粒度的桶来区分更接近的数字。 这两个参数之间存在直接的权衡关系。为了达到小 `error_rate` 所承诺的高精度,UDDSketch 算法需要足够的 `bucket_num`,特别是对于跨度较大的数据。`bucket_num` 充当了精度的物理限制。如果你的 `bucket_num` 受到内存限制,那么将 `error_rate` 设置为极小值并不会提高精度,因为受到可用桶数量的限制。 ### UDDSketch 完整使用示例 本示例演示了如何使用上述三个 `uddsketch` 函数来计算一组值的近似分位数。 首先创建用于存储原始数据的基表 `percentile_base`,以及用于存储 5 秒时间窗口内 UDDSketch 状态的 `percentile_5s` 表。请注意,`percentile_state` 列的类型为 `BINARY`,它将以二进制格式存储 UDDSketch 状态。 ```sql CREATE TABLE percentile_base ( `id` INT PRIMARY KEY, `value` DOUBLE, `ts` timestamp(0) time index ); CREATE TABLE percentile_5s ( `percentile_state` BINARY, `time_window` timestamp(0) time index ); ``` 向 `percentile_base` 插入一些示例数据: ```sql INSERT INTO percentile_base (`id`, `value`, `ts`) VALUES (1, 10.0, 1), (2, 20.0, 2), (3, 30.0, 3), (4, 40.0, 4), (5, 50.0, 5), (6, 60.0, 6), (7, 70.0, 7), (8, 80.0, 8), (9, 90.0, 9), (10, 100.0, 10); ``` 现在我们可以使用 `uddsketch_state` 函数为 `value` 列创建一个 UDDSketch 状态,其中桶数量为 128,误差率为 0.01 (1%)。输出将是 UDDSketch 状态的二进制表示,其中包含后续计算近似分位数所需的信息。`date_bin` 函数用于将数据分到 5 秒的时间窗口中。因此,此 `INSERT INTO` 语句将为 `percentile_base` 表中每个 5 秒时间窗口创建 UDDSketch 状态,并将其插入到 `percentile_5s` 表中: ```sql INSERT INTO percentile_5s SELECT uddsketch_state(128, 0.01, `value`) AS percentile_state, date_bin('5 seconds' :: INTERVAL, `ts`) AS time_window FROM percentile_base GROUP BY time_window; -- 结果类似: -- Query OK, 3 rows affected (0.05 sec) ``` 现在我们可以使用 `uddsketch_calc` 函数从 UDDSketch 状态中计算近似分位数。例如,要获取每个 5 秒时间窗口的近似第 99 百分位数 (p99),我们可以运行以下查询: ```sql -- 查询 percentile_5s 以获取近似第 99 百分位数 SELECT time_window, uddsketch_calc(0.99, `percentile_state`) AS p99 FROM percentile_5s; -- 结果如下: -- +---------------------+--------------------+ -- | time_window | p99 | -- +---------------------+--------------------+ -- | 1970-01-01 00:00:00 | 40.04777053326359 | -- | 1970-01-01 00:00:05 | 89.13032933635911 | -- | 1970-01-01 00:00:10 | 100.49456770856492 | -- +---------------------+--------------------+ ``` 请注意,在上述查询中,`percentile_state` 列是由 `uddsketch_state` 创建的 UDDSketch 状态。 此外,我们可以通过使用 `uddsketch_merge` 合并 UDDSketch 状态,将 5 秒的数据聚合到 1 分钟级别。这使我们能够计算更大时间窗口的近似分位数,这对于分析随时间变化的趋势非常有用。以下查询演示了如何实现: ```sql -- 此外,我们可以通过使用 `uddsketch_merge` 合并 UDDSketch 状态,将 5 秒的数据聚合到 1 分钟级别。 SELECT date_bin('1 minute' :: INTERVAL, `time_window`) AS time_window_1m, uddsketch_calc(0.99, uddsketch_merge(128, 0.01, `percentile_state`)) AS p99 FROM percentile_5s GROUP BY time_window_1m; -- 结果如下: -- +---------------------+--------------------+ -- | time_window_1m | p99 | -- +---------------------+--------------------+ -- | 1970-01-01 00:00:00 | 100.49456770856492 | -- +---------------------+--------------------+ ``` 请注意 `uddsketch_merge` 函数是如何用于合并 `percentile_5s` 表中的 UDDSketch 状态,然后 `uddsketch_calc` 函数用于计算每个 1 分钟时间窗口的近似第 99 百分位数 (p99)。 以下流程图说明了 UDDSketch 函数的上述用法。首先,原始事件数据按时间窗口分组,然后使用 `uddsketch_state` 函数为每个时间窗口创建一个 UDDSketch 状态,接着使用 `uddsketch_calc` 函数检索每个时间窗口的近似第 99 分位数。最后,使用 `uddsketch_merge` 函数合并每个时间窗口的 UDDSketch 状态,然后再次使用 `uddsketch_calc` 函数检索 1 分钟时间窗口的近似第 99 分位数。 ![UDDSketch 用例流程图](/udd.svg) --- ## DataFusion Functions This page is generated from the [Apache DataFusion](https://datafusion.apache.org/user-guide/sql/) project's documents: * [DataFusion Scalar Functions](#scalar-functions) * [DataFusion Aggregate Functions](#aggregate-functions) * [DataFusion Window Functions](#window-functions) * [DataFusion Special Functions](#special-functions) ## Scalar Functions ### Math Functions - [abs](#abs) - [acos](#acos) - [acosh](#acosh) - [asin](#asin) - [asinh](#asinh) - [atan](#atan) - [atan2](#atan2) - [atanh](#atanh) - [cbrt](#cbrt) - [ceil](#ceil) - [cos](#cos) - [cosh](#cosh) - [cot](#cot) - [degrees](#degrees) - [exp](#exp) - [factorial](#factorial) - [floor](#floor) - [gcd](#gcd) - [isnan](#isnan) - [iszero](#iszero) - [lcm](#lcm) - [ln](#ln) - [log](#log) - [log10](#log10) - [log2](#log2) - [nanvl](#nanvl) - [pi](#pi) - [pow](#pow) - [power](#power) - [radians](#radians) - [random](#random) - [round](#round) - [signum](#signum) - [sin](#sin) - [sinh](#sinh) - [sqrt](#sqrt) - [tan](#tan) - [tanh](#tanh) - [trunc](#trunc) ##### `abs` Returns the absolute value of a number. ```sql abs(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT abs(-5); +----------+ | abs(-5) | +----------+ | 5 | +----------+ ``` ##### `acos` Returns the arc cosine or inverse cosine of a number. ```sql acos(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT acos(1); +----------+ | acos(1) | +----------+ | 0.0 | +----------+ ``` ##### `acosh` Returns the area hyperbolic cosine or inverse hyperbolic cosine of a number. ```sql acosh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT acosh(2); +------------+ | acosh(2) | +------------+ | 1.31696 | +------------+ ``` ##### `asin` Returns the arc sine or inverse sine of a number. ```sql asin(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT asin(0.5); +------------+ | asin(0.5) | +------------+ | 0.5235988 | +------------+ ``` ##### `asinh` Returns the area hyperbolic sine or inverse hyperbolic sine of a number. ```sql asinh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT asinh(1); +------------+ | asinh(1) | +------------+ | 0.8813736 | +------------+ ``` ##### `atan` Returns the arc tangent or inverse tangent of a number. ```sql atan(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT atan(1); +-----------+ | atan(1) | +-----------+ | 0.7853982 | +-----------+ ``` ##### `atan2` Returns the arc tangent or inverse tangent of `expression_y / expression_x`. ```sql atan2(expression_y, expression_x) ``` ###### Arguments - **expression_y**: First numeric expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **expression_x**: Second numeric expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. ###### Example ```sql > SELECT atan2(1, 1); +------------+ | atan2(1,1) | +------------+ | 0.7853982 | +------------+ ``` ##### `atanh` Returns the area hyperbolic tangent or inverse hyperbolic tangent of a number. ```sql atanh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT atanh(0.5); +-------------+ | atanh(0.5) | +-------------+ | 0.5493061 | +-------------+ ``` ##### `cbrt` Returns the cube root of a number. ```sql cbrt(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cbrt(27); +-----------+ | cbrt(27) | +-----------+ | 3.0 | +-----------+ ``` ##### `ceil` Returns the nearest integer greater than or equal to a number. ```sql ceil(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT ceil(3.14); +------------+ | ceil(3.14) | +------------+ | 4.0 | +------------+ ``` ##### `cos` Returns the cosine of a number. ```sql cos(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cos(0); +--------+ | cos(0) | +--------+ | 1.0 | +--------+ ``` ##### `cosh` Returns the hyperbolic cosine of a number. ```sql cosh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cosh(1); +-----------+ | cosh(1) | +-----------+ | 1.5430806 | +-----------+ ``` ##### `cot` Returns the cotangent of a number. ```sql cot(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT cot(1); +---------+ | cot(1) | +---------+ | 0.64209 | +---------+ ``` ##### `degrees` Converts radians to degrees. ```sql degrees(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT degrees(pi()); +------------+ | degrees(0) | +------------+ | 180.0 | +------------+ ``` ##### `exp` Returns the base-e exponential of a number. ```sql exp(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT exp(1); +---------+ | exp(1) | +---------+ | 2.71828 | +---------+ ``` ##### `factorial` Factorial. Returns 1 if value is less than 2. ```sql factorial(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT factorial(5); +---------------+ | factorial(5) | +---------------+ | 120 | +---------------+ ``` ##### `floor` Returns the nearest integer less than or equal to a number. ```sql floor(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT floor(3.14); +-------------+ | floor(3.14) | +-------------+ | 3.0 | +-------------+ ``` ##### `gcd` Returns the greatest common divisor of `expression_x` and `expression_y`. Returns 0 if both inputs are zero. ```sql gcd(expression_x, expression_y) ``` ###### Arguments - **expression_x**: First numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_y**: Second numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT gcd(48, 18); +------------+ | gcd(48,18) | +------------+ | 6 | +------------+ ``` ##### `isnan` Returns true if a given number is +NaN or -NaN otherwise returns false. ```sql isnan(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT isnan(1); +----------+ | isnan(1) | +----------+ | false | +----------+ ``` ##### `iszero` Returns true if a given number is +0.0 or -0.0 otherwise returns false. ```sql iszero(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT iszero(0); +------------+ | iszero(0) | +------------+ | true | +------------+ ``` ##### `lcm` Returns the least common multiple of `expression_x` and `expression_y`. Returns 0 if either input is zero. ```sql lcm(expression_x, expression_y) ``` ###### Arguments - **expression_x**: First numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_y**: Second numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT lcm(4, 5); +----------+ | lcm(4,5) | +----------+ | 20 | +----------+ ``` ##### `ln` Returns the natural logarithm of a number. ```sql ln(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT ln(2.71828); +-------------+ | ln(2.71828) | +-------------+ | 1.0 | +-------------+ ``` ##### `log` Returns the base-x logarithm of a number. Can either provide a specified base, or if omitted then takes the base-10 of a number. ```sql log(base, numeric_expression) log(numeric_expression) ``` ###### Arguments - **base**: Base numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT log(10); +---------+ | log(10) | +---------+ | 1.0 | +---------+ ``` ##### `log10` Returns the base-10 logarithm of a number. ```sql log10(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT log10(100); +-------------+ | log10(100) | +-------------+ | 2.0 | +-------------+ ``` ##### `log2` Returns the base-2 logarithm of a number. ```sql log2(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT log2(8); +-----------+ | log2(8) | +-----------+ | 3.0 | +-----------+ ``` ##### `nanvl` Returns the first argument if it's not _NaN_. Returns the second argument otherwise. ```sql nanvl(expression_x, expression_y) ``` ###### Arguments - **expression_x**: Numeric expression to return if it's not _NaN_. Can be a constant, column, or function, and any combination of arithmetic operators. - **expression_y**: Numeric expression to return if the first expression is _NaN_. Can be a constant, column, or function, and any combination of arithmetic operators. ###### Example ```sql > SELECT nanvl(0, 5); +------------+ | nanvl(0,5) | +------------+ | 0 | +------------+ ``` ##### `pi` Returns an approximate value of π. ```sql pi() ``` ##### `pow` _Alias of [power](#power)._ ##### `power` Returns a base expression raised to the power of an exponent. ```sql power(base, exponent) ``` ###### Arguments - **base**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **exponent**: Exponent numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT power(2, 3); +-------------+ | power(2,3) | +-------------+ | 8 | +-------------+ ``` ###### Aliases - pow ##### `radians` Converts degrees to radians. ```sql radians(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT radians(180); +----------------+ | radians(180) | +----------------+ | 3.14159265359 | +----------------+ ``` ##### `random` Returns a random float value in the range [0, 1). The random seed is unique to each row. ```sql random() ``` ###### Example ```sql > SELECT random(); +------------------+ | random() | +------------------+ | 0.7389238902938 | +------------------+ ``` ##### `round` Rounds a number to the nearest integer. ```sql round(numeric_expression[, decimal_places]) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **decimal_places**: Optional. The number of decimal places to round to. Defaults to 0. ###### Example ```sql > SELECT round(3.14159); +--------------+ | round(3.14159)| +--------------+ | 3.0 | +--------------+ ``` ##### `signum` Returns the sign of a number. Negative numbers return `-1`. Zero and positive numbers return `1`. ```sql signum(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT signum(-42); +-------------+ | signum(-42) | +-------------+ | -1 | +-------------+ ``` ##### `sin` Returns the sine of a number. ```sql sin(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT sin(0); +----------+ | sin(0) | +----------+ | 0.0 | +----------+ ``` ##### `sinh` Returns the hyperbolic sine of a number. ```sql sinh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT sinh(1); +-----------+ | sinh(1) | +-----------+ | 1.1752012 | +-----------+ ``` ##### `sqrt` Returns the square root of a number. ```sql sqrt(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `tan` Returns the tangent of a number. ```sql tan(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT tan(pi()/4); +--------------+ | tan(PI()/4) | +--------------+ | 1.0 | +--------------+ ``` ##### `tanh` Returns the hyperbolic tangent of a number. ```sql tanh(numeric_expression) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT tanh(20); +----------+ | tanh(20) | +----------+ | 1.0 | +----------+ ``` ##### `trunc` Truncates a number to a whole number or truncated to the specified decimal places. ```sql trunc(numeric_expression[, decimal_places]) ``` ###### Arguments - **numeric_expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. - **decimal_places**: Optional. The number of decimal places to truncate to. Defaults to 0 (truncate to a whole number). If `decimal_places` is a positive integer, truncates digits to the right of the decimal point. If `decimal_places` is a negative integer, replaces digits to the left of the decimal point with `0`. ###### Example ```sql > SELECT trunc(42.738); +----------------+ | trunc(42.738) | +----------------+ | 42 | +----------------+ ``` ### Conditional Functions - [coalesce](#coalesce) - [greatest](#greatest) - [ifnull](#ifnull) - [least](#least) - [nullif](#nullif) - [nvl](#nvl) - [nvl2](#nvl2) ##### `coalesce` Returns the first of its arguments that is not _null_. Returns _null_ if all arguments are _null_. This function is often used to substitute a default value for _null_ values. ```sql coalesce(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expression to use if previous expressions are _null_. Can be a constant, column, or function, and any combination of arithmetic operators. Pass as many expression arguments as necessary. ###### Example ```sql > select coalesce(null, null, 'datafusion'); +----------------------------------------+ | coalesce(NULL,NULL,Utf8("datafusion")) | +----------------------------------------+ | datafusion | +----------------------------------------+ ``` ##### `greatest` Returns the greatest value in a list of expressions. Returns _null_ if all expressions are _null_. ```sql greatest(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expressions to compare and return the greatest value.. Can be a constant, column, or function, and any combination of arithmetic operators. Pass as many expression arguments as necessary. ###### Example ```sql > select greatest(4, 7, 5); +---------------------------+ | greatest(4,7,5) | +---------------------------+ | 7 | +---------------------------+ ``` ##### `ifnull` _Alias of [nvl](#nvl)._ ##### `least` Returns the smallest value in a list of expressions. Returns _null_ if all expressions are _null_. ```sql least(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expressions to compare and return the smallest value. Can be a constant, column, or function, and any combination of arithmetic operators. Pass as many expression arguments as necessary. ###### Example ```sql > select least(4, 7, 5); +---------------------------+ | least(4,7,5) | +---------------------------+ | 4 | +---------------------------+ ``` ##### `nullif` Returns _null_ if _expression1_ equals _expression2_; otherwise it returns _expression1_. This can be used to perform the inverse operation of [`coalesce`](#coalesce). ```sql nullif(expression1, expression2) ``` ###### Arguments - **expression1**: Expression to compare and return if equal to expression2. Can be a constant, column, or function, and any combination of operators. - **expression2**: Expression to compare to expression1. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select nullif('datafusion', 'data'); +-----------------------------------------+ | nullif(Utf8("datafusion"),Utf8("data")) | +-----------------------------------------+ | datafusion | +-----------------------------------------+ > select nullif('datafusion', 'datafusion'); +-----------------------------------------------+ | nullif(Utf8("datafusion"),Utf8("datafusion")) | +-----------------------------------------------+ | | +-----------------------------------------------+ ``` ##### `nvl` Returns _expression2_ if _expression1_ is NULL otherwise it returns _expression1_ and _expression2_ is not evaluated. This function can be used to substitute a default value for NULL values. ```sql nvl(expression1, expression2) ``` ###### Arguments - **expression1**: Expression to return if not null. Can be a constant, column, or function, and any combination of operators. - **expression2**: Expression to return if expr1 is null. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select nvl(null, 'a'); +---------------------+ | nvl(NULL,Utf8("a")) | +---------------------+ | a | +---------------------+\ > select nvl('b', 'a'); +--------------------------+ | nvl(Utf8("b"),Utf8("a")) | +--------------------------+ | b | +--------------------------+ ``` ###### Aliases - ifnull ##### `nvl2` Returns _expression2_ if _expression1_ is not NULL; otherwise it returns _expression3_. ```sql nvl2(expression1, expression2, expression3) ``` ###### Arguments - **expression1**: Expression to test for null. Can be a constant, column, or function, and any combination of operators. - **expression2**: Expression to return if expr1 is not null. Can be a constant, column, or function, and any combination of operators. - **expression3**: Expression to return if expr1 is null. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select nvl2(null, 'a', 'b'); +--------------------------------+ | nvl2(NULL,Utf8("a"),Utf8("b")) | +--------------------------------+ | b | +--------------------------------+ > select nvl2('data', 'a', 'b'); +----------------------------------------+ | nvl2(Utf8("data"),Utf8("a"),Utf8("b")) | +----------------------------------------+ | a | +----------------------------------------+ ``` ### String Functions - [ascii](#ascii) - [bit_length](#bit_length) - [btrim](#btrim) - [char_length](#char_length) - [character_length](#character_length) - [chr](#chr) - [concat](#concat) - [concat_ws](#concat_ws) - [contains](#contains) - [ends_with](#ends_with) - [find_in_set](#find_in_set) - [initcap](#initcap) - [instr](#instr) - [left](#left) - [length](#length) - [levenshtein](#levenshtein) - [lower](#lower) - [lpad](#lpad) - [ltrim](#ltrim) - [octet_length](#octet_length) - [overlay](#overlay) - [position](#position) - [repeat](#repeat) - [replace](#replace) - [reverse](#reverse) - [right](#right) - [rpad](#rpad) - [rtrim](#rtrim) - [split_part](#split_part) - [starts_with](#starts_with) - [strpos](#strpos) - [substr](#substr) - [substr_index](#substr_index) - [substring](#substring) - [substring_index](#substring_index) - [to_hex](#to_hex) - [translate](#translate) - [trim](#trim) - [upper](#upper) - [uuid](#uuid) ##### `ascii` Returns the first Unicode scalar value of a string. ```sql ascii(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select ascii('abc'); +--------------------+ | ascii(Utf8("abc")) | +--------------------+ | 97 | +--------------------+ > select ascii('🚀'); +-------------------+ | ascii(Utf8("🚀")) | +-------------------+ | 128640 | +-------------------+ ``` **Related functions**: - [chr](#chr) ##### `bit_length` Returns the bit length of a string. ```sql bit_length(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select bit_length('datafusion'); +--------------------------------+ | bit_length(Utf8("datafusion")) | +--------------------------------+ | 80 | +--------------------------------+ ``` **Related functions**: - [length](#length) - [octet_length](#octet_length) ##### `btrim` Trims the specified trim string from the start and end of a string. If no trim string is provided, all spaces are removed from the start and end of the input string. ```sql btrim(str[, trim_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **trim_str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. _Default is a space._ ###### Example ```sql > select btrim('__datafusion____', '_'); +-------------------------------------------+ | btrim(Utf8("__datafusion____"),Utf8("_")) | +-------------------------------------------+ | datafusion | +-------------------------------------------+ ``` ###### Alternative Syntax ```sql trim(BOTH trim_str FROM str) ``` ```sql trim(trim_str FROM str) ``` ###### Aliases - trim **Related functions**: - [ltrim](#ltrim) - [rtrim](#rtrim) ##### `char_length` _Alias of [character_length](#character_length)._ ##### `character_length` Returns the number of characters in a string. ```sql character_length(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select character_length('Ångström'); +------------------------------------+ | character_length(Utf8("Ångström")) | +------------------------------------+ | 8 | +------------------------------------+ ``` ###### Aliases - length - char_length **Related functions**: - [bit_length](#bit_length) - [octet_length](#octet_length) ##### `chr` Returns a string containing the character with the specified Unicode scalar value. ```sql chr(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select chr(128640); +--------------------+ | chr(Int64(128640)) | +--------------------+ | 🚀 | +--------------------+ ``` **Related functions**: - [ascii](#ascii) ##### `concat` Concatenates multiple strings together. ```sql concat(str[, ..., str_n]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **str_n**: Subsequent string expressions to concatenate. ###### Example ```sql > select concat('data', 'f', 'us', 'ion'); +-------------------------------------------------------+ | concat(Utf8("data"),Utf8("f"),Utf8("us"),Utf8("ion")) | +-------------------------------------------------------+ | datafusion | +-------------------------------------------------------+ ``` **Related functions**: - [concat_ws](#concat_ws) ##### `concat_ws` Concatenates multiple strings together with a specified separator. ```sql concat_ws(separator, str[, ..., str_n]) ``` ###### Arguments - **separator**: Separator to insert between concatenated strings. - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **str_n**: Subsequent string expressions to concatenate. ###### Example ```sql > select concat_ws('_', 'data', 'fusion'); +--------------------------------------------------+ | concat_ws(Utf8("_"),Utf8("data"),Utf8("fusion")) | +--------------------------------------------------+ | data_fusion | +--------------------------------------------------+ ``` **Related functions**: - [concat](#concat) ##### `contains` Return true if search_str is found within string (case-sensitive). ```sql contains(str, search_str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **search_str**: The string to search for in str. ###### Example ```sql > select contains('the quick brown fox', 'row'); +---------------------------------------------------+ | contains(Utf8("the quick brown fox"),Utf8("row")) | +---------------------------------------------------+ | true | +---------------------------------------------------+ ``` ##### `ends_with` Tests if a string ends with a substring. ```sql ends_with(str, substr) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring to test for. ###### Example ```sql > select ends_with('datafusion', 'soin'); +--------------------------------------------+ | ends_with(Utf8("datafusion"),Utf8("soin")) | +--------------------------------------------+ | false | +--------------------------------------------+ > select ends_with('datafusion', 'sion'); +--------------------------------------------+ | ends_with(Utf8("datafusion"),Utf8("sion")) | +--------------------------------------------+ | true | +--------------------------------------------+ ``` ##### `find_in_set` Returns a value in the range of 1 to N if the string str is in the string list strlist consisting of N substrings. ```sql find_in_set(str, strlist) ``` ###### Arguments - **str**: String expression to find in strlist. - **strlist**: A string list is a string composed of substrings separated by , characters. ###### Example ```sql > select find_in_set('b', 'a,b,c,d'); +----------------------------------------+ | find_in_set(Utf8("b"),Utf8("a,b,c,d")) | +----------------------------------------+ | 2 | +----------------------------------------+ ``` ##### `initcap` Capitalizes the first character in each word in the input string. Words are delimited by non-alphanumeric characters. ```sql initcap(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select initcap('apache datafusion'); +------------------------------------+ | initcap(Utf8("apache datafusion")) | +------------------------------------+ | Apache Datafusion | +------------------------------------+ ``` **Related functions**: - [lower](#lower) - [upper](#upper) ##### `instr` _Alias of [strpos](#strpos)._ ##### `left` Returns a specified number of characters from the left side of a string. ```sql left(str, n) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: Number of characters to return. ###### Example ```sql > select left('datafusion', 4); +-----------------------------------+ | left(Utf8("datafusion"),Int64(4)) | +-----------------------------------+ | data | +-----------------------------------+ ``` **Related functions**: - [right](#right) ##### `length` _Alias of [character_length](#character_length)._ ##### `levenshtein` Returns the [`Levenshtein distance`](https://en.wikipedia.org/wiki/Levenshtein_distance) between the two given strings. ```sql levenshtein(str1, str2) ``` ###### Arguments - **str1**: String expression to compute Levenshtein distance with str2. - **str2**: String expression to compute Levenshtein distance with str1. ###### Example ```sql > select levenshtein('kitten', 'sitting'); +---------------------------------------------+ | levenshtein(Utf8("kitten"),Utf8("sitting")) | +---------------------------------------------+ | 3 | +---------------------------------------------+ ``` ##### `lower` Converts a string to lower-case. ```sql lower(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select lower('Ångström'); +-------------------------+ | lower(Utf8("Ångström")) | +-------------------------+ | ångström | +-------------------------+ ``` **Related functions**: - [initcap](#initcap) - [upper](#upper) ##### `lpad` Pads the left side of a string with another string to a specified string length. ```sql lpad(str, n[, padding_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: String length to pad to. If the input string is longer than this length, it is truncated (on the right). - **padding_str**: Optional string expression to pad with. Can be a constant, column, or function, and any combination of string operators. _Default is a space._ ###### Example ```sql > select lpad('Dolly', 10, 'hello'); +---------------------------------------------+ | lpad(Utf8("Dolly"),Int64(10),Utf8("hello")) | +---------------------------------------------+ | helloDolly | +---------------------------------------------+ ``` **Related functions**: - [rpad](#rpad) ##### `ltrim` Trims the specified trim string from the beginning of a string. If no trim string is provided, spaces are removed from the start of the input string. ```sql ltrim(str[, trim_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **trim_str**: String expression to trim from the beginning of the input string. Can be a constant, column, or function, and any combination of arithmetic operators. _Default is a space._ ###### Example ```sql > select ltrim(' datafusion '); +-------------------------------+ | ltrim(Utf8(" datafusion ")) | +-------------------------------+ | datafusion | +-------------------------------+ > select ltrim('___datafusion___', '_'); +-------------------------------------------+ | ltrim(Utf8("___datafusion___"),Utf8("_")) | +-------------------------------------------+ | datafusion___ | +-------------------------------------------+ ``` ###### Alternative Syntax ```sql trim(LEADING trim_str FROM str) ``` **Related functions**: - [btrim](#btrim) - [rtrim](#rtrim) ##### `octet_length` Returns the length of a string in bytes. ```sql octet_length(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select octet_length('Ångström'); +--------------------------------+ | octet_length(Utf8("Ångström")) | +--------------------------------+ | 10 | +--------------------------------+ ``` **Related functions**: - [bit_length](#bit_length) - [length](#length) ##### `overlay` Returns the string which is replaced by another string from the specified position and specified count length. ```sql overlay(str PLACING substr FROM pos [FOR count]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring to replace in str. - **pos**: The start position to start the replace in str. - **count**: The count of characters to be replaced from start position of str. If not specified, will use substr length instead. ###### Example ```sql > select overlay('Txxxxas' placing 'hom' from 2 for 4); +--------------------------------------------------------+ | overlay(Utf8("Txxxxas"),Utf8("hom"),Int64(2),Int64(4)) | +--------------------------------------------------------+ | Thomas | +--------------------------------------------------------+ ``` ##### `position` _Alias of [strpos](#strpos)._ ##### `repeat` Returns a string with an input string repeated a specified number. ```sql repeat(str, n) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: Number of times to repeat the input string. ###### Example ```sql > select repeat('data', 3); +-------------------------------+ | repeat(Utf8("data"),Int64(3)) | +-------------------------------+ | datadatadata | +-------------------------------+ ``` ##### `replace` Replaces all occurrences of a specified substring in a string with a new substring. ```sql replace(str, substr, replacement) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring expression to replace in the input string. Substring expression to operate on. Can be a constant, column, or function, and any combination of operators. - **replacement**: Replacement substring expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select replace('ABabbaBA', 'ab', 'cd'); +-------------------------------------------------+ | replace(Utf8("ABabbaBA"),Utf8("ab"),Utf8("cd")) | +-------------------------------------------------+ | ABcdbaBA | +-------------------------------------------------+ ``` ##### `reverse` Reverses the character order of a string. ```sql reverse(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select reverse('datafusion'); +-----------------------------+ | reverse(Utf8("datafusion")) | +-----------------------------+ | noisufatad | +-----------------------------+ ``` ##### `right` Returns a specified number of characters from the right side of a string. ```sql right(str, n) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: Number of characters to return. ###### Example ```sql > select right('datafusion', 6); +------------------------------------+ | right(Utf8("datafusion"),Int64(6)) | +------------------------------------+ | fusion | +------------------------------------+ ``` **Related functions**: - [left](#left) ##### `rpad` Pads the right side of a string with another string to a specified string length. ```sql rpad(str, n[, padding_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **n**: String length to pad to. If the input string is longer than this length, it is truncated. - **padding_str**: String expression to pad with. Can be a constant, column, or function, and any combination of string operators. _Default is a space._ ###### Example ```sql > select rpad('datafusion', 20, '_-'); +-----------------------------------------------+ | rpad(Utf8("datafusion"),Int64(20),Utf8("_-")) | +-----------------------------------------------+ | datafusion_-_-_-_-_- | +-----------------------------------------------+ ``` **Related functions**: - [lpad](#lpad) ##### `rtrim` Trims the specified trim string from the end of a string. If no trim string is provided, all spaces are removed from the end of the input string. ```sql rtrim(str[, trim_str]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **trim_str**: String expression to trim from the end of the input string. Can be a constant, column, or function, and any combination of arithmetic operators. _Default is a space._ ###### Example ```sql > select rtrim(' datafusion '); +-------------------------------+ | rtrim(Utf8(" datafusion ")) | +-------------------------------+ | datafusion | +-------------------------------+ > select rtrim('___datafusion___', '_'); +-------------------------------------------+ | rtrim(Utf8("___datafusion___"),Utf8("_")) | +-------------------------------------------+ | ___datafusion | +-------------------------------------------+ ``` ###### Alternative Syntax ```sql trim(TRAILING trim_str FROM str) ``` **Related functions**: - [btrim](#btrim) - [ltrim](#ltrim) ##### `split_part` Splits a string based on a specified delimiter and returns the substring in the specified position. ```sql split_part(str, delimiter, pos) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **delimiter**: String or character to split on. - **pos**: Position of the part to return (counting from 1). Negative values count backward from the end of the string. ###### Example ```sql > select split_part('1.2.3.4.5', '.', 3); +--------------------------------------------------+ | split_part(Utf8("1.2.3.4.5"),Utf8("."),Int64(3)) | +--------------------------------------------------+ | 3 | +--------------------------------------------------+ ``` ##### `starts_with` Tests if a string starts with a substring. ```sql starts_with(str, substr) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring to test for. ###### Example ```sql > select starts_with('datafusion','data'); +----------------------------------------------+ | starts_with(Utf8("datafusion"),Utf8("data")) | +----------------------------------------------+ | true | +----------------------------------------------+ ``` ##### `strpos` Returns the starting position of a specified substring in a string. Positions begin at 1. If the substring does not exist in the string, the function returns 0. ```sql strpos(str, substr) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **substr**: Substring expression to search for. ###### Example ```sql > select strpos('datafusion', 'fus'); +----------------------------------------+ | strpos(Utf8("datafusion"),Utf8("fus")) | +----------------------------------------+ | 5 | +----------------------------------------+ ``` ###### Alternative Syntax ```sql position(substr in origstr) ``` ###### Aliases - instr - position ##### `substr` Extracts a substring of a specified number of characters from a specific starting position in a string. ```sql substr(str, start_pos[, length]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **start_pos**: Character position to start the substring at. The first character in the string has a position of 1. If the start position is less than 1, it is treated as if it is before the start of the string and the (absolute) number of characters before position 1 is subtracted from `length` (if given). For example, `substr('abc', -3, 6)` returns `'ab'`. - **length**: Number of characters to extract. If not specified, returns the rest of the string after the start position. ###### Example ```sql > select substr('datafusion', 5, 3); +----------------------------------------------+ | substr(Utf8("datafusion"),Int64(5),Int64(3)) | +----------------------------------------------+ | fus | +----------------------------------------------+ ``` ###### Alternative Syntax ```sql substring(str from start_pos for length) ``` ###### Aliases - substring ##### `substr_index` Returns the substring from str before count occurrences of the delimiter delim. If count is positive, everything to the left of the final delimiter (counting from the left) is returned. If count is negative, everything to the right of the final delimiter (counting from the right) is returned. ```sql substr_index(str, delim, count) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **delim**: The string to find in str to split str. - **count**: The number of times to search for the delimiter. Can be either a positive or negative number. ###### Example ```sql > select substr_index('www.apache.org', '.', 1); +---------------------------------------------------------+ | substr_index(Utf8("www.apache.org"),Utf8("."),Int64(1)) | +---------------------------------------------------------+ | www | +---------------------------------------------------------+ > select substr_index('www.apache.org', '.', -1); +----------------------------------------------------------+ | substr_index(Utf8("www.apache.org"),Utf8("."),Int64(-1)) | +----------------------------------------------------------+ | org | +----------------------------------------------------------+ ``` ###### Aliases - substring_index ##### `substring` _Alias of [substr](#substr)._ ##### `substring_index` _Alias of [substr_index](#substr_index)._ ##### `to_hex` Converts an integer to a hexadecimal string. ```sql to_hex(int) ``` ###### Arguments - **int**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select to_hex(12345689); +-------------------------+ | to_hex(Int64(12345689)) | +-------------------------+ | bc6159 | +-------------------------+ ``` ##### `translate` Performs character-wise substitution based on a mapping. ```sql translate(str, from, to) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **from**: The characters to be replaced. - **to**: The characters to replace them with. Each character in **from** that is found in **str** is replaced by the character at the same index in **to**. Any characters in **from** that don't have a corresponding character in **to** are removed. If a character appears more than once in **from**, the first occurrence determines the mapping. ###### Example ```sql > select translate('twice', 'wic', 'her'); +--------------------------------------------------+ | translate(Utf8("twice"),Utf8("wic"),Utf8("her")) | +--------------------------------------------------+ | there | +--------------------------------------------------+ ``` ##### `trim` _Alias of [btrim](#btrim)._ ##### `upper` Converts a string to upper-case. ```sql upper(str) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select upper('dataFusion'); +---------------------------+ | upper(Utf8("dataFusion")) | +---------------------------+ | DATAFUSION | +---------------------------+ ``` **Related functions**: - [initcap](#initcap) - [lower](#lower) ##### `uuid` Returns [`UUID v4`](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_%28random%29) string value which is unique per row. ```sql uuid() ``` ###### Example ```sql > select uuid(); +--------------------------------------+ | uuid() | +--------------------------------------+ | 6ec17ef8-1934-41cc-8d59-d0c8f9eea1f0 | +--------------------------------------+ ``` ### Binary String Functions - [decode](#decode) - [encode](#encode) ##### `decode` Decode binary data from textual representation in string. ```sql decode(expression, format) ``` ###### Arguments - **expression**: Expression containing encoded string data - **format**: Same arguments as [encode](#encode) **Related functions**: - [encode](#encode) ##### `encode` Encode binary data into a textual representation. ```sql encode(expression, format) ``` ###### Arguments - **expression**: Expression containing string or binary data - **format**: Supported formats are: `base64`, `base64pad`, `hex` **Related functions**: - [decode](#decode) ### Regular Expression Functions Apache DataFusion uses a [PCRE-like](https://en.wikibooks.org/wiki/Regular_Expressions/Perl-Compatible_Regular_Expressions) regular expression [syntax](https://docs.rs/regex/latest/regex/#syntax) (minus support for several features including look-around and backreferences). The following regular expression functions are supported: - [regexp_count](#regexp_count) - [regexp_instr](#regexp_instr) - [regexp_like](#regexp_like) - [regexp_match](#regexp_match) - [regexp_replace](#regexp_replace) ##### `regexp_count` Returns the number of matches that a [regular expression](https://docs.rs/regex/latest/regex/#syntax) has in a string. ```sql regexp_count(str, regexp[, start, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to operate on. Can be a constant, column, or function, and any combination of operators. - **start**: - **start**: Optional start position (the first position is 1) to search for the regular expression. Can be a constant, column, or function. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql > select regexp_count('abcAbAbc', 'abc', 2, 'i'); +---------------------------------------------------------------+ | regexp_count(Utf8("abcAbAbc"),Utf8("abc"),Int64(2),Utf8("i")) | +---------------------------------------------------------------+ | 1 | +---------------------------------------------------------------+ ``` ##### `regexp_instr` Returns the position in a string where the specified occurrence of a POSIX regular expression is located. ```sql regexp_instr(str, regexp[, start[, N[, flags[, subexpr]]]]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to operate on. Can be a constant, column, or function, and any combination of operators. - **start**: - **start**: Optional start position (the first position is 1) to search for the regular expression. Can be a constant, column, or function. Defaults to 1 - **N**: - **N**: Optional The N-th occurrence of pattern to find. Defaults to 1 (first match). Can be a constant, column, or function. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? - **subexpr**: Optional Specifies which capture group (subexpression) to return the position for. Defaults to 0, which returns the position of the entire match. ###### Example ```sql > SELECT regexp_instr('ABCDEF', 'C(.)(..)'); +---------------------------------------------------------------+ | regexp_instr(Utf8("ABCDEF"),Utf8("C(.)(..)")) | +---------------------------------------------------------------+ | 3 | +---------------------------------------------------------------+ ``` ##### `regexp_like` Returns true if a [regular expression](https://docs.rs/regex/latest/regex/#syntax) has at least one match in a string, false otherwise. ```sql regexp_like(str, regexp[, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to operate on. Can be a constant, column, or function, and any combination of operators. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql select regexp_like('Köln', '[a-zA-Z]ö[a-zA-Z]{2}'); +--------------------------------------------------------+ | regexp_like(Utf8("Köln"),Utf8("[a-zA-Z]ö[a-zA-Z]{2}")) | +--------------------------------------------------------+ | true | +--------------------------------------------------------+ SELECT regexp_like('aBc', '(b|d)', 'i'); +--------------------------------------------------+ | regexp_like(Utf8("aBc"),Utf8("(b|d)"),Utf8("i")) | +--------------------------------------------------+ | true | +--------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/regexp.rs) ##### `regexp_match` Returns the first [regular expression](https://docs.rs/regex/latest/regex/#syntax) matches in a string. ```sql regexp_match(str, regexp[, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to match against. Can be a constant, column, or function. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql > select regexp_match('Köln', '[a-zA-Z]ö[a-zA-Z]{2}'); +---------------------------------------------------------+ | regexp_match(Utf8("Köln"),Utf8("[a-zA-Z]ö[a-zA-Z]{2}")) | +---------------------------------------------------------+ | [Köln] | +---------------------------------------------------------+ SELECT regexp_match('aBc', '(b|d)', 'i'); +---------------------------------------------------+ | regexp_match(Utf8("aBc"),Utf8("(b|d)"),Utf8("i")) | +---------------------------------------------------+ | [B] | +---------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/regexp.rs) ##### `regexp_replace` Replaces substrings in a string that match a [regular expression](https://docs.rs/regex/latest/regex/#syntax). ```sql regexp_replace(str, regexp, replacement[, flags]) ``` ###### Arguments - **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **regexp**: Regular expression to match against. Can be a constant, column, or function. - **replacement**: Replacement string expression to operate on. Can be a constant, column, or function, and any combination of operators. - **flags**: Optional regular expression flags that control the behavior of the regular expression. The following flags are supported: - **g**: (global) Search globally and don't return after the first match - **i**: case-insensitive: letters match both upper and lower case - **m**: multi-line mode: ^ and $ match begin/end of line - **s**: allow . to match \n - **R**: enables CRLF mode: when multi-line mode is enabled, \r\n is used - **U**: swap the meaning of x* and x*? ###### Example ```sql > select regexp_replace('foobarbaz', 'b(..)', 'X\\1Y', 'g'); +------------------------------------------------------------------------+ | regexp_replace(Utf8("foobarbaz"),Utf8("b(..)"),Utf8("X\1Y"),Utf8("g")) | +------------------------------------------------------------------------+ | fooXarYXazY | +------------------------------------------------------------------------+ SELECT regexp_replace('aBc', '(b|d)', 'Ab\\1a', 'i'); +-------------------------------------------------------------------+ | regexp_replace(Utf8("aBc"),Utf8("(b|d)"),Utf8("Ab\1a"),Utf8("i")) | +-------------------------------------------------------------------+ | aAbBac | +-------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/regexp.rs) ### Time and Date Functions - [current_date](#current_date) - [current_time](#current_time) - [current_timestamp](#current_timestamp) - [date_bin](#date_bin) - [date_format](#date_format) - [date_part](#date_part) - [date_trunc](#date_trunc) - [datepart](#datepart) - [datetrunc](#datetrunc) - [from_unixtime](#from_unixtime) - [make_date](#make_date) - [make_time](#make_time) - [now](#now) - [to_char](#to_char) - [to_date](#to_date) - [to_local_time](#to_local_time) - [to_time](#to_time) - [to_timestamp](#to_timestamp) - [to_timestamp_micros](#to_timestamp_micros) - [to_timestamp_millis](#to_timestamp_millis) - [to_timestamp_nanos](#to_timestamp_nanos) - [to_timestamp_seconds](#to_timestamp_seconds) - [to_unixtime](#to_unixtime) - [today](#today) ##### `current_date` Returns the current date in the session time zone. The `current_date()` return value is determined at query time and will return the same date, no matter when in the query plan the function executes. ```sql current_date() (optional) SET datafusion.execution.time_zone = '+00:00'; SELECT current_date(); ``` ###### Example ```sql > SELECT current_date(); +----------------+ | current_date() | +----------------+ | 2024-12-23 | +----------------+ -- The current date is based on the session time zone (UTC by default) > SET datafusion.execution.time_zone = 'Asia/Tokyo'; > SELECT current_date(); +----------------+ | current_date() | +----------------+ | 2024-12-24 | +----------------+ ``` ###### Aliases - today ##### `current_time` Returns the current time in the session time zone. The `current_time()` return value is determined at query time and will return the same time, no matter when in the query plan the function executes. The session time zone can be set using the statement 'SET datafusion.execution.time_zone = desired time zone'. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql current_time() (optional) SET datafusion.execution.time_zone = '+00:00'; SELECT current_time(); ``` ###### Example ```sql > SELECT current_time(); +--------------------+ | current_time() | +--------------------+ | 06:30:00.123456789 | +--------------------+ -- The current time is based on the session time zone (UTC by default) > SET datafusion.execution.time_zone = 'Asia/Tokyo'; > SELECT current_time(); +--------------------+ | current_time() | +--------------------+ | 15:30:00.123456789 | +--------------------+ ``` ##### `current_timestamp` _Alias of [now](#now)._ ##### `date_bin` Calculates time intervals and returns the start of the interval nearest to the specified timestamp. Use `date_bin` to downsample time series data by grouping rows into time-based "bins" or "windows" and applying an aggregate or selector function to each window. For example, if you "bin" or "window" data into 15 minute intervals, an input timestamp of `2023-01-01T18:18:18Z` will be updated to the start time of the 15 minute bin it is in: `2023-01-01T18:15:00Z`. ```sql date_bin(interval, expression, origin-timestamp) ``` ###### Arguments - **interval**: Bin interval. - **expression**: Time expression to operate on. Can be a constant, column, or function. - **origin-timestamp**: Optional. Starting point used to determine bin boundaries. If not specified defaults 1970-01-01T00:00:00Z (the UNIX epoch in UTC). The following intervals are supported: - nanoseconds - microseconds - milliseconds - seconds - minutes - hours - days - weeks - months - years - century ###### Example ```sql -- Bin the timestamp into 1 day intervals > SELECT date_bin(interval '1 day', time) as bin FROM VALUES ('2023-01-01T18:18:18Z'), ('2023-01-03T19:00:03Z') t(time); +---------------------+ | bin | +---------------------+ | 2023-01-01T00:00:00 | | 2023-01-03T00:00:00 | +---------------------+ 2 row(s) fetched. -- Bin the timestamp into 1 day intervals starting at 3AM on 2023-01-01 > SELECT date_bin(interval '1 day', time, '2023-01-01T03:00:00') as bin FROM VALUES ('2023-01-01T18:18:18Z'), ('2023-01-03T19:00:03Z') t(time); +---------------------+ | bin | +---------------------+ | 2023-01-01T03:00:00 | | 2023-01-03T03:00:00 | +---------------------+ 2 row(s) fetched. -- Bin the time into 15 minute intervals starting at 1 min > SELECT date_bin(interval '15 minutes', time, TIME '00:01:00') as bin FROM VALUES (TIME '02:18:18'), (TIME '19:00:03') t(time); +----------+ | bin | +----------+ | 02:16:00 | | 18:46:00 | +----------+ 2 row(s) fetched. ``` ##### `date_format` _Alias of [to_char](#to_char)._ ##### `date_part` Returns the specified part of the date as an integer. ```sql date_part(part, expression) ``` ###### Arguments - **part**: Part of the date to return. The following date parts are supported: - year - isoyear (ISO 8601 week-numbering year) - quarter (emits value in inclusive range [1, 4] based on which quartile of the year the date is in) - month - week (week of the year) - day (day of the month) - hour - minute - second - millisecond - microsecond - nanosecond - dow (day of the week where Sunday is 0) - doy (day of the year) - epoch (seconds since Unix epoch for timestamps/dates, total seconds for intervals) - isodow (day of the week where Monday is 0) - **expression**: Time expression to operate on. Can be a constant, column, or function. ###### Example ```sql > SELECT date_part('year', '2024-05-01T00:00:00'); +-----------------------------------------------------+ | date_part(Utf8("year"),Utf8("2024-05-01T00:00:00")) | +-----------------------------------------------------+ | 2024 | +-----------------------------------------------------+ > SELECT extract(day FROM timestamp '2024-05-01T00:00:00'); +----------------------------------------------------+ | date_part(Utf8("DAY"),Utf8("2024-05-01T00:00:00")) | +----------------------------------------------------+ | 1 | +----------------------------------------------------+ ``` ###### Alternative Syntax ```sql extract(field FROM source) ``` ###### Aliases - datepart ##### `date_trunc` Truncates a timestamp or time value to a specified precision. ```sql date_trunc(precision, expression) ``` ###### Arguments - **precision**: Time precision to truncate to. The following precisions are supported: For Timestamp types: - year / YEAR - quarter / QUARTER - month / MONTH - week / WEEK - day / DAY - hour / HOUR - minute / MINUTE - second / SECOND - millisecond / MILLISECOND - microsecond / MICROSECOND For Time types (hour, minute, second, millisecond, microsecond only): - hour / HOUR - minute / MINUTE - second / SECOND - millisecond / MILLISECOND - microsecond / MICROSECOND - **expression**: Timestamp or time expression to operate on. Can be a constant, column, or function. ###### Example ```sql > SELECT date_trunc('month', '2024-05-15T10:30:00'); +-----------------------------------------------+ | date_trunc(Utf8("month"),Utf8("2024-05-15T10:30:00")) | +-----------------------------------------------+ | 2024-05-01T00:00:00 | +-----------------------------------------------+ > SELECT date_trunc('hour', '2024-05-15T10:30:00'); +----------------------------------------------+ | date_trunc(Utf8("hour"),Utf8("2024-05-15T10:30:00")) | +----------------------------------------------+ | 2024-05-15T10:00:00 | +----------------------------------------------+ ``` ###### Aliases - datetrunc ##### `datepart` _Alias of [date_part](#date_part)._ ##### `datetrunc` _Alias of [date_trunc](#date_trunc)._ ##### `from_unixtime` Converts an integer to RFC3339 timestamp format (`YYYY-MM-DDT00:00:00.000000000Z`). Integers and unsigned integers are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00Z`) return the corresponding timestamp. ```sql from_unixtime(expression[, timezone]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **timezone**: Optional timezone to use when converting the integer to a timestamp. If not provided, the default timezone is UTC. ###### Example ```sql > select from_unixtime(1599572549, 'America/New_York'); +-----------------------------------------------------------+ | from_unixtime(Int64(1599572549),Utf8("America/New_York")) | +-----------------------------------------------------------+ | 2020-09-08T09:42:29-04:00 | +-----------------------------------------------------------+ ``` ##### `make_date` Make a date from year/month/day component parts. ```sql make_date(year, month, day) ``` ###### Arguments - **year**: Year to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. - **month**: Month to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. - **day**: Day to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. ###### Example ```sql > select make_date(2023, 1, 31); +-------------------------------------------+ | make_date(Int64(2023),Int64(1),Int64(31)) | +-------------------------------------------+ | 2023-01-31 | +-------------------------------------------+ > select make_date('2023', '01', '31'); +-----------------------------------------------+ | make_date(Utf8("2023"),Utf8("01"),Utf8("31")) | +-----------------------------------------------+ | 2023-01-31 | +-----------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `make_time` Make a time from hour/minute/second component parts. ```sql make_time(hour, minute, second) ``` ###### Arguments - **hour**: Hour to use when making the time. Can be a constant, column or function, and any combination of arithmetic operators. - **minute**: Minute to use when making the time. Can be a constant, column or function, and any combination of arithmetic operators. - **second**: Second to use when making the time. Can be a constant, column or function, and any combination of arithmetic operators. ###### Example ```sql > select make_time(13, 23, 1); +-------------------------------------------+ | make_time(Int64(13),Int64(23),Int64(1)) | +-------------------------------------------+ | 13:23:01 | +-------------------------------------------+ > select make_time('23', '01', '31'); +-----------------------------------------------+ | make_time(Utf8("23"),Utf8("01"),Utf8("31")) | +-----------------------------------------------+ | 23:01:31 | +-----------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `now` Returns the current timestamp in the system configured timezone (None by default). The `now()` return value is determined at query time and will return the same timestamp, no matter when in the query plan the function executes. ```sql now() ``` ###### Example ```sql > SELECT now(); +----------------------------------+ | now() | +----------------------------------+ | 2024-12-23T06:30:00.123456789 | +----------------------------------+ -- The timezone of the returned timestamp depends on the session time zone > SET datafusion.execution.time_zone = 'America/New_York'; > SELECT now(); +--------------------------------------+ | now() | +--------------------------------------+ | 2024-12-23T01:30:00.123456789-05:00 | +--------------------------------------+ ``` ###### Aliases - current_timestamp ##### `to_char` Returns a string representation of a date, time, timestamp or duration based on a [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html). Unlike the PostgreSQL equivalent of this function numerical formatting is not supported. ```sql to_char(expression, format) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function that results in a date, time, timestamp or duration. - **format**: A [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) string to use to convert the expression. - **day**: Day to use when making the date. Can be a constant, column or function, and any combination of arithmetic operators. ###### Example ```sql > select to_char('2023-03-01'::date, '%d-%m-%Y'); +----------------------------------------------+ | to_char(Utf8("2023-03-01"),Utf8("%d-%m-%Y")) | +----------------------------------------------+ | 01-03-2023 | +----------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ###### Aliases - date_format ##### `to_date` Converts a value to a date (`YYYY-MM-DD`). Supports strings, numeric and timestamp types as input. Strings are parsed as YYYY-MM-DD (e.g. '2023-07-20') if no [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html)s are provided. Integers and doubles are interpreted as days since the unix epoch (`1970-01-01T00:00:00Z`). Returns the corresponding date. Note: `to_date` returns Date32, which represents its values as the number of days since unix epoch(`1970-01-01`) stored as signed 32 bit value. The largest supported date value is `9999-12-31`. ```sql to_date('2017-05-31', '%Y-%m-%d') ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. ###### Example ```sql > select to_date('2023-01-31'); +-------------------------------+ | to_date(Utf8("2023-01-31")) | +-------------------------------+ | 2023-01-31 | +-------------------------------+ > select to_date('2023/01/31', '%Y-%m-%d', '%Y/%m/%d'); +---------------------------------------------------------------------+ | to_date(Utf8("2023/01/31"),Utf8("%Y-%m-%d"),Utf8("%Y/%m/%d")) | +---------------------------------------------------------------------+ | 2023-01-31 | +---------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_local_time` Converts a timestamp with a timezone to a timestamp without a timezone (with no offset or timezone information). This function handles daylight saving time changes. ```sql to_local_time(expression) ``` ###### Arguments - **expression**: Time expression to operate on. Can be a constant, column, or function. ###### Example ```sql > SELECT to_local_time('2024-04-01T00:00:20Z'::timestamp); +---------------------------------------------+ | to_local_time(Utf8("2024-04-01T00:00:20Z")) | +---------------------------------------------+ | 2024-04-01T00:00:20 | +---------------------------------------------+ > SELECT to_local_time('2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels'); +---------------------------------------------+ | to_local_time(Utf8("2024-04-01T00:00:20Z")) | +---------------------------------------------+ | 2024-04-01T00:00:20 | +---------------------------------------------+ > SELECT time, arrow_typeof(time) as type, to_local_time(time) as to_local_time, arrow_typeof(to_local_time(time)) as to_local_time_type FROM ( SELECT '2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels' AS time ); +---------------------------+----------------------------------+---------------------+--------------------+ | time | type | to_local_time | to_local_time_type | +---------------------------+----------------------------------+---------------------+--------------------+ | 2024-04-01T00:00:20+02:00 | Timestamp(ns, "Europe/Brussels") | 2024-04-01T00:00:20 | Timestamp(ns) | +---------------------------+----------------------------------+---------------------+--------------------+ ## combine `to_local_time()` with `date_bin()` to bin on boundaries in the timezone rather ## than UTC boundaries > SELECT date_bin(interval '1 day', to_local_time('2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels')) AS date_bin; +---------------------+ | date_bin | +---------------------+ | 2024-04-01T00:00:00 | +---------------------+ > SELECT date_bin(interval '1 day', to_local_time('2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels')) AT TIME ZONE 'Europe/Brussels' AS date_bin_with_timezone; +---------------------------+ | date_bin_with_timezone | +---------------------------+ | 2024-04-01T00:00:00+02:00 | +---------------------------+ ``` ##### `to_time` Converts a value to a time (`HH:MM:SS.nnnnnnnnn`). Supports strings and timestamps as input. Strings are parsed as `HH:MM:SS`, `HH:MM:SS.nnnnnnnnn`, or `HH:MM` if no [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html)s are provided. Timestamps will have the time portion extracted. Returns the corresponding time. Note: `to_time` returns Time64(Nanosecond), which represents the time of day in nanoseconds since midnight. ```sql to_time('12:30:45', '%H:%M:%S') ``` ###### Arguments - **expression**: String or Timestamp expression to operate on. Can be a constant, column, or function, and any combination of operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. ###### Example ```sql > select to_time('12:30:45'); +---------------------------+ | to_time(Utf8("12:30:45")) | +---------------------------+ | 12:30:45 | +---------------------------+ > select to_time('12-30-45', '%H-%M-%S'); +--------------------------------------------+ | to_time(Utf8("12-30-45"),Utf8("%H-%M-%S")) | +--------------------------------------------+ | 12:30:45 | +--------------------------------------------+ > select to_time('2024-01-15 14:30:45'::timestamp); +--------------------------------------------------+ | to_time(Utf8("2024-01-15 14:30:45")) | +--------------------------------------------------+ | 14:30:45 | +--------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00Z`). Note: `to_timestamp` returns `Timestamp(ns, TimeZone)` where the time zone is the session time zone. The supported range for integer input is between`-9223372037` and `9223372036`. Supported range for string input is between `1677-09-21T00:12:44.0` and `2262-04-11T23:47:16.0`. Please use `to_timestamp_seconds` for the input outside of supported bounds. The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp('2023-01-31T09:26:56.123456789-05:00'); +-----------------------------------------------------------+ | to_timestamp(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +-----------------------------------------------------------+ | 2023-01-31T14:26:56.123456789 | +-----------------------------------------------------------+ > select to_timestamp('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +--------------------------------------------------------------------------------------------------------+ | to_timestamp(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +--------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123456789 | +--------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_micros` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as microseconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_micros(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_micros('2023-01-31T09:26:56.123456789-05:00'); +------------------------------------------------------------------+ | to_timestamp_micros(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +------------------------------------------------------------------+ | 2023-01-31T14:26:56.123456 | +------------------------------------------------------------------+ > select to_timestamp_micros('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +---------------------------------------------------------------------------------------------------------------+ | to_timestamp_micros(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +---------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123456 | +---------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_millis` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as milliseconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_millis(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_millis('2023-01-31T09:26:56.123456789-05:00'); +------------------------------------------------------------------+ | to_timestamp_millis(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +------------------------------------------------------------------+ | 2023-01-31T14:26:56.123 | +------------------------------------------------------------------+ > select to_timestamp_millis('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +---------------------------------------------------------------------------------------------------------------+ | to_timestamp_millis(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +---------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123 | +---------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_nanos` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00.000000000`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone. Integers, unsigned integers, and doubles are interpreted as nanoseconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_nanos(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_nanos('2023-01-31T09:26:56.123456789-05:00'); +-----------------------------------------------------------------+ | to_timestamp_nanos(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +-----------------------------------------------------------------+ | 2023-01-31T14:26:56.123456789 | +-----------------------------------------------------------------+ > select to_timestamp_nanos('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +--------------------------------------------------------------------------------------------------------------+ | to_timestamp_nanos(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +--------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00.123456789 | +---------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_timestamp_seconds` Converts a value to a timestamp (`YYYY-MM-DDT00:00:00`) in the session time zone. Supports strings, integer, unsigned integer, and double types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Strings that parse without a time zone are treated as if they are in the session time zone, or UTC if no session time zone is set. Integers, unsigned integers, and doubles are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00Z`). The session time zone can be set using the statement `SET TIMEZONE = 'desired time zone'`. The time zone can be a value like +00:00, 'Europe/London' etc. ```sql to_timestamp_seconds(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. Note: parsing of named timezones (e.g. 'America/New_York') using %Z is only supported at the end of the string preceded by a space. ###### Example ```sql > select to_timestamp_seconds('2023-01-31T09:26:56.123456789-05:00'); +-------------------------------------------------------------------+ | to_timestamp_seconds(Utf8("2023-01-31T09:26:56.123456789-05:00")) | +-------------------------------------------------------------------+ | 2023-01-31T14:26:56 | +-------------------------------------------------------------------+ > select to_timestamp_seconds('03:59:00.123456789 05-17-2023', '%c', '%+', '%H:%M:%S%.f %m-%d-%Y'); +----------------------------------------------------------------------------------------------------------------+ | to_timestamp_seconds(Utf8("03:59:00.123456789 05-17-2023"),Utf8("%c"),Utf8("%+"),Utf8("%H:%M:%S%.f %m-%d-%Y")) | +----------------------------------------------------------------------------------------------------------------+ | 2023-05-17T03:59:00 | +----------------------------------------------------------------------------------------------------------------+ ``` Additional examples can be found [here](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/builtin_functions/date_time.rs) ##### `to_unixtime` Converts a value to seconds since the unix epoch (`1970-01-01T00:00:00`). Supports strings, dates, timestamps, integer, unsigned integer, and float types as input. Strings are parsed as RFC3339 (e.g. '2023-07-20T05:44:00') if no [Chrono formats](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) are provided. Integers, unsigned integers, and floats are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00`). ```sql to_unixtime(expression[, ..., format_n]) ``` ###### Arguments - **expression**: Expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators. - **format_n**: Optional [Chrono format](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) strings to use to parse the expression. Formats will be tried in the order they appear with the first successful one being returned. If none of the formats successfully parse the expression an error will be returned. ###### Example ```sql > select to_unixtime('2020-09-08T12:00:00+00:00'); +------------------------------------------------+ | to_unixtime(Utf8("2020-09-08T12:00:00+00:00")) | +------------------------------------------------+ | 1599566400 | +------------------------------------------------+ > select to_unixtime('01-14-2023 01:01:30+05:30', '%q', '%d-%m-%Y %H/%M/%S', '%+', '%m-%d-%Y %H:%M:%S%#z'); +-----------------------------------------------------------------------------------------------------------------------------+ | to_unixtime(Utf8("01-14-2023 01:01:30+05:30"),Utf8("%q"),Utf8("%d-%m-%Y %H/%M/%S"),Utf8("%+"),Utf8("%m-%d-%Y %H:%M:%S%#z")) | +-----------------------------------------------------------------------------------------------------------------------------+ | 1673638290 | +-----------------------------------------------------------------------------------------------------------------------------+ ``` ##### `today` _Alias of [current_date](#current_date)._ ### Array Functions - [array_any_value](#array_any_value) - [array_append](#array_append) - [array_cat](#array_cat) - [array_concat](#array_concat) - [array_contains](#array_contains) - [array_dims](#array_dims) - [array_distance](#array_distance) - [array_distinct](#array_distinct) - [array_element](#array_element) - [array_empty](#array_empty) - [array_except](#array_except) - [array_extract](#array_extract) - [array_has](#array_has) - [array_has_all](#array_has_all) - [array_has_any](#array_has_any) - [array_indexof](#array_indexof) - [array_intersect](#array_intersect) - [array_join](#array_join) - [array_length](#array_length) - [array_max](#array_max) - [array_min](#array_min) - [array_ndims](#array_ndims) - [array_pop_back](#array_pop_back) - [array_pop_front](#array_pop_front) - [array_position](#array_position) - [array_positions](#array_positions) - [array_prepend](#array_prepend) - [array_push_back](#array_push_back) - [array_push_front](#array_push_front) - [array_remove](#array_remove) - [array_remove_all](#array_remove_all) - [array_remove_n](#array_remove_n) - [array_repeat](#array_repeat) - [array_replace](#array_replace) - [array_replace_all](#array_replace_all) - [array_replace_n](#array_replace_n) - [array_resize](#array_resize) - [array_reverse](#array_reverse) - [array_slice](#array_slice) - [array_sort](#array_sort) - [array_to_string](#array_to_string) - [array_union](#array_union) - [arrays_overlap](#arrays_overlap) - [arrays_zip](#arrays_zip) - [cardinality](#cardinality) - [empty](#empty) - [flatten](#flatten) - [generate_series](#generate_series) - [list_any_value](#list_any_value) - [list_append](#list_append) - [list_cat](#list_cat) - [list_concat](#list_concat) - [list_contains](#list_contains) - [list_dims](#list_dims) - [list_distance](#list_distance) - [list_distinct](#list_distinct) - [list_element](#list_element) - [list_empty](#list_empty) - [list_except](#list_except) - [list_extract](#list_extract) - [list_has](#list_has) - [list_has_all](#list_has_all) - [list_has_any](#list_has_any) - [list_indexof](#list_indexof) - [list_intersect](#list_intersect) - [list_join](#list_join) - [list_length](#list_length) - [list_max](#list_max) - [list_ndims](#list_ndims) - [list_pop_back](#list_pop_back) - [list_pop_front](#list_pop_front) - [list_position](#list_position) - [list_positions](#list_positions) - [list_prepend](#list_prepend) - [list_push_back](#list_push_back) - [list_push_front](#list_push_front) - [list_remove](#list_remove) - [list_remove_all](#list_remove_all) - [list_remove_n](#list_remove_n) - [list_repeat](#list_repeat) - [list_replace](#list_replace) - [list_replace_all](#list_replace_all) - [list_replace_n](#list_replace_n) - [list_resize](#list_resize) - [list_reverse](#list_reverse) - [list_slice](#list_slice) - [list_sort](#list_sort) - [list_to_string](#list_to_string) - [list_union](#list_union) - [list_zip](#list_zip) - [make_array](#make_array) - [make_list](#make_list) - [range](#range) - [string_to_array](#string_to_array) - [string_to_list](#string_to_list) ##### `array_any_value` Returns the first non-null element in the array. ```sql array_any_value(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_any_value([NULL, 1, 2, 3]); +-------------------------------+ | array_any_value(List([NULL,1,2,3])) | +-------------------------------------+ | 1 | +-------------------------------------+ ``` ###### Aliases - list_any_value ##### `array_append` Appends an element to the end of an array. ```sql array_append(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to append to the array. ###### Example ```sql > select array_append([1, 2, 3], 4); +--------------------------------------+ | array_append(List([1,2,3]),Int64(4)) | +--------------------------------------+ | [1, 2, 3, 4] | +--------------------------------------+ ``` ###### Aliases - list_append - array_push_back - list_push_back ##### `array_cat` _Alias of [array_concat](#array_concat)._ ##### `array_concat` Concatenates arrays. ```sql array_concat(array[, ..., array_n]) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array_n**: Subsequent array column or literal array to concatenate. ###### Example ```sql > select array_concat([1, 2], [3, 4], [5, 6]); +---------------------------------------------------+ | array_concat(List([1,2]),List([3,4]),List([5,6])) | +---------------------------------------------------+ | [1, 2, 3, 4, 5, 6] | +---------------------------------------------------+ ``` ###### Aliases - array_cat - list_concat - list_cat ##### `array_contains` _Alias of [array_has](#array_has)._ ##### `array_dims` Returns an array of the array's dimensions. ```sql array_dims(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_dims([[1, 2, 3], [4, 5, 6]]); +---------------------------------+ | array_dims(List([1,2,3,4,5,6])) | +---------------------------------+ | [2, 3] | +---------------------------------+ ``` ###### Aliases - list_dims ##### `array_distance` Returns the Euclidean distance between two input arrays of equal length. ```sql array_distance(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_distance([1, 2], [1, 4]); +------------------------------------+ | array_distance(List([1,2], [1,4])) | +------------------------------------+ | 2.0 | +------------------------------------+ ``` ###### Aliases - list_distance ##### `array_distinct` Returns distinct values from the array after removing duplicates. ```sql array_distinct(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_distinct([1, 3, 2, 3, 1, 2, 4]); +---------------------------------+ | array_distinct(List([1,2,3,4])) | +---------------------------------+ | [1, 2, 3, 4] | +---------------------------------+ ``` ###### Aliases - list_distinct ##### `array_element` Extracts the element with the index n from the array. ```sql array_element(array, index) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **index**: Index to extract the element from the array. ###### Example ```sql > select array_element([1, 2, 3, 4], 3); +-----------------------------------------+ | array_element(List([1,2,3,4]),Int64(3)) | +-----------------------------------------+ | 3 | +-----------------------------------------+ ``` ###### Aliases - array_extract - list_element - list_extract ##### `array_empty` _Alias of [empty](#empty)._ ##### `array_except` Returns an array of the elements that appear in the first array but not in the second. ```sql array_except(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_except([1, 2, 3, 4], [5, 6, 3, 4]); +----------------------------------------------------+ | array_except([1, 2, 3, 4], [5, 6, 3, 4]); | +----------------------------------------------------+ | [1, 2] | +----------------------------------------------------+ > select array_except([1, 2, 3, 4], [3, 4, 5, 6]); +----------------------------------------------------+ | array_except([1, 2, 3, 4], [3, 4, 5, 6]); | +----------------------------------------------------+ | [1, 2] | +----------------------------------------------------+ ``` ###### Aliases - list_except ##### `array_extract` _Alias of [array_element](#array_element)._ ##### `array_has` Returns true if the array contains the element. ```sql array_has(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Scalar or Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_has([1, 2, 3], 2); +-----------------------------+ | array_has(List([1,2,3]), 2) | +-----------------------------+ | true | +-----------------------------+ ``` ###### Aliases - list_has - array_contains - list_contains ##### `array_has_all` Returns true if all elements of sub-array exist in array. ```sql array_has_all(array, sub-array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **sub-array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_has_all([1, 2, 3, 4], [2, 3]); +--------------------------------------------+ | array_has_all(List([1,2,3,4]), List([2,3])) | +--------------------------------------------+ | true | +--------------------------------------------+ ``` ###### Aliases - list_has_all ##### `array_has_any` Returns true if the arrays have any elements in common. ```sql array_has_any(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_has_any([1, 2, 3], [3, 4]); +------------------------------------------+ | array_has_any(List([1,2,3]), List([3,4])) | +------------------------------------------+ | true | +------------------------------------------+ ``` ###### Aliases - list_has_any - arrays_overlap ##### `array_indexof` _Alias of [array_position](#array_position)._ ##### `array_intersect` Returns an array of elements in the intersection of array1 and array2. ```sql array_intersect(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_intersect([1, 2, 3, 4], [5, 6, 3, 4]); +----------------------------------------------------+ | array_intersect([1, 2, 3, 4], [5, 6, 3, 4]); | +----------------------------------------------------+ | [3, 4] | +----------------------------------------------------+ > select array_intersect([1, 2, 3, 4], [5, 6, 7, 8]); +----------------------------------------------------+ | array_intersect([1, 2, 3, 4], [5, 6, 7, 8]); | +----------------------------------------------------+ | [] | +----------------------------------------------------+ ``` ###### Aliases - list_intersect ##### `array_join` _Alias of [array_to_string](#array_to_string)._ ##### `array_length` Returns the length of the array dimension. ```sql array_length(array, dimension) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **dimension**: Array dimension. ###### Example ```sql > select array_length([1, 2, 3, 4, 5], 1); +-------------------------------------------+ | array_length(List([1,2,3,4,5]), 1) | +-------------------------------------------+ | 5 | +-------------------------------------------+ ``` ###### Aliases - list_length ##### `array_max` Returns the maximum value in the array. ```sql array_max(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_max([3,1,4,2]); +-----------------------------------------+ | array_max(List([3,1,4,2])) | +-----------------------------------------+ | 4 | +-----------------------------------------+ ``` ###### Aliases - list_max ##### `array_min` Returns the minimum value in the array. ```sql array_min(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_min([3,1,4,2]); +-----------------------------------------+ | array_min(List([3,1,4,2])) | +-----------------------------------------+ | 1 | +-----------------------------------------+ ``` ##### `array_ndims` Returns the number of dimensions of the array. ```sql array_ndims(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Array element. ###### Example ```sql > select array_ndims([[1, 2, 3], [4, 5, 6]]); +----------------------------------+ | array_ndims(List([1,2,3,4,5,6])) | +----------------------------------+ | 2 | +----------------------------------+ ``` ###### Aliases - list_ndims ##### `array_pop_back` Returns the array without the last element. ```sql array_pop_back(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_pop_back([1, 2, 3]); +-------------------------------+ | array_pop_back(List([1,2,3])) | +-------------------------------+ | [1, 2] | +-------------------------------+ ``` ###### Aliases - list_pop_back ##### `array_pop_front` Returns the array without the first element. ```sql array_pop_front(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_pop_front([1, 2, 3]); +-------------------------------+ | array_pop_front(List([1,2,3])) | +-------------------------------+ | [2, 3] | +-------------------------------+ ``` ###### Aliases - list_pop_front ##### `array_position` Returns the position of the first occurrence of the specified element in the array, or NULL if not found. Comparisons are done using `IS DISTINCT FROM` semantics, so NULL is considered to match NULL. ```sql array_position(array, element) array_position(array, element, index) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to search for in the array. - **index**: Index at which to start searching (1-indexed). ###### Example ```sql > select array_position([1, 2, 2, 3, 1, 4], 2); +----------------------------------------------+ | array_position(List([1,2,2,3,1,4]),Int64(2)) | +----------------------------------------------+ | 2 | +----------------------------------------------+ > select array_position([1, 2, 2, 3, 1, 4], 2, 3); +----------------------------------------------------+ | array_position(List([1,2,2,3,1,4]),Int64(2), Int64(3)) | +----------------------------------------------------+ | 3 | +----------------------------------------------------+ ``` ###### Aliases - list_position - array_indexof - list_indexof ##### `array_positions` Searches for an element in the array, returns all occurrences. ```sql array_positions(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to search for in the array. ###### Example ```sql > select array_positions([1, 2, 2, 3, 1, 4], 2); +-----------------------------------------------+ | array_positions(List([1,2,2,3,1,4]),Int64(2)) | +-----------------------------------------------+ | [2, 3] | +-----------------------------------------------+ ``` ###### Aliases - list_positions ##### `array_prepend` Prepends an element to the beginning of an array. ```sql array_prepend(element, array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to prepend to the array. ###### Example ```sql > select array_prepend(1, [2, 3, 4]); +---------------------------------------+ | array_prepend(Int64(1),List([2,3,4])) | +---------------------------------------+ | [1, 2, 3, 4] | +---------------------------------------+ ``` ###### Aliases - list_prepend - array_push_front - list_push_front ##### `array_push_back` _Alias of [array_append](#array_append)._ ##### `array_push_front` _Alias of [array_prepend](#array_prepend)._ ##### `array_remove` Removes the first element from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries. ```sql array_remove(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to be removed from the array. ###### Example ```sql > select array_remove([1, 2, 2, 3, 2, 1, 4], 2); +----------------------------------------------+ | array_remove(List([1,2,2,3,2,1,4]),Int64(2)) | +----------------------------------------------+ | [1, 2, 3, 2, 1, 4] | +----------------------------------------------+ > select array_remove([1, 2, NULL, 2, 4], 2); +---------------------------------------------------+ | array_remove(List([1,2,NULL,2,4]),Int64(2)) | +---------------------------------------------------+ | [1, NULL, 2, 4] | +---------------------------------------------------+ ``` ###### Aliases - list_remove ##### `array_remove_all` Removes all elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries. ```sql array_remove_all(array, element) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to be removed from the array. ###### Example ```sql > select array_remove_all([1, 2, 2, 3, 2, 1, 4], 2); +--------------------------------------------------+ | array_remove_all(List([1,2,2,3,2,1,4]),Int64(2)) | +--------------------------------------------------+ | [1, 3, 1, 4] | +--------------------------------------------------+ > select array_remove_all([1, 2, NULL, 2, 4], 2); +-----------------------------------------------------+ | array_remove_all(List([1,2,NULL,2,4]),Int64(2)) | +-----------------------------------------------------+ | [1, NULL, 4] | +-----------------------------------------------------+ ``` ###### Aliases - list_remove_all ##### `array_remove_n` Removes the first `max` elements from the array equal to the given value. NULL elements already in the array are preserved when removing a non-NULL value. If `element` evaluates to NULL, the result is NULL rather than removing NULL entries. ```sql array_remove_n(array, element, max) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **element**: Element to be removed from the array. - **max**: Number of first occurrences to remove. ###### Example ```sql > select array_remove_n([1, 2, 2, 3, 2, 1, 4], 2, 2); +---------------------------------------------------------+ | array_remove_n(List([1,2,2,3,2,1,4]),Int64(2),Int64(2)) | +---------------------------------------------------------+ | [1, 3, 2, 1, 4] | +---------------------------------------------------------+ > select array_remove_n([1, 2, NULL, 2, 4], 2, 2); +----------------------------------------------------------+ | array_remove_n(List([1,2,NULL,2,4]),Int64(2),Int64(2)) | +----------------------------------------------------------+ | [1, NULL, 4] | +----------------------------------------------------------+ ``` ###### Aliases - list_remove_n ##### `array_repeat` Returns an array containing element `count` times. ```sql array_repeat(element, count) ``` ###### Arguments - **element**: Element expression. Can be a constant, column, or function, and any combination of array operators. - **count**: Value of how many times to repeat the element. ###### Example ```sql > select array_repeat(1, 3); +---------------------------------+ | array_repeat(Int64(1),Int64(3)) | +---------------------------------+ | [1, 1, 1] | +---------------------------------+ > select array_repeat([1, 2], 2); +------------------------------------+ | array_repeat(List([1,2]),Int64(2)) | +------------------------------------+ | [[1, 2], [1, 2]] | +------------------------------------+ ``` ###### Aliases - list_repeat ##### `array_replace` Replaces the first occurrence of the specified element with another specified element. ```sql array_replace(array, from, to) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **from**: Initial element. - **to**: Final element. ###### Example ```sql > select array_replace([1, 2, 2, 3, 2, 1, 4], 2, 5); +--------------------------------------------------------+ | array_replace(List([1,2,2,3,2,1,4]),Int64(2),Int64(5)) | +--------------------------------------------------------+ | [1, 5, 2, 3, 2, 1, 4] | +--------------------------------------------------------+ ``` ###### Aliases - list_replace ##### `array_replace_all` Replaces all occurrences of the specified element with another specified element. ```sql array_replace_all(array, from, to) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **from**: Initial element. - **to**: Final element. ###### Example ```sql > select array_replace_all([1, 2, 2, 3, 2, 1, 4], 2, 5); +------------------------------------------------------------+ | array_replace_all(List([1,2,2,3,2,1,4]),Int64(2),Int64(5)) | +------------------------------------------------------------+ | [1, 5, 5, 3, 5, 1, 4] | +------------------------------------------------------------+ ``` ###### Aliases - list_replace_all ##### `array_replace_n` Replaces the first `max` occurrences of the specified element with another specified element. ```sql array_replace_n(array, from, to, max) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **from**: Initial element. - **to**: Final element. - **max**: Number of first occurrences to replace. ###### Example ```sql > select array_replace_n([1, 2, 2, 3, 2, 1, 4], 2, 5, 2); +-------------------------------------------------------------------+ | array_replace_n(List([1,2,2,3,2,1,4]),Int64(2),Int64(5),Int64(2)) | +-------------------------------------------------------------------+ | [1, 5, 5, 3, 2, 1, 4] | +-------------------------------------------------------------------+ ``` ###### Aliases - list_replace_n ##### `array_resize` Resizes the list to contain size elements. Initializes new elements with value or empty if value is not set. ```sql array_resize(array, size, value) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **size**: New size of given array. - **value**: Defines new elements' value or empty if value is not set. ###### Example ```sql > select array_resize([1, 2, 3], 5, 0); +-------------------------------------+ | array_resize(List([1,2,3],5,0)) | +-------------------------------------+ | [1, 2, 3, 0, 0] | +-------------------------------------+ ``` ###### Aliases - list_resize ##### `array_reverse` Returns the array with the order of the elements reversed. ```sql array_reverse(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_reverse([1, 2, 3, 4]); +------------------------------------------------------------+ | array_reverse(List([1, 2, 3, 4])) | +------------------------------------------------------------+ | [4, 3, 2, 1] | +------------------------------------------------------------+ ``` ###### Aliases - list_reverse ##### `array_slice` Returns a slice of the array based on 1-indexed start and end positions. ```sql array_slice(array, begin, end) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **begin**: Index of the first element. If negative, it counts backward from the end of the array. - **end**: Index of the last element. If negative, it counts backward from the end of the array. - **stride**: Stride of the array slice. The default is 1. ###### Example ```sql > select array_slice([1, 2, 3, 4, 5, 6, 7, 8], 3, 6); +--------------------------------------------------------+ | array_slice(List([1,2,3,4,5,6,7,8]),Int64(3),Int64(6)) | +--------------------------------------------------------+ | [3, 4, 5, 6] | +--------------------------------------------------------+ ``` ###### Aliases - list_slice ##### `array_sort` Sort array. ```sql array_sort(array, desc, nulls_first) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **desc**: Whether to sort in ascending (`ASC`) or descending (`DESC`) order. The default is `ASC`. - **nulls_first**: Whether to sort nulls first (`NULLS FIRST`) or last (`NULLS LAST`). The default is `NULLS FIRST`. ###### Example ```sql > select array_sort([3, 1, 2]); +-----------------------------+ | array_sort(List([3,1,2])) | +-----------------------------+ | [1, 2, 3] | +-----------------------------+ ``` ###### Aliases - list_sort ##### `array_to_string` Converts each element to its text representation. ```sql array_to_string(array, delimiter[, null_string]) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **delimiter**: Array element separator. - **null_string**: Optional. String to use for null values in the output. If not provided, nulls will be omitted. ###### Example ```sql > select array_to_string([[1, 2, 3, 4], [5, 6, 7, 8]], ','); +----------------------------------------------------+ | array_to_string(List([1,2,3,4,5,6,7,8]),Utf8(",")) | +----------------------------------------------------+ | 1,2,3,4,5,6,7,8 | +----------------------------------------------------+ ``` ###### Aliases - list_to_string - array_join - list_join ##### `array_union` Returns an array of elements that are present in both arrays (all elements from both arrays) without duplicates. ```sql array_union(array1, array2) ``` ###### Arguments - **array1**: Array expression. Can be a constant, column, or function, and any combination of array operators. - **array2**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select array_union([1, 2, 3, 4], [5, 6, 3, 4]); +----------------------------------------------------+ | array_union([1, 2, 3, 4], [5, 6, 3, 4]); | +----------------------------------------------------+ | [1, 2, 3, 4, 5, 6] | +----------------------------------------------------+ > select array_union([1, 2, 3, 4], [5, 6, 7, 8]); +----------------------------------------------------+ | array_union([1, 2, 3, 4], [5, 6, 7, 8]); | +----------------------------------------------------+ | [1, 2, 3, 4, 5, 6, 7, 8] | +----------------------------------------------------+ ``` ###### Aliases - list_union ##### `arrays_overlap` _Alias of [array_has_any](#array_has_any)._ ##### `arrays_zip` Returns an array of structs created by combining the elements of each input array at the same index. If the arrays have different lengths, shorter arrays are padded with NULLs. ```sql arrays_zip(array1[, ..., array_n]) ``` ###### Arguments - **array1**: First array expression. - **array_n**: Optional additional array expressions. ###### Example ```sql > select arrays_zip([1, 2, 3]); +---------------------------------------------------+ | arrays_zip([1, 2, 3]) | +---------------------------------------------------+ | [{1: 1}, {1: 2}, {1: 3}] | +---------------------------------------------------+ > select arrays_zip([1, 2], [3, 4, 5]); +---------------------------------------------------+ | arrays_zip([1, 2], [3, 4, 5]) | +---------------------------------------------------+ | [{1: 1, 2: 3}, {1: 2, 2: 4}, {1: NULL, 2: 5}] | +---------------------------------------------------+ ``` ###### Aliases - list_zip ##### `cardinality` Returns the total number of elements in the array. ```sql cardinality(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select cardinality([[1, 2, 3, 4], [5, 6, 7, 8]]); +--------------------------------------+ | cardinality(List([1,2,3,4,5,6,7,8])) | +--------------------------------------+ | 8 | +--------------------------------------+ ``` ##### `empty` Returns 1 for an empty array or 0 for a non-empty array. ```sql empty(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select empty([1]); +------------------+ | empty(List([1])) | +------------------+ | 0 | +------------------+ ``` ###### Aliases - array_empty - list_empty ##### `flatten` Converts an array of arrays to a flat array. - Applies to any depth of nested arrays - Does not change arrays that are already flat The flattened array contains all the elements from all source arrays. ```sql flatten(array) ``` ###### Arguments - **array**: Array expression. Can be a constant, column, or function, and any combination of array operators. ###### Example ```sql > select flatten([[1, 2], [3, 4]]); +------------------------------+ | flatten(List([1,2], [3,4])) | +------------------------------+ | [1, 2, 3, 4] | +------------------------------+ ``` ##### `generate_series` Similar to the range function, but it includes the upper bound. ```sql generate_series(stop) generate_series(start, stop[, step]) ``` ###### Arguments - **start**: Start of the series. Ints, timestamps, dates or string types that can be coerced to Date32 are supported. - **end**: End of the series (included). Type must be the same as start. - **step**: Increase by step (can not be 0). Steps less than a day are supported only for timestamp ranges. ###### Example ```sql > select generate_series(1,3); +------------------------------------+ | generate_series(Int64(1),Int64(3)) | +------------------------------------+ | [1, 2, 3] | +------------------------------------+ ``` ##### `list_any_value` _Alias of [array_any_value](#array_any_value)._ ##### `list_append` _Alias of [array_append](#array_append)._ ##### `list_cat` _Alias of [array_concat](#array_concat)._ ##### `list_concat` _Alias of [array_concat](#array_concat)._ ##### `list_contains` _Alias of [array_has](#array_has)._ ##### `list_dims` _Alias of [array_dims](#array_dims)._ ##### `list_distance` _Alias of [array_distance](#array_distance)._ ##### `list_distinct` _Alias of [array_distinct](#array_distinct)._ ##### `list_element` _Alias of [array_element](#array_element)._ ##### `list_empty` _Alias of [empty](#empty)._ ##### `list_except` _Alias of [array_except](#array_except)._ ##### `list_extract` _Alias of [array_element](#array_element)._ ##### `list_has` _Alias of [array_has](#array_has)._ ##### `list_has_all` _Alias of [array_has_all](#array_has_all)._ ##### `list_has_any` _Alias of [array_has_any](#array_has_any)._ ##### `list_indexof` _Alias of [array_position](#array_position)._ ##### `list_intersect` _Alias of [array_intersect](#array_intersect)._ ##### `list_join` _Alias of [array_to_string](#array_to_string)._ ##### `list_length` _Alias of [array_length](#array_length)._ ##### `list_max` _Alias of [array_max](#array_max)._ ##### `list_ndims` _Alias of [array_ndims](#array_ndims)._ ##### `list_pop_back` _Alias of [array_pop_back](#array_pop_back)._ ##### `list_pop_front` _Alias of [array_pop_front](#array_pop_front)._ ##### `list_position` _Alias of [array_position](#array_position)._ ##### `list_positions` _Alias of [array_positions](#array_positions)._ ##### `list_prepend` _Alias of [array_prepend](#array_prepend)._ ##### `list_push_back` _Alias of [array_append](#array_append)._ ##### `list_push_front` _Alias of [array_prepend](#array_prepend)._ ##### `list_remove` _Alias of [array_remove](#array_remove)._ ##### `list_remove_all` _Alias of [array_remove_all](#array_remove_all)._ ##### `list_remove_n` _Alias of [array_remove_n](#array_remove_n)._ ##### `list_repeat` _Alias of [array_repeat](#array_repeat)._ ##### `list_replace` _Alias of [array_replace](#array_replace)._ ##### `list_replace_all` _Alias of [array_replace_all](#array_replace_all)._ ##### `list_replace_n` _Alias of [array_replace_n](#array_replace_n)._ ##### `list_resize` _Alias of [array_resize](#array_resize)._ ##### `list_reverse` _Alias of [array_reverse](#array_reverse)._ ##### `list_slice` _Alias of [array_slice](#array_slice)._ ##### `list_sort` _Alias of [array_sort](#array_sort)._ ##### `list_to_string` _Alias of [array_to_string](#array_to_string)._ ##### `list_union` _Alias of [array_union](#array_union)._ ##### `list_zip` _Alias of [arrays_zip](#arrays_zip)._ ##### `make_array` Returns an array using the specified input expressions. ```sql make_array(expression1[, ..., expression_n]) ``` ###### Arguments - **expression_n**: Expression to include in the output array. Can be a constant, column, or function, and any combination of arithmetic or string operators. ###### Example ```sql > select make_array(1, 2, 3, 4, 5); +----------------------------------------------------------+ | make_array(Int64(1),Int64(2),Int64(3),Int64(4),Int64(5)) | +----------------------------------------------------------+ | [1, 2, 3, 4, 5] | +----------------------------------------------------------+ ``` ###### Aliases - make_list ##### `make_list` _Alias of [make_array](#make_array)._ ##### `range` Returns an Arrow array between start and stop with step. The range start..end contains all values with start <= x < end. It is empty if start >= end. Step cannot be 0. ```sql range(stop) range(start, stop[, step]) ``` ###### Arguments - **start**: Start of the range. Ints, timestamps, dates or string types that can be coerced to Date32 are supported. - **end**: End of the range (not included). Type must be the same as start. - **step**: Increase by step (cannot be 0). Steps less than a day are supported only for timestamp ranges. ###### Example ```sql > select range(2, 10, 3); +-----------------------------------+ | range(Int64(2),Int64(10),Int64(3))| +-----------------------------------+ | [2, 5, 8] | +-----------------------------------+ > select range(DATE '1992-09-01', DATE '1993-03-01', INTERVAL '1' MONTH); +--------------------------------------------------------------------------+ | range(DATE '1992-09-01', DATE '1993-03-01', INTERVAL '1' MONTH) | +--------------------------------------------------------------------------+ | [1992-09-01, 1992-10-01, 1992-11-01, 1992-12-01, 1993-01-01, 1993-02-01] | +--------------------------------------------------------------------------+ ``` ##### `string_to_array` Splits a string into an array of substrings based on a delimiter. Any substrings matching the optional `null_str` argument are replaced with NULL. ```sql string_to_array(str, delimiter[, null_str]) ``` ###### Arguments - **str**: String expression to split. - **delimiter**: Delimiter string to split on. - **null_str**: Substring values to be replaced with `NULL`. ###### Example ```sql > select string_to_array('abc##def', '##'); +-----------------------------------+ | string_to_array(Utf8('abc##def')) | +-----------------------------------+ | ['abc', 'def'] | +-----------------------------------+ > select string_to_array('abc def', ' ', 'def'); +---------------------------------------------+ | string_to_array(Utf8('abc def'), Utf8(' '), Utf8('def')) | +---------------------------------------------+ | ['abc', NULL] | +---------------------------------------------+ ``` ###### Aliases - string_to_list ##### `string_to_list` _Alias of [string_to_array](#string_to_array)._ ### Struct Functions - [named_struct](#named_struct) - [row](#row) - [struct](#struct) ##### `named_struct` Returns an Arrow struct using the specified name and input expressions pairs. For information on comparing and ordering struct values (including `NULL` handling), see [Comparison and Ordering](df-functions/struct_coercion.md#comparison-and-ordering). ```sql named_struct(expression1_name, expression1_input[, ..., expression_n_name, expression_n_input]) ``` ###### Arguments - **expression_n_name**: Name of the column field. Must be a constant string. - **expression_n_input**: Expression to include in the output struct. Can be a constant, column, or function, and any combination of arithmetic or string operators. ###### Example For example, this query converts two columns `a` and `b` to a single column with a struct type of fields `field_a` and `field_b`: ```sql > select * from t; +---+---+ | a | b | +---+---+ | 1 | 2 | | 3 | 4 | +---+---+ > select named_struct('field_a', a, 'field_b', b) from t; +-------------------------------------------------------+ | named_struct(Utf8("field_a"),t.a,Utf8("field_b"),t.b) | +-------------------------------------------------------+ | {field_a: 1, field_b: 2} | | {field_a: 3, field_b: 4} | +-------------------------------------------------------+ ``` ##### `row` _Alias of [struct](#struct)._ ##### `struct` Returns an Arrow struct using the specified input expressions optionally named. Fields in the returned struct use the optional name or the `cN` naming convention. For example: `c0`, `c1`, `c2`, etc. For information on comparing and ordering struct values (including `NULL` handling), see [Comparison and Ordering](df-functions/struct_coercion.md#comparison-and-ordering). ```sql struct(expression1[, ..., expression_n]) ``` ###### Arguments - **expression1, expression_n**: Expression to include in the output struct. Can be a constant, column, or function, any combination of arithmetic or string operators. ###### Example For example, this query converts two columns `a` and `b` to a single column with a struct type of fields `field_a` and `c1`: ```sql > select * from t; +---+---+ | a | b | +---+---+ | 1 | 2 | | 3 | 4 | +---+---+ -- use default names `c0`, `c1` > select struct(a, b) from t; +-----------------+ | struct(t.a,t.b) | +-----------------+ | {c0: 1, c1: 2} | | {c0: 3, c1: 4} | +-----------------+ -- name the first field `field_a` select struct(a as field_a, b) from t; +--------------------------------------------------+ | named_struct(Utf8("field_a"),t.a,Utf8("c1"),t.b) | +--------------------------------------------------+ | {field_a: 1, c1: 2} | | {field_a: 3, c1: 4} | +--------------------------------------------------+ ``` ###### Aliases - row ### Map Functions - [element_at](#element_at) - [map](#map) - [map_entries](#map_entries) - [map_extract](#map_extract) - [map_keys](#map_keys) - [map_values](#map_values) ##### `element_at` _Alias of [map_extract](#map_extract)._ ##### `map` Returns an Arrow map with the specified key-value pairs. The `make_map` function creates a map from two lists: one for keys and one for values. Each key must be unique and non-null. ```sql map(key, value) map(key: value) make_map(['key1', 'key2'], ['value1', 'value2']) ``` ###### Arguments - **key**: For `map`: Expression to be used for key. Can be a constant, column, function, or any combination of arithmetic or string operators. For `make_map`: The list of keys to be used in the map. Each key must be unique and non-null. - **value**: For `map`: Expression to be used for value. Can be a constant, column, function, or any combination of arithmetic or string operators. For `make_map`: The list of values to be mapped to the corresponding keys. ###### Example ```sql -- Using map function SELECT MAP('type', 'test'); ---- {type: test} SELECT MAP(['POST', 'HEAD', 'PATCH'], [41, 33, null]); ---- {POST: 41, HEAD: 33, PATCH: NULL} SELECT MAP([[1,2], [3,4]], ['a', 'b']); ---- {[1, 2]: a, [3, 4]: b} SELECT MAP { 'a': 1, 'b': 2 }; ---- {a: 1, b: 2} -- Using make_map function SELECT MAKE_MAP(['POST', 'HEAD'], [41, 33]); ---- {POST: 41, HEAD: 33} SELECT MAKE_MAP(['key1', 'key2'], ['value1', null]); ---- {key1: value1, key2: } ``` ##### `map_entries` Returns a list of all entries in the map. ```sql map_entries(map) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. ###### Example ```sql SELECT map_entries(MAP {'a': 1, 'b': NULL, 'c': 3}); ---- [{'key': a, 'value': 1}, {'key': b, 'value': NULL}, {'key': c, 'value': 3}] SELECT map_entries(map([100, 5], [42, 43])); ---- [{'key': 100, 'value': 42}, {'key': 5, 'value': 43}] ``` ##### `map_extract` Returns a list containing the value for the given key or an empty list if the key is not present in the map. ```sql map_extract(map, key) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. - **key**: Key to extract from the map. Can be a constant, column, or function, any combination of arithmetic or string operators, or a named expression of the previously listed. ###### Example ```sql SELECT map_extract(MAP {'a': 1, 'b': NULL, 'c': 3}, 'a'); ---- [1] SELECT map_extract(MAP {1: 'one', 2: 'two'}, 2); ---- ['two'] SELECT map_extract(MAP {'x': 10, 'y': NULL, 'z': 30}, 'y'); ---- [] ``` ###### Aliases - element_at ##### `map_keys` Returns a list of all keys in the map. ```sql map_keys(map) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. ###### Example ```sql SELECT map_keys(MAP {'a': 1, 'b': NULL, 'c': 3}); ---- [a, b, c] SELECT map_keys(map([100, 5], [42, 43])); ---- [100, 5] ``` ##### `map_values` Returns a list of all values in the map. ```sql map_values(map) ``` ###### Arguments - **map**: Map expression. Can be a constant, column, or function, and any combination of map operators. ###### Example ```sql SELECT map_values(MAP {'a': 1, 'b': NULL, 'c': 3}); ---- [1, , 3] SELECT map_values(map([100, 5], [42, 43])); ---- [42, 43] ``` ### Hashing Functions - [digest](#digest) - [md5](#md5) - [sha224](#sha224) - [sha256](#sha256) - [sha384](#sha384) - [sha512](#sha512) ##### `digest` Computes the binary hash of an expression using the specified algorithm. ```sql digest(expression, algorithm) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. - **algorithm**: String expression specifying algorithm to use. Must be one of: - md5 - sha224 - sha256 - sha384 - sha512 - blake2s - blake2b - blake3 ###### Example ```sql > select digest('foo', 'sha256'); +------------------------------------------------------------------+ | digest(Utf8("foo"),Utf8("sha256")) | +------------------------------------------------------------------+ | 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae | +------------------------------------------------------------------+ ``` ##### `md5` Computes an MD5 128-bit checksum for a string expression. ```sql md5(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select md5('foo'); +----------------------------------+ | md5(Utf8("foo")) | +----------------------------------+ | acbd18db4cc2f85cedef654fccc4a4d8 | +----------------------------------+ ``` ##### `sha224` Computes the SHA-224 hash of a binary string. ```sql sha224(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha224('foo'); +----------------------------------------------------------+ | sha224(Utf8("foo")) | +----------------------------------------------------------+ | 0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db | +----------------------------------------------------------+ ``` ##### `sha256` Computes the SHA-256 hash of a binary string. ```sql sha256(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha256('foo'); +------------------------------------------------------------------+ | sha256(Utf8("foo")) | +------------------------------------------------------------------+ | 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae | +------------------------------------------------------------------+ ``` ##### `sha384` Computes the SHA-384 hash of a binary string. ```sql sha384(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha384('foo'); +--------------------------------------------------------------------------------------------------+ | sha384(Utf8("foo")) | +--------------------------------------------------------------------------------------------------+ | 98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb | +--------------------------------------------------------------------------------------------------+ ``` ##### `sha512` Computes the SHA-512 hash of a binary string. ```sql sha512(expression) ``` ###### Arguments - **expression**: String expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select sha512('foo'); +----------------------------------------------------------------------------------------------------------------------------------+ | sha512(Utf8("foo")) | +----------------------------------------------------------------------------------------------------------------------------------+ | f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7 | +----------------------------------------------------------------------------------------------------------------------------------+ ``` ### Union Functions Functions to work with the union data type, also know as tagged unions, variant types, enums or sum types. Note: Not related to the SQL UNION operator - [union_extract](#union_extract) - [union_tag](#union_tag) ##### `union_extract` Returns the value of the given field in the union when selected, or NULL otherwise. ```sql union_extract(union, field_name) ``` ###### Arguments - **union**: Union expression to operate on. Can be a constant, column, or function, and any combination of operators. - **field_name**: String expression to operate on. Must be a constant. ###### Example ```sql ❯ select union_column, union_extract(union_column, 'a'), union_extract(union_column, 'b') from table_with_union; +--------------+----------------------------------+----------------------------------+ | union_column | union_extract(union_column, 'a') | union_extract(union_column, 'b') | +--------------+----------------------------------+----------------------------------+ | {a=1} | 1 | | | {b=3.0} | | 3.0 | | {a=4} | 4 | | | {b=} | | | | {a=} | | | +--------------+----------------------------------+----------------------------------+ ``` ##### `union_tag` Returns the name of the currently selected field in the union ```sql union_tag(union_expression) ``` ###### Arguments - **union**: Union expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql ❯ select union_column, union_tag(union_column) from table_with_union; +--------------+-------------------------+ | union_column | union_tag(union_column) | +--------------+-------------------------+ | {a=1} | a | | {b=3.0} | b | | {a=4} | a | | {b=} | b | | {a=} | a | +--------------+-------------------------+ ``` ### Other Functions - [arrow_cast](#arrow_cast) - [arrow_metadata](#arrow_metadata) - [arrow_try_cast](#arrow_try_cast) - [arrow_typeof](#arrow_typeof) - [get_field](#get_field) - [version](#version) ##### `arrow_cast` Casts a value to a specific Arrow data type. ```sql arrow_cast(expression, datatype) ``` ###### Arguments - **expression**: Expression to cast. The expression can be a constant, column, or function, and any combination of operators. - **datatype**: [Arrow data type](https://docs.rs/arrow/latest/arrow/datatypes/enum.DataType.html) name to cast to, as a string. The format is the same as that returned by [`arrow_typeof`] ###### Example ```sql > select arrow_cast(-5, 'Int8') as a, arrow_cast('foo', 'Dictionary(Int32, Utf8)') as b, arrow_cast('bar', 'LargeUtf8') as c; +----+-----+-----+ | a | b | c | +----+-----+-----+ | -5 | foo | bar | +----+-----+-----+ > select arrow_cast('2023-01-02T12:53:02', 'Timestamp(µs, "+08:00")') as d, arrow_cast('2023-01-02T12:53:02', 'Timestamp(µs)') as e; +---------------------------+---------------------+ | d | e | +---------------------------+---------------------+ | 2023-01-02T12:53:02+08:00 | 2023-01-02T12:53:02 | +---------------------------+---------------------+ ``` ##### `arrow_metadata` Returns the metadata of the input expression. If a key is provided, returns the value for that key. If no key is provided, returns a Map of all metadata. ```sql arrow_metadata(expression[, key]) ``` ###### Arguments - **expression**: The expression to retrieve metadata from. Can be a column or other expression. - **key**: Optional. The specific metadata key to retrieve. ###### Example ```sql > select arrow_metadata(col) from table; +----------------------------+ | arrow_metadata(table.col) | +----------------------------+ | {k: v} | +----------------------------+ > select arrow_metadata(col, 'k') from table; +-------------------------------+ | arrow_metadata(table.col, 'k')| +-------------------------------+ | v | +-------------------------------+ ``` ##### `arrow_try_cast` Casts a value to a specific Arrow data type, returning NULL if the cast fails. ```sql arrow_try_cast(expression, datatype) ``` ###### Arguments - **expression**: Expression to cast. The expression can be a constant, column, or function, and any combination of operators. - **datatype**: [Arrow data type](https://docs.rs/arrow/latest/arrow/datatypes/enum.DataType.html) name to cast to, as a string. The format is the same as that returned by [`arrow_typeof`] ###### Example ```sql > select arrow_try_cast('123', 'Int64') as a, arrow_try_cast('not_a_number', 'Int64') as b; +-----+------+ | a | b | +-----+------+ | 123 | NULL | +-----+------+ ``` ##### `arrow_typeof` Returns the name of the underlying [Arrow data type](https://docs.rs/arrow/latest/arrow/datatypes/enum.DataType.html) of the expression. ```sql arrow_typeof(expression) ``` ###### Arguments - **expression**: Expression to evaluate. The expression can be a constant, column, or function, and any combination of operators. ###### Example ```sql > select arrow_typeof('foo'), arrow_typeof(1); +---------------------------+------------------------+ | arrow_typeof(Utf8("foo")) | arrow_typeof(Int64(1)) | +---------------------------+------------------------+ | Utf8 | Int64 | +---------------------------+------------------------+ ``` ##### `get_field` Returns a field within a map or a struct with the given key. Supports nested field access by providing multiple field names. Note: most users invoke `get_field` indirectly via field access syntax such as `my_struct_col['field_name']` which results in a call to `get_field(my_struct_col, 'field_name')`. Nested access like `my_struct['a']['b']` is optimized to a single call: `get_field(my_struct, 'a', 'b')`. ```sql get_field(expression, field_name[, field_name2, ...]) ``` ###### Arguments - **expression**: The map or struct to retrieve a field from. - **field_name**: The field name(s) to access, in order for nested access. Must evaluate to strings. ###### Example ```sql > -- Access a field from a struct column > create table test( struct_col) as values ({name: 'Alice', age: 30}), ({name: 'Bob', age: 25}); > select struct_col from test; +-----------------------------+ | struct_col | +-----------------------------+ | {name: Alice, age: 30} | | {name: Bob, age: 25} | +-----------------------------+ > select struct_col['name'] as name from test; +-------+ | name | +-------+ | Alice | | Bob | +-------+ > -- Nested field access with multiple arguments > create table test(struct_col) as values ({outer: {inner_val: 42}}); > select struct_col['outer']['inner_val'] as result from test; +--------+ | result | +--------+ | 42 | +--------+ ``` ##### `version` Returns the version of DataFusion. ```sql version() ``` ###### Example ```sql > select version(); +--------------------------------------------+ | version() | +--------------------------------------------+ | Apache DataFusion 42.0.0, aarch64 on macos | +--------------------------------------------+ ``` ## Aggregate Functions Aggregate functions operate on a set of values to compute a single result. ### Filter clause Aggregate functions support the SQL `FILTER (WHERE ...)` clause to restrict which input rows contribute to the aggregate result. ```sql function([exprs]) FILTER (WHERE condition) ``` Example: ```sql SELECT sum(salary) FILTER (WHERE salary > 0) AS sum_positive_salaries, count(*) FILTER (WHERE active) AS active_count FROM employees; ``` Note: When no rows pass the filter, `COUNT` returns `0` while `SUM`/`AVG`/`MIN`/`MAX` return `NULL`. ### WITHIN GROUP / Ordered-set aggregates Some aggregate functions accept the SQL `WITHIN GROUP (ORDER BY ...)` clause to specify the ordering the aggregate relies on. In DataFusion this is opt-in: only aggregate functions whose implementation returns `true` from `AggregateUDFImpl::supports_within_group_clause()` accept the `WITHIN GROUP` clause. Attempting to use `WITHIN GROUP` with a regular aggregate (for example, `SELECT SUM(x) WITHIN GROUP (ORDER BY x)`) will fail during planning with an error: "WITHIN GROUP is only supported for ordered-set aggregate functions". Currently, the built-in aggregate functions that support `WITHIN GROUP` are: - `percentile_cont` — exact percentile aggregate (also available as `percentile_cont(column, percentile)`) - `approx_percentile_cont` — approximate percentile using the t-digest algorithm - `approx_percentile_cont_with_weight` — approximate weighted percentile using the t-digest algorithm Note: rank-like functions such as `rank()`, `dense_rank()`, and `percent_rank()` are window functions and use the `OVER (...)` clause; they are not ordered-set aggregates that accept `WITHIN GROUP` in DataFusion. Example (ordered-set aggregate): ```sql percentile_cont(0.5) WITHIN GROUP (ORDER BY value) ``` Example (invalid usage — planner will error): ```sql -- This will fail: SUM is not an ordered-set aggregate SELECT SUM(x) WITHIN GROUP (ORDER BY x) FROM t; ``` ### General Functions - [array_agg](#array_agg) - [avg](#avg) - [bit_and](#bit_and) - [bit_or](#bit_or) - [bit_xor](#bit_xor) - [bool_and](#bool_and) - [bool_or](#bool_or) - [count](#count) - [first_value](#first_value) - [grouping](#grouping) - [last_value](#last_value) - [max](#max) - [mean](#mean) - [median](#median) - [min](#min) - [percentile_cont](#percentile_cont) - [quantile_cont](#quantile_cont) - [string_agg](#string_agg) - [sum](#sum) - [var](#var) - [var_pop](#var_pop) - [var_population](#var_population) - [var_samp](#var_samp) - [var_sample](#var_sample) ##### `array_agg` Returns an array created from the expression elements. If ordering is required, elements are inserted in the specified order. This aggregation function can only mix DISTINCT and ORDER BY if the ordering expression is exactly the same as the argument expression. ```sql array_agg(expression [ORDER BY expression]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT array_agg(column_name ORDER BY other_column) FROM table_name; +-----------------------------------------------+ | array_agg(column_name ORDER BY other_column) | +-----------------------------------------------+ | [element1, element2, element3] | +-----------------------------------------------+ > SELECT array_agg(DISTINCT column_name ORDER BY column_name) FROM table_name; +--------------------------------------------------------+ | array_agg(DISTINCT column_name ORDER BY column_name) | +--------------------------------------------------------+ | [element1, element2, element3] | +--------------------------------------------------------+ ``` ##### `avg` Returns the average of numeric values in the specified column. ```sql avg(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT avg(column_name) FROM table_name; +---------------------------+ | avg(column_name) | +---------------------------+ | 42.75 | +---------------------------+ ``` ###### Aliases - mean ##### `bit_and` Computes the bitwise AND of all non-null input values. ```sql bit_and(expression) ``` ###### Arguments - **expression**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `bit_or` Computes the bitwise OR of all non-null input values. ```sql bit_or(expression) ``` ###### Arguments - **expression**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `bit_xor` Computes the bitwise exclusive OR of all non-null input values. ```sql bit_xor(expression) ``` ###### Arguments - **expression**: Integer expression to operate on. Can be a constant, column, or function, and any combination of operators. ##### `bool_and` Returns true if all non-null input values are true, otherwise false. ```sql bool_and(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT bool_and(column_name) FROM table_name; +----------------------------+ | bool_and(column_name) | +----------------------------+ | true | +----------------------------+ ``` ##### `bool_or` Returns true if all non-null input values are true, otherwise false. ```sql bool_and(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT bool_and(column_name) FROM table_name; +----------------------------+ | bool_and(column_name) | +----------------------------+ | true | +----------------------------+ ``` ##### `count` Returns the number of non-null values in the specified column. To include null values in the total count, use `count(*)`. ```sql count(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT count(column_name) FROM table_name; +-----------------------+ | count(column_name) | +-----------------------+ | 100 | +-----------------------+ > SELECT count(*) FROM table_name; +------------------+ | count(*) | +------------------+ | 120 | +------------------+ ``` ##### `first_value` Returns the first element in an aggregation group according to the requested ordering. If no ordering is given, returns an arbitrary element from the group. ```sql first_value(expression [ORDER BY expression]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT first_value(column_name ORDER BY other_column) FROM table_name; +-----------------------------------------------+ | first_value(column_name ORDER BY other_column)| +-----------------------------------------------+ | first_element | +-----------------------------------------------+ ``` ##### `grouping` Returns 1 if the data is aggregated across the specified column, or 0 if it is not aggregated in the result set. ```sql grouping(expression) ``` ###### Arguments - **expression**: Expression to evaluate whether data is aggregated across the specified column. Can be a constant, column, or function. ###### Example ```sql > SELECT column_name, GROUPING(column_name) AS group_column FROM table_name GROUP BY GROUPING SETS ((column_name), ()); +-------------+-------------+ | column_name | group_column | +-------------+-------------+ | value1 | 0 | | value2 | 0 | | NULL | 1 | +-------------+-------------+ ``` ##### `last_value` Returns the last element in an aggregation group according to the requested ordering. If no ordering is given, returns an arbitrary element from the group. ```sql last_value(expression [ORDER BY expression]) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT last_value(column_name ORDER BY other_column) FROM table_name; +-----------------------------------------------+ | last_value(column_name ORDER BY other_column) | +-----------------------------------------------+ | last_element | +-----------------------------------------------+ ``` ##### `max` Returns the maximum value in the specified column. ```sql max(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT max(column_name) FROM table_name; +----------------------+ | max(column_name) | +----------------------+ | 150 | +----------------------+ ``` ##### `mean` _Alias of [avg](#avg)._ ##### `median` Returns the median value in the specified column. ```sql median(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT median(column_name) FROM table_name; +----------------------+ | median(column_name) | +----------------------+ | 45.5 | +----------------------+ ``` ##### `min` Returns the minimum value in the specified column. ```sql min(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT min(column_name) FROM table_name; +----------------------+ | min(column_name) | +----------------------+ | 12 | +----------------------+ ``` ##### `percentile_cont` Returns the exact percentile of input values, interpolating between values if needed. ```sql percentile_cont(percentile) WITHIN GROUP (ORDER BY expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **percentile**: Percentile to compute. Must be a float value between 0 and 1 (inclusive). ###### Example ```sql > SELECT percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) FROM table_name; +----------------------------------------------------------+ | percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) | +----------------------------------------------------------+ | 45.5 | +----------------------------------------------------------+ ``` An alternate syntax is also supported: ```sql > SELECT percentile_cont(column_name, 0.75) FROM table_name; +---------------------------------------+ | percentile_cont(column_name, 0.75) | +---------------------------------------+ | 45.5 | +---------------------------------------+ ``` ###### Aliases - quantile_cont ##### `quantile_cont` _Alias of [percentile_cont](#percentile_cont)._ ##### `string_agg` Concatenates the values of string expressions and places separator values between them. If ordering is required, strings are concatenated in the specified order. This aggregation function can only mix DISTINCT and ORDER BY if the ordering expression is exactly the same as the first argument expression. ```sql string_agg([DISTINCT] expression, delimiter [ORDER BY expression]) ``` ###### Arguments - **expression**: The string expression to concatenate. Can be a column or any valid string expression. - **delimiter**: A literal string used as a separator between the concatenated values. ###### Example ```sql > SELECT string_agg(name, ', ') AS names_list FROM employee; +--------------------------+ | names_list | +--------------------------+ | Alice, Bob, Bob, Charlie | +--------------------------+ > SELECT string_agg(name, ', ' ORDER BY name DESC) AS names_list FROM employee; +--------------------------+ | names_list | +--------------------------+ | Charlie, Bob, Bob, Alice | +--------------------------+ > SELECT string_agg(DISTINCT name, ', ' ORDER BY name DESC) AS names_list FROM employee; +--------------------------+ | names_list | +--------------------------+ | Charlie, Bob, Alice | +--------------------------+ ``` ##### `sum` Returns the sum of all values in the specified column. ```sql sum(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT sum(column_name) FROM table_name; +-----------------------+ | sum(column_name) | +-----------------------+ | 12345 | +-----------------------+ ``` ##### `var` Returns the statistical sample variance of a set of numbers. ```sql var(expression) ``` ###### Arguments - **expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Aliases - var_sample - var_samp ##### `var_pop` Returns the statistical population variance of a set of numbers. ```sql var_pop(expression) ``` ###### Arguments - **expression**: Numeric expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Aliases - var_population ##### `var_population` _Alias of [var_pop](#var_pop)._ ##### `var_samp` _Alias of [var](#var)._ ##### `var_sample` _Alias of [var](#var)._ ### Statistical Functions - [corr](#corr) - [covar](#covar) - [covar_pop](#covar_pop) - [covar_samp](#covar_samp) - [nth_value](#nth_value) - [regr_avgx](#regr_avgx) - [regr_avgy](#regr_avgy) - [regr_count](#regr_count) - [regr_intercept](#regr_intercept) - [regr_r2](#regr_r2) - [regr_slope](#regr_slope) - [regr_sxx](#regr_sxx) - [regr_sxy](#regr_sxy) - [regr_syy](#regr_syy) - [stddev](#stddev) - [stddev_pop](#stddev_pop) - [stddev_samp](#stddev_samp) ##### `corr` Returns the coefficient of correlation between two numeric values. ```sql corr(expression1, expression2) ``` ###### Arguments - **expression1**: First expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression2**: Second expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT corr(column1, column2) FROM table_name; +--------------------------------+ | corr(column1, column2) | +--------------------------------+ | 0.85 | +--------------------------------+ ``` ##### `covar` _Alias of [covar_samp](#covar_samp)._ ##### `covar_pop` Returns the sample covariance of a set of number pairs. ```sql covar_samp(expression1, expression2) ``` ###### Arguments - **expression1**: First expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression2**: Second expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT covar_samp(column1, column2) FROM table_name; +-----------------------------------+ | covar_samp(column1, column2) | +-----------------------------------+ | 8.25 | +-----------------------------------+ ``` ##### `covar_samp` Returns the sample covariance of a set of number pairs. ```sql covar_samp(expression1, expression2) ``` ###### Arguments - **expression1**: First expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression2**: Second expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT covar_samp(column1, column2) FROM table_name; +-----------------------------------+ | covar_samp(column1, column2) | +-----------------------------------+ | 8.25 | +-----------------------------------+ ``` ###### Aliases - covar ##### `nth_value` Returns the nth value in a group of values. ```sql nth_value(expression, n ORDER BY expression) ``` ###### Arguments - **expression**: The column or expression to retrieve the nth value from. - **n**: The position (nth) of the value to retrieve, based on the ordering. ###### Example ```sql > SELECT dept_id, salary, NTH_VALUE(salary, 2) OVER (PARTITION BY dept_id ORDER BY salary ASC) AS second_salary_by_dept FROM employee; +---------+--------+-------------------------+ | dept_id | salary | second_salary_by_dept | +---------+--------+-------------------------+ | 1 | 30000 | NULL | | 1 | 40000 | 40000 | | 1 | 50000 | 40000 | | 2 | 35000 | NULL | | 2 | 45000 | 45000 | +---------+--------+-------------------------+ ``` ##### `regr_avgx` Computes the average of the independent variable (input) expression_x for the non-null paired data points. ```sql regr_avgx(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table daily_sales(day int, total_sales int) as values (1,100), (2,150), (3,200), (4,NULL), (5,250); select * from daily_sales; +-----+-------------+ | day | total_sales | | --- | ----------- | | 1 | 100 | | 2 | 150 | | 3 | 200 | | 4 | NULL | | 5 | 250 | +-----+-------------+ SELECT regr_avgx(total_sales, day) AS avg_day FROM daily_sales; +----------+ | avg_day | +----------+ | 2.75 | +----------+ ``` ##### `regr_avgy` Computes the average of the dependent variable (output) expression_y for the non-null paired data points. ```sql regr_avgy(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table daily_temperature(day int, temperature int) as values (1,30), (2,32), (3, NULL), (4,35), (5,36); select * from daily_temperature; +-----+-------------+ | day | temperature | | --- | ----------- | | 1 | 30 | | 2 | 32 | | 3 | NULL | | 4 | 35 | | 5 | 36 | +-----+-------------+ -- temperature as Dependent Variable(Y), day as Independent Variable(X) SELECT regr_avgy(temperature, day) AS avg_temperature FROM daily_temperature; +-----------------+ | avg_temperature | +-----------------+ | 33.25 | +-----------------+ ``` ##### `regr_count` Counts the number of non-null paired data points. ```sql regr_count(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table daily_metrics(day int, user_signups int) as values (1,100), (2,120), (3, NULL), (4,110), (5,NULL); select * from daily_metrics; +-----+---------------+ | day | user_signups | | --- | ------------- | | 1 | 100 | | 2 | 120 | | 3 | NULL | | 4 | 110 | | 5 | NULL | +-----+---------------+ SELECT regr_count(user_signups, day) AS valid_pairs FROM daily_metrics; +-------------+ | valid_pairs | +-------------+ | 3 | +-------------+ ``` ##### `regr_intercept` Computes the y-intercept of the linear regression line. For the equation (y = kx + b), this function returns b. ```sql regr_intercept(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table weekly_performance(week int, productivity_score int) as values (1,60), (2,65), (3, 70), (4,75), (5,80); select * from weekly_performance; +------+---------------------+ | week | productivity_score | | ---- | ------------------- | | 1 | 60 | | 2 | 65 | | 3 | 70 | | 4 | 75 | | 5 | 80 | +------+---------------------+ SELECT regr_intercept(productivity_score, week) AS intercept FROM weekly_performance; +----------+ |intercept| |intercept | +----------+ | 55 | +----------+ ``` ##### `regr_r2` Computes the square of the correlation coefficient between the independent and dependent variables. ```sql regr_r2(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table weekly_performance(day int ,user_signups int) as values (1,60), (2,65), (3, 70), (4,75), (5,80); select * from weekly_performance; +-----+--------------+ | day | user_signups | +-----+--------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | | 4 | 75 | | 5 | 80 | +-----+--------------+ SELECT regr_r2(user_signups, day) AS r_squared FROM weekly_performance; +---------+ |r_squared| +---------+ | 1.0 | +---------+ ``` ##### `regr_slope` Returns the slope of the linear regression line for non-null pairs in aggregate columns. Given input column Y and X: regr_slope(Y, X) returns the slope (k in Y = k\*X + b) using minimal RSS fitting. ```sql regr_slope(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table weekly_performance(day int, user_signups int) as values (1,60), (2,65), (3, 70), (4,75), (5,80); select * from weekly_performance; +-----+--------------+ | day | user_signups | +-----+--------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | | 4 | 75 | | 5 | 80 | +-----+--------------+ SELECT regr_slope(user_signups, day) AS slope FROM weekly_performance; +--------+ | slope | +--------+ | 5.0 | +--------+ ``` ##### `regr_sxx` Computes the sum of squares of the independent variable. ```sql regr_sxx(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table study_hours(student_id int, hours int, test_score int) as values (1,2,55), (2,4,65), (3,6,75), (4,8,85), (5,10,95); select * from study_hours; +------------+-------+------------+ | student_id | hours | test_score | +------------+-------+------------+ | 1 | 2 | 55 | | 2 | 4 | 65 | | 3 | 6 | 75 | | 4 | 8 | 85 | | 5 | 10 | 95 | +------------+-------+------------+ SELECT regr_sxx(test_score, hours) AS sxx FROM study_hours; +------+ | sxx | +------+ | 40.0 | +------+ ``` ##### `regr_sxy` Computes the sum of products of paired data points. ```sql regr_sxy(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table employee_productivity(week int, productivity_score int) as values(1,60), (2,65), (3,70); select * from employee_productivity; +------+--------------------+ | week | productivity_score | +------+--------------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | +------+--------------------+ SELECT regr_sxy(productivity_score, week) AS sum_product_deviations FROM employee_productivity; +------------------------+ | sum_product_deviations | +------------------------+ | 10.0 | +------------------------+ ``` ##### `regr_syy` Computes the sum of squares of the dependent variable. ```sql regr_syy(expression_y, expression_x) ``` ###### Arguments - **expression_y**: Dependent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. - **expression_x**: Independent variable expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql create table employee_productivity(week int, productivity_score int) as values (1,60), (2,65), (3,70); select * from employee_productivity; +------+--------------------+ | week | productivity_score | +------+--------------------+ | 1 | 60 | | 2 | 65 | | 3 | 70 | +------+--------------------+ SELECT regr_syy(productivity_score, week) AS sum_squares_y FROM employee_productivity; +---------------+ | sum_squares_y | +---------------+ | 50.0 | +---------------+ ``` ##### `stddev` Returns the standard deviation of a set of numbers. ```sql stddev(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT stddev(column_name) FROM table_name; +----------------------+ | stddev(column_name) | +----------------------+ | 12.34 | +----------------------+ ``` ###### Aliases - stddev_samp ##### `stddev_pop` Returns the population standard deviation of a set of numbers. ```sql stddev_pop(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT stddev_pop(column_name) FROM table_name; +--------------------------+ | stddev_pop(column_name) | +--------------------------+ | 10.56 | +--------------------------+ ``` ##### `stddev_samp` _Alias of [stddev](#stddev)._ ### Approximate Functions - [approx_distinct](#approx_distinct) - [approx_median](#approx_median) - [approx_percentile_cont](#approx_percentile_cont) - [approx_percentile_cont_with_weight](#approx_percentile_cont_with_weight) ##### `approx_distinct` Returns the approximate number of distinct input values calculated using the HyperLogLog algorithm. ```sql approx_distinct(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT approx_distinct(column_name) FROM table_name; +-----------------------------------+ | approx_distinct(column_name) | +-----------------------------------+ | 42 | +-----------------------------------+ ``` ##### `approx_median` Returns the approximate median (50th percentile) of input values. It is an alias of `approx_percentile_cont(0.5) WITHIN GROUP (ORDER BY x)`. ```sql approx_median(expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. ###### Example ```sql > SELECT approx_median(column_name) FROM table_name; +-----------------------------------+ | approx_median(column_name) | +-----------------------------------+ | 23.5 | +-----------------------------------+ ``` ##### `approx_percentile_cont` Returns the approximate percentile of input values using the t-digest algorithm. ```sql approx_percentile_cont(percentile [, centroids]) WITHIN GROUP (ORDER BY expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **percentile**: Percentile to compute. Must be a float value between 0 and 1 (inclusive). - **centroids**: Number of centroids to use in the t-digest algorithm. _Default is 100_. A higher number results in more accurate approximation but requires more memory. ###### Example ```sql > SELECT approx_percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) FROM table_name; +------------------------------------------------------------------+ | approx_percentile_cont(0.75) WITHIN GROUP (ORDER BY column_name) | +------------------------------------------------------------------+ | 65.0 | +------------------------------------------------------------------+ > SELECT approx_percentile_cont(0.75, 100) WITHIN GROUP (ORDER BY column_name) FROM table_name; +-----------------------------------------------------------------------+ | approx_percentile_cont(0.75, 100) WITHIN GROUP (ORDER BY column_name) | +-----------------------------------------------------------------------+ | 65.0 | +-----------------------------------------------------------------------+ ``` An alternate syntax is also supported: ```sql > SELECT approx_percentile_cont(column_name, 0.75) FROM table_name; +-----------------------------------------------+ | approx_percentile_cont(column_name, 0.75) | +-----------------------------------------------+ | 65.0 | +-----------------------------------------------+ > SELECT approx_percentile_cont(column_name, 0.75, 100) FROM table_name; +----------------------------------------------------------+ | approx_percentile_cont(column_name, 0.75, 100) | +----------------------------------------------------------+ | 65.0 | +----------------------------------------------------------+ ``` ##### `approx_percentile_cont_with_weight` Returns the weighted approximate percentile of input values using the t-digest algorithm. ```sql approx_percentile_cont_with_weight(weight, percentile [, centroids]) WITHIN GROUP (ORDER BY expression) ``` ###### Arguments - **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators. - **weight**: Expression to use as weight. Can be a constant, column, or function, and any combination of arithmetic operators. - **percentile**: Percentile to compute. Must be a float value between 0 and 1 (inclusive). - **centroids**: Number of centroids to use in the t-digest algorithm. _Default is 100_. A higher number results in more accurate approximation but requires more memory. ###### Example ```sql > SELECT approx_percentile_cont_with_weight(weight_column, 0.90) WITHIN GROUP (ORDER BY column_name) FROM table_name; +---------------------------------------------------------------------------------------------+ | approx_percentile_cont_with_weight(weight_column, 0.90) WITHIN GROUP (ORDER BY column_name) | +---------------------------------------------------------------------------------------------+ | 78.5 | +---------------------------------------------------------------------------------------------+ > SELECT approx_percentile_cont_with_weight(weight_column, 0.90, 100) WITHIN GROUP (ORDER BY column_name) FROM table_name; +--------------------------------------------------------------------------------------------------+ | approx_percentile_cont_with_weight(weight_column, 0.90, 100) WITHIN GROUP (ORDER BY column_name) | +--------------------------------------------------------------------------------------------------+ | 78.5 | +--------------------------------------------------------------------------------------------------+ ``` An alternative syntax is also supported: ```sql > SELECT approx_percentile_cont_with_weight(column_name, weight_column, 0.90) FROM table_name; +--------------------------------------------------+ | approx_percentile_cont_with_weight(column_name, weight_column, 0.90) | +--------------------------------------------------+ | 78.5 | +--------------------------------------------------+ ``` ## Window Functions A _window function_ performs a calculation across a set of table rows that are somehow related to the current row. This is comparable to the type of calculation that can be done with an aggregate function. However, window functions do not cause rows to become grouped into a single output row like non-window aggregate calls would. Instead, the rows retain their separate identities. Behind the scenes, the window function is able to access more than just the current row of the query result Here is an example that shows how to compare each employee's salary with the average salary in his or her department: ```sql SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary; +-----------+-------+--------+-------------------+ | depname | empno | salary | avg | +-----------+-------+--------+-------------------+ | personnel | 2 | 3900 | 3700.0 | | personnel | 5 | 3500 | 3700.0 | | develop | 8 | 6000 | 5020.0 | | develop | 10 | 5200 | 5020.0 | | develop | 11 | 5200 | 5020.0 | | develop | 9 | 4500 | 5020.0 | | develop | 7 | 4200 | 5020.0 | | sales | 1 | 5000 | 4866.666666666667 | | sales | 4 | 4800 | 4866.666666666667 | | sales | 3 | 4800 | 4866.666666666667 | +-----------+-------+--------+-------------------+ ``` A window function call always contains an OVER clause directly following the window function's name and argument(s). This is what syntactically distinguishes it from a normal function or non-window aggregate. The OVER clause determines exactly how the rows of the query are split up for processing by the window function. The PARTITION BY clause within OVER divides the rows into groups, or partitions, that share the same values of the PARTITION BY expression(s). For each row, the window function is computed across the rows that fall into the same partition as the current row. The previous example showed how to count the average of a column per partition. You can also control the order in which rows are processed by window functions using ORDER BY within OVER. (The window ORDER BY does not even have to match the order in which the rows are output.) Here is an example: ```sql SELECT depname, empno, salary, rank() OVER (PARTITION BY depname ORDER BY salary DESC) FROM empsalary; +-----------+-------+--------+--------+ | depname | empno | salary | rank | +-----------+-------+--------+--------+ | personnel | 2 | 3900 | 1 | | develop | 8 | 6000 | 1 | | develop | 10 | 5200 | 2 | | develop | 11 | 5200 | 2 | | develop | 9 | 4500 | 4 | | develop | 7 | 4200 | 5 | | sales | 1 | 5000 | 1 | | sales | 4 | 4800 | 2 | | personnel | 5 | 3500 | 2 | | sales | 3 | 4800 | 2 | +-----------+-------+--------+--------+ ``` There is another important concept associated with window functions: for each row, there is a set of rows within its partition called its window frame. Some window functions act only on the rows of the window frame, rather than of the whole partition. Here is an example of using window frames in queries: ```sql SELECT depname, empno, salary, avg(salary) OVER(ORDER BY salary ASC ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS avg, min(salary) OVER(ORDER BY empno ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cum_min FROM empsalary ORDER BY empno ASC; +-----------+-------+--------+--------------------+---------+ | depname | empno | salary | avg | cum_min | +-----------+-------+--------+--------------------+---------+ | sales | 1 | 5000 | 5000.0 | 5000 | | personnel | 2 | 3900 | 3866.6666666666665 | 3900 | | sales | 3 | 4800 | 4700.0 | 3900 | | sales | 4 | 4800 | 4866.666666666667 | 3900 | | personnel | 5 | 3500 | 3700.0 | 3500 | | develop | 7 | 4200 | 4200.0 | 3500 | | develop | 8 | 6000 | 5600.0 | 3500 | | develop | 9 | 4500 | 4500.0 | 3500 | | develop | 10 | 5200 | 5133.333333333333 | 3500 | | develop | 11 | 5200 | 5466.666666666667 | 3500 | +-----------+-------+--------+--------------------+---------+ ``` When a query involves multiple window functions, it is possible to write out each one with a separate OVER clause, but this is duplicative and error-prone if the same windowing behavior is wanted for several functions. Instead, each windowing behavior can be named in a WINDOW clause and then referenced in OVER. For example: ```sql SELECT sum(salary) OVER w, avg(salary) OVER w FROM empsalary WINDOW w AS (PARTITION BY depname ORDER BY salary DESC); ``` ### Syntax The syntax for the OVER-clause is ```sql function([expr]) OVER( [PARTITION BY expr[, …]] [ORDER BY expr [ ASC | DESC ][, …]] [ frame_clause ] ) ``` where **frame_clause** is one of: ```sql { RANGE | ROWS | GROUPS } frame_start { RANGE | ROWS | GROUPS } BETWEEN frame_start AND frame_end ``` and **frame_start** and **frame_end** can be one of ```sql UNBOUNDED PRECEDING offset PRECEDING CURRENT ROW offset FOLLOWING UNBOUNDED FOLLOWING ``` where **offset** is an non-negative integer. RANGE and GROUPS modes require an ORDER BY clause (with RANGE the ORDER BY must specify exactly one column). ### Filter clause for aggregate window functions Aggregate window functions support the SQL `FILTER (WHERE ...)` clause to include only rows that satisfy the predicate from the window frame in the aggregation. ```sql sum(salary) FILTER (WHERE salary > 0) OVER (PARTITION BY depname ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ``` If no rows in the frame satisfy the filter for a given output row, `COUNT` yields `0` while `SUM`/`AVG`/`MIN`/`MAX` yield `NULL`. ### Aggregate functions All [aggregate functions](#aggregate-functions) can be used as window functions. ### Ranking Functions - [cume_dist](#cume_dist) - [dense_rank](#dense_rank) - [ntile](#ntile) - [percent_rank](#percent_rank) - [rank](#rank) - [row_number](#row_number) ##### `cume_dist` Relative rank of the current row: (number of rows preceding or peer with the current row) / (total rows). ```sql cume_dist() ``` ###### Example ```sql -- Example usage of the cume_dist window function: SELECT salary, cume_dist() OVER (ORDER BY salary) AS cume_dist FROM employees; +--------+-----------+ | salary | cume_dist | +--------+-----------+ | 30000 | 0.33 | | 50000 | 0.67 | | 70000 | 1.00 | +--------+-----------+ ``` ##### `dense_rank` Returns the rank of the current row without gaps. This function ranks rows in a dense manner, meaning consecutive ranks are assigned even for identical values. ```sql dense_rank() ``` ###### Example ```sql -- Example usage of the dense_rank window function: SELECT department, salary, dense_rank() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank FROM employees; +-------------+--------+------------+ | department | salary | dense_rank | +-------------+--------+------------+ | Sales | 70000 | 1 | | Sales | 50000 | 2 | | Sales | 50000 | 2 | | Sales | 30000 | 3 | | Engineering | 90000 | 1 | | Engineering | 80000 | 2 | +-------------+--------+------------+ ``` ##### `ntile` Integer ranging from 1 to the argument value, dividing the partition as equally as possible ```sql ntile(expression) ``` ###### Arguments - **expression**: An integer describing the number groups the partition should be split into ###### Example ```sql -- Example usage of the ntile window function: SELECT employee_id, salary, ntile(4) OVER (ORDER BY salary DESC) AS quartile FROM employees; +-------------+--------+----------+ | employee_id | salary | quartile | +-------------+--------+----------+ | 1 | 90000 | 1 | | 2 | 85000 | 1 | | 3 | 80000 | 2 | | 4 | 70000 | 2 | | 5 | 60000 | 3 | | 6 | 50000 | 3 | | 7 | 40000 | 4 | | 8 | 30000 | 4 | +-------------+--------+----------+ ``` ##### `percent_rank` Returns the percentage rank of the current row within its partition. The value ranges from 0 to 1 and is computed as `(rank - 1) / (total_rows - 1)`. ```sql percent_rank() ``` ###### Example ```sql -- Example usage of the percent_rank window function: SELECT employee_id, salary, percent_rank() OVER (ORDER BY salary) AS percent_rank FROM employees; +-------------+--------+---------------+ | employee_id | salary | percent_rank | +-------------+--------+---------------+ | 1 | 30000 | 0.00 | | 2 | 50000 | 0.50 | | 3 | 70000 | 1.00 | +-------------+--------+---------------+ ``` ##### `rank` Returns the rank of the current row within its partition, allowing gaps between ranks. This function provides a ranking similar to `row_number`, but skips ranks for identical values. ```sql rank() ``` ###### Example ```sql -- Example usage of the rank window function: SELECT department, salary, rank() OVER (PARTITION BY department ORDER BY salary DESC) AS rank FROM employees; +-------------+--------+------+ | department | salary | rank | +-------------+--------+------+ | Sales | 70000 | 1 | | Sales | 50000 | 2 | | Sales | 50000 | 2 | | Sales | 30000 | 4 | | Engineering | 90000 | 1 | | Engineering | 80000 | 2 | +-------------+--------+------+ ``` ##### `row_number` Number of the current row within its partition, counting from 1. ```sql row_number() ``` ###### Example ```sql -- Example usage of the row_number window function: SELECT department, salary, row_number() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num FROM employees; +-------------+--------+---------+ | department | salary | row_num | +-------------+--------+---------+ | Sales | 70000 | 1 | | Sales | 50000 | 2 | | Sales | 50000 | 3 | | Sales | 30000 | 4 | | Engineering | 90000 | 1 | | Engineering | 80000 | 2 | +-------------+--------+---------+ ``` ### Analytical Functions - [first_value](#first_value) - [lag](#lag) - [last_value](#last_value) - [lead](#lead) - [nth_value](#nth_value) ##### `first_value` Returns value evaluated at the row that is the first row of the window frame. ```sql first_value(expression) ``` ###### Arguments - **expression**: Expression to operate on ###### Example ```sql -- Example usage of the first_value window function: SELECT department, employee_id, salary, first_value(salary) OVER (PARTITION BY department ORDER BY salary DESC) AS top_salary FROM employees; +-------------+-------------+--------+------------+ | department | employee_id | salary | top_salary | +-------------+-------------+--------+------------+ | Sales | 1 | 70000 | 70000 | | Sales | 2 | 50000 | 70000 | | Sales | 3 | 30000 | 70000 | | Engineering | 4 | 90000 | 90000 | | Engineering | 5 | 80000 | 90000 | +-------------+-------------+--------+------------+ ``` ##### `lag` Returns value evaluated at the row that is offset rows before the current row within the partition; if there is no such row, instead return default (which must be of the same type as value). ```sql lag(expression, offset, default) ``` ###### Arguments - **expression**: Expression to operate on - **offset**: Integer. Specifies how many rows back the value of expression should be retrieved. Defaults to 1. - **default**: The default value if the offset is not within the partition. Must be of the same type as expression. ###### Example ```sql -- Example usage of the lag window function: SELECT employee_id, salary, lag(salary, 1, 0) OVER (ORDER BY employee_id) AS prev_salary FROM employees; +-------------+--------+-------------+ | employee_id | salary | prev_salary | +-------------+--------+-------------+ | 1 | 30000 | 0 | | 2 | 50000 | 30000 | | 3 | 70000 | 50000 | | 4 | 60000 | 70000 | +-------------+--------+-------------+ ``` ##### `last_value` Returns value evaluated at the row that is the last row of the window frame. ```sql last_value(expression) ``` ###### Arguments - **expression**: Expression to operate on ###### Example ```sql -- SQL example of last_value: SELECT department, employee_id, salary, last_value(salary) OVER (PARTITION BY department ORDER BY salary) AS running_last_salary FROM employees; +-------------+-------------+--------+---------------------+ | department | employee_id | salary | running_last_salary | +-------------+-------------+--------+---------------------+ | Sales | 1 | 30000 | 30000 | | Sales | 2 | 50000 | 50000 | | Sales | 3 | 70000 | 70000 | | Engineering | 4 | 40000 | 40000 | | Engineering | 5 | 60000 | 60000 | +-------------+-------------+--------+---------------------+ ``` ##### `lead` Returns value evaluated at the row that is offset rows after the current row within the partition; if there is no such row, instead return default (which must be of the same type as value). ```sql lead(expression, offset, default) ``` ###### Arguments - **expression**: Expression to operate on - **offset**: Integer. Specifies how many rows forward the value of expression should be retrieved. Defaults to 1. - **default**: The default value if the offset is not within the partition. Must be of the same type as expression. ###### Example ```sql -- Example usage of lead window function: SELECT employee_id, department, salary, lead(salary, 1, 0) OVER (PARTITION BY department ORDER BY salary) AS next_salary FROM employees; +-------------+-------------+--------+--------------+ | employee_id | department | salary | next_salary | +-------------+-------------+--------+--------------+ | 1 | Sales | 30000 | 50000 | | 2 | Sales | 50000 | 70000 | | 3 | Sales | 70000 | 0 | | 4 | Engineering | 40000 | 60000 | | 5 | Engineering | 60000 | 0 | +-------------+-------------+--------+--------------+ ``` ##### `nth_value` Returns the value evaluated at the nth row of the window frame (counting from 1). Returns NULL if no such row exists. ```sql nth_value(expression, n) ``` ###### Arguments - **expression**: The column from which to retrieve the nth value. - **n**: Integer. Specifies the row number (starting from 1) in the window frame. ###### Example ```sql -- Sample employees table: CREATE TABLE employees (id INT, salary INT); INSERT INTO employees (id, salary) VALUES (1, 30000), (2, 40000), (3, 50000), (4, 60000), (5, 70000); -- Example usage of nth_value: SELECT nth_value(salary, 2) OVER ( ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS nth_value FROM employees; +-----------+ | nth_value | +-----------+ | 40000 | | 40000 | | 40000 | | 40000 | | 40000 | +-----------+ ``` ## Special Functions ### Expansion Functions - [unnest](#unnest) - [unnest(struct)](#unnest-struct) ##### `unnest` Expands an array or map into rows. ###### Arguments - **array**: Array expression to unnest. Can be a constant, column, or function, and any combination of array operators. ###### Examples ```sql > select unnest(make_array(1, 2, 3, 4, 5)) as unnested; +----------+ | unnested | +----------+ | 1 | | 2 | | 3 | | 4 | | 5 | +----------+ ``` ```sql > select unnest(range(0, 10)) as unnested_range; +----------------+ | unnested_range | +----------------+ | 0 | | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 | +----------------+ ``` ##### `unnest (struct)` Expand a struct fields into individual columns. Each field of the struct will be prefixed with `__unnest_placeholder` and could be accessed via `"__unnest_placeholder()."`. ###### Arguments - **struct**: Object expression to unnest. Can be a constant, column, or function, and any combination of object operators. ###### Examples ```sql > create table foo as values ({a: 5, b: 'a string'}), ({a:6, b: 'another string'}); > create view foov as select column1 as struct_column from foo; > select * from foov; +---------------------------+ | struct_column | +---------------------------+ | {a: 5, b: a string} | | {a: 6, b: another string} | +---------------------------+ > select unnest(struct_column) from foov; +--------------------------------------------+--------------------------------------------+ | __unnest_placeholder(foov.struct_column).a | __unnest_placeholder(foov.struct_column).b | +--------------------------------------------+--------------------------------------------+ | 5 | a string | | 6 | another string | +--------------------------------------------+--------------------------------------------+ ``` --- ## 地理函数 这个页面列出了 GreptimeDB 中的所有地理空间相关函数。当您启用了 `common-function/geo` 特性(默认为开启状态)时,这些函数才会生效。 ## Geo 数据类型函数 地理相关数据类型转换。 ### `wkt_point_from_latlng` 将纬度、经度转换成 WKT 点。 ```sql SELECT wkt_point_from_latlng(37.76938, -122.3889) AS point; ``` ## Geohash 了解 [更多关于 geohash 编码](https://en.wikipedia.org/wiki/Geohash)。 ### `geohash` 从纬度、经度和分辨率获取 geohash 编码的字符串。 ```sql SELECT geohash(37.76938, -122.3889, 11); ``` ### `geohash_neighbours` 给定坐标和分辨率获取所有 geohash 邻接点。 请注意,此函数返回一个字符串数组,并且仅在我们的 HTTP 查询 API 和 Postgres 通道上生效。 ```sql SELECT geohash_neighbours(37.76938, -122.3889, 11); ``` ## H3 H3 地理坐标编码算法。[了解更多](https://h3geo.org/)。 ### `h3_latlng_to_cell` 将坐标(纬度,经度)编码为指定分辨率下的 h3 索引,并返回该单元格的 UInt64 表示。 ```sql SELECT h3_latlng_to_cell(37.76938, -122.3889, 1); ``` ### `h3_latlng_to_cell_string` 类似于 `h3_latlng_to_cell` ,但返回字符串编码格式。 ```sql SELECT h3_latlng_to_cell_string(37.76938, -122.3889, 1); ``` ### `h3_cell_to_string` 将单元格索引(UInt64)转换为其字符串表示形式。 ```sql SELECT h3_cell_to_string(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_string_to_cell` 将十六进制编码的单元 ID 转换为其 UInt64 形式。 ```sql SELECT h3_string_to_cell(h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt64)); ``` ### `h3_cell_center_latlng` 返回单元中心的纬度和经度。 请注意,此函数返回一个浮点数数组,并且仅在我们的 HTTP 查询 API 和 Postgres 通道上有效。 ```sql SELECT h3_cell_center_latlng(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_resolution` 给定单元格的返回分辨率。 ```sql SELECT h3_cell_resolution(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_base` 返回给定单元的 Base 单元。 ```sql SELECT h3_cell_base(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_is_pentagon` 如果单元格是五边形,则返回 true。 ```sql SELECT h3_cell_is_pentagon(h3_latlng_to_cell(37.76938, -122.3889, 8)); ``` ### `h3_cell_parent` 返回给定分辨率下单元的父单元。 ```sql SELECT h3_cell_parent(h3_latlng_to_cell(37.76938, -122.3889, 8), 6); ``` ### `h3_cell_to_children` 根据给定的分辨率返回子单元格。 请注意,此函数返回一个 UInt64 数组,并且仅在我们的 HTTP 查询 API 和 Postgres 通道上生效。 ```sql SELECT h3_cell_to_children(h3_latlng_to_cell(37.76938, -122.3889, 8), 10); ``` ### `h3_cell_to_children_size` 根据给定的分辨率,返回单元格中的子单元数量。 ```sql SELECT h3_cell_to_children_size(h3_latlng_to_cell(37.76938, -122.3889, 8), 10); ``` ### `h3_cell_to_child_pos` 根据给定分辨率,返回单元在其父单元的位置。位置是单元在所有子单元中的索引。 ```sql SELECT h3_cell_to_child_pos(h3_latlng_to_cell(37.76938, -122.3889, 8), 6) ``` ### `h3_child_pos_to_cell` 在给定分辨率下,返回父单元中给定位置的单元。 参数: - 位置 - 单元索引 - 分辨率 ```sql SELECT h3_child_pos_to_cell(25, h3_latlng_to_cell(37.76938, -122.3889, 8), 11); ``` ### `h3_cells_contains` 测试输入的单元集合是否包含指定的单元,或其父单元。 参数: - 单元集合:可以是 int64/uint64/string 数组,或逗号分割的字符串单元 ID - 单元索引 ```sql SELECT h3_cells_contains('86283470fffffff,862834777ffffff, 862834757ffffff, 86283471fffffff, 862834707ffffff', '8b283470d112fff') AS R00, h3_cells_contains(['86283470fffffff', '862834777ffffff', '862834757ffffff', '86283471fffffff', '862834707ffffff'], '8b283470d112fff') AS R11, h3_cells_contains([604189641255419903, 604189643000250367, 604189642463379455, 604189641523855359, 604189641121202175], 604189641792290815) AS R21; ``` ### `h3_grid_disk` 返回给定单元格的 k 个距离对应的单元格。 请注意,此函数返回一个 UInt64 数组,并且仅能在我们的 HTTP 查询 API 和 Postgres 通道上工作。 ```sql SELECT h3_grid_disk(h3_latlng_to_cell(37.76938, -122.3889, 8), 3); ``` ### `h3_grid_disk_distances` 返回给定单元格范围内所有距离为 *k* 的单元格。 请注意,此函数返回一个 UInt64 数组,并且仅适用于我们的 HTTP 查询 API 和 Postgres 通道。 ```sql SELECT h3_grid_disk_distance(h3_latlng_to_cell(37.76938, -122.3889, 8), 3); ``` ### `h3_grid_distance` 返回两单元的距离。 ```sql SELECT h3_grid_distance(cell1, cell2) AS distance, FROM ( SELECT h3_latlng_to_cell(37.76938, -122.3889, 8) AS cell1, h3_latlng_to_cell(39.634, -104.999, 8) AS cell2 ); ``` ### `h3_grid_path_cells` 此函数可在两个单元格之间返回路径单元格。请注意,如果两个单元格相距很远,该函数可能会失败。 ```sql SELECT h3_grid_path_cells(cell1, cell2) AS path_cells, FROM ( SELECT h3_latlng_to_cell(37.76938, -122.3889, 8) AS cell1, h3_latlng_to_cell(39.634, -104.999, 8) AS cell2 ); ``` ### `h3_distance_sphere_km` 返回两个单元中心的大圆距离,单位:千米 ```sql SELECT round(h3_distance_sphere_km(cell1, cell2), 5) AS sphere_distance FROM ( SELECT h3_string_to_cell('86283082fffffff') AS cell1, h3_string_to_cell('86283470fffffff') AS cell2 ); ``` ### `h3_distance_degree` 返回两个单元中心的欧式距离,单位:度 ```sql SELECT round(h3_distance_degree(cell1, cell2), 14) AS euclidean_distance FROM ( SELECT h3_string_to_cell('86283082fffffff') AS cell1, h3_string_to_cell('86283470fffffff') AS cell2 ); ``` ## S2 了解[更多关于 S2 编码的信息](http://s2geometry.io/). ### `s2_latlng_to_cell` 给定坐标对应的 s2 单元索引。 ```sql SELECT s2_latlng_to_cell(37.76938, -122.3889); ``` ### `s2_cell_to_token` 给定单元格的字符串表示形式。 ```sql SELECT s2_cell_to_token(s2_latlng_to_cell(37.76938, -122.3889)); ``` ### `s2_cell_level` 返回给定单元格的级别。 ```sql SELECT s2_cell_level(s2_latlng_to_cell(37.76938, -122.3889)); ``` ### `s2_cell_parent` 返回给定单元格位于特定级别的父单元。 ```sql SELECT s2_cell_parent(s2_latlng_to_cell(37.76938, -122.3889), 3); ``` ## 编码 ### `json_encode_path` 将纬度、经度按时间戳排序并编码为一个 JSON 数组。 参数: - 纬度 - 经度 - 时间戳 返回一个字符串类型的 JSON 数组。请注意,结果坐标中的顺序为 [经度,纬度],以符合 GeoJSON 规范。 ```sql SELECT json_encode_path(lat, lon, ts); ``` 示例输出: ```json [[-122.3888,37.77001],[-122.3839,37.76928],[-122.3889,37.76938],[-122.382,37.7693]] ``` ## 空间关系 ### `st_contains` 测试两个空间对象是否为包含关系。 参数:WKT 编码的地理对象。 ```sql SELECT st_contains(polygon1, p1), st_contains(polygon2, p1), FROM ( SELECT wkt_point_from_latlng(37.383287, -122.01325) AS p1, 'POLYGON ((-122.031661 37.428252, -122.139829 37.387072, -122.135365 37.361971, -122.057759 37.332222, -121.987707 37.328946, -121.943754 37.333041, -121.919373 37.349145, -121.945814 37.376705, -121.975689 37.417345, -121.998696 37.409164, -122.031661 37.428252))' AS polygon1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon2, ); ``` ### `st_within` 测试两个空间对象是否为被包含关系。 参数:WKT 编码的地理对象。 ```sql SELECT st_within(p1, polygon1), st_within(p1, polygon2), FROM ( SELECT wkt_point_from_latlng(37.383287, -122.01325) AS p1, 'POLYGON ((-122.031661 37.428252, -122.139829 37.387072, -122.135365 37.361971, -122.057759 37.332222, -121.987707 37.328946, -121.943754 37.333041, -121.919373 37.349145, -121.945814 37.376705, -121.975689 37.417345, -121.998696 37.409164, -122.031661 37.428252))' AS polygon1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon2, ); ``` ### `st_intersects` 测试两个空间对象是否为重叠关系。 参数:WKT 编码的地理对象。 ```sql SELECT st_intersects(polygon1, polygon2), st_intersects(polygon1, polygon3), FROM ( SELECT 'POLYGON ((-122.031661 37.428252, -122.139829 37.387072, -122.135365 37.361971, -122.057759 37.332222, -121.987707 37.328946, -121.943754 37.333041, -121.919373 37.349145, -121.945814 37.376705, -121.975689 37.417345, -121.998696 37.409164, -122.031661 37.428252))' AS polygon1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon2, 'POLYGON ((-122.089628 37.450332, -122.20535 37.378342, -122.093062 37.36088, -122.044301 37.372886, -122.089628 37.450332))' AS polygon3, ); ``` ## 空间测量 ### `st_distance` 返回两个对象的在 WGS84 坐标系下的欧式距离,单位:度。 参数:WKT 编码的地理对象。 ```sql SELECT st_distance(p1, p2) AS euclidean_dist, st_distance(p1, polygon1) AS euclidean_dist_pp, FROM ( SELECT wkt_point_from_latlng(37.76938, -122.3889) AS p1, wkt_point_from_latlng(38.5216, -121.4247) AS p2, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon1, ); ``` ### `st_distance_sphere_m` 返回两点的大圆距离,单位:米。 参数:WKT 编码的地理对象。 ```sql SELECT st_distance_sphere_m(p1, p2) AS sphere_dist_m, FROM ( SELECT wkt_point_from_latlng(37.76938, -122.3889) AS p1, wkt_point_from_latlng(38.5216, -121.4247) AS p2, ); ``` ### `st_area` 返回地理对象的面积。 参数:WKT 编码的地理对象。 ```sql SELECT st_area(p1) as area_point, st_area(polygon1) as area_polygon, FROM ( SELECT wkt_point_from_latlng(37.76938, -122.3889) AS p1, 'POLYGON ((-121.491698 38.653343, -121.582353 38.556757, -121.469721 38.449287, -121.315883 38.541721, -121.491698 38.653343))' AS polygon1, ); ``` --- ## GreptimeDB 函数 ## 字符串函数 DataFusion [字符串函数](./df-functions.md#string-functions)。 GreptimeDB 提供: * `matches_term(expression, term)` 用于全文检索。阅读[查询日志](/user-guide/logs/fulltext-search.md)文档获取更多详情。 * `regexp_extract(str, regexp)` 提取字符串中与正则表达式匹配的第一个子串。如果没有找到匹配项则返回 `NULL`。 **MySQL 兼容的字符串函数:** GreptimeDB 还提供以下 MySQL 兼容的字符串函数: * `locate(substr, str[, pos])` - 返回子串第一次出现的位置 * `elt(N, str1, str2, ...)` - 返回列表中第 N 个字符串 * `field(str, str1, str2, ...)` - 返回第一个匹配的字符串的索引 * `insert(str, pos, len, newstr)` - 在指定位置插入子串 * `space(N)` - 返回包含 N 个空格的字符串 * `format(X, D)` - 使用千位分隔符格式化数字,并保留 D 位小数 ### regexp_extract 提取字符串中与[正则表达式](https://docs.rs/regex/latest/regex/#syntax)匹配的第一个子串。如果没有找到匹配项则返回 `NULL`。 ```sql regexp_extract(str, regexp) ``` **参数:** - **str**: 要操作的字符串表达式。可以是常量、列或函数,以及运算符的任意组合。 - **regexp**: 要匹配的正则表达式。可以是常量、列或函数。 **关于转义的说明:** GreptimeDB 在 MySQL 和 PostgreSQL 兼容模式下的正则表达式转义行为有所不同: - **MySQL 模式**:转义序列需要使用双反斜杠(例如 `\\d`、`\\s`) - **PostgreSQL 模式**:默认情况下单反斜杠即可(例如 `\d`、`\s`),或者使用 `E''` 前缀以与 MySQL 保持一致(例如 `E'\\d'`) **示例:** ```sql SELECT regexp_extract('version 1.2.3', '\d+\.\d+\.\d+'); -- 返回: 1.2.3 SELECT regexp_extract('Phone: 123-456-7890', '\d{3}-\d{3}-\d{4}'); -- 返回: 123-456-7890 SELECT regexp_extract('no match here', '\d+\.\d+\.\d+'); -- 返回: NULL ``` ### locate 返回子串 `substr` 在字符串 `str` 中第一次出现的位置。可选参数 `pos` 指定搜索起始位置。如果未找到子串则返回 0。 ```sql locate(substr, str[, pos]) ``` **参数:** - **substr**: 要搜索的子串。 - **str**: 要搜索的字符串。 - **pos**(可选): 开始搜索的位置(从 1 开始)。如果省略,则从头开始搜索。 **示例:** ```sql SELECT locate('world', 'hello world'); -- 返回: 7 SELECT locate('o', 'hello world', 6); -- 返回: 8 (找到第二个 'o') SELECT locate('xyz', 'hello world'); -- 返回: 0 (未找到) ``` ### elt 从字符串列表中返回第 N 个字符串。如果 N 小于 1、大于字符串数量或为 `NULL`,则返回 `NULL`。 ```sql elt(N, str1, str2, str3, ...) ``` **参数:** - **N**: 要返回的字符串的索引(从 1 开始)。 - **str1, str2, str3, ...**: 字符串列表。 **示例:** ```sql SELECT elt(2, 'apple', 'banana', 'cherry'); -- 返回: banana SELECT elt(0, 'apple', 'banana', 'cherry'); -- 返回: NULL ``` ### field 返回 `str` 在列表中第一次出现的索引(从 1 开始)。如果未找到匹配项或 `str` 为 `NULL`,则返回 0。 ```sql field(str, str1, str2, str3, ...) ``` **参数:** - **str**: 要搜索的字符串。 - **str1, str2, str3, ...**: 要搜索的字符串列表。 **示例:** ```sql SELECT field('banana', 'apple', 'banana', 'cherry'); -- 返回: 2 SELECT field('grape', 'apple', 'banana', 'cherry'); -- 返回: 0 (未找到) ``` ### insert 在字符串的指定位置插入子串,替换指定数量的字符。 ```sql insert(str, pos, len, newstr) ``` **参数:** - **str**: 原始字符串。 - **pos**: 开始插入的位置(从 1 开始)。 - **len**: 要替换的字符数。 - **newstr**: 要插入的字符串。 **示例:** ```sql SELECT insert('Quadratic', 3, 4, 'What'); -- 返回: QuWhattic SELECT insert('Quadratic', 3, 100, 'What'); -- 返回: QuWhat (替换到字符串末尾) ``` ### space 返回由 N 个空格字符组成的字符串。 ```sql space(N) ``` **参数:** - **N**: 要返回的空格数。如果 N 为负数,则返回空字符串。 **示例:** ```sql SELECT space(5); -- 返回: ' ' (5 个空格) SELECT concat('hello', space(3), 'world'); -- 返回: 'hello world' ``` ### format 使用千位分隔符格式化数字,并保留指定的小数位数。 ```sql format(X, D) ``` **参数:** - **X**: 要格式化的数字。 - **D**: 小数位数(0-30)。 **示例:** ```sql SELECT format(1234567.891, 2); -- 返回: 1,234,567.89 SELECT format(1234567.891, 0); -- 返回: 1,234,568 ``` ## 数学函数 DataFusion [数学函数](./df-functions.md#math-functions)。GreptimeDB 额外提供: ### clamp * `clamp(value, lower, upper)` 限制给定值在上下限之间: ```sql SELECT CLAMP(10, 0, 1); +------------------------------------+ | clamp(Int64(10),Int64(0),Int64(1)) | +------------------------------------+ | 1 | +------------------------------------+ ``` ```sql SELECT CLAMP(0.5, 0, 1) +---------------------------------------+ | clamp(Float64(0.5),Int64(0),Int64(1)) | +---------------------------------------+ | 0.5 | +---------------------------------------+ ``` ### mod * `mod(x, y)` 计算除法的余数: ```sql SELECT mod(18, 4); +-------------------------+ | mod(Int64(18),Int64(4)) | +-------------------------+ | 2 | +-------------------------+ ``` ## 日期与时间函数 DataFusion [时间函数](./df-functions.md#time-and-date-functions)。 GreptimeDB 提供: * [date_add](#date_add) * [date_sub](#date_sub) * [date_format](#date_format) * [to_unixtime](#to_unixtime) * [timezone](#timezone) ### date_add * `date_add(expression, interval)` 为 Timestamp、Date 或 DateTime 增加一个区间值 ```sql SELECT date_add('2023-12-06'::DATE, '3 month 5 day'); ``` ``` +----------------------------------------------------+ | date_add(Utf8("2023-12-06"),Utf8("3 month 5 day")) | +----------------------------------------------------+ | 2024-03-11 | +----------------------------------------------------+ ``` ### date_sub * `date_sub(expression, interval)` 为 Timestamp、Date 或 DateTime 减去一个区间值 ```sql SELECT date_sub('2023-12-06 07:39:46.222'::TIMESTAMP_MS, '5 day'::INTERVAL); ``` ``` +-----------------------------------------------------------------------------------------------------------------------------------------+ | date_sub(arrow_cast(Utf8("2023-12-06 07:39:46.222"),Utf8("Timestamp(Millisecond, None)")),IntervalMonthDayNano("92233720368547758080")) | +-----------------------------------------------------------------------------------------------------------------------------------------+ | 2023-12-01 07:39:46.222000 | +-----------------------------------------------------------------------------------------------------------------------------------------+ ``` ### date_format * `date_format(expression, fmt)` 根据格式将 Timestamp、Date 或 DateTime 转为字符串: 支持 `Date32`、`Date64` 以及所有 `Timestamp` 类型。 ```sql SELECT date_format('2023-12-06 07:39:46.222'::TIMESTAMP, '%Y-%m-%d %H:%M:%S:%3f'); ``` ``` +-----------------------------------------------------------------------------------------------------------------------------+ | date_format(arrow_cast(Utf8("2023-12-06 07:39:46.222"),Utf8("Timestamp(Millisecond, None)")),Utf8("%Y-%m-%d %H:%M:%S:%3f")) | +-----------------------------------------------------------------------------------------------------------------------------+ | 2023-12-06 07:39:46:222 | +-----------------------------------------------------------------------------------------------------------------------------+ ``` 支持的格式化符号请参考 [chrono::format::strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) 模块。 ### to_unixtime * `to_unixtime(expression)` 将表达式转换为秒级 Unix 时间戳。参数可以是整数(毫秒级时间戳)、Timestamp、Date、DateTime 或字符串。如果参数是字符串类型,函数会先尝试解析为 DateTime、Timestamp 或 Date。 ```sql select to_unixtime('2023-03-01T06:35:02Z'); ``` ``` +-------------------------------------------+ | to_unixtime(Utf8("2023-03-01T06:35:02Z")) | +-------------------------------------------+ | 1677652502 | +-------------------------------------------+ ``` ```sql select to_unixtime('2023-03-01'::date); ``` ``` +---------------------------------+ | to_unixtime(Utf8("2023-03-01")) | +---------------------------------+ | 1677628800 | +---------------------------------+ ``` ### timezone * `timezone()` 获取当前会话时区: ```sql select timezone(); ``` ``` +------------+ | timezone() | +------------+ | UTC | +------------+ ``` ## 系统函数 * `isnull(expression)` 判断表达式是否为 `NULL`: ```sql SELECT isnull(1); +------------------+ | isnull(Int64(1)) | +------------------+ | 0 | +------------------+ ``` ```sql SELECT isnull(NULL); +--------------+ | isnull(NULL) | +--------------+ | 1 | +--------------+ ``` * `build()` 返回 GreptimeDB 构建信息。 * `version()` 返回 GreptimeDB 版本信息。 * `database()` 返回当前会话数据库: ```sql select database(); +------------+ | database() | +------------+ | public | +------------+ ``` ## 管理函数 GreptimeDB 提供 `ADMIN` 语句来运行管理函数,详见 [ADMIN](/reference/sql/admin.md) 文档。 --- ## IP 函数 本文档介绍了可用于 IP 地址操作和比较的函数。 ### `ipv4_to_cidr(ip_string [, subnet_mask])` **描述:** 将 IPv4 地址字符串转换为 CIDR 表示法。如果提供了 `subnet_mask` 参数(UInt8 类型,取值范围 0-32),则使用指定的子网掩码。否则,函数会根据输入字符串末尾的零或提供的八位字节数来自动检测子网(例如,'192.168' 表示 /16,'192' 表示 /8)。生成的 CIDR 表示法中的 IP 地址会根据子网掩码将主机位清零。 **参数:** * `ip_string`: String - IPv4 地址字符串(例如,'192.168.1.1','10.0.0.0','172.16')。不完整的地址将用零补全。 * `subnet_mask` (可选): UInt8 - 期望的子网掩码长度(例如,24, 16, 8)。 **返回类型:** String - CIDR 表示法中的 IPv4 地址(例如,'192.168.1.0/24')。若输入无效,则返回 NULL。 **示例:** ```sql -- 自动检测子网 SELECT ipv4_to_cidr('192.168.1.0'); -- 输出: '192.168.1.0/24' SELECT ipv4_to_cidr('172.16'); -- 输出: '172.16.0.0/16' -- 指定子网掩码 SELECT ipv4_to_cidr('192.168.1.1', 24); -- 输出: '192.168.1.0/24' SELECT ipv4_to_cidr('10.0.0.1', 16); -- 输出: '10.0.0.0/16' ``` ### `ipv6_to_cidr(ip_string [, subnet_mask])` **描述:** 将 IPv6 地址字符串转换为 CIDR 表示法。如果提供了 `subnet_mask` 参数(UInt8 类型,取值范围 0-128),则使用指定的子网掩码。否则,函数会尝试根据地址末尾的零段或常见前缀(如 `fe80::` 代表 /16 或 `2001:db8::` 代表 /32)来自动检测子网。生成的 CIDR 表示法中的 IP 地址会根据子网掩码将主机位清零。 **参数:** * `ip_string`: String - IPv6 地址字符串(例如,'2001:db8::1','fe80::')。不完整的地址在可能的情况下会被补全(例如,'2001:db8' 变为 '2001:db8::')。 * `subnet_mask` (可选): UInt8 - 期望的子网掩码长度(例如,48, 64, 128)。 **返回类型:** String - CIDR 表示法中的 IPv6 地址(例如,'2001:db8::/32')。若输入无效,则返回 NULL。 **示例:** ```sql -- 自动检测子网 SELECT ipv6_to_cidr('2001:db8::'); -- 输出: '2001:db8::/32' SELECT ipv6_to_cidr('fe80::1'); -- 输出: 'fe80::/16' SELECT ipv6_to_cidr('::1'); -- 输出: '::1/128' -- 指定子网掩码 SELECT ipv6_to_cidr('2001:db8::', 48); -- 输出: '2001:db8::/48' SELECT ipv6_to_cidr('fe80::1', 10); -- 输出: 'fe80::/10' ``` ### `ipv4_num_to_string(ip_number)` **描述:** 将 UInt32 类型的数字转换为标准的 A.B.C.D 格式的 IPv4 地址字符串。该数字被视为大端字节序(Big-Endian)的 IPv4 地址。 **参数:** * `ip_number`: UInt32 - IPv4 地址的数字形式。 **返回类型:** String - 点分十进制表示法中的 IPv4 地址(例如,'192.168.0.1')。 **示例:** ```sql SELECT ipv4_num_to_string(3232235521::uint32); -- 0xC0A80001 -- 输出: '192.168.0.1' SELECT ipv4_num_to_string(167772161::uint32); -- 0x0A000001 -- 输出: '10.0.0.1' SELECT ipv4_num_to_string(0::uint32); -- 输出: '0.0.0.0' ``` ### `ipv4_string_to_num(ip_string)` **描述:** 将 A.B.C.D 格式的 IPv4 地址字符串转换为其对应的 UInt32 数字(大端序)。 **参数:** * `ip_string`: String - 点分十进制表示法中的 IPv4 地址。 **返回类型:** UInt32 - IPv4 地址的数字表示。若输入格式无效,则返回 NULL 或抛出错误。 **示例:** ```sql SELECT ipv4_string_to_num('192.168.0.1'); -- 输出: 3232235521 SELECT ipv4_string_to_num('10.0.0.1'); -- 输出: 167772161 SELECT ipv4_string_to_num('0.0.0.0'); -- 输出: 0 ``` ### `ipv6_num_to_string(hex_string)` **描述:** 将 32 个字符长的十六进制字符串(代表 IPv6 地址)转换为其标准格式的字符串表示(例如,'2001:db8::1')。能正确处理 IPv4 映射的 IPv6 地址(例如,'::ffff:192.168.0.1')。十六进制字符的大小写不敏感。 **参数:** * `hex_string`: String - 代表 IPv6 地址 16 个字节的 32 位十六进制字符串。 **返回类型:** String - 标准格式的 IPv6 地址字符串。若输入不是有效的 32 位十六进制字符串,则返回 NULL 或抛出错误。 **示例:** ```sql SELECT ipv6_num_to_string('20010db8000000000000000000000001'); -- 输出: '2001:db8::1' SELECT ipv6_num_to_string('00000000000000000000ffffc0a80001'); -- 输出: '::ffff:192.168.0.1' ``` ### `ipv6_string_to_num(ip_string)` **描述:** 将标准格式的 IPv6 地址字符串或点分十进制格式的 IPv4 地址字符串转换为其 16 字节的二进制表示。如果输入是 IPv4 地址字符串,它会先被内部转换为 IPv6 映射的等价形式(例如,'192.168.0.1' 内部变为 '::ffff:192.168.0.1'),然后再转换为二进制表示。 **参数:** * `ip_string`: String - IPv6 或 IPv4 地址字符串。 **返回类型:** Binary - IPv6 地址的 16 字节二进制数据。若输入格式无效,则返回 NULL 或抛出错误。 **示例:** ```sql -- IPv6 输入 SELECT ipv6_string_to_num('2001:db8::1'); -- 输出: 2001:db8::1 的二进制表示 -- IPv4 输入 (映射到 IPv6) SELECT ipv6_string_to_num('192.168.0.1'); -- 输出: ::ffff:192.168.0.1 的二进制表示 -- IPv4 映射的 IPv6 输入 SELECT ipv6_string_to_num('::ffff:192.168.0.1'); -- 输出: ::ffff:192.168.0.1 的二进制表示 ``` ### `ipv4_in_range(ip_string, cidr_string)` **描述:** 检查给定的 IPv4 地址字符串是否落在指定的 CIDR 范围字符串之内。 **参数:** * `ip_string`: String - 待检查的 IPv4 地址(例如,'192.168.1.5')。 * `cidr_string`: String - 用于检查的 CIDR 范围(例如,'192.168.1.0/24')。 **返回类型:** Boolean - 如果 IP 地址在指定范围内,则返回 `true`,否则返回 `false`。若输入无效,则返回 NULL 或抛出错误。 **示例:** ```sql SELECT ipv4_in_range('192.168.1.5', '192.168.1.0/24'); -- 输出: true SELECT ipv4_in_range('192.168.2.1', '192.168.1.0/24'); -- 输出: false SELECT ipv4_in_range('10.0.0.1', '10.0.0.0/8'); -- 输出: true SELECT ipv4_in_range('8.8.8.8', '0.0.0.0/0'); -- /0 匹配所有地址 -- 输出: true SELECT ipv4_in_range('192.168.1.1', '192.168.1.1/32'); -- /32 表示精确匹配单个地址 -- 输出: true ``` ### `ipv6_in_range(ip_string, cidr_string)` **描述:** 检查给定的 IPv6 地址字符串是否落在指定的 CIDR 范围字符串之内。 **参数:** * `ip_string`: String - 待检查的 IPv6 地址(例如,'2001:db8::1')。 * `cidr_string`: String - 用于检查的 CIDR 范围(例如,'2001:db8::/32')。 **返回类型:** Boolean - 如果 IP 地址在指定范围内,则返回 `true`,否则返回 `false`。若输入无效,则返回 NULL 或抛出错误。 **示例:** ```sql SELECT ipv6_in_range('2001:db8::1', '2001:db8::/32'); -- 输出: true SELECT ipv6_in_range('2001:db8:1::', '2001:db8::/32'); -- 输出: true SELECT ipv6_in_range('2001:db9::1', '2001:db8::/32'); -- 输出: false SELECT ipv6_in_range('::1', '::1/128'); -- 输出: true SELECT ipv6_in_range('fe80::1', 'fe80::/16'); -- 输出: true ``` --- ## JSON 函数(试验功能) :::warning JSON 类型目前仍处于实验阶段,在未来的版本中可能会有所调整。 ::: 本页面列出了 GreptimeDB 中所有 JSON 类型相关的函数。 ## 转换 JSON 类型与其他类型的值之间的转换。 * `parse_json(string)` 尝试将字符串解析为 JSON 类型。非法的 JSON 字符串将返回错误。 * `json_to_string(json)` 将 JSON 类型的值转换为字符串。 ```sql SELECT json_to_string(parse_json('{"a": 1, "b": 2}')); +----------------------------------------------------------+ | json_to_string(parse_json(Utf8("{\"a\": 1, \"b\": 2}"))) | +----------------------------------------------------------+ | {"a":1,"b":2} | +----------------------------------------------------------+ ``` ## 提取 通过给定的路径和给定的数据类型,从 JSON 中提取值。 * `json_get_bool(json, path)` 按照路径 `path` 从 JSON 中获取布尔值。 * `json_get_int(json, path)` 按照路径 `path` 从 JSON 中获取整数值。布尔值将被转换为整数。 * `json_get_float(json, path)` 按照路径 `path` 从 JSON 中获取浮点数值。布尔值、整数值将被转换为浮点数。 * `json_get_string(json, path)` 按照路径 `path` 从 JSON 中获取字符串。所有类型的 JSON 值都将被转换为字符串,包括数组、对象和 null。 * `json_get_object(json, path)` 按照路径 `path` 从 JSON 中获取对象值。如果路径未指向对象,则返回 NULL。 `path` 是一个用于从 JSON 值中选择和提取元素的字符串。`path` 中支持的操作符有: | 操作符 | 描述 | 示例 | | ------------------------ | ----------------------------------------- | ------------------ | | `$` | 根元素 | `$` | | `@` | 过滤表达式中的当前元素 | `$.event?(@ == 1)` | | `.*` | 选择对象中的所有元素 | `$.*` | | `.` | 选择对象中匹配名称的元素 | `$.event` | | `:` | `.` 的别名 | `$:event` | | `[""]` | `.` 的别名 | `$["event"]` | | `[*]` | 选择数组中的所有元素 | `$[*]` | | `[, ..]` | 选择数组中基于 0 的第 `n` 个元素 | `$[1, 2]` | | `[last - , ..]` | 选择数组中最后一个元素之前的第 `n` 个元素 | `$[0, last - 1]` | | `[ to , ..]` | 选择数组中某个范围内的所有元素 | `$[1 to last - 2]` | | `?()` | 选择所有匹配过滤表达式的元素 | `$?(@.price < 10)` | 如果 `path` 是无效的,函数将返回 `NULL`。 ```sql SELECT json_get_int(parse_json('{"a": {"c": 3}, "b": 2}'), 'a.c'); +-----------------------------------------------------------------------+ | json_get_int(parse_json(Utf8("{"a": {"c": 3}, "b": 2}")),Utf8("a.c")) | +-----------------------------------------------------------------------+ | 3 | +-----------------------------------------------------------------------+ SELECT json_to_string(json_get_object(parse_json('{"a": {"b": {"c": {"d": 42}}}}'), 'a.b.c')); +---------------------------------------------------------------------------------------------------+ | json_to_string(json_get_object(parse_json(Utf8("{"a": {"b": {"c": {"d": 42}}}}")),Utf8("a.b.c"))) | +---------------------------------------------------------------------------------------------------+ | {"d":42} | +---------------------------------------------------------------------------------------------------+ ``` ## 验证 检查 JSON 值的类型。 * `json_is_null(json)` 检查 JSON 中的值是否为 `NULL`。 * `json_is_bool(json)` 检查 JSON 中的值是否为布尔值。 * `json_is_int(json)` 检查 JSON 中的值是否为整数。 * `json_is_float(json)` 检查 JSON 中的值是否为浮点数。 * `json_is_string(json)` 检查 JSON 中的值是否为字符串。 * `json_is_array(json)` 检查 JSON 中的值是否为数组。 * `json_is_object(json)` 检查 JSON 中的值是否为对象。 ```sql SELECT json_is_array(parse_json('[1, 2, 3]')); +----------------------------------------------+ | json_is_array(parse_json(Utf8("[1, 2, 3]"))) | +----------------------------------------------+ | 1 | +----------------------------------------------+ SELECT json_is_object(parse_json('1')); +---------------------------------------+ | json_is_object(parse_json(Utf8("1"))) | +---------------------------------------+ | 0 | +---------------------------------------+ ``` * `json_path_exists(json, path)` 检查 JSON 中是否存在指定的路径。 如果 `path` 是无效的,函数将返回错误。 如果 `path` 或 `json` 是 `NULL`,函数将返回 `NULL`。 ```sql SELECT json_path_exists(parse_json('{"a": 1, "b": 2}'), 'a'); +------------------------------------------------------------------+ | json_path_exists(parse_json(Utf8("{"a": 1, "b": 2}")),Utf8("a")) | +------------------------------------------------------------------+ | 1 | +------------------------------------------------------------------+ SELECT json_path_exists(parse_json('{"a": 1, "b": 2}'), 'c.d'); +--------------------------------------------------------------------+ | json_path_exists(parse_json(Utf8("{"a": 1, "b": 2}")),Utf8("c.d")) | +--------------------------------------------------------------------+ | 0 | +--------------------------------------------------------------------+ SELECT json_path_exists(parse_json('{"a": 1, "b": 2}'), NULL); +-------------------------------------------------------------+ | json_path_exists(parse_json(Utf8("{"a": 1, "b": 2}")),NULL) | +-------------------------------------------------------------+ | NULL | +-------------------------------------------------------------+ ``` * `json_path_match(json, path)` 检查 JSON 值是否匹配指定 JSON 路径表达式中的谓词。仅支持谓词表达式。 如果 `path` 无效或不是谓词表达式,函数将返回 `NULL`。 如果 `json` 是 `NULL`,函数将返回 `NULL`。 ```sql SELECT json_path_match(parse_json('{"a": 1, "b": 2}'), '$.a == 1'); +------------------------------------------------------------------------+ | json_path_match(parse_json(Utf8("{"a": 1, "b": 2}")),Utf8("$.a == 1")) | +------------------------------------------------------------------------+ | 1 | +------------------------------------------------------------------------+ SELECT json_path_match(parse_json('{"a":1,"b":[1,2,3]}'), '$.b[1 to last] >= 2'); +--------------------------------------------------------------------------------------+ | json_path_match(parse_json(Utf8("{"a":1,"b":[1,2,3]}")),Utf8("$.b[1 to last] >= 2")) | +--------------------------------------------------------------------------------------+ | 1 | +--------------------------------------------------------------------------------------+ SELECT json_path_match(parse_json('{"a":1,"b":[1,2,3]}'), '$.b[0] > 1'); +-----------------------------------------------------------------------------+ | json_path_match(parse_json(Utf8("{"a":1,"b":[1,2,3]}")),Utf8("$.b[0] > 1")) | +-----------------------------------------------------------------------------+ | 0 | +-----------------------------------------------------------------------------+ ``` --- ## 函数 这里是 GreptimeDB 函数文档的导览入口。 ## 文档导航 - [DataFusion 函数](./df-functions.md) - GreptimeDB 函数 - [核心函数(字符串/数学/时间/系统/管理)](./greptimedb.md) - [地理空间函数](./geo.md) - [IP 函数](./ip.md) - [JSON 函数](./json.md) - [向量函数](./vector.md) - [近似函数](./approximate.md) - [异常检测函数](./anomaly.md) --- ## 向量函数 本页面列出了 GreptimeDB 中所有支持的向量相关函数。向量函数主要用于处理向量运算,比如基础运算、距离计算、转换函数等。 ## 基础运算 ### `vec_scalar_add` 向量与标量的加法运算。将向量中的每个元素与标量相加,返回新的向量。 示例: ```sql SELECT vec_to_string(vec_scalar_add(2.0, parse_vec('[1.0, 2.0, 3.0]'))); ``` ```sql +------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_add(Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +------------------------------------------------------------------------------+ | [3,4,5] | +------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_scalar_add(2.0, '[1.0, 2.0, 3.0]')); -- 隐式转换字符串为向量 ``` ```sql +-------------------------------------------------------------------+ | vec_to_string(vec_scalar_add(Float64(2),Utf8("[1.0, 2.0, 3.0]"))) | +-------------------------------------------------------------------+ | [3,4,5] | +-------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_scalar_add(-2.0, parse_vec('[1.0, 2.0, 3.0]'))); -- 减法运算 ``` ```sql +-------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_add(Float64(-2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +-------------------------------------------------------------------------------+ | [-1,0,1] | +-------------------------------------------------------------------------------+ ``` ### `vec_scalar_mul` 向量与标量的乘法运算。将向量中的每个元素与标量相乘,返回新的向量。 示例: ```sql SELECT vec_to_string(vec_scalar_mul(2.0, parse_vec('[1.0, 2.0, 3.0]'))); ``` ```sql +------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_mul(Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +------------------------------------------------------------------------------+ | [2,4,6] | +------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_scalar_mul(2.0, '[1.0, 2.0, 3.0]')); -- 隐式转换字符串为向量 ``` ```sql +------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_mul(Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +------------------------------------------------------------------------------+ | [2,4,6] | +------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_scalar_mul(1.0/2.0, parse_vec('[1.0, 2.0, 3.0]'))); -- 除法运算 ``` ```sql +-------------------------------------------------------------------------------------------+ | vec_to_string(vec_scalar_mul(Float64(1) / Float64(2),parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +-------------------------------------------------------------------------------------------+ | [0.5,1,1.5] | +-------------------------------------------------------------------------------------------+ ``` ### `vec_add` 向量之间的加法运算。将两个向量的对应元素相加,返回新的向量。 示例: ```sql SELECT vec_to_string(vec_add(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_add(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [3,3,7] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_add('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- 隐式转换字符串为向量 ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_add(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [3,3,7] | +-------------------------------------------------------------------------+ ``` ### `vec_sub` 向量之间的减法运算。将两个向量的对应元素相减,返回新的向量。 示例: ```sql SELECT vec_to_string(vec_sub(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_sub(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [-1,1,-1] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_sub('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- 隐式转换字符串为向量 ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_sub(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [-1,1,-1] | +-------------------------------------------------------------------------+ ``` ### `vec_mul` 向量之间的乘法运算。将两个向量的对应元素相乘,返回新的向量。 示例: ```sql SELECT vec_to_string(vec_mul(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_mul(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [2,2,12] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_mul('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- 隐式转换字符串为向量 ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_mul(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [2,2,12] | +-------------------------------------------------------------------------+ ``` ### `vec_div` 向量之间的除法运算。将两个向量的对应元素相除,返回新的向量。 示例: ```sql SELECT vec_to_string(vec_div(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]'))); ``` ```sql +-----------------------------------------------------------------------------------------------+ | vec_to_string(vec_div(parse_vec(Utf8("[1.0, 2.0, 3.0]")),parse_vec(Utf8("[2.0, 1.0, 4.0]")))) | +-----------------------------------------------------------------------------------------------+ | [0.5,2,0.75] | +-----------------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_div('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]')); -- 隐式转换字符串为向量 ``` ```sql +-------------------------------------------------------------------------+ | vec_to_string(vec_div(Utf8("[1.0, 2.0, 3.0]"),Utf8("[2.0, 1.0, 4.0]"))) | +-------------------------------------------------------------------------+ | [0.5,2,0.75] | +-------------------------------------------------------------------------+ ``` ### `vec_elem_sum` 向量中所有元素求和,返回一个标量。 示例: ```sql SELECT vec_elem_sum(parse_vec('[1.0, 2.0, 3.0]')); ``` ```sql +--------------------------------------------------+ | vec_elem_sum(parse_vec(Utf8("[1.0, 2.0, 3.0]"))) | +--------------------------------------------------+ | 6 | +--------------------------------------------------+ ``` ```sql SELECT vec_elem_sum('[1.0, 2.0, 3.0]'); -- 隐式转换字符串为向量 ``` ```sql +---------------------------------------+ | vec_elem_sum(Utf8("[1.0, 2.0, 3.0]")) | +---------------------------------------+ | 6 | +---------------------------------------+ ``` ### `vec_elem_product` 向量中所有元素求积,返回一个标量。 示例: ```sql SELECT vec_elem_product(parse_vec('[1.0, 2.0, 3.0]')); ``` ```sql +------------------------------------------------------+ | vec_elem_product(parse_vec(Utf8("[1.0, 2.0, 3.0]"))) | +------------------------------------------------------+ | 6 | +------------------------------------------------------+ ``` ```sql SELECT vec_elem_product('[1.0, 2.0, 3.0]'); -- 隐式转换字符串为向量 ``` ```sql +-------------------------------------------+ | vec_elem_product(Utf8("[1.0, 2.0, 3.0]")) | +-------------------------------------------+ | 6 | +-------------------------------------------+ ``` ### `vec_norm` 归一化向量。将向量中的每个元素除以向量的 L2 范数,返回新的向量。 等价于 `vec_scalar_mul(1.0 / sqrt(vec_elem_sum(vec_mul(vec, vec))), vec)`。 示例: ```sql SELECT vec_to_string(vec_norm(parse_vec('[1.0, 2.0, 3.0]'))); ``` ```sql +-------------------------------------------------------------+ | vec_to_string(vec_norm(parse_vec(Utf8("[1.0, 2.0, 3.0]")))) | +-------------------------------------------------------------+ | [0.26726124,0.5345225,0.8017837] | +-------------------------------------------------------------+ -- 等价于 -- SELECT vec_to_string(vec_scalar_mul(1.0 / sqrt(vec_elem_sum(vec_mul(vec, vec))), vec)) -- FROM (SELECT '[1.0, 2.0, 3.0]' AS vec); -- +--------------------------------------------------------------------------------------+ -- | vec_to_string(vec_scalar_mul(Float64(1) / sqrt(vec_elem_sum(vec_mul(vec,vec))),vec)) | -- +--------------------------------------------------------------------------------------+ -- | [0.26726124,0.5345225,0.8017837] | -- +--------------------------------------------------------------------------------------+ ``` ```sql SELECT vec_to_string(vec_norm('[1.0, 2.0, 3.0]')); -- 隐式转换字符串为向量 ``` ```sql +--------------------------------------------------+ | vec_to_string(vec_norm(Utf8("[1.0, 2.0, 3.0]"))) | +--------------------------------------------------+ | [0.26726124,0.5345225,0.8017837] | +--------------------------------------------------+ ``` ## 聚合函数 ### `vec_sum` 将向量列中的所有向量按元素相加,返回一个新的向量。 示例: ```sql CREATE TABLE vectors ( ts TIMESTAMP TIME INDEX, vec_col VECTOR(3), ); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:01', '[1.0, 2.0, 3.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:02', '[2.0, 1.0, 4.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:03', '[3.0, 3.0, 3.0]'); SELECT vec_to_string(vec_sum(vec_col)) FROM vectors; ``` ```sql +-----------------------------------------+ | vec_to_string(vec_sum(vectors.vec_col)) | +-----------------------------------------+ | [6,6,10] | +-----------------------------------------+ ``` ### `vec_product` 将向量列中的所有向量按元素相乘,返回一个新的向量。 示例: ```sql CREATE TABLE vectors ( ts TIMESTAMP TIME INDEX, vec_col VECTOR(3), ); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:01', '[1.0, 2.0, 3.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:02', '[2.0, 1.0, 4.0]'); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:03', '[3.0, 3.0, 3.0]'); SELECT vec_to_string(vec_product(vec_col)) FROM vectors; ``` ```sql +---------------------------------------------+ | vec_to_string(vec_product(vectors.vec_col)) | +---------------------------------------------+ | [6,6,36] | +---------------------------------------------+ ``` ## 距离计算 GreptimeDB 提供了以下常用的距离计算函数: * `vec_l2sq_distance(vec1, vec2)`:计算两个向量之间的 L2 距离的平方。 * `vec_cos_distance(vec1, vec2)`:计算两个向量之间的余弦距离。 * `vec_dot_product(vec1, vec2)`:计算两个向量之间的点积。 这些函数接受向量值作为参数。你可以通过 `parse_vec` 函数将字符串转变为向量值,例如 `parse_vec('[1.0, 2.0, 3.0]')`。同时,字符串格式的向量(例如 `[1.0, 2.0, 3.0]`)也可以直接使用,它们会被自动转换。无论采用哪种方式,向量的维度必须保持一致。 ### `vec_l2sq_distance` 计算两个向量之间的平方欧几里得距离(L2 距离的平方)。L2 距离是几何空间中两个点之间的直线距离,此函数返回其平方值以提高计算效率。 示例: ```sql SELECT vec_l2sq_distance(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]')); ``` 或者 ```sql SELECT vec_l2sq_distance('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]'); ``` 说明: * 参数为两个维度一致的向量。 * 返回值类型为 `Float32` 标量。 ### `vec_cos_distance` 计算两个向量之间的余弦距离。余弦距离是两个向量之间的夹角余弦值,用于衡量向量之间的相似度。 示例: ```sql SELECT vec_cos_distance(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]')); ``` 或者 ```sql SELECT vec_cos_distance('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]'); ``` 说明: * 参数为两个维度一致的向量。 * 返回值类型为 `Float32` 标量。 ### `vec_dot_product` 计算两个向量之间的点积。点积是两个向量对应元素的乘积之和,常用于度量两个向量的相似性或用于机器学习的线性变换中。 示例: ```sql SELECT vec_dot_product(parse_vec('[1.0, 2.0, 3.0]'), parse_vec('[2.0, 1.0, 4.0]')); ``` 或者 ```sql SELECT vec_dot_product('[1.0, 2.0, 3.0]', '[2.0, 1.0, 4.0]'); ``` 说明: * 参数为两个维度一致的向量。 * 返回值类型为 `Float32` 标量。 ## 转换函数 在处理数据库中的向量数据时,GreptimeDB 提供了方便的函数,用于在字符串和向量值之间进行转换。 ### `parse_vec` 将字符串转换为向量值。字符串必须以方括号 `[]` 包围,并且包含 `Float32` 类型的元素,元素之间用逗号分隔。 示例: ```sql CREATE TABLE vectors ( ts TIMESTAMP, vec_col VECTOR(3) ); INSERT INTO vectors (ts, vec_col) VALUES ('2024-11-18 00:00:01', parse_vec('[1.0, 2.0, 3.0]')); ``` ### `vec_to_string` 将向量值转换为字符串。转换后的字符串格式为 `[, , ...]`。 示例: ```sql SELECT vec_to_string(vec_col) FROM vectors; ``` --- ## Greptime Private GreptimeDB 将一些重要的内部信息以系统表的形式存储在 `greptime_private` 数据库中。与普通表类似,系统表也会持久化存储。你可以通过系统表获取系统配置和统计信息。 ## 表 | 表名 | 描述 | | ----------------------------------- | -------------------------------------------------------- | | [`slow_queries`](./slow_queries.md) | 包含 GreptimeDB 的慢查询信息,包括查询语句、执行时间等。 | | [`pipelines`](./pipelines.md) | 包含 GreptimeDB 的 Pipeline 信息。 | --- ## pipelines `pipelines` 表包含 GreptimeDB 的 Pipeline 信息。 ```sql USE greptime_private; SELECT * FROM pipelines; ``` 输出如下: ```sql +----------------+--------+--------------+----------------------------------------------------------------------------------------------------------------------------------+----------------------------+ | name | schema | content_type | pipeline | created_at | +----------------+--------+--------------+----------------------------------------------------------------------------------------------------------------------------------+----------------------------+ | nginx_pipeline | | yaml | transform: | 2025-07-03 07:23:15.227539 | - fields: - response_size type: int32 - fields: - timestamp type: time index: timestamp +----------------+--------+--------------+----------------------------------------------------------------------------------------------------------------------------------+----------------------------+ ``` - `name`: pipeline 名称; - `schema`: 已废弃。如果你在 `v0.15` 之后创建 pipeline,这个字段会是一个空字符串。 - `content_type`: pipeline 的类型; - `pipeline`: pipeline 的具体内容; - `created_at`: pipeline 的创建时间; 更多详情可参考 [管理 Pipelines](/user-guide/logs/manage-pipelines.md) 文档。 --- ## slow_queries `slow_queries` 表包含 GreptimeDB 的慢查询信息: :::tip 注意 `slow_queries` 表需要开启慢查询日志功能。详见[慢查询](/user-guide/deployments-administration/monitoring/slow-query.md)配置说明。 ::: ```sql USE greptime_private; SELECT * FROM slow_queries; ``` 输出如下: ```sql +------+-----------+---------------------------------------------+-----------+----------------------------+--------------+-------------+---------------------+---------------------+ | cost | threshold | query | is_promql | timestamp | promql_range | promql_step | promql_start | promql_end | +------+-----------+---------------------------------------------+-----------+----------------------------+--------------+-------------+---------------------+---------------------+ | 2 | 0 | irate(process_cpu_seconds_total[1h]) | 1 | 2025-05-14 13:59:36.368575 | 86400000 | 3600000 | 2024-11-24 00:00:00 | 2024-11-25 00:00:00 | | 22 | 0 | SELECT * FROM greptime_private.slow_queries | 0 | 2025-05-14 13:59:44.844201 | 0 | 0 | 1970-01-01 00:00:00 | 1970-01-01 00:00:00 | +------+-----------+---------------------------------------------+-----------+----------------------------+--------------+-------------+---------------------+---------------------+ ``` - `cost`:查询的耗时(毫秒)。 - `threshold`:查询的阈值(毫秒)。 - `query`:查询语句,可以是 SQL 或 PromQL。 - `is_promql`:是否为 PromQL 查询。 - `timestamp`:查询的时间戳。 - `promql_range`:查询的范围,仅在 is_promql 为 true 时使用。 - `promql_step`:查询的步长,仅在 is_promql 为 true 时使用。 - `promql_start`:查询的起始时间,仅在 is_promql 为 true 时使用。 - `promql_end`:查询的结束时间,仅在 is_promql 为 true 时使用。 更多详情可参考 [慢查询](/user-guide/deployments-administration/monitoring/slow-query.md) 文档。 --- ## GROUP BY SQL 中的 `GROUP BY` 语句用于对具有一个或多个列中的相同值的行进行分组。 该子句通常与聚合函数(如 `COUNT`、`SUM`、`AVG` 等)一起使用,以生成汇总报表。 ## Syntax `GROUP BY` 的基本语法如下: ```sql SELECT column1, column2, ..., aggregate_function(column_name) FROM table_name GROUP BY column1, column2, ...; ``` `GROUP BY` 语句根据子句中指定的列对结果集进行分组。 聚合函数应用于具有相同值的组。 ## 示例 假设有如下名为 `system_metrics` 的表: ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` ### 根据 Tags 聚合 要获取每个 `idc` 中的 memory_util 平均值,可以使用以下 SQL: ```sql SELECT idc, AVG(memory_util) FROM system_metrics GROUP BY idc; ``` 结果如下: ```sql +-------+---------------------------------+ | idc | AVG(system_metrics.memory_util) | +-------+---------------------------------+ | idc_b | 66.7 | | idc_c | 66.8 | | idc_e | 66.7 | | idc_a | 40.3 | +-------+---------------------------------+ ``` ### 根据 Time Interval 聚合 要获取 memory_util 的日均值,SQL 如下: ```sql SELECT date_trunc('day', ts) as dt, avg(memory_util) FROM system_metrics GROUP BY dt ``` 请参考 [date_trunc](./functions/overview.md#date_trunc) 获取更多信息。 --- ## HAVING `HAVING` 子句允许你过滤分组(聚合)结果——它的作用类似于 `WHERE`,但是在分组发生之后才起作用。 `HAVING` 子句被添加到 SQL 中,是因为 `WHERE` 子句不能与聚合函数一起使用。 ## 例子 查找平均 CPU 利用率超过 80% 的日期窗口: ```sql SELECT date_trunc('day', ts) AS day, AVG(cpu_util) AS avg_cpu_util FROM system_metrics GROUP BY day HAVING avg_cpu_util > 80; ``` 查找错误日志数量大于 100 的小时窗口: ```sql SELECT DATE_TRUNC('hour', log_time) AS hour, COUNT(*) AS error_count FROM application_logs WHERE log_level = 'ERROR' GROUP BY hour HAVING error_count > 100; ``` --- ## Alerts :::tip 注意 本功能仅在 GreptimeDB 企业版中可用。 ::: `ALERTS` 表用于展示由 Trigger 生成的所有告警实例的信息。 ```sql DESC TABLE INFORMATION_SCHEMA.ALERTS; ``` ```sql +--------------+---------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------+---------------------+------+------+---------+---------------+ | trigger_id | UInt64 | | NO | | FIELD | | trigger_name | String | | NO | | FIELD | | labels | Json | | NO | | FIELD | | annotations | Json | | YES | | FIELD | | status | String | | NO | | FIELD | | active_at | TimestampNanosecond | | NO | | FIELD | | fired_at | TimestampNanosecond | | YES | | FIELD | | resolved_at | TimestampNanosecond | | YES | | FIELD | | last_sent_at | TimestampNanosecond | | YES | | FIELD | +--------------+---------------------+------+------+---------+---------------+ ``` 表中的列: * `trigger_id`:生成该告警实例的 Trigger 的 id。 * `trigger_name`:生成该告警实例的 Trigger 的名称。 * `labels`:与告警实例关联的标签(key-value)集合。标签集合用于唯一标识一个告警 实例。 * `annotations`:与告警实例关联的注解(key-value)集合。 * `status`:当前告警实例的状态。 * `active_at`:告警实例变为活跃的时间戳。 * `fired_at`:告警实例首次进入 `Firing` 状态的时间戳。 * `resolved_at`:告警实例被解决的时间戳。 * `last_sent_at`:最近一次发送通知的时间戳。 --- ## BUILD_INFO `BUILD_INFO` 表提供了系统的构建信息: ```sql USE INFORMATION_SCHEMA; SELECT * FROM BUILD_INFO; ``` 结果如下: ```sql +------------+------------------------------------------+------------------+-----------+-------------+ | git_branch | git_commit | git_commit_short | git_clean | pkg_version | +------------+------------------------------------------+------------------+-----------+-------------+ | | c595a56ac89bef78b19a76aa60d8c6bcac7354a5 | c595a56a | true | 0.9.0 | +------------+------------------------------------------+------------------+-----------+-------------+ ``` 结果中的列: * `branch`:构建的 git 分支名称。 * `git_commit`:提交构建的 `commit`。 * `git_commit_short`:提交构建的 `commit` 缩写。 * `git_clean`:如果构建源目录包含了所有提交的更改,则为 `true`。 * `pkg_version`:GreptimeDB 版本。 --- ## CHARACTER_SETS `CHARACTER_SETS` 提供了 GreptimeDB 支持的可用字符集。 ```sql USE INFORMATION_SCHEMA; SELECT * FROM CHARACTER_SETS; ``` 结果如下: ```sql +--------------------+----------------------+---------------+--------+ | character_set_name | default_collate_name | description | maxlen | +--------------------+----------------------+---------------+--------+ | utf8 | utf8_bin | UTF-8 Unicode | 4 | +--------------------+----------------------+---------------+--------+ ``` 结果中的列: * `character_set_name`:字符集的名称。 * `default_collate_name`:字符集的默认排序规则名称。 * `description`:字符集的描述。 * `MAXLEN`:存储一个字符所需的最大字节数。 --- ## CLUSTER_INFO `CLUSTER_INFO` 表提供了集群的节点拓扑信息。 ```sql USE INFORMATION_SCHEMA; DESC TABLE CLUSTER_INFO; ``` 输出如下: ```sql +-----------------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------------+----------------------+------+------+---------+---------------+ | peer_id | Int64 | | NO | | FIELD | | peer_type | String | | NO | | FIELD | | peer_addr | String | | YES | | FIELD | | peer_hostname | String | | YES | | FIELD | | total_cpu_millicores | Int64 | | NO | | FIELD | | total_memory_bytes | Int64 | | NO | | FIELD | | cpu_usage_millicores | Int64 | | NO | | FIELD | | memory_usage_bytes | Int64 | | NO | | FIELD | | version | String | | NO | | FIELD | | git_commit | String | | NO | | FIELD | | start_time | TimestampMillisecond | | YES | | FIELD | | uptime | String | | YES | | FIELD | | active_time | String | | YES | | FIELD | | node_status | String | | YES | | FIELD | +-----------------------+----------------------+------+------+---------+---------------+ ``` 每个列的含义: * `peer_id`: 节点的服务器 ID。对于 standalone 来讲,该字段总是为 `0`,对于集群模式下的 frontend 该字段总为 `-1`。因为在这两种情况下,该字段没有实际含义。 * `peer_type`: 节点类型,分布式集群里可能是 `METASRV`、`FRONTEND` 或者 `DATANODE`。单机模式显示为 `STANDALONE`。 * `peer_addr`: 节点的 gRPC 服务地址。对于单机部署,该字段总为空。 * `peer_hostname`: 节点的主机名。 * `total_cpu_millicores`: 节点的总 CPU 毫核数。 * `total_memory_bytes`: 节点的总内存字节数。 * `cpu_usage_millicores`: 节点的 CPU 使用毫核数。此功能仅在容器化环境 (cgroup v2) 中有效。 * `memory_usage_bytes`: 节点的内存使用字节数。此功能仅在容器化环境 (cgroup v2) 中有效。 * `version`: 节点的版本号,形如 `0.7.2` 的字符串。 * `git_commit`: 节点编译的 git 版本号。 * `start_time`: 节点的启动时间。 * `uptime`: 节点的持续运行时间,形如 `24h 10m 59s 150ms` 的字符串。 * `active_time`: 距离节点上一次活跃(也就是发送心跳请求)过去的时间,形如 `24h 10m 59s 150ms` 的字符串。单机模式下该字段总为空。 * `node_status`: 节点的状态信息。 尝试查询下这张表: ```sql SELECT * FROM CLUSTER_INFO; ``` 一个单机模式的样例输出: ```sql +---------+------------+-----------+---------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+--------+-------------+-------------+ | peer_id | peer_type | peer_addr | peer_hostname | total_cpu_millicores | total_memory_bytes | cpu_usage_millicores | memory_usage_bytes | version | git_commit| start_time | uptime | active_time | node_status | +---------+------------+-----------+---------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+--------+-------------+-------------+ | 0 | STANDALONE | | | 16000 | 17179869184 | 0 | 0 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:02.074 | 18ms | | NULL | +---------+------------+-----------+---------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+--------+-------------+-------------+ ``` 另一个输出来自一个分布式集群,它有三个 Datanode、一个 Frontend 和一个 Metasrv: ```sql +---------+-----------+----------------+-------------------------------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+----------+-------------+-------------------------------------------------------------------+ | peer_id | peer_type | peer_addr | peer_hostname | total_cpu_millicores | total_memory_bytes | cpu_usage_millicores | memory_usage_bytes | version | git_commit| start_time | uptime | active_time | node_status | +---------+-----------+----------------+-------------------------------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+----------+-------------+-------------------------------------------------------------------+ | 1 | DATANODE | 127.0.0.1:4101 | mycluster-datanode-0 | 1000 | 1073741824 | 1 | 34570240 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:04.791 | 4s 478ms | 1s 467ms | {"workloads":["hybrid"],"leader_regions":46,"follower_regions":0} | | 2 | DATANODE | 127.0.0.1:4102 | mycluster-datanode-1 | 1000 | 1073741824 | 1 | 38170624 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:06.098 | 3s 171ms | 162ms | {"workloads":["hybrid"],"leader_regions":46,"follower_regions":0} | | 3 | DATANODE | 127.0.0.1:4103 | mycluster-datanode-2 | 1000 | 1073741824 | 1 | 37085184 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:07.425 | 1s 844ms | 1s 839ms | {"workloads":["hybrid"],"leader_regions":46,"follower_regions":0} | | -1 | FRONTEND | 127.0.0.1:4001 | mycluster-frontend-6c5d4bcf78-m7jtx | 1000 | 1073741824 | 1 | 45465600 | 0.7.2 | 86ab3d9 | 2024-04-30T06:40:08.815 | 454ms | 47ms | NULL | | 0 | METASRV | 127.0.0.1:3002 | mycluster-meta-54bd44bd94-g8dzm | 1000 | 1073741824 | 0 | 28368896 | unknown | unknown | | | | {"is_leader":true} | +---------+-----------+----------------+-------------------------------------+----------------------+--------------------+----------------------+--------------------+---------+-----------+----------------------------+----------+-------------+-------------------------------------------------------------------+ ``` --- ## COLLATION_CHARACTER_SET_APPLICABILITY `COLLATION_CHARACTER_SET_APPLICABILITY` 表示了每个排序规则适用的字符集。 ```sql USE INFORMATION_SCHEMA; SELECT * FROM COLLATION_CHARACTER_SET_APPLICABILITY; ``` 结果如下: ```sql +----------------+--------------------+ | collation_name | character_set_name | +----------------+--------------------+ | utf8_bin | utf8 | +----------------+--------------------+ ``` 结果中的列: * `collation_name`:排序规则名称。 * `character_set_name`:与排序规则关联的字符集名称。 --- ## COLLATIONS `COLLATIONS` 提供了每个字符集的排序规则信息。 ```sql USE INFORMATION_SCHEMA; SELECT * FROM COLLATIONS; ``` 结果如下: ```sql +----------------+--------------------+------+------------+-------------+---------+ | collation_name | character_set_name | id | is_default | is_compiled | sortlen | +----------------+--------------------+------+------------+-------------+---------+ | utf8_bin | utf8 | 1 | Yes | Yes | 1 | +----------------+--------------------+------+------------+-------------+---------+ ``` 表中有这些列: * `collation_name`:排序规则名称。 * `character_set_name`:字符集名称。 * `id`:排序规则 ID。 * `is_default`:是否为字符集的默认排序规则。 * `is_compiled`:字符集是否已编译到系统中。 * `sortlen`:以字符集表示的字符串排序所需的最小内存量。 --- ## COLUMNS `COLUMNS` 提供了关于表中每列的详细信息。 ```sql USE INFORMATION_SCHEMA; DESC COLUMNS; ``` 结果如下: ```sql +--------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------------+--------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | column_name | String | | NO | | FIELD | | ordinal_position | Int64 | | NO | | FIELD | | character_maximum_length | Int64 | | YES | | FIELD | | character_octet_length | Int64 | | YES | | FIELD | | numeric_precision | Int64 | | YES | | FIELD | | numeric_scale | Int64 | | YES | | FIELD | | datetime_precision | Int64 | | YES | | FIELD | | character_set_name | String | | YES | | FIELD | | collation_name | String | | YES | | FIELD | | column_key | String | | NO | | FIELD | | extra | String | | NO | | FIELD | | privileges | String | | NO | | FIELD | | generation_expression | String | | NO | | FIELD | | greptime_data_type | String | | NO | | FIELD | | data_type | String | | NO | | FIELD | | semantic_type | String | | NO | | FIELD | | column_default | String | | YES | | FIELD | | is_nullable | String | | NO | | FIELD | | column_type | String | | NO | | FIELD | | column_comment | String | | YES | | FIELD | | srs_id | Int64 | | YES | | FIELD | +--------------------------+--------+------+------+---------+---------------+ 24 rows in set (0.00 sec) ``` 创建表 `public.t1` 并查询其在 `COLUMNS` 中的信息: ```sql CREATE TABLE public.t1 (h STRING, v FLOAT64, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX, PRIMARY KEY(h)); SELECT * FROM COLUMNS WHERE table_schema='public' AND TABLE_NAME='t1'\G ``` 结果如下: ```sql *************************** 1. row *************************** table_catalog: greptime table_schema: public table_name: t1 column_name: h ordinal_position: 1 character_maximum_length: 2147483647 character_octet_length: 2147483647 numeric_precision: NULL numeric_scale: NULL datetime_precision: NULL character_set_name: utf8 collation_name: utf8_bin column_key: PRI extra: privileges: select,insert generation_expression: greptime_data_type: String data_type: string semantic_type: TAG column_default: NULL is_nullable: Yes column_type: string column_comment: NULL srs_id: NULL *************************** 2. row *************************** table_catalog: greptime table_schema: public table_name: t1 column_name: v ordinal_position: 2 character_maximum_length: NULL character_octet_length: NULL numeric_precision: 22 numeric_scale: NULL datetime_precision: NULL character_set_name: NULL collation_name: NULL column_key: extra: privileges: select,insert generation_expression: greptime_data_type: Float64 data_type: double semantic_type: FIELD column_default: NULL is_nullable: Yes column_type: double column_comment: NULL srs_id: NULL *************************** 3. row *************************** table_catalog: greptime table_schema: public table_name: t1 column_name: ts ordinal_position: 3 character_maximum_length: NULL character_octet_length: NULL numeric_precision: NULL numeric_scale: NULL datetime_precision: 3 character_set_name: NULL collation_name: NULL column_key: TIME INDEX extra: privileges: select,insert generation_expression: greptime_data_type: TimestampMillisecond data_type: timestamp(3) semantic_type: TIMESTAMP column_default: current_timestamp() is_nullable: No column_type: timestamp(3) column_comment: NULL srs_id: NULL 3 rows in set (0.03 sec) ``` `COLUMNS` 表中列的描述如下: - `table_catalog`:列所属的目录的名称。在 OSS 项目中该值始终为 `greptime`。 - `table_schema`:包含列的表所属的数据库的名称。 - `table_name`:包含列的表的名称。 - `column_name`:列的名称。 - `ordinal_position`:列在表中的位置。 - `character_maximum_length`:对于字符串列,以字符为单位的最大长度。 - `character_octet_length`:对于字符串列,以字节为单位的最大长度。 - `numeric_precision`:对于数值数据类型,列的精度。 - `numeric_scale`:对于数值数据类型,列的标度。 - `datetime_precision`:对于日期时间数据类型,列的小数秒精度。 - `character_set_name`:字符串列的字符集的名称。 - `collation_name`:字符串列的排序规则的名称。 - `column_key`:列的键类型。可以是以下之一:`PRI`、`TIME INDEX` 或空字符串。 - `extra`:关于列的附加信息。 - `privileges`:当前用户对该列的权限。 - `generation_expression`:对于生成的列,此值显示用于计算列值的表达式。对于非生成的列,该值为空。 - `greptime_data_type`:列的 GreptimeDB [数据类型](/reference/sql/data-types.md)。 - `data_type`:列中的数据类型。 - `semantic_type`:列的类型。可以是以下之一:`TAG`、`FIELD` 或 `TIMESTAMP`。 - `column_default`:列的默认值。如果默认值被明确设定为 `NULL`,或者列定义中不包含 `default` 子句,则该值为 `NULL`。 - `is_nullable`:列是否可为空。如果列可以存储空值,则该值为 `YES`;否则,为 `NO`。 - `column_type`:列的数据类型。与 `DATA_TYPE` 列相同。 - `column_comment`:列定义中包含的注释。 - `srs_id`:列的空间参考系统(SRS)的 ID。 相应的 `SHOW` 语句如下: ```sql SHOW COLUMNS FROM t1 FROM public; ``` 结果如下: ```sql +-------+--------------+------+------------+---------------------+-------+----------------------+ | Field | Type | Null | Key | Default | Extra | Greptime_type | +-------+--------------+------+------------+---------------------+-------+----------------------+ | h | string | Yes | PRI | NULL | | String | | ts | timestamp(3) | No | TIME INDEX | current_timestamp() | | TimestampMillisecond | | v | double | Yes | | NULL | | Float64 | +-------+--------------+------+------------+---------------------+-------+----------------------+ 3 rows in set (0.01 sec) ``` --- ## ENGINES `ENGINES`表提供了关于存储引擎的信息。当你需要检查 GreptimeDB 是否支持某个存储引擎或者查看默认的存储引擎时,该表非常有用。 `ENGINES`表包含以下列: * `engine`:存储引擎名称。 * `support`:存储引擎的支持级别: |值 | 含义| | --- | --- | | `YES` | 支持且在使用中 | | `DEFAULT` | 支持且在使用中,且是默认的存储引擎 | | `NO` | 不支持 | | `DISABLED` | 支持但已被禁用 | * `comment`:存储引擎的简要描述。 * `transactions`:存储引擎是否支持事务。 * `xa`:存储引擎是否支持 XA 事务。 * `savepoints`:存储引擎是否支持保存点。 例如: ```sql SELECT * from INFORMATION_SCHEMA.ENGINES\G ``` 结果如下: ```sql *************************** 1. row *************************** engine: mito support: DEFAULT comment: Storage engine for time-series data transactions: NO xa: NO savepoints: NO *************************** 2. row *************************** engine: metric support: YES comment: Storage engine for observability scenarios, which is adept at handling a large number of small tables, making it particularly suitable for cloud-native monitoring transactions: NO xa: NO savepoints: NO ``` --- ## FLOWS `Flows` 表提供了 Flow 任务的相关信息。 ```sql DESC TABLE INFORMATION_SCHEMA.FLOWS; ``` ```sql Column | Type | Key | Null | Default | Semantic Type ------------------+--------+-----+------+---------+--------------- flow_name | String | | NO | | FIELD flow_id | UInt32 | | NO | | FIELD table_catalog | String | | NO | | FIELD flow_definition | String | | NO | | FIELD comment | String | | YES | | FIELD expire_after | Int64 | | YES | | FIELD source_table_ids | String | | YES | | FIELD sink_table_name | String | | NO | | FIELD flownode_ids | String | | YES | | FIELD options | String | | YES | | FIELD (10 rows) ``` 表中的列: * `flow_name`: Flow 任务的名称。 * `flow_id`: Flow 任务的 id。 * `table_catalog`: 该 Flow 所属的目录,命名为 `table_catalog` 以保持与 `INFORMATION_SCHEMA` 标准一致。 * `flow_definition`: Flow 任务的定义,是用于创建 Flow 任务的 SQL 语句。 * `comment`: Flow 任务的注释。 * `expire_after`: Flow 任务的过期时间。 * `source_table_ids`: Flow 任务的源表 id。 * `sink_table_name`: Flow 任务的目标表名称。 * `flownode_ids`: Flow 任务使用的 flownode id。 * `options`: Flow 任务的其他额外选项。 --- ## KEY_COLUMN_USAGE `KEY_COLUMN_USAGE` 表描述列的键约束,例如时间索引键的约束。 ```sql USE INFORMATION_SCHEMA; DESC KEY_COLUMN_USAGE; ``` 结果如下: ```sql +-------------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-------------------------------+--------+------+------+---------+---------------+ | constraint_catalog | String | | NO | | FIELD | | constraint_schema | String | | NO | | FIELD | | constraint_name | String | | NO | | FIELD | | table_catalog | String | | NO | | FIELD | | real_table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | column_name | String | | NO | | FIELD | | ordinal_position | UInt32 | | NO | | FIELD | | position_in_unique_constraint | UInt32 | | YES | | FIELD | | referenced_table_schema | String | | YES | | FIELD | | referenced_table_name | String | | YES | | FIELD | | referenced_column_name | String | | YES | | FIELD | +-------------------------------+--------+------+------+---------+---------------+ ``` ```sql SELECT * FROM key_column_usage WHERE table_schema='public' and table_name='monitor'\G ``` ```sql *************************** 1. row *************************** constraint_catalog: def constraint_schema: public constraint_name: TIME INDEX table_catalog: def real_table_catalog: greptime table_schema: public table_name: monitor column_name: ts ordinal_position: 1 position_in_unique_constraint: NULL referenced_table_schema: NULL referenced_table_name: NULL referenced_column_name: NULL *************************** 2. row *************************** constraint_catalog: def constraint_schema: public constraint_name: PRIMARY table_catalog: def real_table_catalog: greptime table_schema: public table_name: monitor column_name: host ordinal_position: 1 position_in_unique_constraint: NULL referenced_table_schema: NULL referenced_table_name: NULL referenced_column_name: NULL 2 rows in set (0.02 sec) ``` `KEY_COLUMN_USAGE` 表中列的描述如下: - `constraint_catalog`:约束所属的目录名称。该值始终为 `def`。 - `constraint_schema`:约束所属的数据库名称。 - `constraint_name`:约束的名称。 - `table_catalog`:表所属目录的名称。该值始终为 `def`。 - `real_table_catalog`:表所属目录的真实名称。该值始终为 `greptime`。 - `table_schema`:表所属的数据库名称。 - `table_name`:具有约束的表的名称。 - `column_name`:具有约束的列的名称。 - `ordinal_position`:列在约束中的位置,而不是在表中的位置。位置编号从 `1` 开始。 - `position_in_unique_constraint`:唯一约束和主键约束为空。对于外键约束,此列是引用表键的位置。 - `referenced_table_schema`:约束引用的数据库名称。目前在 GreptimeDB 中,除外键约束外,所有约束中此列的值均为 `NULL`。 - `referenced_table_name`:约束引用的表名称。目前在 GreptimeDB 中,除外键约束外,所有约束中此列的值均为 `NULL`。 - `referenced_column_name`:约束引用的列名称。目前在 GreptimeDB 中,除外键约束外,所有约束中此列的值均为 `NULL`。 --- ## INFORMATION_SCHEMA `INFORMATION_SCHEMA` 提供了对系统元数据的访问,例如数据库或表的名称、列的数据类型等。GreptimeDB 还提供了一些自定义的 `INFORMATION_SCHEMA` 表,用于查询有关 GreptimeDB 系统本身、集群信息和运行时指标等元数据。很多 `INFORMATION_SCHEMA` 表都有对应的 `SHOW` 命令,查询 `INFORMATION_SCHEMA` 的好处是可以在表之间进行连接。 `INFORMATION_SCHEMA` 依然有很多工作要做,请跟踪 `INFORMATION_SCHEMA` 的 [issue](https://github.com/GreptimeTeam/greptimedb/issues/2931)。 ## MySQL 兼容性 |表名 | 描述| | --- | --- | | [`CHARACTER_SETS`](./character-sets.md) | 提供了可用字符集的信息。 | | `CHECK_CONSTRAINTS`| 未实现。返回零行。 | | [`COLLATIONS`](./collations.md) | 提供了服务器支持的排序规则列表。 | | [`COLLATION_CHARACTER_SET_APPLICABILITY`](./collation-character-set-applicability.md) | 解释了哪些排序规则适用于哪些字符集。 | | [`COLUMNS`](./columns.md) | 提供了所有表的列列表。 | | `COLUMN_PRIVILEGES` | 未实现。返回零行。 | | `COLUMN_STATISTICS` | 不支持。 | | [`ENGINES`](./engines.md) | 提供了支持的存储引擎列表。 | | `EVENTS` | 未实现。返回零行。 | | `FILES` | 未实现。返回零行。 | | `GLOBAL_STATUS` | 未实现。返回零行。 | | `GLOBAL_VARIABLES` | 不支持。 | | [`KEY_COLUMN_USAGE`](./key-column-usage.md) | 描述了列的关键约束,例如主键和时间索引约束。 | | `OPTIMIZER_TRACE` | 未实现。返回零行。 | | `PARAMETERS` | 未实现。返回零行。 | | [`PARTITIONS`](./partitions.md) | 提供了表分区的列表。 | | `PLUGINS` | 不支持。| | `PROCESSLIST` | 不支持,请使用 `PROCESS_LIST` 表 | | `PROFILING` | 未实现。返回零行。 | | `REFERENTIAL_CONSTRAINTS` | 未实现。返回零行。 | | `ROUTINES` | 未实现。返回零行。 | | [`SCHEMATA`](./schemata.md) | 提供了类似于 `SHOW DATABASES` 的信息。 | | `SCHEMA_PRIVILEGES` | 未实现。返回零行。 | | `SESSION_STATUS` | 未实现。返回零行。 | | `SESSION_VARIABLES` | 不支持。 | | `STATISTICS` | 不支持。 | | [`TABLES`](./tables.md) | 提供了当前用户可见的表列表。类似于 `SHOW TABLES`。 | | `TABLESPACES` | 不支持。 | | `TABLE_PRIVILEGES` | 未实现。返回零行。 | | `TRIGGERS` | 不支持。 | | `USER_ATTRIBUTES` | 不支持。 | | `USER_PRIVILEGES` | 不支持。| | `VARIABLES_INFO` | 不支持。 | | [`VIEWS`](./views.md)| 提供了当前用户可见的视图(View)列表及相关信息。 | | [`TABLE_CONSTRAINTS`](./table-constraints.md) | 提供了主键、唯一索引和外键的信息。 | ## GreptimeDB 提供的表 |表名 | 描述| | --- | --- | | [`BUILD_INFO`](./build-info.md) | 提供了系统构建的信息。 | | [`REGION_PEERS`](./region-peers.md) | 提供了表的 Region 存储的详细信息。 | | [`REGION_STATISTICS`](./region-statistics.md) | 提供 Region 的详细统计信息,例如行数等。 | | [`CLUSTER_INFO`](./cluster-info.md)| 提供了集群的节点拓扑信息。| | [`FLOWS`](./flows.md) | 提供 Flow 相关信息。| | [`PROCEDURE_INFO`](./procedure-info.md) | 提供 Procedure 相关信息。| | [`PROCESS_LIST`](./process-list.md) | 提供集群内正在执行的查询信息。 | | [`SSTS_INDEX_META`](./ssts-index-meta.md) | 提供 SST 索引元数据,包括倒排索引、全文索引和布隆过滤器。| | [`SSTS_MANIFEST`](./ssts-manifest.md) | 提供从 manifest 获取的 SST 文件信息,包括文件路径、大小、时间范围和行数。| | [`SSTS_STORAGE`](./ssts-storage.md) | 提供从存储层获取的 SST 文件信息,用于验证和调试。| | [`TRIGGERS`](./triggers.md) | 提供 Trigger 的相关信息。 | | [`ALERTS`](./alerts.md) | 提供告警的相关信息。 | --- ## PARTITIONS `PARTITIONS` 表提供了关于分区表的信息。 ```sql USE INFORMATION_SCHEMA; DESC PARTITIONS; ``` 结果如下: ```sql +-------------------------------+----------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-------------------------------+----------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | partition_name | String | | NO | | FIELD | | subpartition_name | String | | YES | | FIELD | | partition_ordinal_position | Int64 | | YES | | FIELD | | subpartition_ordinal_position | Int64 | | YES | | FIELD | | partition_method | String | | YES | | FIELD | | subpartition_method | String | | YES | | FIELD | | partition_expression | String | | YES | | FIELD | | subpartition_expression | String | | YES | | FIELD | | partition_description | String | | YES | | FIELD | | table_rows | Int64 | | YES | | FIELD | | avg_row_length | Int64 | | YES | | FIELD | | data_length | Int64 | | YES | | FIELD | | max_data_length | Int64 | | YES | | FIELD | | index_length | Int64 | | YES | | FIELD | | data_free | Int64 | | YES | | FIELD | | create_time | TimestampSecond | | YES | | FIELD | | update_time | TimestampSecond | | YES | | FIELD | | check_time | TimestampSecond | | YES | | FIELD | | checksum | Int64 | | YES | | FIELD | | partition_comment | String | | YES | | FIELD | | nodegroup | String | | YES | | FIELD | | tablespace_name | String | | YES | | FIELD | | greptime_partition_id | UInt64 | | YES | | FIELD | +-------------------------------+----------+------+------+---------+---------------+ 26 rows in set (0.01 sec) ``` 主要列包括: * `table_catalog`:表所属目录的名称。该值始终为 `def`。 * `table_schema`:表所属的 schema(数据库)的名称。 * `table_name`:包含分区(region)的表的名称。 * `partition_name`:分区(region)的名称。 * `partition_ordinal_position`:所有分区按照定义的顺序进行索引,1 是分配给第一个分区的编号。 * `partition_method`:该值始终为 `RANGE`,GreptimeDB 仅支持范围分区。 * `partition_expression`:该分区的表达式。 * `create_time`:分区创建的时间。 * `greptime_partition_id`:GreptimeDB 扩展字段,也就是 Region Id。 创建一张分区表并查询: ```sql CREATE TABLE public.test_p ( a INT PRIMARY KEY, b STRING, ts TIMESTAMP TIME INDEX, ) PARTITION ON COLUMNS (a) ( a < 10, a >= 10 AND a < 20, a >= 20 ); -- 查询表的分区信息 SELECT * FROM PARTITIONS WHERE table_schema='public' AND table_name='test_p'\G ``` 示例输出如下: ```sql *************************** 1. row *************************** table_catalog: greptime table_schema: public table_name: test_p partition_name: p0 subpartition_name: NULL partition_ordinal_position: 1 subpartition_ordinal_position: NULL partition_method: RANGE subpartition_method: NULL partition_expression: (a) VALUES LESS THAN (PartitionExpr { lhs: Column("a"), op: Lt, rhs: Value(Int32(10)) }) subpartition_expression: NULL partition_description: NULL table_rows: NULL avg_row_length: NULL data_length: NULL max_data_length: NULL index_length: NULL data_free: NULL create_time: 2024-04-01 10:49:49.468000 update_time: NULL check_time: NULL checksum: NULL partition_comment: NULL nodegroup: NULL tablespace_name: NULL greptime_partition_id: 4453881085952 *************************** 2. row *************************** table_catalog: greptime table_schema: public table_name: test_p partition_name: p1 subpartition_name: NULL partition_ordinal_position: 2 subpartition_ordinal_position: NULL partition_method: RANGE subpartition_method: NULL partition_expression: (a) VALUES LESS THAN (PartitionExpr { lhs: Column("a"), op: GtEq, rhs: Value(Int32(20)) }) subpartition_expression: NULL partition_description: NULL table_rows: NULL avg_row_length: NULL data_length: NULL max_data_length: NULL index_length: NULL data_free: NULL create_time: 2024-04-01 10:49:49.468000 update_time: NULL check_time: NULL checksum: NULL partition_comment: NULL nodegroup: NULL tablespace_name: NULL greptime_partition_id: 4453881085954 *************************** 3. row *************************** table_catalog: greptime table_schema: public table_name: test_p partition_name: p2 subpartition_name: NULL partition_ordinal_position: 3 subpartition_ordinal_position: NULL partition_method: RANGE subpartition_method: NULL partition_expression: (a) VALUES LESS THAN (PartitionExpr { lhs: Expr(PartitionExpr { lhs: Column("a"), op: Gt, rhs: Value(Int32(10)) }), op: And, rhs: Expr(PartitionExpr { lhs: Column("a"), op: Lt, rhs: Value(Int32(20)) }) }) subpartition_expression: NULL partition_description: NULL table_rows: NULL avg_row_length: NULL data_length: NULL max_data_length: NULL index_length: NULL data_free: NULL create_time: 2024-04-01 10:49:49.468000 update_time: NULL check_time: NULL checksum: NULL partition_comment: NULL nodegroup: NULL tablespace_name: NULL greptime_partition_id: 4453881085953 ``` --- ## PROCEDURE_INFO `PROCEDURE_INFO` 表提供了各种 Procedure 的详细信息。 ```sql DESC TABLE INFORMATION_SCHEMA.PROCEDURE_INFO; ``` ```sql +----------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +----------------+----------------------+------+------+---------+---------------+ | procedure_id | String | | NO | | FIELD | | procedure_type | String | | NO | | FIELD | | start_time | TimestampMillisecond | | YES | | FIELD | | end_time | TimestampMillisecond | | YES | | FIELD | | status | String | | NO | | FIELD | | lock_keys | String | | YES | | FIELD | +----------------+----------------------+------+------+---------+---------------+ ``` `PROCEDURE_INFO` 表中的字段描述如下: - `procedure_id`: Procedure 的 ID。 - `procedure_type`: Procedure 的类型。 - `start_time`: Procedure 开始的时间戳。 - `end_time`: Procedure 结束的时间戳。 - `status`: Procedure 当前的状态。 - `lock_keys`: Procedure 锁定的键。 --- ## PROCESS_LIST `PROCESS_LIST` 表提供了 GreptimeDB 集群中所有正在运行的查询的视图。 :::tip NOTE `PROCESS_LIST`表特意选择了一个与 MySQL 的 `PROCESSLIST` 不同的名称,因为它们的列并不相通。 ::: ```sql USE INFORMATION_SCHEMA; DESC PROCESS_LIST; ``` 输出如下: ```sql +-----------------+----------------------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------+----------------------+------+------+---------+---------------+ | id | String | | NO | | FIELD | | catalog | String | | NO | | FIELD | | schemas | String | | NO | | FIELD | | query | String | | NO | | FIELD | | client | String | | NO | | FIELD | | frontend | String | | NO | | FIELD | | start_timestamp | TimestampMillisecond | | NO | | FIELD | | elapsed_time | DurationMillisecond | | NO | | FIELD | +-----------------+----------------------+------+------+---------+---------------+ ``` `PROCESS_LIST` 表中的字段描述如下: - `id`: 查询的 ID。 - `catalog`: 查询的 catalog 名称。 - `schemas`: 客户端发出查询时所处的 schema 名称。 - `query`: 查询语句。 - `client`: 客户端信息,包括客户端地址和使用的协议。 - `frontend`: 查询正在运行的 frontend 实例。 - `start_timestamp`: 查询的开始时间戳。 - `elapsed_time`: 查询已运行多长时间。 :::tip NOTE 你还可以使用 `SHOW [FULL] PROCESSLIST` 语句作为直接查询 `INFORMATION_SCHEMA.PROCESS_LIST` 表的替代方法。 ::: # 终止一个查询 当从 `PROCESS_LIST` 表中识别到正在运行的查询时,你可以使用 `KILL ` 语句终止该查询,其中 `` 是 `PROCESS_LIST` 表中的 `id` 字段。 ```sql mysql> select * from process_list; +-----------------------+----------+--------------------+----------------------------+------------------------+---------------------+----------------------------+-----------------+ | id | catalog | schemas | query | client | frontend | start_timestamp | elapsed_time | +-----------------------+----------+--------------------+----------------------------+------------------------+---------------------+----------------------------+-----------------+ | 112.40.36.208/7 | greptime | public | SELECT * FROM some_very_large_table | mysql[127.0.0.1:34692] | 112.40.36.208:4001 | 2025-06-30 07:04:11.118000 | 00:00:12.002000 | +-----------------------+----------+--------------------+----------------------------+------------------------+---------------------+----------------------------+-----------------+ KILL '112.40.36.208/7'; Query OK, 1 row affected (0.00 sec) ``` --- ## REGION_PEERS `REGION_PEERS` 表显示了 GreptimeDB 中单个 Region 节点的详细信息,例如它是 learner 还是 leader。 ```sql USE INFORMATION_SCHEMA; DESC REGION_PEERS; ``` 结果如下: ```sql +--------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +---------------+--------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | region_id | UInt64 | | NO | | FIELD | | peer_id | UInt64 | | YES | | FIELD | | peer_addr | String | | YES | | FIELD | | is_leader | String | | YES | | FIELD | | status | String | | YES | | FIELD | | down_seconds | Int64 | | YES | | FIELD | +---------------+--------+------+------+---------+---------------+ 6 rows in set (0.00 sec) ``` `REGION_PEERS` 表中的字段描述如下: - `table_catalog`:表所属的目录。 - `table_schema`:表所属的数据库。 - `table_name`:表的名称。 - `region_id`:Region 的 ID。 - `peer_id`:Region peer 的 ID。 - `peer_addr`:peer 的地址。 - `is_leader`:peer 是否为 leader。 - `status`:peer 的状态,`ALIVE` 或 `DOWNGRADED`。 - `ALIVE`:peer 在线。 - `DOWNGRADED`:Region peer 不可用(例如,已崩溃、网络断开),或者计划将 Region peer 迁移到另一个 peer。 - `down_seconds`:离线时长,单位为秒。 --- ## REGION_STATISTICS `REGION_STATISTICS` 表提供了关于某个 Region 统计信息的详细数据,包括总行数、磁盘大小等。这些统计信息都是近似值。 ```sql USE INFORMATION_SCHEMA; DESC REGION_STATISTICS; ``` 输出如下: ```sql +--------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------------+--------+------+------+---------+---------------+ | region_id | UInt64 | | NO | | FIELD | | table_id | UInt32 | | NO | | FIELD | | region_number | UInt32 | | NO | | FIELD | | region_rows | UInt64 | | YES | | FIELD | | written_bytes_since_open | UInt64 | | YES | | FIELD | | disk_size | UInt64 | | YES | | FIELD | | memtable_size | UInt64 | | YES | | FIELD | | manifest_size | UInt64 | | YES | | FIELD | | sst_size | UInt64 | | YES | | FIELD | | sst_num | UInt64 | | YES | | FIELD | | index_size | UInt64 | | YES | | FIELD | | engine | String | | YES | | FIELD | | region_role | String | | YES | | FIELD | +--------------------------+--------+------+------+---------+---------------+ ``` `REGION_STATISTICS` 表中的字段描述如下: - `region_id`: Region 的 ID。 - `table_id`: 表的 ID。 - `region_number`: Region 在表中的编号。 - `region_rows`: Region 中的记录行数。 - `written_bytes_since_open`: Region 自打开以来写入的字节数。 - `disk_size`: Region 中数据文件的总大小,包括数据、索引及元信息等。 - `memtable_size`: Region 中内存 memtables 的总大小。 - `manifest_size`: Region 中元信息 manifest 文件的总大小。 - `sst_num`: Region 中 SST 文件的总数量。 - `sst_size`: Region 中 SST 文件的总大小。 - `index_size`: Region 中索引文件的总大小。 - `engine`: Region 的引擎类型,可以是 `mito` 或 `metric`。 - `region_role`: Region 的角色,可以是 `Leader` 或 `Follower`。 获取某张表的 Region 统计信息如下: ```sql SELECT r.* FROM REGION_STATISTICS r LEFT JOIN TABLES t on r.table_id = t.table_id \ WHERE t.table_name = 'system_metrics'; ``` 输出: ```sql +---------------+----------+---------------+-------------+--------------------------+-----------+---------------+---------------+----------+---------+------------+--------+-------------+ | region_id | table_id | region_number | region_rows | written_bytes_since_open | disk_size | memtable_size | manifest_size | sst_size | sst_num | index_size | engine | region_role | +---------------+----------+---------------+-------------+--------------------------+-----------+---------------+---------------+----------+---------+------------+--------+-------------+ | 4398046511104 | 1024 | 0 | 8 | 0 | 4922 | 0 | 1338 | 3249 | 1 | 335 | mito | Leader | +---------------+----------+---------------+-------------+--------------------------+-----------+---------------+---------------+----------+---------+------------+--------+-------------+ ``` --- ## SCHEMATA `SCHEMATA` 表提供数据库的相关信息。表数据等同于 `SHOW DATABASES` 语句的结果。 ```sql USE INFORMATION_SCHEMA; DESC SCHEMATA; ``` 结果如下: ```sql +----------------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +----------------------------+--------+------+------+---------+---------------+ | catalog_name | String | | NO | | FIELD | | schema_name | String | | NO | | FIELD | | default_character_set_name | String | | NO | | FIELD | | default_collation_name | String | | NO | | FIELD | | sql_path | String | | YES | | FIELD | | options | String | | YES | | FIELD | +----------------------------+--------+------+------+---------+---------------+ ``` ```sql SELECT * FROM SCHEMATA; ``` ```sql +--------------+--------------------+----------------------------+------------------------+----------+-------------+ | catalog_name | schema_name | default_character_set_name | default_collation_name | sql_path | options | +--------------+--------------------+----------------------------+------------------------+----------+-------------+ | greptime | greptime_private | utf8 | utf8_bin | NULL | | | greptime | information_schema | utf8 | utf8_bin | NULL | | | greptime | public | utf8 | utf8_bin | NULL | | | greptime | test | utf8 | utf8_bin | NULL | ttl='7days' | +--------------+--------------------+----------------------------+------------------------+----------+-------------+ ``` `SCHEMATA` 表中的字段描述如下: - `catalog_name`:数据库所属的目录。 - `schema_name`:数据库的名称。 - `default_character_set_name`:数据库的默认字符集。 - `default_collation_name`:数据库的默认排序规则。 - `sql_path`:该项的值始终为 `NULL`。 - `options`: GreptimeDB 扩展字段,数据库的配置参数。 --- ## SSTS_INDEX_META `SSTS_INDEX_META` 表提供对从清单中收集的 SST(排序字符串表)索引元数据的访问。该表显示 Puffin 索引元数据的信息,包括倒排索引、全文索引和布隆过滤器。 ```sql USE INFORMATION_SCHEMA; DESC SSTS_INDEX_META; ``` 输出如下: ```sql +-----------------+--------+-----+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------+--------+-----+------+---------+---------------+ | table_dir | String | | NO | | FIELD | | index_file_path | String | | NO | | FIELD | | region_id | UInt64 | | NO | | FIELD | | table_id | UInt32 | | NO | | FIELD | | region_number | UInt32 | | NO | | FIELD | | region_group | UInt8 | | NO | | FIELD | | region_sequence | UInt32 | | NO | | FIELD | | file_id | String | | NO | | FIELD | | index_file_size | UInt64 | | YES | | FIELD | | index_type | String | | NO | | FIELD | | target_type | String | | NO | | FIELD | | target_key | String | | NO | | FIELD | | target_json | String | | NO | | FIELD | | blob_size | UInt64 | | NO | | FIELD | | meta_json | String | | YES | | FIELD | | node_id | UInt64 | | YES | | FIELD | +-----------------+--------+-----+------+---------+---------------+ ``` `SSTS_INDEX_META` 表中的字段描述如下: - `table_dir`:表的目录路径。 - `index_file_path`:Puffin 索引文件的完整路径。 - `region_id`:Region 的 ID。 - `table_id`:表的 ID。 - `region_number`:表中的 Region 编号。 - `region_group`:Region 的组标识符。 - `region_sequence`:Region 的序列号。 - `file_id`:索引文件的唯一标识符(UUID)。 - `index_file_size`:索引文件的大小(字节)。 - `index_type`:索引的类型。可能的值包括: - `inverted`:用于快速词条查找的倒排索引 - `fulltext_bloom`:全文索引和布隆过滤器的组合索引 - `bloom_filter`:用于快速成员测试的布隆过滤器 - `target_type`:被索引目标的类型。通常是 `column`,表示基于列的索引。 - `target_key`:标识目标的键(例如,列 ID)。 - `target_json`:目标配置的 JSON 表示,例如 `{"column":0}`。 - `blob_size`:blob 数据的大小(字节)。 - `meta_json`:包含索引特定信息的 JSON 元数据,例如: - 对于倒排索引:FST 大小、位图类型、段行数等 - 对于布隆过滤器:布隆过滤器大小、行数、段数 - 对于全文索引:分析器类型、大小写敏感设置 - `node_id`:索引所在数据节点的 ID。 ## 示例 查询所有索引元数据: ```sql SELECT * FROM INFORMATION_SCHEMA.SSTS_INDEX_META; ``` 通过与 `TABLES` 表连接查询特定表的索引元数据: ```sql SELECT s.* FROM INFORMATION_SCHEMA.SSTS_INDEX_META s JOIN INFORMATION_SCHEMA.TABLES t ON s.table_id = t.table_id WHERE t.table_name = 'my_table'; ``` 仅查询倒排索引元数据: ```sql SELECT table_dir, index_file_path, index_type, target_json, meta_json FROM INFORMATION_SCHEMA.SSTS_INDEX_META WHERE index_type = 'inverted'; ``` 按索引类型分组查询索引元数据: ```sql SELECT index_type, COUNT(*) as count, SUM(index_file_size) as total_size FROM INFORMATION_SCHEMA.SSTS_INDEX_META GROUP BY index_type; ``` 输出样例: ```sql mysql> SELECT * FROM INFORMATION_SCHEMA.SSTS_INDEX_META LIMIT 1\G; *************************** 1. row *************************** table_dir: data/greptime/public/1814/ index_file_path: data/greptime/public/1814/1814_0000000000/data/index/aba4af59-1247-4bfb-a20b-69242cdd9374.puffin region_id: 7791070674944 table_id: 1814 region_number: 0 region_group: 0 region_sequence: 0 file_id: aba4af59-1247-4bfb-a20b-69242cdd9374 index_file_size: 838 index_type: bloom_filter target_type: column target_key: 2147483652 target_json: {"column":2147483652} blob_size: 688 meta_json: {"bloom":{"bloom_filter_size":640,"row_count":2242,"rows_per_segment":1024,"segment_count":3}} node_id: 0 1 row in set (0.02 sec) ``` --- ## SSTS_MANIFEST `SSTS_MANIFEST` 表提供从清单中收集的 SST(排序字符串表)文件信息。此表显示每个 SST 文件的详细信息,包括文件路径、大小、级别、时间范围和行数。 ```sql USE INFORMATION_SCHEMA; DESC SSTS_MANIFEST; ``` 输出如下: ```sql +------------------+---------------------+-----+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------+---------------------+-----+------+---------+---------------+ | table_dir | String | | NO | | FIELD | | region_id | UInt64 | | NO | | FIELD | | table_id | UInt32 | | NO | | FIELD | | region_number | UInt32 | | NO | | FIELD | | region_group | UInt8 | | NO | | FIELD | | region_sequence | UInt32 | | NO | | FIELD | | file_id | String | | NO | | FIELD | | level | UInt8 | | NO | | FIELD | | file_path | String | | NO | | FIELD | | file_size | UInt64 | | NO | | FIELD | | index_file_path | String | | YES | | FIELD | | index_file_size | UInt64 | | YES | | FIELD | | num_rows | UInt64 | | NO | | FIELD | | num_row_groups | UInt64 | | NO | | FIELD | | min_ts | TimestampNanosecond | | YES | | FIELD | | max_ts | TimestampNanosecond | | YES | | FIELD | | sequence | UInt64 | | YES | | FIELD | | origin_region_id | UInt64 | | NO | | FIELD | | node_id | UInt64 | | YES | | FIELD | | visible | Boolean | | NO | | FIELD | +------------------+---------------------+-----+------+---------+---------------+ ``` `SSTS_MANIFEST` 表中的字段描述如下: - `table_dir`:表的目录路径。 - `region_id`:引用该文件的 Region ID。 - `table_id`:表的 ID。 - `region_number`:表中的 Region 编号。 - `region_group`:Region 的组标识符。 - `region_sequence`:Region 的序列号。 - `file_id`:SST 文件的唯一标识符(UUID)。 - `level`:LSM 树中的 SST 级别(0 表示未压缩,1 表示已压缩)。 - `file_path`:对象存储中 SST 文件的完整路径。 - `file_size`:SST 文件的大小(字节)。 - `index_file_path`:对象存储中索引文件的完整路径(如果存在)。 - `index_file_size`:索引文件的大小(字节,如果存在)。 - `num_rows`:SST 文件中的行数。 - `num_row_groups`:SST 文件中的行组数。 - `min_ts`:SST 文件中的最小时间戳。 - `max_ts`:SST 文件中的最大时间戳。 - `sequence`:与此文件关联的序列号。 - `origin_region_id`:创建该文件的 Region ID。 - `node_id`:文件所在的数据节点 ID。 - `visible`:该文件在当前版本中是否可见。 ## 示例 查询清单中的所有 SST 文件: ```sql SELECT * FROM INFORMATION_SCHEMA.SSTS_MANIFEST; ``` 通过与 `TABLES` 表连接查询特定表的 SST 文件: ```sql SELECT s.* FROM INFORMATION_SCHEMA.SSTS_MANIFEST s JOIN INFORMATION_SCHEMA.TABLES t ON s.table_id = t.table_id WHERE t.table_name = 'my_table'; ``` 仅查询已压缩的 SST 文件(级别 1): ```sql SELECT file_path, file_size, num_rows, level FROM INFORMATION_SCHEMA.SSTS_MANIFEST WHERE level = 1; ``` 查询 SST 文件及其时间范围: ```sql SELECT table_id, file_path, num_rows, min_ts, max_ts FROM INFORMATION_SCHEMA.SSTS_MANIFEST ORDER BY table_id, min_ts; ``` 计算每个表的 SST 文件总大小: ```sql SELECT table_id, COUNT(*) as sst_count, SUM(file_size) as total_size FROM INFORMATION_SCHEMA.SSTS_MANIFEST GROUP BY table_id; ``` 输出样例: ```sql mysql> SELECT * FROM INFORMATION_SCHEMA.SSTS_MANIFEST LIMIT 1\G; *************************** 1. row *************************** table_dir: data/greptime/public/1024/ region_id: 4398046511104 table_id: 1024 region_number: 0 region_group: 0 region_sequence: 0 file_id: 01234567-89ab-cdef-0123-456789abcdef level: 0 file_path: data/greptime/public/1024/4398046511104_0/01234567-89ab-cdef-0123-456789abcdef.parquet file_size: 1234 index_file_path: data/greptime/public/1024/4398046511104_0/index/01234567-89ab-cdef-0123-456789abcdef.puffin index_file_size: 256 num_rows: 100 num_row_groups: 1 min_ts: 2025-01-01 00:00:00.000000000 max_ts: 2025-01-01 00:01:00.000000000 sequence: 1 origin_region_id: 4398046511104 node_id: 0 visible: true 1 row in set (0.02 sec) ``` --- ## SSTS_STORAGE `SSTS_STORAGE` 表提供直接从存储层列出的 SST(排序字符串表)文件信息。此表显示来自对象存储的原始文件元数据,可能包括尚未反映在清单中的文件或已孤立的文件。 ```sql USE INFORMATION_SCHEMA; DESC SSTS_STORAGE; ``` 输出如下: ```sql +------------------+----------------------+-----+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------+----------------------+-----+------+---------+---------------+ | file_path | String | | NO | | FIELD | | file_size | UInt64 | | YES | | FIELD | | last_modified_ms | TimestampMillisecond | | YES | | FIELD | | node_id | UInt64 | | YES | | FIELD | +------------------+----------------------+-----+------+---------+---------------+ ``` `SSTS_STORAGE` 表中的字段描述如下: - `file_path`:对象存储中文件的完整路径。 - `file_size`:文件的大小(字节,如果存储中可用)。 - `last_modified_ms`:最后修改时间(毫秒,如果存储中可用)。 - `node_id`:文件所在的数据节点 ID。 ## 使用场景 `SSTS_STORAGE` 表适用于: - **存储验证**:将存储中的文件与清单进行比较,以检测孤立文件或不一致性。 - **存储调试**:识别存在于存储中但可能未在清单中正确跟踪的文件。 - **清理操作**:查找并删除不再被引用的孤立 SST 文件。 - **存储审计**:获取存储层中所有 SST 文件的完整视图。 ## 示例 查询存储中的所有 SST 文件: ```sql SELECT * FROM INFORMATION_SCHEMA.SSTS_STORAGE; ``` 查找存储中但不在清单中的文件(潜在的孤立文件): ```sql SELECT s.file_path, s.file_size, s.last_modified_ms FROM INFORMATION_SCHEMA.SSTS_STORAGE s LEFT JOIN INFORMATION_SCHEMA.SSTS_MANIFEST m ON s.file_path = m.file_path WHERE m.file_path IS NULL; ``` 查找存储中最大的 SST 文件: ```sql SELECT file_path, file_size FROM INFORMATION_SCHEMA.SSTS_STORAGE WHERE file_size IS NOT NULL ORDER BY file_size DESC LIMIT 10; ``` 计算 SST 文件的总存储使用量: ```sql SELECT COUNT(*) as file_count, SUM(file_size) as total_size FROM INFORMATION_SCHEMA.SSTS_STORAGE WHERE file_size IS NOT NULL; ``` 输出样例: ```sql mysql> SELECT * FROM INFORMATION_SCHEMA.SSTS_STORAGE LIMIT 1\G; *************************** 1. row *************************** file_path: data/greptime/public/1024/4398046511104_0/01234567-89ab-cdef-0123-456789abcdef.parquet file_size: 1234 last_modified_ms: 2025-01-01 00:00:00.000 node_id: 0 1 row in set (0.02 sec) ``` ## 与 SSTS_MANIFEST 的区别 | 方面 | SSTS_MANIFEST | SSTS_STORAGE | |------|---------------|--------------| | **数据源** | 清单元数据 | 直接从存储层 | | **信息** | 详细的 SST 元数据(行数、时间范围等) | 仅基本文件元数据 | | **文件覆盖** | 仅清单中跟踪的文件 | 存储中的所有文件 | | **使用场景** | 查询 SST 元数据进行分析 | 验证存储、查找孤立文件 | | **性能** | 快速(从清单读取) | 较慢(扫描存储) | --- ## TABLE_CONSTRAINTS `TABLE_CONSTRAINTS` 表描述了哪些表具有约束(constraint)以及相关信息。 ```sql DESC INFORMATION_SCHEMA.table_constraints; ``` ```sql +--------------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +--------------------+--------+------+------+---------+---------------+ | constraint_catalog | String | | NO | | FIELD | | constraint_schema | String | | NO | | FIELD | | constraint_name | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | constraint_type | String | | NO | | FIELD | | enforced | String | | NO | | FIELD | +--------------------+--------+------+------+---------+---------------+ ``` 表中的列: * `CONSTRAINT_CATALOG`: 约束所属 catalog 的名称。此值始终为 `def`。 * `CONSTRAINT_SCHEMA`: 约束所属数据库的名称。 * `CONSTRAINT_NAME`: 约束的名称,可以是 `TIME INDEX` 或 `PRIMARY`。 * `TABLE_NAME`: 表的名称。 * `CONSTRAINT_TYPE`: 约束的类型。值可以是 `TIME INDEX` 或 `PRIMARY KEY`。`TIME INDEX` 和 `PRIMARY KEY` 信息类似于 `SHOW INDEX` 语句的执行结果。 * `enforced`: 不支持 `CHECK` 约束,此值始终为 `YES`。 ```sql select * from INFORMATION_SCHEMA.table_constraints WHERE table_name = 'monitor'\G; ``` 输出结果: ```sql *************************** 1. row *************************** constraint_catalog: def constraint_schema: public constraint_name: TIME INDEX table_schema: public table_name: monitor constraint_type: TIME INDEX enforced: YES *************************** 2. row *************************** constraint_catalog: def constraint_schema: public constraint_name: PRIMARY table_schema: public table_name: monitor constraint_type: PRIMARY KEY enforced: YES ``` --- ## TABLES `TABLES` 表提供数据库中表的信息: ```sql USE INFORMATION_SCHEMA; DESC TABLES; ``` 结果如下: ```sql +------------------+----------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +------------------+----------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | table_type | String | | NO | | FIELD | | table_id | UInt32 | | YES | | FIELD | | data_length | UInt64 | | YES | | FIELD | | max_data_length | UInt64 | | YES | | FIELD | | index_length | UInt64 | | YES | | FIELD | | max_index_length | UInt64 | | YES | | FIELD | | avg_row_length | UInt64 | | YES | | FIELD | | engine | String | | YES | | FIELD | | version | UInt64 | | YES | | FIELD | | row_format | String | | YES | | FIELD | | table_rows | UInt64 | | YES | | FIELD | | data_free | UInt64 | | YES | | FIELD | | auto_increment | UInt64 | | YES | | FIELD | | create_time | TimestampSecond | | YES | | FIELD | | update_time | TimestampSecond | | YES | | FIELD | | check_time | TimestampSecond | | YES | | FIELD | | table_collation | String | | YES | | FIELD | | checksum | UInt64 | | YES | | FIELD | | create_options | String | | YES | | FIELD | | table_comment | String | | YES | | FIELD | | temporary | String | | YES | | FIELD | +------------------+----------+------+------+---------+---------------+ ``` ```sql SELECT * FROM tables WHERE table_schema='public' AND table_name='monitor'\G ``` ```sql *************************** 1. row *************************** table_catalog: greptime table_schema: public table_name: monitor table_type: BASE TABLE table_id: 1054 data_length: 0 max_data_length: 0 index_length: 0 max_index_length: 0 avg_row_length: 0 engine: mito version: 11 row_format: Fixed table_rows: 0 data_free: 0 auto_increment: 0 create_time: 2024-07-24 22:06:18.085000 update_time: NULL check_time: NULL table_collation: NULL checksum: 0 create_options: table_comment: NULL temporary: N 1 row in set (0.01 sec) ``` 下方的语句是等价的: ```sql SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = '' [AND table_name LIKE 'monitor'] SHOW TABLES FROM db_name [LIKE 'monitor'] ``` `TABLES` 表的字段描述如下: - `table_catalog`:表所属的目录。该值始终为 `greptime`。 - `table_schema`:表所属的数据库。 - `table_name`:表的名称。 - `table_type`:表的类型。 - `BASE TABLE`:基础表 - `TEMPORARY`:临时结果集 - `VIEW`:视图表 - `table_id`:表 ID。 - `data_length`: 表大小,即表中 SST 文件的总长度(以字节为单位),近似值。 - `index_length`: 表索引大小,即表中索引文件的总长度(以字节为单位),近似值。 - `table_rows`: 表中总的记录行数,近似值。 - `avg_row_length`: 表中记录的平均大小(以字节为单位),近似值。 - `engine`:该表使用的存储引擎。 - `version`: 版本。固定值为 `11`。 - `create_time`: 表创建的时间戳。 - `table_comment`: 表的注释。 - 其他列如 `table_rows`, `row_format` 等不支持,仅用于兼容 MySQL。GreptimeDB 未来可能会支持其中的一些列。 --- ## Triggers :::tip 注意 本功能仅在 GreptimeDB 企业版中可用。 ::: `TRIGGERS` 表用于展示所有已创建 Trigger 的元数据信息。 ```sql DESC TABLE INFORMATION_SCHEMA.TRIGGERS; ``` ```sql +-----------------+--------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-----------------+--------+------+------+---------+---------------+ | trigger_name | String | | NO | | FIELD | | trigger_id | UInt64 | | NO | | FIELD | | raw_sql | String | | NO | | FIELD | | interval | UInt64 | | NO | | FIELD | | labels | Json | | YES | | FIELD | | annotations | Json | | YES | | FIELD | | for | UInt64 | | YES | | FIELD | | keep_firing_for | UInt64 | | YES | | FIELD | | channels | Json | | YES | | FIELD | | flownode_id | UInt64 | | YES | | FIELD | +-----------------+--------+------+------+---------+---------------+ ``` 表中的列: * `trigger_name`:Trigger 的名称。 * `trigger_id`:Trigger 的唯一 ID。 * `raw_sql`:Trigger 周期性执行的 SQL 查询。 * `interval`:Trigger 的执行间隔(单位:秒)。 * `labels`:通过 `LABELS` 子句定义的静态标签(key-value)。 * `annotations`:通过 `ANNOTATIONS` 子句定义的静态注解(key-value)。 * `for`:告警条件需持续满足多长时间(秒)后,告警实例才会进入 `Firing` 状态。 * `keep_firing_for`:告警实例进入 `Firing` 状态后,即使条件不再满足,仍保持 `Firing` 状态的时长(秒)。 * `channels`:Trigger 配置的通知 channel 列表。 * `flownode_id`:负责执行该 Trigger 的 FlowNode id。 --- ## VIEWS `VIEWS` 表提供了当前用户可见的视图(View)列表。 ```sql DESC TABLE INFORMATION_SCHEMA.VIEWS; ``` ```sql +----------------------+---------+------+------+---------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +----------------------+---------+------+------+---------+---------------+ | table_catalog | String | | NO | | FIELD | | table_schema | String | | NO | | FIELD | | table_name | String | | NO | | FIELD | | view_definition | String | | NO | | FIELD | | check_option | String | | YES | | FIELD | | is_updatable | Boolean | | YES | | FIELD | | definer | String | | YES | | FIELD | | security_type | String | | YES | | FIELD | | character_set_client | String | | YES | | FIELD | | collation_connection | String | | YES | | FIELD | +----------------------+---------+------+------+---------+---------------+ ``` 表中的列: * `table_catalog`: 视图所属 catalog 的名称。 * `table_schema`: 视图所属数据库的名称。 * `table_name`: 视图名称。 * `view_definition`: 视图的定义,即创建视图时的 `SELECT` 语句。 * `check_option`: 不支持,始终为 `NULL`。 * `is_updatable`: 视图是否可以进行 `UPDATE/INSERT/DELETE` 操作,始终为 `NO`。 * `definer`: 创建视图的用户的名称。 * `security_type`: 不支持,始终为 `NULL`。 * `character_set_client`: 创建视图时 `character_set_client` 会话变量的值,始终为 `utf8`。 * `collation_connection`: 创建视图时 `collation_connection` 会话变量的值,始终为 `utf8_bin`。 --- ## INSERT `INSERT` 用于将一条或多条记录插入到 GreptimeDB 中的表中。 ## `INSERT INTO` Statement ### Syntax `INSERT INTO` 语法如下: ```sql INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...); ``` 在上述语法中,`table_name` 是要插入数据的表名,`column1`、`column2`、`column3` 等是表中的列名。 如果你想要插入数据到指定的列中,可以在 `INSERT INTO` 语句中指定列名。 如果你不指定列名,数据将会插入到表中的所有列中。 `VALUES` 关键字后面跟着的是一个值列表,这个值列表的顺序必须和 `INSERT INTO` 语句中的列顺序一致。 VALUES 值支持以下数据类型: - `DEFAULT` 关键字指定该列的默认值。 这在你不想在插入记录时显式指定某些列的值时非常有用。 它允许使用表 schema 中定义的列默认值来替代需要显示指定的值。 如果该列没有定义默认值,将会使用数据库的默认值(通常是 NULL)。 - 使用十六进制字面值插入二进制字面值。 - 使用 `{Value}::{Type}` 语法将特殊的数值 `Infinity`、`-Infinity` 和 `NaN` 转换为指定的数值类型。 ### 示例 #### 插入数据 使用 `INSERT INTO` 语句将一条记录插入到名为 `system_metrics` 的表中: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_b", 50.0, 66.7, 40.6, 1667446797462); ``` 上述语句将一条记录插入到 `system_metrics` 表中,该记录的 host 为 "host1",idc 为 "idc_b",cpu_util 为 50.0,memory_util 为 66.7, 你还可以使用 `INSERT INTO` 语句一次向表中插入多条记录,例如向 `system_metrics` 表中插入多条记录: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", 11.8, 10.3, 10.3, 1667446797460), ("host2", "idc_a", 80.1, 70.3, 90.0, 1667446797461), ("host1", "idc_c", 50.1, 66.8, 40.8, 1667446797463); ``` 此语句将三条记录插入到 `system_metrics` 表中,每列都有指定的值。 #### 使用默认值插入数据 下面的 SQL 语句使用 `DEFAULT` 关键字为 `cpu_util` 列插入默认值: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", DEFAULT, 10.3, 10.3, 1667446797460); ``` #### 插入二进制数据 当我们想要插入二进制数据时,其列的数据类型为 `blob` 或 `bytea`: ```sql CREATE TABLE test(b BLOB, ts TIMESTAMP TIME INDEX); ``` 推荐使用预编译语句,例如 JDBC: ```java PreparedStatement pstmt = conn.prepareStatement("insert into test values(?,?)"); pstmt.setBytes(1, "hello".getBytes()); pstmt.setInt(2, 1687867163); pstmt.addBatch(); ...... pstmt.executeBatch(); ``` 如果我们想要插入字面值的二进制数据,可以使用十六进制字面值: ```sql INSERT INTO test VALUES(X'9fad5e9eefdfb449', 1687867163); -- or -- INSERT INTO test VALUES(0x9fad5e9eefdfb449, 1687867163); ``` #### 插入特殊数字值 使用 `{Value}::{Type}` 将特殊的数值 `Infinity`、`-Infinity` 和 `NaN` 转换为指定的数值类型: ```sql INSERT INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", 66.6, 'NaN'::double, 'Infinity'::double, 1667446797460); ``` ## `INSERT INTO SELECT` Statement `INSERT INTO SELECT` 语句用于将一张表中的数据复制到另一张表中。 ### Syntax `INSERT INTO SELECT` 的语法如下: ```sql INSERT INTO table2 (column1, column2, ...) SELECT column1, column2, ... FROM table1; ``` 在上述语法中,`table1` 是你想要从中复制数据的源表,`table2` 是你想要将数据插入的目标表。 `table1` 和 `table2` 需要有用于复制数据的拥有同样名称和数据类型的列。 `SELECT` 语句从源表中选择要插入的列。 如果在`INSERT INTO`语句中没有指定列名,那么数据将被插入到目标表的所有列中。 当你想要从一个表中复制数据到另一个表时,`INSERT INTO SELECT` 语句非常有用。例如归档或备份数据时,比起备份整个数据库并恢复,这种方式更加高效。 ### 示例 ```sql INSERT INTO system_metrics2 (host, idc, cpu_util, memory_util, disk_util, ts) SELECT host, idc, cpu_util, memory_util, disk_util, ts FROM system_metrics; ``` --- ## JOIN `JOIN` 用于组合两个或多个表中基于相关列的行。 它允许你从多个表中提取数据,并将其呈现为单个结果集。 JOIN 语法有以下类型: - INNER JOIN:仅返回两个表中具有匹配值的行。 - LEFT JOIN:返回左表中的所有行和右表中的匹配行。 - RIGHT JOIN:返回右表中的所有行和左表中的匹配行。 - FULL OUTER JOIN:返回两个表中的所有行。 ## 示例 下面是使用 JOIN 子句的一些示例: ```sql -- Select all rows from the system_metrics table and idc_info table where the idc_id matches SELECT a.* FROM system_metrics a JOIN idc_info b ON a.idc = b.idc_id; -- Select all rows from the idc_info table and system_metrics table where the idc_id matches, and include null values for idc_info without any matching system_metrics SELECT a.* FROM idc_info a LEFT JOIN system_metrics b ON a.idc_id = b.idc; -- Select all rows from the system_metrics table and idc_info table where the idc_id matches, and include null values for idc_info without any matching system_metrics SELECT b.* FROM system_metrics a RIGHT JOIN idc_info b ON a.idc = b.idc_id; ``` --- ## LIMIT `LIMIT` 用于限制查询返回的行数。当处理大数据集时该子句特别有用,因为它通过减少需要处理的数据量来提高查询性能。 ## Syntax `LIMIT` 的基本语法如下: ```sql SELECT column1, column2, ... FROM table_name LIMIT number_of_rows; ``` `number_of_rows` 参数用于指定要返回的最大行数。如果该参数的值为负数,则不返回任何行。 ## 示例 假如我们有一个名为 `system_metrics` 的表: ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` 使用 `LIMIT` 获取 `memory_util` 列中的前 3 个值: ```sql SELECT host, idc, memory_util FROM system_metrics ORDER BY memory_util DESC LIMIT 3; ``` 结果为: ```sql +-------+-------+-------------+ | host | idc | memory_util | +-------+-------+-------------+ | host2 | idc_a | 70.3 | | host1 | idc_c | 66.8 | | host1 | idc_b | 66.7 | +-------+-------+-------------+ ``` `LIMIT n, m` 允许在跳过前 n 行后从结果中选择 m 行,等价于`LIMIT m OFFSET n` 语法。 ```sql SELECT host, idc, memory_util FROM system_metrics ORDER BY memory_util DESC LIMIT 2 OFFSET 1; ``` 或 ```sql SELECT host, idc, memory_util FROM system_metrics ORDER BY memory_util DESC LIMIT 1, 2; ``` 结果如下: ```sql +-------+-------+-------------+ | host | idc | memory_util | +-------+-------+-------------+ | host1 | idc_c | 66.8 | | host1 | idc_b | 66.7 | +-------+-------+-------------+ ``` --- ## OFFSET `OFFSET` 子句指定在开始从查询返回行之前要跳过的行数。它通常与 LIMIT 结合使用,用于对大型结果集进行分页。 例如: ```sql SELECT * FROM system_metrics ORDER BY cpu_util DESC LIMIT 10 OFFSET 10; ``` 它从 `system_metrics` 表中选择按降序 `cpu_util` 排序的第 11 到 20 行的所有列。 虽然将 `OFFSET` 和 `LIMIT` 与 `ORDER BY` 子句结合使用可以实现分页,但这种方法效率不高。我们建议记录每页返回的最后一条记录的时间索引(时间戳),并使用该值来过滤和限制后续页面的数据。这种方法提供了更好的分页性能。 ## 使用时间戳的高效分页 假设您的 `system_metrics` 表有一个作为时间索引(时间戳)的 `ts` 列。您可以使用上一页最后一条记录的时间戳来高效地获取下一页。 第一页(最新的 10 条记录): ```sql SELECT * FROM system_metrics ORDER BY ts DESC LIMIT 10; ``` 第二页(使用上一页的最后一个时间戳),如果第一页的最后一条记录的 `ts` 值为 `'2024-07-01 16:03:00'`,您可以这样获取下一页: ```sql SELECT * FROM system_metrics WHERE ts < '2024-07-01 16:03:00' ORDER BY ts DESC LIMIT 10; ``` 每次查询后,记录最后一行的 `ts` 值并将其用于下一个查询的过滤器。 这种方法消除了扫描和跳过行(如使用 OFFSET)的需要,从而使分页效率更高,尤其是在大型表中。 --- ## ORDER BY `ORDER BY` 语法用于根据 `SELECT` 语句中的一个或多个列对数据进行升序或降序排序。 # Syntax `ORDER BY` 的基本语法如下: ```sql SELECT column1, column2, ... FROM table_name ORDER BY column1 [ASC | DESC], column2 [ASC | DESC], ...; ``` `ORDER BY` 可以用于一个或多个列。ASC 关键字用于升序排序(默认),DESC 关键字用于降序排序。 # 示例 假如我们有一个名为 `system_metrics` 的表: ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` 要根据 `memory_util` 列对数据进行升序排序,可以使用以下 SQL 语句: ```sql SELECT * FROM system_metrics ORDER BY memory_util ASC; ``` 结果为: ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` 要根据 `disk_util` 列对数据进行降序排序,可以使用以下 SQL 语句: ```sql SELECT * FROM system_metrics ORDER BY disk_util DESC; ``` 结果为: ```sql +-------+-------+----------+-------------+-----------+---------------------+ | host | idc | cpu_util | memory_util | disk_util | ts | +-------+-------+----------+-------------+-----------+---------------------+ | host2 | idc_a | 80.1 | 70.3 | 90 | 2022-11-03 03:39:57 | | host1 | idc_c | 50.1 | 66.8 | 40.8 | 2022-11-03 03:39:57 | | host1 | idc_b | 50 | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_e | NULL | 66.7 | 40.6 | 2022-11-03 03:39:57 | | host1 | idc_a | 11.8 | 10.3 | 10.3 | 2022-11-03 03:39:57 | +-------+-------+----------+-------------+-----------+---------------------+ ``` --- ## SQL(Sql) ## 数据类型 * [数据类型](data-types.md) ## 语句和子句 * [ADMIN](./admin.md) * [ALTER](./alter.md) * [ANSI Compatibility](./compatibility.md) * [CASE](./case.md) * [CAST](./cast.md) * [COPY](./copy.md) * [CREATE](./create.md) * [DELETE](./delete.md) * [DESCRIBE TABLE](./describe_table.md) * [DISTINCT](./distinct.md) * [DROP](./drop.md) * [EXPLAIN](./explain.md) * [GROUP BY](./group_by.md) * [HAVING](./having.md) * [INSERT](./insert.md) * [JOIN](./join.md) * [LIMIT](./limit.md) * [OFFSET](./offset.md) * [ORDER BY](./order_by.md) * [RANGE](./range.md) * [REPLACE](./replace.md) * [SELECT](./select.md) * [SHOW](./show.md) * [TQL](./tql.md) * [TRUNCATE](./truncate.md) * [WHERE](./where.md) * [WITH](./with.md) ## 函数 * [Functions](./functions/overview.md) ## 系统表 * [INFORMATION_SCHEMA](./information-schema/overview.md) ## Greptime Private 内的系统表 * [Greptime Private](./greptime-private/overview.md) --- ## RANGE QUERY 查询并聚合一个给定长度的时间范围的数据是时序数据常见的一种查询模式,例如 `PromQL` 中的 `Range selector`。而 GreptimeDB 在 SQL 中支持了 Range 查询,用于将时序数据汇总为时间块,并在时间块上进行数据的聚合。Range 查询作为 `SELECT` 语句的一部分,可与 SQL 灵活结合,从而在 SQL 中提供更强大的时序数据查询能力。 ## Syntax Range query 使用 `Time Index` 列作为聚合的时间线。 一个合法的 Range 查询语法结构如下所示: ```sql SELECT AGGR_FUNCTION(column1, column2,..) RANGE INTERVAL [FILL FILL_OPTION], ... FROM table_name [ WHERE ] ALIGN INTERVAL [ TO TO_OPTION ] [BY (columna, columnb,..)] [FILL FILL_OPTION] [ ORDER BY ] [ LIMIT ]; INTERVAL := TIME_INTERVAL | ( INTERVAL expr ) ``` - 关键字 `ALIGN`,必选字段,后接参数 `INTERVAL` ,`ALIGN` 指明了 Range 查询的步长。 - 子关键字 `TO` ,可选字段,指定 Range 查询对齐到的时间点,合法的 `TO_OPTION` 参数见[TO Option](#to-选项) 。 - 子关键字 `BY` ,可选字段,后接参数 `(columna, columnb,..)` ,描述了聚合键。详情请见[BY OPTION](#by-选项)。 - 参数 `INTERVAL` ,主要用于给出一段时间长度,有两种参数形式: - 基于 `PromQL Time Durations` 格式的字符串(例如:`3h`、`1h30m`)。访问 [Prometheus 文档](https://prometheus.io/docs/prometheus/latest/querying/basics/#float-literals-and-time-durations) 获取该格式更详细的说明。 - `Interval` 类型,使用 `Interval` 类型需要携带括号,(例如:`('1 year 3 hours 20 minutes'::INTERVAL)`)。访问 [Interval](./data-types.md#interval-type) 获取该格式更详细的说明。 - `AGGR_FUNCTION(column1, column2,..) RANGE INTERVAL [FILL FILL_OPTION]` 称为一个 Range 表达式。 - `AGGR_FUNCTION(column1, column2,..)` 是一个聚合函数,代表需要聚合的表达式。 - 关键字 `RANGE`,必选字段,后接参数 `INTERVAL` 指定了每次数据聚合的时间范围, - 关键字 `FILL`,可选字段,详情请见 [`FILL` Option](#fill-选项)。 - Range 表达式可与其他运算结合,实现更复杂的查询。具体见[嵌套使用 Range 表达式](#嵌套使用-range-表达式) 。 - 关键字 `FILL`,可以跟在一个 Range 表达式后,详情请见[FILL Option](#fill-选项) 。 ## `FILL` 选项 `FILL` 选项指定了在某个聚合的时间片上没有数据,或者聚合字段的值为空时的数据填充方法。 它可以跟在一个 Range 表达式后,作为这个 Range 表达式的数据填充方法;也可以放在 `ALIGN` 后面作为所有未指定 `FILL` 选项的 Range 表达式的填充方法。 例如,在下面的 SQL 代码中, `max(val) RANGE '10s'` 范围表达式使用 `FILL` 选项 `LINEAR`,而 `min(val) RANGE '10s'` 没有指定 `FILL` 选项,它将使用在 `ALIGN`关键字之后指定的选项`PREV`。 ```sql SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FILL LINEAR FROM host_cpu ALIGN '5s' BY (host) FILL PREV; ``` `FILL` 有以下几种选项: | FILL | 描述 | | :------: | :------------------------------------------------------------------------------------------------------------: | | `NULL` | 直接使用 `NULL` 填充 | | `PREV` | 使用前一个点的数据填充 | | `LINEAR` | 使用线性插值法填充数据,如果一个整数类型使用 `LINEAR` 填充,则该列的变量类型会在计算的时候被隐式转换为浮点类型 | | `X` | 填充一个常量,该常量的数据类型必须和 Range 表达式的变量类型一致 | 以下面这张表为例 ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('1970-01-01 00:00:00', 'host1', 0), ('1970-01-01 00:00:15', 'host1', 6), ('1970-01-01 00:00:00', 'host2', 6), ('1970-01-01 00:00:15', 'host2', 12); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:15 | host1 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | +---------------------+-------+------+ ``` 不同 `FILL` 选项的结果如下: ```sql SELECT ts, host, min(val) RANGE '5s' FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 5s | +---------------------+-------+----------------------------+ | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:15 | host1 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | +---------------------+-------+----------------------------+ ``` ```sql SELECT ts, host, min(val) RANGE '5s' FILL NULL FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+--------------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL NULL | +---------------------+-------+--------------------------------------+ | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | NULL | | 1970-01-01 00:00:10 | host2 | NULL | | 1970-01-01 00:00:15 | host2 | 12 | | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | NULL | | 1970-01-01 00:00:10 | host1 | NULL | | 1970-01-01 00:00:15 | host1 | 6 | +---------------------+-------+--------------------------------------+ ``` ```sql SELECT ts, host, min(val) RANGE '5s' FILL PREV FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+--------------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL PREV | +---------------------+-------+--------------------------------------+ | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | 0 | | 1970-01-01 00:00:10 | host1 | 0 | | 1970-01-01 00:00:15 | host1 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | 6 | | 1970-01-01 00:00:10 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | +---------------------+-------+--------------------------------------+ ``` ```sql SELECT ts, host, min(val) RANGE '5s' FILL LINEAR FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+----------------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL LINEAR | +---------------------+-------+----------------------------------------+ | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | 8 | | 1970-01-01 00:00:10 | host2 | 10 | | 1970-01-01 00:00:15 | host2 | 12 | | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | 2 | | 1970-01-01 00:00:10 | host1 | 4 | | 1970-01-01 00:00:15 | host1 | 6 | +---------------------+-------+----------------------------------------+ ``` ```sql [FILL Constant Value 6.0] SELECT ts, host, min(val) RANGE '5s' FILL 6 FROM host_val ALIGN '5s'; ``` ```sql +---------------------+-------+-----------------------------------+ | ts | host | min(host_val.val) RANGE 5s FILL 6 | +---------------------+-------+-----------------------------------+ | 1970-01-01 00:00:00 | host2 | 6 | | 1970-01-01 00:00:05 | host2 | 6 | | 1970-01-01 00:00:10 | host2 | 6 | | 1970-01-01 00:00:15 | host2 | 12 | | 1970-01-01 00:00:00 | host1 | 0 | | 1970-01-01 00:00:05 | host1 | 6 | | 1970-01-01 00:00:10 | host1 | 6 | | 1970-01-01 00:00:15 | host1 | 6 | +---------------------+-------+-----------------------------------+ ``` 注意,如果存在多个 Range 表达式,只对其中的一个表达式使用了 FILL 方法的话,为了保持 SQL 输出行数的统一,其他 Range 表达式会被使用 FILL NULL 方法来填充缺失的时间片段。 所以下面两句 SQL 在输出上是等价的: ```sql SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FILL LINEAR FROM host_val ALIGN '5s'; ``` ```sql SELECT ts, host, min(val) RANGE '10s' FILL NULL, max(val) RANGE '10s' FILL LINEAR FROM host_val ALIGN '5s'; ``` 上述 SQL 的结果如下: ```sql +---------------------+-------+---------------------------------------+-----------------------------------------+ | ts | host | min(host_val.val) RANGE 10s FILL NULL | max(host_val.val) RANGE 10s FILL LINEAR | +---------------------+-------+---------------------------------------+-----------------------------------------+ | 1969-12-31 23:59:55 | host1 | 0 | 0 | | 1970-01-01 00:00:00 | host1 | 0 | 0 | | 1970-01-01 00:00:05 | host1 | NULL | 2.9999999999999996 | | 1970-01-01 00:00:10 | host1 | 6 | 6 | | 1970-01-01 00:00:15 | host1 | 6 | 6 | | 1969-12-31 23:59:55 | host2 | 6 | 6 | | 1970-01-01 00:00:00 | host2 | 6 | 6 | | 1970-01-01 00:00:05 | host2 | NULL | 9 | | 1970-01-01 00:00:10 | host2 | 12 | 12 | | 1970-01-01 00:00:15 | host2 | 12 | 12 | +---------------------+-------+---------------------------------------+-----------------------------------------+ ``` ## `TO` 选项 `TO` 选项的值用于组确定范围查询的初始时间点。 `TO` 选项、`RANGE` 选项和 `ALIGN INTERVAL` 共同决定了范围查询的时间窗口。 请参考[时间范围窗口](/user-guide/query-data/sql.md#时间范围窗口)。 `TO` 选项的默认值为当前查询客户端的时区。如果想要设置时区,请参考 [MySQL 客户端](/user-guide/protocols/mysql.md#时区) 或 [PostgreSQL 客户端](/user-guide/protocols/postgresql.md#时区)文档中的时区设置。其他可用的 `TO` 选项有: | TO | 描述 | | :---------: | :----------------------------------------------------------------: | | `NOW` | 对齐到当前查询时间 | | `Timestamp` | 对齐到一个用户指定的时间戳上,支持时间戳格式 `RFC3339` / `ISO8601` | 假设我们有一个名为 `host_val` 的表有下面这些数据: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('2023-01-01 23:00:00', 'host1', 0), ('2023-01-02 01:00:00', 'host1', 1), ('2023-01-01 23:00:00', 'host2', 2), ('2023-01-02 01:00:00', 'host2', 3); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 2023-01-01 23:00:00 | host1 | 0 | | 2023-01-02 01:00:00 | host1 | 1 | | 2023-01-01 23:00:00 | host2 | 2 | | 2023-01-02 01:00:00 | host2 | 3 | +---------------------+-------+------+ ``` 对不同的 `TO` 选项的查询结果如下: ```sql -- 使用 mysql 协议查询数据库时区,当前处于 UTC 时区 SELECT @@time_zone; ``` ```sql +-------------+ | @@time_zone | +-------------+ | UTC | +-------------+ ``` ```sql -- 如果没有指定 `TO` 选项 -- 会使用当前查询指定的时区作为初始的对齐时间 SELECT ts, host, min(val) RANGE '1d' FROM host_val ALIGN '1d'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 1d | +---------------------+-------+----------------------------+ | 2023-01-01 00:00:00 | host1 | 0 | | 2023-01-02 00:00:00 | host1 | 1 | | 2023-01-01 00:00:00 | host2 | 2 | | 2023-01-02 00:00:00 | host2 | 3 | +---------------------+-------+----------------------------+ ``` ```sql -- 如果你想要将查询范围的初始时间对齐到当前时间, -- 可以使用 `NOW` 关键字。 -- 假如当前的时间为 `2023-01-02T09:16:40.503000`。 SELECT ts, host, min(val) RANGE '1d' FROM host_val ALIGN '1d' TO NOW; ``` ```sql +----------------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 1d | +----------------------------+-------+----------------------------+ | 2023-01-01 09:54:55.456000 | host1 | 0 | | 2023-01-01 09:54:55.456000 | host2 | 2 | +----------------------------+-------+----------------------------+ ``` ```sql -- 如果你想要将查询范围的初始时间对其到特定的时间戳, -- 例如北京时间 2023 年 12 月 1 日, -- 你可以将 `TO` 选项的值设定为特定的时间戳 '2023-01-01T00:00:00+08:00'。 SELECT ts, host, min(val) RANGE '1d' FROM host_val ALIGN '1d' TO '2023-01-01T00:00:00+08:00'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 1d | +---------------------+-------+----------------------------+ | 2023-01-01 16:00:00 | host1 | 0 | | 2023-01-01 16:00:00 | host2 | 2 | +---------------------+-------+----------------------------+ ``` 如果要查询特定时间范围内的数据,也可以使用 `TO` 关键字指定时间戳达到目的。 例如,要查询 `val` 在 `00:45` 和 `06:45` 之间的每日最小值, 你可以使用 `2023-01-01T00:45:00` 作为 `TO` 选项以及指定 `6h` 的查询范围。 ```sql SELECT ts, host, min(val) RANGE '6h' FROM host_val ALIGN '1d' TO '2023-01-01T00:45:00'; ``` ```sql +---------------------+-------+----------------------------+ | ts | host | min(host_val.val) RANGE 6h | +---------------------+-------+----------------------------+ | 2023-01-02 00:45:00 | host2 | 3 | | 2023-01-02 00:45:00 | host1 | 1 | +---------------------+-------+----------------------------+ ``` ## `BY` 选项 `BY` 选项描述聚合键。如果不指定该字段,则默认使用表的主键作为聚合键。如果表没有指定主键,则不能省略 `BY` 关键字。 假设我们有一个名为 `host_val` 的表有以下数据: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('2023-01-01 23:00:00', 'host1', 0), ('2023-01-02 01:00:00', 'host1', 1), ('2023-01-01 23:00:00', 'host2', 2), ('2023-01-02 01:00:00', 'host2', 3); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 2023-01-01 23:00:00 | host1 | 0 | | 2023-01-02 01:00:00 | host1 | 1 | | 2023-01-01 23:00:00 | host2 | 2 | | 2023-01-02 01:00:00 | host2 | 3 | +---------------------+-------+------+ ``` 下面的 SQL 使用 `host` 作为聚合键: ```sql SELECT ts, host, min(val) RANGE '10s' FROM host_val ALIGN '5s' BY (host); ``` ```sql +---------------------+-------+-----------------------------+ | ts | host | min(host_val.val) RANGE 10s | +---------------------+-------+-----------------------------+ | 2023-01-01 22:59:55 | host1 | 0 | | 2023-01-01 23:00:00 | host1 | 0 | | 2023-01-02 00:59:55 | host1 | 1 | | 2023-01-02 01:00:00 | host1 | 1 | | 2023-01-01 22:59:55 | host2 | 2 | | 2023-01-01 23:00:00 | host2 | 2 | | 2023-01-02 00:59:55 | host2 | 3 | | 2023-01-02 01:00:00 | host2 | 3 | +---------------------+-------+-----------------------------+ ``` 你还可以使用 `BY` 关键字 你还可以使用 `BY` 关键字声明其他列作为数据聚合的依据。比如下面这个 RANGE 查询,使用 `host` 列的字符串长度 `length(host)` 作为数据聚合的依据。 ```sql SELECT ts, length(host), min(val) RANGE '10s' FROM host_val ALIGN '5s' BY (length(host)); ``` 得到的结果如下: ```sql +---------------------+---------------------------------+-----------------------------+ | ts | character_length(host_val.host) | min(host_val.val) RANGE 10s | +---------------------+---------------------------------+-----------------------------+ | 2023-01-01 22:59:55 | 5 | 0 | | 2023-01-01 23:00:00 | 5 | 0 | | 2023-01-02 00:59:55 | 5 | 1 | | 2023-01-02 01:00:00 | 5 | 1 | +---------------------+---------------------------------+-----------------------------+ ``` 你也可以显式通过 `BY ()` 声明不需要使用聚合键,将所有数据全部聚合到一个 group 里。**但如果直接将 `BY` 关键字省略,则代表着使用数据表的主键来作为数据的聚合键。** ```sql SELECT ts, min(val) RANGE '10s' FROM host_val ALIGN '5s' BY (); ``` 得到的结果如下: ```sql +---------------------+-----------------------------+ | ts | min(host_val.val) RANGE 10s | +---------------------+-----------------------------+ | 2023-01-01 22:59:55 | 0 | | 2023-01-01 23:00:00 | 0 | | 2023-01-02 00:59:55 | 1 | | 2023-01-02 01:00:00 | 1 | +---------------------+-----------------------------+ ``` ## 聚合函数中的 `ORDER BY` 选项 Range 查询支持在聚合函数 `first_value` 和 `last_value` 中使用 `order by` 表达式,默认情况下,聚合函数使用时间索引列升序排列数据。 以该数据表为例: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, addon DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('1970-01-01 00:00:00', 'host1', 0, 3), ('1970-01-01 00:00:01', 'host1', 1, 2), ('1970-01-01 00:00:02', 'host1', 2, 1); ``` ```sql +---------------------+-------+------+-------+ | ts | host | val | addon | +---------------------+-------+------+-------+ | 1970-01-01 00:00:00 | host1 | 0 | 3 | | 1970-01-01 00:00:01 | host1 | 1 | 2 | | 1970-01-01 00:00:02 | host1 | 2 | 1 | +---------------------+-------+------+-------+ ``` 如果不指定 `order by` 表达式,默认使用时间索引 `ts` 列升序排列。 以下两个 SQL 是等价的: ```sql SELECT ts, first_value(val) RANGE '5s', last_value(val) RANGE '5s' FROM host_val ALIGN '5s'; ``` ```sql SELECT ts, first_value(val order by ts ASC) RANGE '5s', last_value(val order by ts ASC) RANGE '5s' FROM host_val ALIGN '5s'; ``` 查询后得到 ```sql +---------------------+------------------------------------+-----------------------------------+ | ts | first_value(host_val.val) RANGE 5s | last_value(host_val.val) RANGE 5s | +---------------------+------------------------------------+-----------------------------------+ | 1970-01-01 00:00:00 | 0 | 2 | +---------------------+------------------------------------+-----------------------------------+ ``` 也可以自定义排序规则,比如使用 `addon` 排序: ```sql SELECT ts, first_value(val ORDER BY addon ASC) RANGE '5s', last_value(val ORDER BY addon ASC) RANGE '5s' FROM host_val ALIGN '5s'; ``` 查询后得到 ```sql +---------------------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ | ts | first_value(host_val.val) ORDER BY [host_val.addon ASC NULLS LAST] RANGE 5s | last_value(host_val.val) ORDER BY [host_val.addon ASC NULLS LAST] RANGE 5s | +---------------------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ | 1970-01-01 00:00:00 | 2 | 0 | +---------------------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------+ ``` ## 嵌套使用 Range 表达式 Range 表达式支持灵活的嵌套,可以将 Range 表达式结合各种运算,提供更强大的查询能力。 以下面这张表为例: ```sql DROP TABLE IF EXISTS host_val; CREATE TABLE host_val ( ts TIMESTAMP TIME INDEX, host STRING, val DOUBLE, PRIMARY KEY (host) ); INSERT INTO host_val VALUES ('2023-01-01 08:00:00', 'host1', 1.1), ('2023-01-01 08:00:05', 'host1', 2.2), ('2023-01-01 08:00:00', 'host2', 3.3), ('2023-01-01 08:00:05', 'host2', 4.4); ``` ```sql +---------------------+-------+------+ | ts | host | val | +---------------------+-------+------+ | 2023-01-01 08:00:00 | host1 | 1.1 | | 2023-01-01 08:00:05 | host1 | 2.2 | | 2023-01-01 08:00:00 | host2 | 3.3 | | 2023-01-01 08:00:05 | host2 | 4.4 | +---------------------+-------+------+ ``` 1. 聚合函数内部和外部都支持计算: ```sql SELECT ts, host, 2.0 * min(val * 2.0) RANGE '10s' FROM host_val ALIGN '5s'; ``` 运行后得到 ```sql +---------------------+-------+-------------------------------------------------------+ | ts | host | Float64(2) * min(host_val.val * Float64(2)) RANGE 10s | +---------------------+-------+-------------------------------------------------------+ | 2023-01-01 07:59:55 | host1 | 4.4 | | 2023-01-01 08:00:00 | host1 | 4.4 | | 2023-01-01 08:00:05 | host1 | 8.8 | | 2023-01-01 07:59:55 | host2 | 13.2 | | 2023-01-01 08:00:00 | host2 | 13.2 | | 2023-01-01 08:00:05 | host2 | 17.6 | +---------------------+-------+-------------------------------------------------------+ ``` 2. 聚合函数内部和外部都支持使用 Scalar 函数: - `min(round(val)) RANGE '10s'` 表示对每个值先使用 `round` 函数四舍五入后再进行聚合 - `round(min(val) RANGE '10s')` 表示对每个聚合完成的结果使用 `round` 函数四舍五入 ```sql SELECT ts, host, min(round(val)) RANGE '10s' FROM host_val ALIGN '5s'; ``` 运行后得到 ```sql +---------------------+-------+------------------------------------+ | ts | host | min(round(host_val.val)) RANGE 10s | +---------------------+-------+------------------------------------+ | 2023-01-01 07:59:55 | host1 | 1 | | 2023-01-01 08:00:00 | host1 | 1 | | 2023-01-01 08:00:05 | host1 | 2 | | 2023-01-01 07:59:55 | host2 | 3 | | 2023-01-01 08:00:00 | host2 | 3 | | 2023-01-01 08:00:05 | host2 | 4 | +---------------------+-------+------------------------------------+ ``` ```sql SELECT ts, host, round(min(val) RANGE '10s') FROM host_val ALIGN '5s'; ``` 运行后得到 ```sql +---------------------+-------+------------------------------------+ | ts | host | round(min(host_val.val) RANGE 10s) | +---------------------+-------+------------------------------------+ | 2023-01-01 07:59:55 | host2 | 3 | | 2023-01-01 08:00:00 | host2 | 3 | | 2023-01-01 08:00:05 | host2 | 4 | | 2023-01-01 07:59:55 | host1 | 1 | | 2023-01-01 08:00:00 | host1 | 1 | | 2023-01-01 08:00:05 | host1 | 2 | +---------------------+-------+------------------------------------+ ``` 3. 多个 Range 表达式也可以相互计算,并且 Range 表达式支持分配律,下面两个表达式都是合法且等价的: ```sql SELECT ts, host, max(val) RANGE '10s' - min(val) RANGE '10s' FROM host_val ALIGN '5s'; ``` ```sql SELECT ts, host, (max(val) - min(val)) RANGE '10s' FROM host_val ALIGN '5s'; ``` 运行后得到 ```sql +---------------------+-------+-----------------------------------------------------------+ | ts | host | max(host_val.val) RANGE 10s - min(host_val.val) RANGE 10s | +---------------------+-------+-----------------------------------------------------------+ | 2023-01-01 07:59:55 | host2 | 0 | | 2023-01-01 08:00:00 | host2 | 1.1000000000000005 | | 2023-01-01 08:00:05 | host2 | 0 | | 2023-01-01 07:59:55 | host1 | 0 | | 2023-01-01 08:00:00 | host1 | 1.1 | | 2023-01-01 08:00:05 | host1 | 0 | +---------------------+-------+-----------------------------------------------------------+ ``` 但注意,Range 表达式修饰的范围是位于 `RANGE` 关键字的前一个表达式,下面的 Range 查询是不合法的,因为 `RANGE` 关键字修饰的是表达式 `2.0`,并不是表达式 `min(val * 2.0) * 2.0` ```sql SELECT ts, host, min(val * 2.0) * 2.0 RANGE '10s' FROM host_val ALIGN '5s'; ERROR 1815 (HY000): sql parser error: Can't use the RANGE keyword in Expr 2.0 without function ``` 可以为表达式加上括号,`RANGE` 关键字会自动应用到括号中包含的所有聚合函数: ```sql SELECT ts, host, (min(val * 2.0) * 2.0) RANGE '10s' FROM host_val ALIGN '5s'; ``` 运行后得到: ```sql +---------------------+-------+-------------------------------------------------------+ | ts | host | min(host_val.val * Float64(2)) RANGE 10s * Float64(2) | +---------------------+-------+-------------------------------------------------------+ | 2023-01-01 07:59:55 | host2 | 13.2 | | 2023-01-01 08:00:00 | host2 | 13.2 | | 2023-01-01 08:00:05 | host2 | 17.6 | | 2023-01-01 07:59:55 | host1 | 4.4 | | 2023-01-01 08:00:00 | host1 | 4.4 | | 2023-01-01 08:00:05 | host1 | 8.8 | +---------------------+-------+-------------------------------------------------------+ ``` Range 表达式不允许嵌套,嵌套的 Range 查询是不合法的: ```sql SELECT ts, host, max(min(val) RANGE '10s') RANGE '10s' FROM host_cpu ALIGN '5s'; ERROR 1815 (HY000): Range Query: Nest Range Query is not allowed ``` --- ## REPLACE `REPLACE` 语句用于向表中插入新记录。在 GreptimeDB 中,这个语句与 `INSERT` 语句完全相同。更多详情请参考 [`INSERT`](/reference/sql/insert.md)。 ## `REPLACE INTO` 语句 ### 语法 REPLACE INTO 语句的语法如下: ```sql REPLACE INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...); ``` ### 示例 以下是使用 `REPLACE INTO` 语句向名为 `system_metrics` 的表中插入一条记录的示例: ```sql REPLACE INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_b", 50.0, 66.7, 40.6, 1667446797462); ``` 以下是使用 `REPLACE INTO` 语句向 `system_metrics` 表中插入多条记录的示例: ```sql REPLACE INTO system_metrics (host, idc, cpu_util, memory_util, disk_util, ts) VALUES ("host1", "idc_a", 11.8, 10.3, 10.3, 1667446797460), ("host2", "idc_a", 80.1, 70.3, 90.0, 1667446797461), ("host1", "idc_c", 50.1, 66.8, 40.8, 1667446797463); ``` --- ## SELECT `SELECT` 语句是 SQL 和 GreptimeDB 中数据检索的基础。它允许你从一个或多个表中提取特定的列或表达式: ## Basic Syntax `SELECT` 的基本语法如下: ```sql SELECT column1, column2, ... FROM table_name [WHERE condition] [GROUP BY column] [HAVING condition] [ORDER BY column] [LIMIT number] [OFFSET number] ``` column1, column2 是要从中获取数据的列的名称,table_name 是要从中获取数据的表的名称。 该语句从 `FROM` 子句中指定的表中选择列。如果要从表中选择所有列,可以使用星号(*)通配符字符,而不是列出单个列名。 ```sql SELECT * FROM table_name; ``` ## 条件过滤 (WHERE 子句) `WHERE` 子句用于根据指定条件过滤 `SELECT` 语句的结果,其语法如下: ```sql SELECT column1, column2, ..., columnN FROM table_name WHERE condition; ``` 其中 `condition` 是一个表达式,它的值为 `true` 或 `false`。只有满足条件的行才会包含在结果集中。 支持的比较运算包括: * 逻辑运算符:`AND`、`OR`、`NOT` * 比较运算符:`=`、`!=`、`>`、`<`、`>=`、`<=` * 模式匹配:`LIKE`、`IN`、`BETWEEN` ```sql -- 从 system_metrics 表中选择所有 idc 为 'idc0' 的行 SELECT * FROM system_metrics WHERE idc = 'idc0'; -- 从 system_metrics 表中选择所有 idc 为 'idc0' 或 'idc0' 的行 SELECT * FROM system_metrics WHERE idc IN ('idc0', 'idc1'); -- 从 system_metrics 表中选择所有idc为'idc0'或'idc0'且CPU利用率大于60%的行 SELECT * FROM system_metrics WHERE idc IN ('idc0', 'idc1') AND cpu_util > 0.6; ``` 请参考 [WHERE](where.md) 获取更多信息。 ## 排序结果(ORDER BY 子句) `ORDER BY` 子句用于根据 SELECT 语句中的一个或多个列,以升序或降序对数据进行排序。 例如: ```sql -- 按 cpu_util 升序排序结果 SELECT * FROM system_metrics ORDER BY cpu_util ASC; -- 按 cpu_util 降序排序结果 SELECT * FROM system_metrics ORDER BY cpu_util DESC; ``` 更多信息请参阅 [ORDER](order_by.md)。 ## 限制结果(LIMIT 子句) `LIMIT` 用于限制查询返回的行数。当处理大数据集时该子句特别有用,因为它通过减少需要处理的数据量来提高查询性能。 ```sql SELECT column1, column2, ... FROM table_name LIMIT number_of_rows; ``` 这里 `number_of_rows` 参数用于指定要返回的最大行数。 ```sql -- 从 system_metrics 表中选择 CPU 使用率最高的 10 行。 SELECT * FROM system_metrics ORDER BY cpu_util DESC LIMIT 10; ``` ## 分页结果 (LIMIT 和 OFFSET) `OFFSET` 子句指定在开始返回查询结果行之前要跳过多少行。它通常与 `LIMIT` 一起使用,用于对大型结果集进行分页。 例如: ```sql SELECT * FROM system_metrics ORDER BY cpu_util DESC LIMIT 10 OFFSET 10; ``` 它从 `system_metrics` 表中选择按 `cpu_util` 降序排列的第 11 行到第 20 行的所有列。 虽然将 `OFFSET` 和 `LIMIT` 与 `ORDER BY` 子句结合使用可以实现分页,但这种方法效率不高。 我们建议记录每页返回的最后一条记录的时间索引(时间戳),并使用此值来过滤和限制后续页面的数据。 请参阅 [OFFSET](offset.md) 以获取更多信息。 ## 连接表(JOIN) `JOIN` 用于组合两个或多个表中基于相关列的行,使用 `JOIN` 的语法如下: ```sql SELECT column1, column2, ... FROM table1 JOIN table2 ON table1.column = table2.column; ``` table1 和 table2 是要连接的表的名称,column 是两个表之间的相关列,请参考[JOIN](join.md) 获取更多信息。 ## 分组和聚合 (GROUP BY 和聚合函数) 使用 `GROUP BY` 可以根据一个或多个列对数据进行分组,并在这些组内执行诸如计数或求平均值之类的计算,其基本语法如下: ```sql SELECT column1, column2, ..., aggregate_function(column) FROM table_name GROUP BY column1, column2, ...; ``` 常见支持的聚合函数: * COUNT * SUM * AVG * MAX * MIN 更多函数,请参阅 [聚合函数](/reference/sql/functions/df-functions.md#aggregate-functions) 和 [窗口函数](/reference/sql/functions/df-functions.md#window-functions)。 示例: ```sql -- 查询每个 idc 的 idc 总数 SELECT idc, COUNT(host) as host_num FROM system_metrics GROUP BY idc; -- 查询每个 idc 的平均 cpu 利用率 SELECT idc, AVG(cpu_util) as cpu_avg FROM system_metrics GROUP BY idc; ``` 请参考 [GROUP BY](group_by.md) 获取更多信息。 ## 过滤分组 (HAVING 子句) `HAVING` 子句允许您过滤分组(聚合)后的结果——它的作用类似于 `WHERE`,但发生在分组之后。 示例: ```sql SELECT DATE_TRUNC('day', event_time) AS log_date, COUNT(*) AS error_count FROM application_logs WHERE log_level = 'ERROR' GROUP BY log_date HAVING error_count > 10; ``` 解释如下: * 按日期分组日志,并统计日志级别为 `'ERROR'` 的事件数量。 * 仅返回错误数量超过 10 的日期。 请参考 [HAVING](having.md) 获取更多信息。 ## RANGE 查询示例 ```sql SELECT ts, host, min(cpu) RANGE '10s', max(cpu) RANGE '10s' FILL LINEAR FROM host_cpu ALIGN '5s' BY (host) FILL PREV; ``` 请参考 [RANGE QUERY](range.md) 获取更多信息。 --- ## SHOW `SHOW` 关键字提供数据库和表信息。 ## SHOW DATABASES 展示所有数据库: ```sql SHOW [FULL] DATABASES; ``` ```sql +----------+ | Database | +----------+ | public | +----------+ 1 row in set (0.01 sec) ``` 展示名称符合 `LIKE` 模式的数据库: ```sql SHOW DATABASES LIKE 'p%'; ``` 根据 `where` 表达式展示数据库: ```sql SHOW DATABASES WHERE Database='test_public_schema'; ``` 展示所有数据库,包括它们的选项: ```sql CREATE DATABASE test WITH(ttl='7d'); SHOW FULL DATABASES; ``` ```sql +--------------------+-------------+ | Database | Options | +--------------------+-------------+ | greptime_private | | | information_schema | | | public | | | test | ttl='7days' | +--------------------+-------------+ ``` ## SHOW CREATE DATABASE 展示创建指定数据库的 `CREATE DATABASE` 语句: ```sql SHOW CREATE DATABASE test; ``` ```sql +----------+------------------------------------------------------------+ | Database | Create Database | +----------+------------------------------------------------------------+ | test | CREATE DATABASE IF NOT EXISTS test WITH( ttl = '7days' ) | +----------+------------------------------------------------------------+ 1 row in set (0.01 sec) ``` ## SHOW TABLES 展示所有表: ```sql SHOW TABLES; ``` ```sql +---------+ | Tables | +---------+ | numbers | | scripts | +---------+ 2 rows in set (0.00 sec) ``` 展示 `test` 数据库中的所有表: ```sql SHOW TABLES FROM test; ``` 展示名称符合 `LIKE` 模式的表: ```sql SHOW TABLES like '%prometheus%'; ``` 根据 `where` 表达式展示表: ```sql SHOW TABLES FROM test WHERE Tables='numbers'; ``` ## SHOW FULL TABLES ```sql SHOW FULL TABLES [IN | FROM] [DATABASE] [LIKE pattern] [WHERE query] ``` 将会展示指定数据库(或者默认 `public`)中所有的表及其类型: ```sql SHOW FULL TABLES; ``` ```sql +---------+------------+ | Tables | Table_type | +---------+------------+ | monitor | BASE TABLE | | numbers | TEMPORARY | +---------+------------+ 2 rows in set (0.00 sec) ``` * `Tables`: 表的名称 * `Table_type`: 表的类型,例如 `BASE_TABLE`, `TEMPORARY` 和 `VIEW` 等等。 同样也支持 `like` 和 `where` 查询: ```sql SHOW FULL TABLES FROM public like '%mo%'; ``` ```sql +---------+------------+ | Tables | Table_type | +---------+------------+ | monitor | BASE TABLE | +---------+------------+ 1 row in set (0.01 sec) ``` ```sql SHOW FULL TABLES WHERE Table_type='BASE TABLE'; ``` ```sql +---------+------------+ | Tables | Table_type | +---------+------------+ | monitor | BASE TABLE | +---------+------------+ 1 row in set (0.01 sec) ``` ## SHOW CREATE TABLE 展示创建指定表的 `CREATE TABLE` 语句: ```sql SHOW CREATE TABLE [table] ``` 例如: ```sql SHOW CREATE TABLE system_metrics; ``` ```sql +----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | system_metrics | CREATE TABLE IF NOT EXISTS `system_metrics` ( `host` STRING NULL, `idc` STRING NULL, `cpu_util` DOUBLE NULL, `memory_util` DOUBLE NULL, `disk_util` DOUBLE NULL, `ts` TIMESTAMP(3) NOT NULL DEFAULT current_timestamp(), TIME INDEX (`ts`), PRIMARY KEY (`host`, `idc`) ) ENGINE=mito WITH( regions = 1 ) | +----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` * `Table`: 表的名称 * `Create Table`: 用于创建该表的 SQL :::note 当表没有明确设置 `ttl` 或 `compaction.*` 选项时,`SHOW CREATE TABLE` 会在 `WITH(...)` 子句中显示数据库级别的设置。这反映了表的实际有效设置,因为这些选项在运行时动态解析,优先级为:表级别 > 数据库级别 > 默认值。 ::: ## SHOW CREATE FLOW 展示创建指定 Flow 任务的 `CREATE FLOW` 语句。 比如: ```sql public=> SHOW CREATE FLOW filter_numbers; ``` ```sql Flow | Create Flow ----------------+------------------------------------------------------- filter_numbers | CREATE OR REPLACE FLOW IF NOT EXISTS filter_numbers + | SINK TO out_num_cnt + | AS SELECT number FROM numbers_input WHERE number > 10 (1 row) ``` ## SHOW FLOWS 展示当前所有 Flow 任务: ```sql public=> SHOW FLOWS; ``` ```sql Flows ---------------- filter_numbers (1 row) ``` 同样也支持 `LIKE` 表达式: ```sql public=> show flows like "filter%"; ``` ```sql Flows ---------------- filter_numbers (1 row) ``` ## SHOW CREATE VIEW 用于显示视图(View)的定义: ```sql SHOW CREATE VIEW cpu_monitor; ``` ``` +-------------+--------------------------------------------------------------+ | View | Create View | +-------------+--------------------------------------------------------------+ | cpu_monitor | CREATE VIEW cpu_monitor AS SELECT cpu, host, ts FROM monitor | +-------------+--------------------------------------------------------------+ ``` ## SHOW VIEWS 列出所有视图: ```sql SHOW VIEWS; ``` ```sql +----------------+ | Views | +----------------+ | cpu_monitor | | memory_monitor | +----------------+ ``` 当然,它也支持 `LIKE` 查询: ```sql SHOW VIEWS LIKE 'cpu%'; ``` ```sql +-------------+ | Views | +-------------+ | cpu_monitor | +-------------+ ``` 以及 `WHERE` 条件: ```sql SHOW VIEWS WHERE Views = 'memory_monitor'; ``` ```sql +----------------+ | Views | +----------------+ | memory_monitor | +----------------+ ``` ## SHOW PROCESSLIST 列出当前所有正在执行的查询列表,本质上是 `SELECT id, catalog, query, elapsed_time FROM INFORMATION_SCHEMA.PROCESS_LIST` 的别名: ```sql SHOW PROCESSLIST; ``` 输出如下: ``` +-----------------------+----------+------------------+-----------------+ | Id | Catalog | Query | Elapsed Time | +-----------------------+----------+------------------+-----------------+ | 192.168.50.164:4001/0 | greptime | SHOW PROCESSLIST | 00:00:00.002000 | +-----------------------+----------+------------------+-----------------+ 1 row in set (0.00 sec) ``` 同时可以指定 `FULL` 参数用于输出 `INFORMATION_SCHEMA.PROCESS_LIST` 表的所有列: ```sql SHOW FULL PROCESSLIST; ``` 输出如下: ```sql +-----------------------+----------+--------------------+------------------------+---------------------+----------------------------+-----------------+-----------------------+ | Id | Catalog | Schema | Client | Frontend | Start Time | Elapsed Time | Query | +-----------------------+----------+--------------------+------------------------+---------------------+----------------------------+-----------------+-----------------------+ | 192.168.50.164:4001/0 | greptime | information_schema | mysql[127.0.0.1:34692] | 192.168.50.164:4001 | 2025-06-30 07:17:46.423000 | 00:00:00.003000 | SHOW FULL PROCESSLIST | +-----------------------+----------+--------------------+------------------------+---------------------+----------------------------+-----------------+-----------------------+ ``` ## SHOW TRIGGERS 请参考 [Trigger 语法](/reference/sql/trigger-syntax.md#show-triggers)文档。 ## SHOW CREATE TRIGGER 请参考 [Trigger 语法](/reference/sql/trigger-syntax.md#show-create-trigger)文档。 ## SHOW 语句的扩展 与 MySQL 类似,一些 `SHOW` 语句的扩展伴随着 [`INFORMATION_SCHEMA`](/reference/sql/information-schema/overview.md) 的实现,它们还接受 `WHERE` 子句,提供了在指定显示的行时更大的灵活性。 GreptimeDB 为 MySQL 兼容性实现了这些扩展的一部分,这对于像 [Navicat for MySQL](https://www.navicat.com/en/products/navicat-for-mysql) 或 [dbeaver](https://dbeaver.io/) 这样的工具连接 GreptimeDB 非常有用。 ```sql SHOW CHARACTER SET; ``` 输出类似于 `INFORMATION_SCHEMA.CHARACTER_SETS` 表: ```sql +---------+---------------+-------------------+--------+ | Charset | Description | Default collation | Maxlen | +---------+---------------+-------------------+--------+ | utf8 | UTF-8 Unicode | utf8_bin | 4 | +---------+---------------+-------------------+--------+ ``` 使用 `SHOW COLLATION` 来查看 `INFORMATION_SCHEMA.COLLATIONS` 表。 ```sql SHOW INDEX FROM monitor; ``` 列出表中的所有索引: ```sql +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+----------------------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+----------------------------+---------+---------------+---------+------------+ | monitor | 1 | PRIMARY | 1 | host | A | NULL | NULL | NULL | YES | greptime-inverted-index-v1 | | | YES | NULL | | monitor | 1 | TIME INDEX | 1 | ts | A | NULL | NULL | NULL | NO | greptime-inverted-index-v1 | | | YES | NULL | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+----------------------------+---------+---------------+---------+------------+ ``` 这是 `INFORMATION_SCHEMA.TABLE_CONSTRAINTS` 的扩展。 列出表中的所有列: ```sql SHOW COLUMNS FROM monitor; ``` 输出类似于 `INFORMATION_SCHEMA.COLUMNS`: ```sql +--------+--------------+------+------------+---------------------+-------+----------------------+ | Field | Type | Null | Key | Default | Extra | Greptime_type | +--------+--------------+------+------------+---------------------+-------+----------------------+ | cpu | double | Yes | | 0 | | Float64 | | host | string | Yes | PRI | NULL | | String | | memory | double | Yes | | NULL | | Float64 | | ts | timestamp(3) | No | TIME INDEX | current_timestamp() | | TimestampMillisecond | +--------+--------------+------+------------+---------------------+-------+----------------------+ ``` 所有这些 `SHOW` 扩展都接受 `WHERE` 子句: ```sql SHOW COLUMNS FROM monitor WHERE Field = 'cpu'; ``` ```sql +-------+--------+------+------+---------+-------+---------------+ | Field | Type | Null | Key | Default | Extra | Greptime_type | +-------+--------+------+------+---------+-------+---------------+ | cpu | double | Yes | | 0 | | Float64 | +-------+--------+------+------+---------+-------+---------------+ ``` 列出表中的所有 Region: ```sql SHOW REGION FROM monitor; ``` ```sql +----------------+---------------+------+--------+ | Table | Region | Peer | Leader | +----------------+---------------+------+--------+ | monitor | 4398046511104 | 0 | Yes | +----------------+---------------+------+--------+ ``` 这是 `INFORMATION_SCHEMA.REGION_PEERS` 的扩展,并且支持 `WHERE` 子句。 语法是: ```sql SHOW REGION FROM [table] [IN database] [WHERE where] ``` 其他 `SHOW` 扩展语句: * `SHOW STATUS` 和 `SHOW VARIABLES` 不支持,仅返回空结果。 * `SHOW TABLE STATUS` 是 `INFORMATION_SCHEMA.TABLES` 的扩展。 --- ## TQL `TQL` 关键字在 SQL 中执行 TQL 语言。TQL 是 Telemetry Query Language 的缩写,是 GreptimeDB 中对 Prometheus 的 [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) 的扩展。 ## EVAL ### Syntax ```sql TQL [EVAL | EVALUATE] (start, end, step, [lookback]) expr [AS alias] ``` `start`, `end` 和 `step` 是查询参数,就像 [Prometheus Query API](https://prometheus.io/docs/prometheus/latest/querying/api/) 一样: - `start`: ``: 查询的起始时间戳,范围中包含该值。 - `end`: ``: 查询的截止时间戳,范围中包含该值。 - `step`: ``: 查询分辨率步长,采用 `duration` 格式或浮点秒数。 - `lookback`: ``: 查询评估的最大过去持续时间,默认 5 分钟,可选参数。 `expr` 是 TQL (PromQL) 的查询字符串。 可选的 `AS alias` 子句允许你为结果中的值列指定自定义名称。这对以下场景很有用: - 为查询结果提供有意义的名称 - 在 SQL 查询中使用 TQL 结果(例如 CTE、JOIN) - 提高复杂查询的可读性 **注意**:值别名目前仅支持单值列结果。 ### 示例 返回过去 5 分钟内 `http_requests_total` 指标的所有时间序列的每秒值: ```sql TQL EVAL (1677057993, 1677058993, '1m') rate(prometheus_http_requests_total{job="prometheus"}[5m]); ``` 其查询结果和 SQL 查询结果类似。 使用值别名为结果提供自定义名称: ```sql TQL EVAL (0, 30, '10s') http_requests_total AS requests; ``` 这将返回值列名为 `requests` 而不是默认字段名的结果。 值别名与聚合: ```sql TQL EVAL (0, 10, '5s') count by (k) (test) AS count_value; ``` 此查询按 `k` 分组计数值,并将结果列命名为 `count_value`。 `start` 和 `end` 还可以是可以被求值为常量的时间表达式,例如查询过去 3 个小时: ```sql TQL EVAL (now() - interval '3' hours, now(), '1m') sum by (namespace, pod) ( increase(kube_pod_container_status_restarts_total[10m:30s]) ); ``` 查询过去一天的数据: ```sql TQL EVAL ( date_trunc('day', now() - interval '1' day), date_trunc('day', now()), '1m' ) sum by (namespace) ( rate(http_requests_total[5m:30s]) ); ``` ### 在 CTE 中使用 TQL TQL `EVAL` 可以在公共表表达式(CTE)中使用,以便将 PromQL 风格的查询与 SQL 处理相结合。有关详细示例和使用指南,请参阅[在 CTE 中使用 TQL](/user-guide/query-data/cte.md#在-cte-中使用-tql)。 ## EXPLAIN `EXPLAIN` 展示特定 PromQL 查询的逻辑计划和执行计划,其语法如下: ``` TQL EXPLAIN [VERBOSE] [FORMAT format] [(start, end, step, [lookback])] expr [AS alias]; ``` 例如,我们可以使用下方示例解释 PromQL `sum by (instance) (rate(node_disk_written_bytes_total[2m])) > 50`: ``` TQL EXPLAIN sum by (instance) (rate(node_disk_written_bytes_total[2m])) > 50; ``` 注意该查询实际上没有被执行,所以 `(start, end, step, [lookback])` 不是必需的,但你仍然可以像在 `TQL EVAL` 中一样提供这些参数: ``` TQL EXPLAIN (0, 100, '10s') sum by (instance) (rate(node_disk_written_bytes_total[2m])) > 50; ``` 你也可以在 EXPLAIN 中使用值别名: ``` TQL EXPLAIN (0, 10, '5s') test AS series; ``` 结果如下: ```txt +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_type | plan | +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | logical_plan | Sort: node_disk_written_bytes_total.instance ASC NULLS LAST, node_disk_written_bytes_total.ts ASC NULLS LAST Filter: SUM(prom_rate(ts_range,field,ts)) > Float64(50) Aggregate: groupBy=[[node_disk_written_bytes_total.instance, node_disk_written_bytes_total.ts]], aggr=[[SUM(prom_rate(ts_range,field,ts))]] Projection: node_disk_written_bytes_total.ts, prom_rate(ts_range, field, node_disk_written_bytes_total.ts) AS prom_rate(ts_range,field,ts), node_disk_written_bytes_total.instance Filter: prom_rate(ts_range, field, node_disk_written_bytes_total.ts) IS NOT NULL Projection: node_disk_written_bytes_total.ts, node_disk_written_bytes_total.instance, field, ts_range PromRangeManipulate: req range=[0..0], interval=[300000], eval range=[120000], time index=[ts], values=["field"] PromSeriesNormalize: offset=[0], time index=[ts], filter NaN: [true] PromSeriesDivide: tags=["instance"] Sort: node_disk_written_bytes_total.instance DESC NULLS LAST, node_disk_written_bytes_total.ts DESC NULLS LAST TableScan: node_disk_written_bytes_total projection=[ts, instance, field], partial_filters=[ts >= TimestampMillisecond(-420000, None), ts <= TimestampMillisecond(300000, None)] | | physical_plan | SortPreservingMergeExec: [instance@0 ASC NULLS LAST,ts@1 ASC NULLS LAST] SortExec: expr=[instance@0 ASC NULLS LAST,ts@1 ASC NULLS LAST] CoalesceBatchesExec: target_batch_size=8192 FilterExec: SUM(prom_rate(ts_range,field,ts))@2 > 50 AggregateExec: mode=FinalPartitioned, gby=[instance@0 as instance, ts@1 as ts], aggr=[SUM(prom_rate(ts_range,field,ts))] CoalesceBatchesExec: target_batch_size=8192 RepartitionExec: partitioning=Hash([Column { name: "instance", index: 0 }, Column { name: "ts", index: 1 }], 32), input_partitions=32 AggregateExec: mode=Partial, gby=[instance@2 as instance, ts@0 as ts], aggr=[SUM(prom_rate(ts_range,field,ts))] ProjectionExec: expr=[ts@0 as ts, prom_rate(ts_range@3, field@2, ts@0) as prom_rate(ts_range,field,ts), instance@1 as instance] CoalesceBatchesExec: target_batch_size=8192 FilterExec: prom_rate(ts_range@3, field@2, ts@0) IS NOT NULL ProjectionExec: expr=[ts@0 as ts, instance@1 as instance, field@2 as field, ts_range@3 as ts_range] PromInstantManipulateExec: req range=[0..0], interval=[300000], eval range=[120000], time index=[ts] PromSeriesNormalizeExec: offset=[0], time index=[ts], filter NaN: [true] PromSeriesDivideExec: tags=["instance"] RepartitionExec: partitioning=RoundRobinBatch(32), input_partitions=1 ExecutionPlan(PlaceHolder) | +---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` ## ANALYZE TQL 同样支持 `ANALYZE` 关键词来分析给定 PromQL 查询的执行,其语法如下: ``` TQL ANALYZE [VERBOSE] [FORMAT format] (start, end, step, [lookback]) expr [AS alias]; ``` 例如: ``` TQL ANALYZE (0, 10, '5s') test; ``` 得到结果: ``` +-------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_type | plan | +-------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Plan with Metrics | CoalescePartitionsExec, metrics=[output_rows=0, elapsed_compute=14.99µs] PromInstantManipulateExec: range=[0..10000], lookback=[300000], interval=[5000], time index=[j], metrics=[output_rows=0, elapsed_compute=1.08µs] PromSeriesNormalizeExec: offset=[0], time index=[j], filter NaN: [false], metrics=[output_rows=0, elapsed_compute=1.11µs] PromSeriesDivideExec: tags=["k"], metrics=[output_rows=0, elapsed_compute=1.3µs] RepartitionExec: partitioning=RoundRobinBatch(32), input_partitions=32, metrics=[send_time=32ns, repart_time=32ns, fetch_time=11.578016ms] RepartitionExec: partitioning=RoundRobinBatch(32), input_partitions=1, metrics=[send_time=1ns, repart_time=1ns, fetch_time=21.07µs] ExecutionPlan(PlaceHolder), metrics=[] | +-------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ``` 使用 `TQL ANALYZE VERBOSE` 可以拿到查询执行时更详细的信息. ``` TQL ANALYZE VERBOSE (0, 10, '5s') test; ``` --- ## Trigger 语法 :::tip 注意 本功能仅在 GreptimeDB 企业版中可用。 ::: ## CREATE TRIGGER 创建 Trigger 的语法: ```sql CREATE TRIGGER [IF NOT EXISTS] ON () EVERY [LABELS (=, ...)] [ANNOTATIONS (=, ...)] [FOR ] [KEEP FIRING FOR ] NOTIFY ( WEBHOOK URL '' [WITH (=, ...)], WEBHOOK URL '' [WITH (=, ...)] ); ``` - Trigger name:Trigger 在 catalog 级别的唯一标识符。 - IF NOT EXISTS:阻止 Trigger 已经存在时的报错。 ### On 子句 #### Query expression 指定的 SQL 查询会被定期执行。每次查询的结果可能形成一个或多个告警实例,具体取决 于返回的行。 Trigger 会从查询结果中提取 `labels` 和 `annotations`,并将这些信息附加到每个告警 实例上。同时,它们也会与 `LABELS` 和 `ANNOTATIONS` 子句中指定的静态键值对合并。 提取规则如下: - 若列名(或别名)以 `label_` 开头,则将该列提取到 LABELS 中,键名为去掉 `label_` 前缀后的列名(或别名)。 - 其余所有列均提取到 ANNOTATIONS 中,键名即为列名(或别名)。 值得注意的是,每个告警实例都由其 Label 集合唯一标识。如果多行查询结果生成的 Label 集合相同,它们只会形成同一个告警实例。 例如,查询表达式如下: ```sql SELECT collect as label_collector, host as label_host, val FROM host_load1 WHERE val > 10 and ts >= now() - '1 minutes'::INTERVAL ``` 假设查询结果非空,且如下所示: | label_collector | label_host | val | |------------------|------------|-----| | collector1 | host1 | 12 | | collector2 | host2 | 15 | 这将产生两条通知。 第一条通知的 labels 与 annotations 如下: - Labels: - collector: collector1 - host: host1 - 以及 `LABELS` 子句中定义的 labels - Annotations: - val: 12 - 以及 `ANNOTATIONS` 子句中定义的 annotations 第二条通知的 labels 与 annotations 如下: - Labels: - collector: collector2 - host: host2 - 以及 `LABELS` 子句中定义的 labels - Annotations: - val: 15 - 以及 `ANNOTATIONS` 子句中定义的 annotations #### Interval expression 指定查询的执行间隔。它表示查询的执行频率。例如,`INTERVAL '1 minute'`、 `INTERVAL '1 hour'` 等。 - INTERVAL 表达式中**禁止**使用 `years` 和 `months`。月和年的时长是可变的,取决于具体的月份或年份,因此不适合用来定义固定的间隔。 - 最小间隔为 1 秒。任何小于 1 秒的间隔都会被自动向上取整为 1 秒。 有关 INTERVAL 表达式的更多语法细节,请参见 [interval-type](/reference/sql/data-types.md#interval-type)。 ### FOR 子句 `FOR ` 子句用于控制某个告警在真正触发前需要保持活跃的持续时 间,其作用与 Prometheus Alerting Rules 中的 `for` 选项类似。 当评估结果中首次出现某个告警实例时,它首先会进入 `Pending` 状态,此时不会触发通 知。若该告警实例在 `FOR` 指定的持续时间内的每次评估中均保持活跃(即始终出现在查 询结果中),则状态将由 `Pending` 转为 `Firing`,并立即发送通知。 若未指定 `FOR` 子句,则告警不会进入 `Pending` 状态,而是在评估结果中首次出现该告 警实例时立即进入 `Firing` 状态,并马上触发通知。 ### KEEP FIRING FOR 子句 `KEEP FIRING FOR ` 子句用于控制某个告警实例在首次进入 `Firing` 状态后,至少需要保持多长时间处于 `Firing` 状态,其作用与 Prometheus Alerting Rules 中的 `keep_firing_for` 选项类似。 当某个告警实例满足条件并进入 `Firing` 状态后,即便后续评估中该告警实例不再出现在 查询结果中,只要距离首次进入 `Firing` 状态尚未超过 `KEEP FIRING FOR` 指定的时长, 该告警实例仍会保持 `Firing` 状态。 一旦超过 `KEEP FIRING FOR` 指定的时长,在下一次评估中如果该告警实例仍未出现在查 询结果中,则会被标记为已恢复,不再处于 Firing 状态。 若未指定 `KEEP FIRING FOR` 子句,则告警实例在进入 `Firing` 状态后,只要在后续评 估中不再出现在查询结果中,就会在该次评估中被标记为已恢复。 ### Labels 和 Annotations 子句 LABELS 和 ANNOTATIONS 子句用于在 Trigger 发送的通知消息中附加静态的键值对,以提 供有关该 Trigger 的额外上下文或元数据。 - LABELS:可用于 Alertmanager 的路由、分组与抑制规则等。 - ANNOTATIONS:通常用于存放供人类阅读的描述信息。 ### Notify 子句 NOTIFY 子句允许指定一个或多个通知通道。目前,GreptimeDB 支持以下通道类型: #### Webhook 当 Trigger 触发时,Webhook 通道会向指定的 URL 发送 HTTP 请求。请求的 payload 与 [Prometheus Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) 兼容,因此我们可以复用 Alertmanager 的分组、抑制、静默和路由功能,而无需任何 额外的胶水代码。 可选的 WITH 子句允许指定额外的参数: - timeout:HTTP 请求的超时时间,例如 `timeout='1m'`。 ## SHOW TRIGGERS 列出所有的 Triggers: ```sql SHOW TRIGGERS; ``` 当然,它也支持 `LIKE` 查询: ```sql SHOW TRIGGERS LIKE ''; ``` 例如: ```sql SHOW TRIGGERS LIKE 'load%'; ``` 以及 `WHERE` 条件: ```sql SHOW TRIGGERS WHERE ; ``` 例如: ```sql SHOW TRIGGERS WHERE name = 'load1_monitor'; ``` ## SHOW CREATE TRIGGER 用于显示 TRIGGER 的定义: ```sql SHOW CREATE TRIGGER ; ``` 例如: ```sql SHOW CREATE TRIGGER load1_monitor; ``` ## DROP TRIGGER 请使用以下 `DROP TRIGGER` 语句删除 Trigger: ```sql DROP TRIGGER [IF EXISTS] ; ``` For example: ```sql DROP TRIGGER IF EXISTS load1_monitor; ``` ## 示例 请参考企业版用户指南中的 [Trigger](/enterprise/trigger.md) 文档。 --- ## TRUNCATE `TRUNCATE TABLE table` 语句用于删除表中的所有数据。它比 `DELETE FROM table` 高效得多。 ```sql TRUNCATE TABLE monitor; ``` ```sql Query OK, 0 rows affected (0.02 sec) ``` --- ## WHERE `WHERE` 子句允许通过指定条件过滤数据。 ## Syntax ```sql SELECT * FROM table_name WHERE condition; ``` 如果有 `WHERE` 子句,则它必须为布尔类型的表达式,这通常是带有比较和逻辑运算符的表达式。此表达式计算结果为 false 的行将会从进一步的转换或结果中排除。 ## 示例 ### 逻辑运算符 支持 `AND`、`OR` 作为逻辑运算符,并可以使用括号()组合条件。 ```sql SELECT * FROM system_metrics WHERE idc = 'idc0' AND (host = 'host1' OR host = 'host2'); ``` ### 数字 支持 `=`, `!=`, `>`, `>=`, `<`, `<=` 作为比较运算符。 ```sql SELECT * FROM system_metrics WHERE cpu_util = 20.0; SELECT * FROM system_metrics WHERE cpu_util != 20.0; SELECT * FROM system_metrics WHERE cpu_util > 20.0; SELECT * FROM system_metrics WHERE cpu_util >= 20.0; SELECT * FROM system_metrics WHERE cpu_util < 20.0; SELECT * FROM system_metrics WHERE cpu_util <= 20.0; ``` ### List 查找 List 子元素的匹配或不匹配。 ### List 匹配 ```sql SELECT * FROM system_metrics WHERE idc IN ('idc_a', 'idc_b'); ``` ### List 不匹配 ```sql SELECT * FROM system_metrics WHERE idc NOT IN ('idc_a', 'idc_b'); ``` ### 字符串 对于字符串列,我们可以使用 `LIKE` 运算符在列中搜索指定的模式。 有两个通配符经常与 LIKE 运算符一起使用: * 百分号 `%` 代表零个、一个或多个字符 * 下划线 `_` 代表单个字符 选择 `host` 列以字母 "a" 开头的所有记录: ```sql SELECT * FROM system_metrics WHERE host LIKE 'a%'; ``` 从 `go_info` 表中选择 instance 列匹配模式 `'localhost:____'` 的所有记录,这意味着 `'localhost:'` 后面跟着恰好四个字符: ```sql SELECT * FROM go_info WHERE instance LIKE 'localhost:____'; ``` 有关在日志中搜索关键字,请阅读[查询日志](/user-guide/logs/fulltext-search.md)。 --- ## WITH 使用 `WITH` 来指定一个公共表表达式(CTE)。 ## 什么是公共表表达式(CTE)? 公共表表达式(CTE)是一个可以在 `SELECT`、`INSERT`、`UPDATE` 或 `DELETE` 语句中引用的临时结果集。CTE 有助于将复杂的查询分解成更易读的部分,并且可以在同一个查询中多次引用。 ## CTE 的基本语法 CTE 通常使用 `WITH` 关键字定义。基本语法如下: ```sql WITH cte_name [(column1, column2, ...)] AS ( QUERY ) SELECT ... FROM cte_name; ``` ## 示例 ### 非递归 CTE ```sql WITH cte AS (SELECT 0 AS number UNION ALL SELECT 1) SELECT * FROM cte t1, cte t2; ``` ```sql +--------+--------+ | number | number | +--------+--------+ | 0 | 0 | | 0 | 1 | | 1 | 0 | | 1 | 1 | +--------+--------+ ``` 如果 CTE 名称后面有一个括起来的名称列表,这些名称就是 CTE 的列名,可以在查询里使用: ```sql WITH cte (col1, col2) AS ( SELECT 1, 2 UNION ALL SELECT 3, 4 ) SELECT col1, col2 FROM cte; ``` 列表中的名称数量必须与结果集中的列数相同。 ```sql +------+------+ | col1 | col2 | +------+------+ | 1 | 2 | | 3 | 4 | +------+------+ ``` 联合查询两个 CTE: ```sql WITH cte1 AS (SELECT 0 AS a UNION ALL SELECT 1), cte2 AS (SELECT 0 AS b UNION ALL SELECT 1) SELECT * FROM cte1 JOIN cte2 ON cte1.a = cte2.b; ``` ```sql +------+------+ | a | b | +------+------+ | 1 | 1 | | 0 | 0 | +------+------+ ``` ### 递归 CTE 递归 CTE 目前尚未实现。 --- ## SQL 工具 GreptimeDB 使用 SQL 作为主要查询语言,并支持许多流行的 SQL 工具。 本文档指导你如何使用 SQL 工具与 GreptimeDB 交互。 ## 编程语言 Driver 推荐使用成熟的 SQL driver 来查询数据。 ### 推荐的查询库 Java 数据库连接(JDBC)是 JavaSoft 规范的标准应用程序编程接口(API),它允许 Java 程序访问数据库管理系统。 许多数据库协议,如 MySQL 或 PostgreSQL,都已经基于 JDBC API 实现了自己的驱动程序。 由于 GreptimeDB [支持多种协议](/user-guide/protocols/overview.md),这里我们使用 MySQL 协议作为示例来演示如何使用 JDBC。 如果你希望使用其他协议,只需要将 MySQL driver 换为相应的 driver。 推荐使用 [GORM](https://gorm.io/) 库来查询数据。 ### 安装 如果你使用的是 [Maven](https://maven.apache.org/),请将以下内容添加到 `pom.xml` 的依赖项列表中: ```xml mysql mysql-connector-java 8.0.33 ``` 使用下方的命令安装 GORM: ```shell go get -u gorm.io/gorm ``` 以 MySQL 为例安装 driver: ```shell go get -u gorm.io/driver/mysql ``` 将库引入到代码中: ```go "gorm.io/gorm" "gorm.io/driver/mysql" ) ``` ### Connect to database 下面以 MySQL 为例演示如何连接到 GreptimeDB。 ```java public static Connection getConnection() throws IOException, ClassNotFoundException, SQLException { Properties prop = new Properties(); prop.load(QueryJDBC.class.getResourceAsStream("/db-connection.properties")); String dbName = (String) prop.get("db.database-driver"); String dbConnUrl = (String) prop.get("db.url"); String dbUserName = (String) prop.get("db.username"); String dbPassword = (String) prop.get("db.password"); Class.forName(dbName); Connection dbConn = DriverManager.getConnection(dbConnUrl, dbUserName, dbPassword); return Objects.requireNonNull(dbConn, "Failed to make connection!"); } ``` 你需要一个 properties 文件来存储数据库连接信息,将其放在 Resources 目录中并命名为 `db-connection.properties`。文件内容如下: ```txt # DataSource db.database-driver=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:4002/public db.username= db.password= ``` 或者你可以从 [这里](https://github.com/GreptimeTeam/greptimedb-ingester-java/blob/main/ingester-example/src/main/resources/db-connection.properties) 获取文件。 ```go type Mysql struct { Host string Port string User string Password string Database string DB *gorm.DB } m := &Mysql{ Host: "127.0.0.1", Port: "4002", // default port for MySQL User: "username", Password: "password", Database: "public", } dsn := fmt.Sprintf("tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", m.Host, m.Port, m.Database) dsn = fmt.Sprintf("%s:%s@%s", m.User, m.Password, dsn) db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { // error handling } m.DB = db ``` #### 时区 通过设置 URL 参数来设置 JDBC 时区: ```txt jdbc:mysql://127.0.0.1:4002?connectionTimeZone=Asia/Shanghai&forceConnectionTimeZoneToSession=true ``` * `connectionTimeZone={LOCAL|SERVER|user-defined-time-zone}` 配置连接时区。 * `forceConnectionTimeZoneToSession=true` 使 session `time_zone` 变量被设置为 `connectionTimeZone` 指定的值。 在 DSN 中设置时区。例如,将时区设置为 `Asia/Shanghai`: ```go dsn := fmt.Sprintf("tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local&time_zone=%27Asia%2FShanghai%27", m.Host, m.Port, m.Database) ``` 更多信息请参考 [MySQL Driver 文档](https://github.com/go-sql-driver/mysql?tab=readme-ov-file#system-variables)。 ### Raw SQL 推荐使用 Raw SQL 来体验 GreptimeDB 的全部功能。 下面的例子展示了如何使用 Raw SQL 查询数据: ```java try (Connection conn = getConnection()) { Statement statement = conn.createStatement(); // DESC table; ResultSet rs = statement.executeQuery("DESC cpu_metric"); LOG.info("Column | Type | Key | Null | Default | Semantic Type "); while (rs.next()) { LOG.info("{} | {} | {} | {} | {} | {}", rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6)); } // SELECT COUNT(*) FROM cpu_metric; rs = statement.executeQuery("SELECT COUNT(*) FROM cpu_metric"); while (rs.next()) { LOG.info("Count: {}", rs.getInt(1)); } // SELECT * FROM cpu_metric ORDER BY ts DESC LIMIT 5; rs = statement.executeQuery("SELECT * FROM cpu_metric ORDER BY ts DESC LIMIT 5"); LOG.info("host | ts | cpu_user | cpu_sys"); while (rs.next()) { LOG.info("{} | {} | {} | {}", rs.getString("host"), rs.getTimestamp("ts"), rs.getDouble("cpu_user"), rs.getDouble("cpu_sys")); } } ``` 请参考 [此处](https://github.com/GreptimeTeam/greptimedb-ingester-java/blob/main/ingester-example/src/main/java/io/greptime/QueryJDBC.java) 获取直接可执行的代码。 The following code declares a GORM object model: ```go type CpuMetric struct { Host string `gorm:"column:host;primaryKey"` Ts time.Time `gorm:"column:ts;primaryKey"` CpuUser float64 `gorm:"column:cpu_user"` CpuSys float64 `gorm:"column:cpu_sys"` } ``` 如果你正在使用 [高层级 API](/user-guide/ingest-data/for-iot/grpc-sdks/go.md#高层级-api) 来插入数据,你可以在模型中同时声明 GORM 和 GreptimeDB Tag。 ```go type CpuMetric struct { Host string `gorm:"column:host;primaryKey" greptime:"tag;column:host;type:string"` Ts time.Time `gorm:"column:ts;primaryKey" greptime:"timestamp;column:ts;type:timestamp;precision:millisecond"` CpuUser float64 `gorm:"column:cpu_user" greptime:"field;column:cpu_user;type:float64"` CpuSys float64 `gorm:"column:cpu_sys" greptime:"field;column:cpu_sys;type:float64"` } ``` 声明表名: ```go func (CpuMetric) TableName() string { return "cpu_metric" } ``` 使用 Raw SQL 查询数据: ```go var cpuMetric CpuMetric db.Raw("SELECT * FROM cpu_metric LIMIT 10").Scan(&result) ``` ### 查询库参考 有关如何使用查询库的更多信息,请参考相应库的文档: - [JDBC 在线教程](https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html) - [GORM](https://gorm.io/docs/index.html) ## 命令行工具 ### MySQL 你可以使用 `mysql` 命令行工具连接到 GreptimeDB。 请参考 [MySQL 协议](/user-guide/protocols/mysql.md) 文档获取连接信息。 连接到服务器后,你可以使用所有 [GreptimeDB SQL 命令](/reference/sql/overview.md)与数据库交互。 ### PostgreSQL 你可以使用 `psql` 命令行工具连接到 GreptimeDB。 请参考 [PostgreSQL 协议](/user-guide/protocols/postgresql.md) 文档获取连接信息。 连接到服务器后,你可以使用所有 [GreptimeDB SQL 命令](/reference/sql/overview.md)与数据库交互。 ## GreptimeDB 控制台 你可以在 [Greptime 控制台](/getting-started/installation/greptimedb-dashboard.md)中运行 SQL 并可视化数据。 ## GUI 工具 ### DBeaver 请参考 [DBeaver 集成指南](/user-guide/integrations/dbeaver.md)。 ## HTTP API 你可以将 POST SQL 到 GreptimeDB HTTP API 以查询数据。 请参考 [HTTP API](/user-guide/protocols/http.md) 文档获取更多信息。 --- ## 指标收集 为了提升我们的服务,GreptimeDB 会收集一些数据,包括 GreptimeDB 版本、节点数量、使用的操作系统、环境架构以及类似的技术细节等信息。但是我们尊重您的隐私,并确保不收集任何特定于用户的数据,其中包括数据库名称、表名称、查询内容等。 你的体验和隐私是我们的首要任务。你可以根据自己的喜好轻松管理此指标收集,通过配置选择启用或禁用它。 ## 将会收集哪些数据 详细的数据信息可能会随着时间的推移而发生变化,这些更改(如果有)将在发行说明中公布。 启用指标收集后,GreptimeDB 将每半小时收集一次以下信息: - GreptimeDB 版本 - GreptimeDB 的构建 git 哈希 - 运行 GreptimeDB 的设备的操作系统(Linux、macOS 等) - GreptimeDB 运行的机器架构(x86_64、arm64 等) - GreptimeDB 运行模式(独立、分布式) - 随机生成的安装 ID - GreptimeDB 集群中的 datanode 数量 - 系统运行时间,非精确数字,仅为 `hours`、`weeks` 等时间范围,并且不带数字 数据示例: ```json { "os": "linux", "version": "0.15.1", "arch": "aarch64", "mode": "Standalone", "git_commit": "00d759e828f5e148ec18141904e20cb1cb7577b0", "nodes": 1, "uuid": "43717682-baa8-41e0-b126-67b797b66606", "uptime": "hours" } ``` ## 如何禁用指标收集 从 GreptimeDB v0.4.0 开始,指标收集将默认启用。你可以通过更改配置来禁用它。 ### 独立模式 将独立配置文件中的 `enable_telemetry` 设置为 `false`: ```toml # Whether to enable greptimedb telemetry, true by default. enable_telemetry = false ``` 或者在启动时通过环境变量 `GREPTIMEDB_STANDALONE__ENABLE_TELEMETRY=false` 进行配置。 ### 分布式模式 将 metasrv 配置文件中的 `enable_telemetry` 设置为 `false`: ```toml # metasrv config file # Whether to enable greptimedb telemetry, true by default. enable_telemetry = false ``` 或者在启动时设置环境变量 `GREPTIMEDB_METASRV__ENABLE_TELEMETRY=false`。 --- ## 时间范围对象 GreptimeDB 使用时间范围对象来表示各种上下文中的时间跨度, 包括 SQL 查询、配置文件和 API 请求。 有关如何使用时间范围对象的信息, 请参阅: - [ALTER](/reference/sql/alter.md) 语句中的 TTL 选项和 TWCS compaction 策略的时间窗口设置。 - [CREATE](/reference/sql/create.md) 语句中的 TTL 选项。 时间范围对象表示为由连接的时间跨度组成的字符串, 每个时间跨度由一个十进制数字序列和一个单位后缀表示。 这些后缀不区分大小写,并且支持单数和复数形式。例如,`1hour 12min 5s`。 每个时间跨度由一个整数和一个后缀组成。支持的后缀有: - `nsec`, `ns`: 纳秒 - `usec`, `us`: 微秒 - `msec`, `ms`: 毫秒 - `seconds`, `second`, `sec`, `s`: 秒 - `minutes`, `minute`, `min`, `m`: 分钟 - `hours`, `hour`, `hr`, `h`: 小时 - `days`, `day`, `d`: 天 - `weeks`, `week`, `w`: 周 - `months`, `month`, `M`: 定义为 30.44 天 - `years`, `year`, `y`: 定义为 365.25 天 在十进制整数后附加上述单位之一,表示等值的秒数。 例如: - `1s`: 等效于 1 秒 - `2m`: 等效于 120 秒 - `1ms`: 等效于 0.001 秒 - `2h`: 等效于 7200 秒 以下写法无效: - `0xABm`: 不支持十六进制数字 - `1.5h`: 不支持浮点数 - `+Infd`: 不支持 `±Inf` 或 `NaN` 值 以下是一些有效的时间范围示例: - `1h`: 一小时 - `1h30m`, `1h 30m`: 一小时三十分钟 - `1h30m10s`, `1h 30m 10s`: 一小时三十分钟十秒 --- ## GreptimeDB 常见问题 # 常见问题 :::tip 想了解基础信息? - GreptimeDB 是什么 / 适用场景 → [为什么选择 GreptimeDB](/user-guide/concepts/why-greptimedb.md) - 性能基准测试 → [功能特性](/user-guide/concepts/features-that-you-concern.md#性能对比其他方案怎么样) - Metrics、Logs、Traces 支持 → [功能特性](/user-guide/concepts/features-that-you-concern.md#greptimedb-如何处理-metricslogs-和-traces) - 高基数处理 → [功能特性](/user-guide/concepts/features-that-you-concern.md#如何解决高基数问题) - 数据模型 → [数据模型](/user-guide/concepts/data-model.md) ::: ## 通用问题 ### 哪里可以找到开箱即用的 Demo? 可以看 [demo-scene](https://github.com/GreptimeTeam/demo-scene) 仓库,里面有覆盖常见场景(metrics、logs、IoT 等)的端到端示例,本地用 Docker Compose 即可运行。 ### GreptimeDB 的性能表现如何? GreptimeDB 针对 metrics、logs、traces 场景优化,写入吞吐高、查询延迟低、存储成本低。以下是已发布的基准测试报告: - [GreptimeDB vs. InfluxDB](https://greptime.cn/blogs/2024-08-08-report) - [GreptimeDB vs. TimescaleDB](https://greptime.cn/blogs/2025-12-09-greptimedb-vs-timescaledb-benchmark) - [GreptimeDB vs. Grafana Mimir](https://greptime.cn/blogs/2024-08-01-grafana) - [GreptimeDB vs. ClickHouse vs. Elasticsearch(日志基准测试)](https://greptime.cn/blogs/2025-03-07-greptimedb-log-benchmark) - [GreptimeDB vs. SQLite](https://greptime.cn/blogs/2024-08-30-sqlite) - [GreptimeDB vs. Loki](https://greptime.cn/blogs/2025-08-07-beyond-loki-greptimedb-log-scenario-performance-report.html) - [JSONBench 10 亿条冷查询 #1](https://greptime.cn/blogs/2025-03-18-json-benchmark-greptimedb) 架构层面的对比参见[对比表格](/user-guide/concepts/why-greptimedb.md#greptimedb-对比)。 ### GreptimeDB 的设计权衡有哪些? GreptimeDB 针对可观测性和时序工作负载做了专门优化,与通用 OLTP 数据库有不同的取舍: - **不支持 ACID 事务**:优先保证高吞吐写入,而非事务一致性。 - **支持删除,但不适合高频删除场景**:GreptimeDB 支持[数据删除](/user-guide/manage-data/overview.md#删除数据)和[基于 TTL 的自动过期](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据),但不适合需要频繁细粒度删除的场景——可观测性数据本身就是追加为主的。 - **支持 Join,但暂时不是优化重点**:GreptimeDB 支持 SQL Join,但查询引擎主要针对时序数据的过滤-聚合模式优化。简单 Join(如关联查询、metrics 与 logs 的交叉分析)可以正常使用。 - **面向时序数据**:针对 IoT、metrics、logs、traces 优化,而非通用 OLTP。 ### GreptimeDB 和 InfluxDB 有什么区别? 主要区别: - **开源策略**:GreptimeDB 的整个分布式系统完全开源。 - **架构**:基于 Region 的分片设计,针对可观测性工作负载优化。 - **查询语言**:SQL + PromQL vs. InfluxQL + SQL。 - **统一模型**:在一个系统中原生支持 metrics、logs 和 traces。 - **存储**:可插拔引擎,针对不同场景做专项优化。 - **云原生**:原生支持 Kubernetes,计算存储分离(参见 [Kubernetes 部署指南](/user-guide/deployments-administration/deploy-on-kubernetes/overview.md))。 详细对比参见 [GreptimeDB vs InfluxDB](https://greptime.cn/compare/influxdb)。更多产品对比(如 vs. ClickHouse、Loki 等)可在[官网](https://greptime.cn)的对比菜单中找到。 ## 数据模型与 Schema ### Tag 列和 Field 列有什么区别? GreptimeDB 使用三种语义列类型:**Tag**、**Timestamp** 和 **Field**。 - **Tag** 列用于标识时间序列。具有相同 Tag 值的行属于同一条时间序列。Tag 列默认加入主键索引,查询过滤快。在 SQL 中通过 `PRIMARY KEY` 声明。 - **Field** 列存储实际测量值(数值、字符串等)。Field 列默认不建索引,但可以按需添加[索引](/user-guide/manage-data/data-index.md)。 - **Timestamp** 是时间索引,每张表必须有且仅有一个。 例如,在 `system_metrics` 表中,`host` 和 `idc` 是 Tag,`cpu_util` 和 `memory_util` 是 Field,`ts` 是 Timestamp。 详细说明和示例参见[数据模型](/user-guide/concepts/data-model.md)和[表设计指南](/user-guide/deployments-administration/performance-tuning/design-table.md)。 ### GreptimeDB 支持无 Schema 写入吗? 支持。通过 gRPC、InfluxDB Line Protocol、OpenTSDB、Prometheus Remote Write、OpenTelemetry、Loki 或 Elasticsearch 兼容 API 写入时,GreptimeDB 会在首次写入时自动创建表和列,无需手动定义 Schema。 详见[自动 Schema 生成](/user-guide/ingest-data/overview.md#自动生成表结构)。 ### 使用自动建表时,如何指定默认的表选项(TTL、append mode 等)? 有三种方式为[自动创建](/user-guide/ingest-data/overview.md#自动生成表结构)的表设置 `ttl`、`append_mode`、`merge_mode`、`skip_wal`、`sst_format` 等表选项: 1. **写入时通过 HTTP Header 指定**:在请求中添加 `x-greptime-hints` 头传递表选项,例如 `x-greptime-hints: ttl=7d, append_mode=true`,表在自动创建时会应用这些选项。详见 [HTTP Hints](/user-guide/protocols/http.md#hints)。 2. **建表后通过 ALTER TABLE 修改**:部分选项支持在建表后修改,包括 `ttl`、`append_mode`、`compaction.*` 和 `sst_format`: ```sql ALTER TABLE my_table SET 'ttl' = '7d'; ALTER TABLE my_table SET 'append_mode' = 'true'; ``` 注意 `merge_mode` 和 `skip_wal` 不支持建表后修改,必须在建表时指定。所有支持的选项和约束参见 [ALTER TABLE](/reference/sql/alter.md#修改表的参数)。 3. **设置数据库级别的默认选项**:创建或修改数据库时指定默认选项,后续自动创建的表会继承这些值: ```sql CREATE DATABASE my_db WITH (ttl = '7d', append_mode = 'true'); -- 或 ALTER DATABASE my_db SET 'ttl' = '7d'; ``` 其中 `ttl` 和 `compaction.*` 选项具有持续效果——没有单独设置的表会一直继承数据库的值。其他选项(`append_mode`、`merge_mode`、`skip_wal`、`sst_format`)仅作为新建表的默认值。所有可用选项参见 [CREATE DATABASE](/reference/sql/create.md#create-database)。 ### 如何自定义 InfluxDB / Prometheus 协议写入时的默认列名? 通过无 Schema 协议写入时,GreptimeDB 会为自动生成的列加上 `greptime_` 前缀。时间戳列在所有无 Schema 协议中默认命名为 `greptime_timestamp`。值列 `greptime_value` 仅用于单值协议(如 Prometheus Remote Write、OpenTelemetry Metrics),因为每条时间序列只有一个数值。多字段协议(如 InfluxDB Line Protocol)直接使用传入数据的字段名,只有时间戳列会使用默认前缀。 要修改前缀,在 `standalone.toml` 或 `frontend.toml` 中设置 `default_column_prefix`: ```toml # 去掉 "greptime_" 前缀,列名变为 "value" 和 "timestamp" default_column_prefix = "" # 或使用自定义前缀,列名变为 "my_value" 和 "my_timestamp" # default_column_prefix = "my" ``` 不设置时默认使用 `greptime_` 前缀。该选项是顶层配置项,修改后需要重启生效。 ### 建表后能修改列的数据类型吗? 可以。使用 `ALTER TABLE ... MODIFY COLUMN` 修改 Field 列的数据类型: ```sql ALTER TABLE monitor MODIFY COLUMN load_15 STRING; ``` 目标列必须是 Field 列(不能是 Tag 或时间索引),且必须可为空(nullable),这样类型转换失败时返回 `NULL` 而非报错。 完整的 `ALTER TABLE` 语法参见 [SQL 参考](/reference/sql/alter.md)。 ### GreptimeDB 如何处理迟到数据和乱序数据? GreptimeDB 接受任意时间戳的写入,没有写入时间窗口或顺序要求。迟到和乱序数据正常写入后立即可查。存储引擎的 [Compaction](/user-guide/deployments-administration/manage-data/compaction.md)会在后台自动排序和合并数据。 对于 Append Only 表(常用于日志),行不会被去重,迟到数据只是新增行。对于有主键的表,Tag + Timestamp 组合相同的行遵循[更新语义](/user-guide/manage-data/overview.md#更新数据)。 ## 集成与迁移 ### GreptimeDB 支持哪些协议、工具和 SDK? **写入协议**:[OpenTelemetry (OTLP)](/user-guide/ingest-data/for-observability/opentelemetry.md)、[Prometheus Remote Write](/user-guide/ingest-data/for-observability/prometheus.md)、[InfluxDB Line Protocol](/user-guide/ingest-data/for-iot/influxdb-line-protocol.md)、[Loki](/user-guide/ingest-data/for-observability/loki.md)、[Elasticsearch](/user-guide/ingest-data/for-observability/elasticsearch.md)、[MySQL](/user-guide/protocols/mysql.md)、[PostgreSQL](/user-guide/protocols/postgresql.md)、[gRPC](/user-guide/protocols/grpc.md)——参见[协议概述](/user-guide/protocols/overview.md)。 **查询语言**:[SQL](/user-guide/query-data/sql.md)、[PromQL](/user-guide/query-data/promql.md)。 **可视化**:[Grafana](/user-guide/integrations/grafana.md)(官方插件 + MySQL/PostgreSQL 数据源),以及任何支持 MySQL 或 PostgreSQL 协议的工具。 **数据管道**:Vector、Fluent Bit、Telegraf、Kafka——参见[集成概述](/user-guide/integrations/overview.md)。 **SDK**: - [Go](https://github.com/GreptimeTeam/greptimedb-ingester-go) - [Java](https://github.com/GreptimeTeam/greptimedb-ingester-java) - [Rust](https://github.com/GreptimeTeam/greptimedb-ingester-rust) - [Erlang](https://github.com/GreptimeTeam/greptimedb-ingester-erl) - [.NET](https://github.com/GreptimeTeam/greptimedb-ingester-dotnet) - [TypeScript](https://github.com/GreptimeTeam/greptimedb-ingester-ts) - 其他语言(Python、Ruby 等):可以使用任何 OpenTelemetry SDK、InfluxDB 客户端库或 MySQL/PostgreSQL 驱动,GreptimeDB 均兼容。 ### 如何选择合适的写入协议? GreptimeDB 支持多种写入协议,吞吐性能差异很大。以下数据来自本地测试环境(100 万时间序列,batch size 1,000)——**请关注相对比例而非绝对数值**,实际吞吐取决于硬件和负载: | 协议 | 相对吞吐 | | --- | --- | | gRPC Bulk (Arrow Flight) | 最高(约 37 倍 SQL) | | gRPC Stream | 约 21 倍 SQL | | gRPC SDK (Unary) | 约 16 倍 SQL | | InfluxDB Line Protocol | 约 12 倍 SQL | | OTLP Logs | 约 8.5 倍 SQL | | MySQL / PostgreSQL INSERT | 基线 | **选择建议:** - **通用场景**:gRPC SDK——简洁易用且性能好,支持无 Schema 写入。 - **批量导入**(数据迁移、回填):gRPC Bulk——吞吐最高,需要预先建表。 - **持续流式写入**(IoT、监控采集器):gRPC Stream——长连接上持续高吞吐。 - **生态集成**:InfluxDB Line Protocol(兼容 Telegraf)或 OTLP(兼容 OpenTelemetry)——吞吐不错且工具生态丰富。 - **开发调试**:SQL 协议(MySQL / PostgreSQL)——吞吐较低但方便排查。 完整的基准测试细节和方法参见[写入协议基准测试](https://greptime.cn/blogs/2026-03-24-ingestion-protocol-benchmark)博客。 ### 如何将 Grafana 连接到 GreptimeDB? GreptimeDB 支持三种 Grafana 数据源接入方式: - **[GreptimeDB 插件](/user-guide/integrations/grafana.md#greptimedb-数据源插件)**:官方插件,支持 SQL 和 PromQL 查询。 - **[Prometheus 数据源](/user-guide/integrations/grafana.md#prometheus-数据源)**:通过 GreptimeDB 的 Prometheus 兼容端点使用 PromQL 仪表板。 - **[MySQL 数据源](/user-guide/integrations/grafana.md#mysql-数据源)**:通过 GreptimeDB 的 MySQL 协议端点接入。 详细配置参见 [Grafana 集成指南](/user-guide/integrations/grafana.md)。 ### 如何从其他数据库迁移到 GreptimeDB? GreptimeDB 提供以下迁移指南: - **从 InfluxDB 迁移**:Line Protocol 和数据迁移 - **从 Prometheus 迁移**:Remote Write 和历史数据迁移 - **从 ClickHouse 迁移**:表结构和数据迁移 - **从 MySQL/PostgreSQL 迁移**:基于 SQL 的迁移 详细说明参见[迁移概述](/user-guide/migrate-to-greptimedb/overview.md)。 ## 部署与运维 ### 有哪些部署方式? **集群部署**(生产环境): - 至少 3 个节点保证高可用 - 三个组件:metasrv、frontend、datanode - 组件可以合并部署或独立部署 - 参见[容量规划指南](/user-guide/deployments-administration/capacity-plan.md) **单机部署**(开发 / 边缘 / IoT): - 单个二进制文件,所有组件集成在一个进程中 - 支持 Linux、macOS、Android ARM64、Raspberry Pi - 参见[安装指南](/getting-started/installation/overview.md) **存储后端**:S3、GCS、Azure Blob(推荐生产);本地磁盘(开发测试或者中小规模)。元数据:集群模式使用推荐 RDS 或 etcd,单机模式本地存储。 完整介绍参见[部署与管理概述](/user-guide/deployments-administration/overview.md)。 ### Metasrv 的元数据存储后端应该选哪个? GreptimeDB 的 metasrv 组件支持 etcd、MySQL 和 PostgreSQL 作为元数据存储后端。 生产环境下,**推荐使用 PostgreSQL 或 MySQL(包括云 RDS 服务)**——大多数团队对关系型数据库有更丰富的运维经验、监控方案和容灾策略。 **etcd 仍然完全受支持并持续维护**,并非被废弃。如果你的团队在 etcd 运维方面有丰富经验和成熟工具链,etcd 也是完全可行的选择。 最终取决于团队的技术栈和已有基础设施。各后端的配置方式参见[元数据存储配置](/user-guide/deployments-administration/manage-metadata/configuration.md)。 ### 如何管理 GreptimeDB? GreptimeDB 使用**标准 SQL 作为管理接口**。你可以通过 SQL 完成[表的基本操作如建表删表](/user-guide/deployments-administration/manage-data/basic-table-operations.md)、[修改 Schema](/reference/sql/alter.md)、设置 [TTL 策略](/user-guide/manage-data/overview.md#使用-ttl-策略保留数据)、配置[索引](/user-guide/manage-data/data-index.md)等操作,不用写配置文件,也不用调专有 API。 节点级别的配置参见[配置指南](/user-guide/deployments-administration/configuration.md)。 ### 如何升级 GreptimeDB? 参见[升级指南](/user-guide/deployments-administration/upgrade.md),包含升级步骤、兼容性说明和不兼容变更。 ### 如何备份和恢复数据? GreptimeDB 提供数据导出和导入工具,支持全库备份与恢复,包括仅导出 Schema 和 S3 导出。 参见[数据导出与导入](/user-guide/deployments-administration/disaster-recovery/back-up-&-restore-data.md)。 ### 能否在单机模式和集群模式之间迁移数据? 可以。使用 [`COPY TO`](/reference/sql/copy.md) 从单机模式导出表数据,再用 [`COPY FROM`](/reference/sql/copy.md) 导入到集群(反过来也一样)。数据以 Parquet 格式导出,可以存放在本地或对象存储(S3、GCS)中。 ### WAL 目录越来越大,正常吗? WAL(Write-Ahead Log)空间在数据刷写到持久存储后会循环复用。如果 WAL 目录看起来很大,通常是因为数据尚未刷写,或者 WAL 保留设置需要调整。WAL 是临时空间,评估存储用量时只看数据目录(`data`)就行。 WAL 配置参见[配置指南](/user-guide/deployments-administration/configuration.md)。 ### 查询报 `Too many files to read concurrently` 怎么处理? 这表示单条查询要扫描的 SST 文件数超过了单查询并发上限。典型错误形如: ``` Too many files to read concurrently: 1528, max allowed: 384 ``` 常见原因有两类: - **小 SST 文件过多** —— 多见于历史数据回填且时间戳跨度大、compaction 还没追上的场景。 - **默认的并发文件上限对你的硬件来说过于保守**。 **诊断**:用 [SSTS_MANIFEST](/reference/sql/information-schema/ssts-manifest.md) 视图看每张表每天的文件数。结果集很大时建议按 `min_ts` 过滤: ```sql SELECT table_id, date_trunc('day', min_ts), COUNT(*) AS files, SUM(num_rows) AS rows FROM information_schema.ssts_manifest WHERE min_ts > '2026-05-01 00:00:00' GROUP BY table_id, date_trunc('day', min_ts) ORDER BY files DESC; ``` **处理方式**: 1. 调高 datanode(或 standalone)`[region_engine.mito]` 下的单查询文件上限: ```toml [region_engine.mito] max_concurrent_scan_files = 1024 ``` 默认 `384` 是偏保守的值。CPU 和内存余量更充裕的机器,可以适当调大让大查询不被拒。改完需要重启对应 datanode。 2. 用 SWCS 触发手动 compaction。如果单天的小文件特别多,可以把窗口调到比默认 1 天更小,参见 [Compaction](/user-guide/deployments-administration/manage-data/compaction.md): ```sql -- 1 小时窗口,并行度 2 ADMIN COMPACT_TABLE('', 'swcs', 'window=3600,parallelism=2'); ``` ### GreptimeDB 的扩展能力如何? - 表和列的数量没有严格限制,性能主要取决于主键设计而非表数量。 - Region 内数据自动按时间组织。 - 通过 `PARTITION` 子句手动分片——参见[表分片指南](/user-guide/deployments-administration/manage-data/table-sharding.md)。 - 多层缓存(写入缓存 + LRU 读缓存)优化性能。 - 对象存储后端(S3/GCS/Azure Blob)提供几乎无限的存储容量。 - 分布式查询执行,支持 MPP 处理大规模数据集。 ### 数据如何分布? - 建表时通过 `PARTITION` 子句手动分区——参见[表分片指南](/user-guide/deployments-administration/manage-data/table-sharding.md)。 - Region 内按时间自动组织。 - 支持手动 Region 迁移进行负载均衡——参见 [Region 迁移指南](/user-guide/deployments-administration/manage-data/region-migration.md)。 - 自动 Region 故障转移保障容灾——参见 [Region 故障转移](/user-guide/deployments-administration/manage-data/region-failover.md)。 ### 有哪些灾备方案? GreptimeDB 提供多种灾备策略: - **单机灾备**:远程 WAL + 对象存储,RPO=0,RTO 分钟级。 - **Region 故障转移**:单个 Region 自动切换,停机时间极短。 - **双活容灾**(企业版):双节点间同步复制请求。 - **跨区域单集群**:横跨三个区域,零 RPO,区域级容错。 - **备份与恢复**:定期数据备份,RPO 取决于备份频率。 参见[灾备方案概述](/user-guide/deployments-administration/disaster-recovery/overview.md)。 ### 写入报 `Procedure poison key already exists` 怎么处理? 这种错误会阻塞写入。原因是 schema-on-write 触发的 `ALTER TABLE`(比如为新进来的 attribute 自动加列)在默认 12 次重试后仍然失败,在元数据存储里留下了一个未清理的 poison key。后续依赖 schema 演化的写入都会被这把锁挡住。 典型错误形如: ``` Procedure poison key already exists with a different value Key: /__procedure_poison/table/ ``` **恢复步骤**: 1. 从元数据存储中删除该 poison key。按你的实际后端和地址替换 `--backend` 与 `--store-addrs`,参见[元数据交互](/reference/command-lines/utilities/metadata-interaction.md#delete-key-value-pair): ```bash greptime cli meta del key \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ /__procedure_poison/table/ ``` 2. 触发表元数据修复,让 Metasrv 与 Datanode 一致。用受影响的 schema 与表名,参见[表元数据修复](/user-guide/deployments-administration/maintenance/table-reconciliation.md): ```sql USE ; ADMIN reconcile_table(''); ``` 3. 如果写入仍然报 `Column ... not found in logical region`,说明逻辑表的列元数据已经和物理表不一致。用 CLI 工具修复,参见[修复逻辑表](/reference/command-lines/utilities/repair-logical-tables.md): ```bash greptime cli meta repair logical-tables \ --store-addrs=$ENDPOINT \ --backend=postgres-store \ --table-names= \ --schema-name= \ --catalog-name=greptime ``` **排查提示**:如果 `ADMIN reconcile_*` 立刻返回 `Done`,但 Metasrv 日志里完全没有 `Reconciling table:` 这类输出,多半是连到了另一个 Metasrv 实例(比如同集群另一个 namespace 里的 GreptimeDB 部署)。先用 `kubectl get pods -A | grep meta` 之类命令确认拓扑,再重试。 ### 如何监控和排查问题? GreptimeDB 暴露 Prometheus 兼容的监控指标,并提供健康检查端点。监控配置和故障排查指南参见[监控概述](/user-guide/deployments-administration/monitoring/overview.md)。 ## 开源版 vs 企业版 vs 云服务 ### 各版本有什么区别? - **开源版**:完整的分布式系统、多协议支持、基础认证。 - **企业版**:在开源版基础上增加 CBO 查询优化、双活容灾、自动扩缩容和索引、RBAC/LDAP 集成、7×24 技术支持。 - **GreptimeCloud**:全托管方案,为生产工作负载提供资源和性能保障、可预测的定价、SLA 保障。 详细功能对比参见[价格与功能](https://greptime.cn/pricing#differences)。 ### GreptimeDB Dashboard 有没有鉴权功能? 开源版 [GreptimeDB Dashboard](/getting-started/installation/greptimedb-dashboard.md) 本身不包含鉴权功能。如需限制访问,你可以: - 在 Dashboard 前面放一个反向代理(如 Nginx、Caddy),配置 HTTP Basic Auth 或其他认证机制。 - 将 Dashboard 托管在你的内部 HTTP 服务后面,结合组织内部的认证体系。 **GreptimeDB 企业版**提供内置鉴权和访问管理的管理控制台。 ### 有哪些安全功能? **开源版**: - 用户名/密码认证 - 用户读写权限控制 - TLS/SSL 连接加密 **企业版 / 云服务**: - 基于角色的访问控制(RBAC) - LDAP 支持 - 团队管理和 API 密钥 - 静态数据加密 - 合规审计日志 --- ## 常见问题及其他 在本节中,我们将介绍[常见问题](./faq.md)和其他一些信息。 --- ## For AI Agents GreptimeDB 为 AI coding agent 而构建。Agent 可以通过标准协议(OTLP、Prometheus、 MySQL/PostgreSQL、SQL/PromQL)自主完成 GreptimeDB 的部署、配置、写入和查询,下面这些 资源帮助它把这些事做对、做稳。 ## 最快上手:一句话指令 入口级的 quickstart 指南以可直接抓取的 markdown 文件形式托管。把下面的提示词交给你的 agent,它就能接手——在运行时抓取这份指南,判断 GreptimeDB 是否适用,选择合适的安装与写入 路径,并通过 `llms.txt` 浏览文档。无需安装任何东西。 > **AGENT ONBOARDING:** 阅读 https://docs.greptime.cn/SKILL.md 并按其中的指引在你的 AI Agent 中使用 GreptimeDB(部署、配置、写入、查询)。 ## GreptimeDB MCP Server [GreptimeDB MCP Server](../user-guide/integrations/mcp.md) 实现了 Model Context Protocol,让 agent 能安全地探索和分析你的数据库——列出表、读取数据,执行 SQL、TQL (兼容 PromQL)和 range 查询。它强制只读访问、支持数据脱敏,并内置了面向 metrics、trace、 PromQL 分析、IoT 监控、表操作和日志 pipeline 创建的场景模板。 ```shell pip install greptimedb-mcp-server ``` 传输方式(stdio、SSE、Streamable HTTP)和配置详见 [greptimedb-mcp-server](https://github.com/GreptimeTeam/greptimedb-mcp-server) 仓库。 ## GreptimeDB Skills GreptimeDB 兼容大多数 coding agent 已经熟悉的开放标准。而对于我们自有的功能——pipeline、 flow、trigger——安装一个 Skill 能把完整工作流教给 agent,效果最好。Skill 告诉 agent *要做什么*,MCP Server 提供*执行*它的工具(例如 pipeline skill 会用 `dryrun_pipeline` 在应用前验证配置)。 - **`greptimedb-quickstart`** —— 入口。何时该用 GreptimeDB、如何安装、选哪种写入协议、 如何查询,以及深入文档的指引。从这里开始。 - **`greptimedb-pipeline`** —— 解析、转换、路由日志(Learn → Create → Verify → Refine)。 - **`greptimedb-flow`** —— 持续聚合与物化视图。 - **`greptimedb-trigger`** —— 告警规则,包括把 Prometheus 告警规则转换为 `CREATE TRIGGER`(企业版)。 - **`self-monitoring-export`** —— 用于集群故障排查:从用户描述中推断日志导出的时间范围, 然后导出集群自监控日志和指标供工程排查。 Skills 遵循 [Agent Skills](https://agentskills.io/) 开放标准,因此可用于 Claude Code、 OpenAI Codex CLI、GitHub Copilot、Cursor 等。每个 Skill 也以可直接抓取的 markdown 文件 托管在 `https://docs.greptime.cn/skills//SKILL.md`(例如 [`greptimedb-pipeline`](https://docs.greptime.cn/skills/greptimedb-pipeline/SKILL.md)), agent 可在运行时加载,无需安装。 如需把 Skill 持久安装进 agent 配置,使用 `skills` CLI: ```shell npx skills add https://github.com/GreptimeTeam/docs/tree/main/skills/greptimedb-quickstart ``` 完整清单和安装命令见 [skills](https://github.com/GreptimeTeam/docs/tree/main/skills) 仓库。 ## 机器可读文档 整个文档站点都按 [llmstxt.org](https://llmstxt.org) 标准构建,便于 agent 消费: - [`llms.txt`](https://docs.greptime.cn/llms.txt) —— 结构化索引,列出每个文档章节及简要 描述。让 agent 指向它,就能直接找到对应页面,无需爬整个站点。 - [`llms-full.txt`](https://docs.greptime.cn/llms-full.txt) —— 把全部文档拼接成单个文件, 一次性加载整个文档语料。 - **任意页面的 markdown** —— 在任意文档 URL 后追加 `.md`,即可得到该页的原始 markdown (例如 [`/user-guide/integrations/mcp.md`](https://docs.greptime.cn/user-guide/integrations/mcp.md))。 临时提问可以用 [docs.greptime.cn](https://docs.greptime.cn/) 上的 **Ask AI** 助手,它基于 官方文档用平实语言作答。 ## 参考资料 - [What GreptimeDB is doing for AI agents](https://greptime.cn/blogs/2026-04-08-greptimedb-agent-friendly-infrastructure) --- ## 数据持久化与索引 与所有类似 LSMT 的存储引擎一样,MemTables 中的数据被持久化到耐久性存储,例如本地磁盘文件系统或对象存储服务。GreptimeDB 采用 [Apache Parquet][1] 作为其持久文件格式。 ## SST 文件格式 Parquet 是一种提供快速数据查询的开源列式存储格式,已经被许多项目采用,例如 Delta Lake。 Parquet 具有层次结构,类似于“行组 - 列-数据页”。Parquet 文件中的数据被水平分区为行组(row group),在其中相同列的所有值一起存储以形成数据页(data pages)。数据页是最小的存储单元。这种结构极大地提高了性能。 首先,数据按列聚集,这使得文件扫描更加高效,特别是当查询只涉及少数列时,这在分析系统中非常常见。 其次,相同列的数据往往是同质的(比如具备近似的值),这有助于在采用字典和 Run-Length Encoding(RLE)等技术进行压缩。 ## 数据持久化 GreptimeDB 提供了 `region_engine.mito.global_write_buffer_size` 的配置项来设置全局的 Memtable 大小阈值。当数据库所有 MemTable 中的数据量之和达到阈值时将自动触发持久化操作,将 MemTable 的数据 flush 到 SST 文件中。 ## SST 文件中的索引数据 Apache Parquet 文件格式在列块和数据页的头部提供了内置的统计信息,用于剪枝和跳过。 例如,在上述 Parquet 文件中,如果你想要过滤 `name` 等于 `Emily` 的行,你可以轻松跳过行组 0,因为 `name` 字段的最大值是 `Charlie`。这些统计信息减少了 IO 操作。 ## 索引文件 对于每个 SST 文件,GreptimeDB 不但维护 SST 文件内部索引,还会单独生成一个文件用于存储针对该 SST 文件的索引结构。 索引文件采用 [Puffin][3] 格式,这种格式具有较大的灵活性,能够存储更多的元数据,并支持更多的索引结构。 ![Puffin](/puffin.png) GreptimeDB 会将多种索引结构作为 Blob 存储在 Puffin 文件中,包括倒排索引、跳数索引(基于 bloom filter)和全文索引。倒排索引是最早支持的索引结构,下面将详细介绍。 ## 倒排索引 在 v0.7 版本中,GreptimeDB 引入了倒排索引(Inverted Index)来加速查询。 倒排索引是一种常见的用于全文搜索的索引结构,它将文档中的每个单词映射到包含该单词的文档列表,GreptimeDB 把这项源自于搜索引擎的技术应用到了时间序列数据库中。 搜索引擎和时间序列数据库虽然运行在不同的领域,但是应用的倒排索引技术背后的原理是相似的。这种相似性需要一些概念上的调整: 1. 单词:在 GreptimeDB 中,指时间线的列值。 2. 文档:在 GreptimeDB 中,指包含多个时间线的数据段。 倒排索引的引入,使得 GreptimeDB 可以跳过不符合查询条件的数据段,从而提高扫描效率。 ![Inverted index searching](/inverted-index-searching.png) 例如,上述查询使用倒排索引来定位数据段,数据段满足条件:`job` 等于 `apiserver`,`handler` 符合正则匹配 `.*users` 及 `status` 符合正则匹配 `4..`,然后扫描这些数据段以产生满足所有条件的最终结果,从而显着减少 IO 操作的次数。 ### 倒排索引格式 ![Inverted index format](/inverted-index-format.png) GreptimeDB 按列构建倒排索引,每个倒排索引包含一个 FST 和多个 Bitmap。 FST(Finite State Transducer)允许 GreptimeDB 以紧凑的格式存储列值到 Bitmap 位置的映射,并且提供了优秀的搜索性能和支持复杂搜索(例如正则表达式匹配);Bitmap 则维护了数据段 ID 列表,每个位表示一个数据段。 ### 索引数据段 GreptimeDB 把一个 SST 文件分割成多个索引数据段,每个数据段包含相同行数的数据。这种分段的目的是通过只扫描符合查询条件的数据段来优化查询性能。 例如,当数据段的行数为 1024,如果查询条件应用倒排索引后,得到的数据段列表为 `[0, 2]`,那么只需扫描 SST 文件中的第 0 和第 2 个数据段(即第 0 行到第 1023 行和第 2048 行到第 3071 行)即可。 数据段的行数由引擎选项 `index.inverted_index.segment_row_count` 控制,默认为 `1024`。较小的值意味着更精确的索引,往往会得到更好的查询性能,但会增加索引存储成本。通过调整该选项,可以在存储成本和查询性能之间进行权衡。 ## 统一数据访问层:OpenDAL GreptimeDB 使用 [OpenDAL][2] 提供统一的数据访问层,因此,存储引擎无需与不同的存储 API 交互,数据可以无缝迁移到基于云的存储,如 AWS S3。 [1]: https://parquet.apache.org [2]: https://github.com/datafuselabs/opendal [3]: https://iceberg.apache.org/puffin-spec --- ## Metric 引擎 ## 概述 `Metric` 引擎是 GreptimeDB 的一个组件,属于存储引擎的一种实现,主要针对可观测 metrics 等存在大量小表的场景。 它的主要特点是利用合成的物理宽表来存储大量的小表数据,实现相同列复用和元数据复用等效果,从而达到减少小表的存储开销以及提高列式压缩效率等目标。表这一概念在 `Metric` 引擎下变得更更加轻量。 ## 概念 `Metric` 引擎引入了两个新的概念,分别是逻辑表与物理表。从用户视角看,逻辑表与普通表完全一样。从存储视角看,物理 Region 就是一个普通的 Region。 ### 逻辑表 逻辑表,即用户定义的表。与普通的表都完全一样,逻辑表的定义包括表的名称、列的定义、索引的定义等。用户的查询、写入等操作都是基于逻辑表进行的。用户在使用过程中不需要关心逻辑表和普通表的区别。 从实现层面来说,逻辑表是一个虚拟的表,它并不直接读写物理的数据,而是通过将读写请求映射成对应物理表的请求来实现数据的存储与查询。 ### 物理表 物理表是真实存储数据的表,它拥有若干个由分区规则定义的物理 Region。 ## 架构及设计 `Metric` 引擎的主要设计架构如下: ![Arch](/metric-engine-arch.png) 在目前版本的实现中,`Metric` 引擎复用了 `Mito` 引擎来实现物理数据的存储及查询能力,并在此之上同时提供物理表与逻辑表的访问能力。 在分区方面,逻辑表拥有与物理表完全一致的分区规则及 Region 分布。这是非常自然的,因为逻辑表的数据直接存储在物理表中,所以分区规则也是一致的。 在路由元数据方面,逻辑表的路由地址为逻辑地址,即该逻辑表所对应的物理表是什么,而后通过该物理表进行二次路由取得真正的物理地址。这一间接路由方式能够显著减少 `Metric` 引擎的 Region 发生迁移调度时所需要修改的元数据数量。 在操作方面,`Metric` 引擎支持对逻辑表进行标准的 DML 操作(INSERT、DELETE、SELECT)。然而,对物理表的操作进行了有限的支持以防止误操作,例如禁止直接写入物理表等操作防止影响用户逻辑表的数据。总体上可以认为物理表是对用户只读的。 为了提升对大量表同时进行 DDL(Data Definition Language,数据操作语言)操作时性能,如 Prometheus Remote Write 冷启动时大量 metrics 带来的自动建表请求,以及前面提到的迁移物理 Region 时大量路由表的修改请求等,`Metric` 引擎引入了一些批量 DDL 操作。这些批量 DDL 操作能够将大量的 DDL 操作合并成一个请求,从而减少了元数据的查询及修改次数,提升了性能。 除了物理表的物理数据 Region 之外,`Metric` 引擎还额外为每一个物理数据 Region 创建了一个物理的元数据 Region,用于存储 `Metric` 引擎自身为了维护映射等状态所需要的一些元数据。这些元数据包括逻辑表与物理表的映射关系,逻辑列与物理列的映射关系等等。 --- ## Datanode(Datanode) ## Introduction `Datanode` 主要的职责是为 GreptimeDB 存储数据,我们知道在 GreptimeDB 中一个 `table` 可以有一个或者多个 `Region`, 而 `Datanode` 的职责便是管理这些 `Region` 的读写。`Datanode` 不感知 `table`,可以认为它是一个 `region server`。 所以 `Frontend` 和 `Metasrv` 按照 `Region` 粒度来操作 `Datanode`。 ![Datanode](/datanode.png) ## Components 一个 datanode 包含了 region server 所需的全部组件。这里列出了比较重要的部分: - 一个 gRPC 服务来提供对 `Region` 数据的读写,`Frontend` 便是使用这个服务来从 `Datanode` 读写数据。 - 一个 HTTP 服务,可以通过它来获得当前节点的 metrics、配置信息等 - `Heartbeat Task` 用来向 `Metasrv` 发送心跳,心跳在 GreptimeDB 的分布式架构中发挥着至关重要的作用, 是分布式协调和调度的基础通信通道,心跳的上行消息中包含了重要信息比如 `Region` 的负载,如果 `Metasrv` 做出了调度 决定(比如 Region 转移),它会通过心跳的下行消息发送指令到 `Datanode` - `Datanode` 不负责解析用户 SQL 或进行分布式规划,用户对一个或多个 `Table` 的查询请求会在 `Frontend` 中被转换为 `Region` 查询请求,`Datanode` 负责用本地 query engine 执行这些 `Region` 查询计划 - 一个 `Region Manager` 用来管理 `Datanode` 上的所有 `Region`s - GreptimeDB 支持可插拔的多引擎架构,目前已有的 engine 包括 `File Engine` 和 `Mito Engine` --- ## Query Engine ## 介绍 GreptimeDB 的查询引擎是基于[Apache DataFusion][1](属于[Apache Arrow][2]的子项目)构建的,它是一个用 Rust 编写的出色的查询引擎。它提供了一整套功能齐全的组件,从逻辑计划、物理计划到执行运行时。下面将解释每个组件如何被整合在一起,以及在执行过程中它们的位置。 ![Execution Procedure](/execution-procedure.png) 入口点是逻辑计划,它被用作查询或执行逻辑等的通用中间表示。逻辑计划的两个主要来源是:1. 用户查询,例如通过 SQL 解析器和规划器的 SQL;2. Frontend 的分布式查询,这将在下一节中详细解释。 接下来是物理计划,或称执行计划。与包含所有逻辑计划变体(除特殊扩展计划节点外)的大型枚举的逻辑计划不同,物理计划实际上是一个定义了在执行过程中调用的一组方法的特性。所有数据处理逻辑都包装在实现该特性的相应结构中。它们是对数据执行的实际操作,如聚合器 `MIN` 或 `AVG` ,以及表扫描 `SELECT ... FROM`。 优化阶段通过转换逻辑计划和物理计划来提高执行性能,现在全部基于规则。它也被称为“基于规则的优化”。一些规则是 DataFusion 原生的,其他一些是在 GreptimeDB 中自定义的。在未来,我们计划添加更多规则,并利用数据统计进行基于成本的优化 (CBO)。 最后一个阶段"执行"是一个动词,代表从存储读取数据、进行计算并生成预期结果的过程。虽然它比之前提到的概念更抽象,但你可以简单地将它想象为执行一个 Rust 异步函数,并且它确实是一个异步流。 当你想知道 SQL 是如何通过逻辑计划或物理计划中表示时,`EXPLAIN [VERBOSE] ` 是非常有用的。 ## 数据表示 GreptimeDB 使用 [Apache Arrow][2]作为内存中的数据表示格式。它是面向列的,以跨平台格式,也包含许多高性能的基础操作。这些特性使得在许多不同的环境中共享数据和实现计算逻辑变得容易。 ## 索引 在时序数据中,有两个重要的维度:时间戳和标签列(或者类似于关系数据库中的主键)。GreptimeDB 将数据分组到时间桶中,因此能在非常低的成本下定位和提取预期时间范围内的数据。GreptimeDB 中主要使用的持久文件格式 [Apache Parquet][3] 提供了多级索引和过滤器,使得在查询过程中很容易修剪数据。在未来,我们将更多地利用这个特性,并开发我们的分离索引来处理更复杂的用例。 ## 分布式查询 参考 [Distributed Querying][6]. [1]: https://github.com/apache/arrow-datafusion [2]: https://arrow.apache.org/ [3]: https://parquet.apache.org [6]: ../frontend/distributed-querying.md --- ## 存储引擎 ## 概述 `存储引擎` 负责存储数据库的数据。Mito 是我们默认使用的存储引擎,基于 [LSMT][1](Log-structured Merge-tree)。我们针对处理时间序列数据的场景做了很多优化,因此 mito 这个存储引擎并不适用于通用用途。 ## 架构 下图展示了存储引擎的架构和处理数据的流程。 ![Architecture](/storage-engine-arch.png) 该架构与传统的 LSMT 引擎相同: - [WAL][2] - 为尚未刷盘的数据提供高持久性保证。 - 基于 `LogStore` API 实现,不关心底层存储介质。 - WAL 的日志记录可以存储在本地磁盘上,也可以存储在实现了 `LogStore` API 的远程日志服务中,例如 Kafka(remote WAL)。 - Memtable - 数据首先写入 `active memtable`,又称 `mutable memtable`。 - 当 `mutable memtable` 已满时,它将变为只读的 `immutable memtable`。 - SST - SST 的全名为有序字符串表(`Sorted String Table`)。 - `immutable memtable` 刷到持久存储后形成一个 SST 文件。 - SST 中的行按照主键和时间索引排序;详见 [SST 文件中的数据布局](#sst-文件中的数据布局)。 - Compactor - `Compactor` 通过 compaction 操作将小的 SST 合并为大的 SST。 - 默认使用 [TWCS][3] 策略进行合并。Compaction 会按照时间窗口组织 SST 文件,并结合 TTL 清理过期数据。详见 [Compaction](/user-guide/deployments-administration/manage-data/compaction.md)。 - Manifest - `Manifest` 存储引擎的元数据,例如 SST 的元数据。 - Cache - 加速查询操作。 [1]: https://en.wikipedia.org/wiki/Log-structured_merge-tree [2]: https://en.wikipedia.org/wiki/Write-ahead_logging [3]: https://cassandra.apache.org/doc/latest/cassandra/operating/compaction/twcs.html ## 数据模型 存储引擎提供的数据模型介于 `key-value` 模型和表模型之间 ```txt tag-1, ..., tag-m, timestamp -> field-1, ..., field-n ``` 每一行数据包含多个 tag 列,一个 timestamp 列和多个 field 列 - `0 ~ m` 个 tag 列 - tag 列是可空的 - 在建表时通过 `PRIMARY KEY` 指定 - 必须包含一个 timestamp 列 - timestamp 列非空 - 在建表时通过 `TIME INDEX` 指定 - `0 ~ n` 个 field 列 - field 列是可空的 - 数据按照 tag 列和 timestamp 列有序存储 ## Region 数据在存储引擎中以 `region` 的形式存储,`region` 是引擎中的一个逻辑隔离存储单元。`region` 中的行必须具有相同的 `schema`(模式),该 `schema` 定义了 `region` 中的 tag 列,timestamp 列和 field 列。数据库中表的数据存储在一到多个 `region` 中。 ## SST 文件中的数据布局 当 memtable 被 flush 时,Mito 会把其中的行写入不可变的 [Apache Parquet](https://parquet.apache.org) SST 文件。关于 Parquet 文件格式本身以及 SST 文件如何建立索引,详见[数据持久化和索引](data-persistence-indexing.md)。 在一个 SST 文件内,行按照 `(primary key, time index)` 排序。具有相同 primary key(tag 列)的行属于同一条时间序列,会连续存储并按时间戳排序。这种局部性使得扫描单条时间序列的成本更低,也有助于提升压缩效果。对于没有 primary key 的 append-only 表,行仅按 time index 排序。 例如,考虑一个存储主机指标的表: ```sql CREATE TABLE host_metrics ( host STRING, region STRING, ts TIMESTAMP TIME INDEX, cpu DOUBLE, memory DOUBLE, PRIMARY KEY (host, region) ); ``` Mito 会按 primary key 对行分组,并按时间排序,因此 SST 中的数据在概念上类似于: | host | region | ts | cpu | memory | | --- | --- | --- | --- | --- | | host-a | us-east | 10:00 | 0.42 | 7.1 | | host-a | us-east | 10:01 | 0.47 | 7.4 | | host-a | us-west | 10:00 | 0.31 | 6.8 | | host-b | us-east | 10:00 | 0.80 | 8.6 | 除了表中的列,Mito 还会在每个 SST 文件中存储三个内部列,以便在从多个 memtable 和 SST 文件读取时正确地合并、去重并应用删除操作: - `__primary_key`:行的编码后 primary key(tags)。 - `__sequence`:行的 sequence number。 - `__op_type`:行的操作类型(put 或 delete)。 每个 Parquet SST 都会被切分为 row group,row group 是 Parquet 可以独立读取或跳过的单位。每个 row group 都带有列统计信息,例如最小值、最大值和 null 数量。Mito 还会为每个 SST 记录文件级元数据,包括时间范围、行数、row group 数量、可用索引以及 primary key 范围。这些统计信息会驱动下面介绍的扫描裁剪。 Mito 支持两种 SST 格式:`flat`(默认)和 `primary_key`。它们以不同方式编码 primary key,并针对不同的 primary key 基数进行优化。如何选择两种格式,详见 [SST format](/reference/sql/create.md#创建指定-sst-格式的表) 和[表设计指南](/user-guide/deployments-administration/performance-tuning/design-table.md#选择合适的-sst-格式)。 ## 扫描裁剪 Mito 会组合多个从粗到细的裁剪步骤,避免读取不可能匹配查询的数据: 1. **时间范围裁剪。** 如果文件和 memtable 的时间范围与查询时间范围不相交,就会在打开 reader 之前被跳过。对于时间序列查询,这通常是成本最低且最有效的步骤。 2. **Row group 统计信息。** 如果 row group 的 min-max 统计信息能够证明没有任何行匹配谓词,则会跳过整个 row group。 3. **索引。** 倒排索引、跳数索引和全文索引可以针对统计信息无法处理的谓词提供更精细的裁剪。详见[数据持久化和索引](data-persistence-indexing.md)。 --- ## 预写日志 ## 介绍 我们的存储引擎受到了日志结构合并树(Log-structured Merge Tree,LSMT)的启发。对数据的变更操作直接应用于 MemTable 而不是持久化到磁盘上的数据页,这显著提高了性能,但也带来了持久化相关的问题,特别是在 Datanode 意外崩溃时。与所有类似 LSMT 的存储引擎一样,GreptimeDB 使用预写日志(Write-Ahead Log,WAL)来确保数据被可靠地持久化,并且保证崩溃时的数据完整性。 预写日志是一个仅提供追加写的文件组。所有的 INSERT 和 DELETE 操作都被转换为操作日志,然后追加到 WAL。一旦操作日志被持久化到底层文件,该操作才可以进一步应用到 MemTable。 当数据节点重新启动时,WAL 中的操作条目将被重放,以重建正确的 MemTable 状态。 ![WAL in Datanode](/wal.png) ## 命名空间 WAL 的命名空间用于区分来自不同 region 的条目。追加和读取操作必须提供一个命名空间。目前,region ID 被用作命名空间,因为每个 region 都有一个在数据节点重新启动时需要重构的 MemTable。 ## 同步/异步刷盘 默认情况下,WAL 的追加写是异步的,这意味着写入方不会等待操作日志被刷入到磁盘并持久化。这个默认设置提供了更高的性能,但在服务器意外关闭时可能会丢失数据。另一方面,同步刷新提供了更高的可靠性,但其代价是性能更低。 在 v0.4 版本中,新的 region worker 架构可以使用批处理来减轻同步刷盘的开销。 --- ## Arrangement Arrangement 存储数据流进程中的状态,存储 flow 的更新流(stream)以供进一步查询和更新。 Arrangement 本质上存储的是带有时间戳的键值对。 在内部,Arrangement 接收类似 `((Key Row, Value Row), timestamp, diff)` 的 tuple,并将其存储在内存中。 你可以使用 `get(now: Timestamp, key: Row)` 查询某个时间的键值对。 Arrangement 假定早于某个时间(也称为 Low Watermark)的所有内容都已被写入到 sink 表中,不会为其保留历史记录。 :::tip 注意 Arrangement 允许通过将传入 tuple 的 `diff` 设置为 -1 来删除键。 此外,如果已将行数据添加到 Arrangement 并且使用不同的值插入相同的键,则原始值将被新值覆盖。 ::: --- ## Flownode 批处理模式开发者指南 本指南简要概述了 `flownode` 中的批处理模式。它旨在帮助希望了解此模式内部工作原理的开发人员。 ## 概述 `flownode` 中的批处理模式专为持续数据聚合而设计。它在离散的、微小的时间窗口上周期性地执行用户定义的 SQL 查询。这与数据在到达时即被处理的流处理模式形成对比。 其核心思想是: 1. 定义一个带有 SQL 查询的 `flow`,该查询将数据从源表聚合到目标表。 2. 查询通常在时间戳列上包含一个时间窗口函数(例如 `date_bin`)。 3. 当新数据插入源表时,系统会将相应的时间窗口标记为“脏”(dirty)。 4. 一个后台任务会周期性地唤醒,识别这些脏窗口,并为那些特定的时间范围重新运行聚合查询。 5. 然后将结果插入到目标表中,从而有效地更新聚合视图。 ## 架构 批处理模式由几个协同工作的关键组件组成,以实现这种持续聚合。如下图所示: ![batching mode architecture](/batching_mode_arch.png) ### `BatchingEngine` `BatchingEngine` 是批处理模式的核心。它是一个管理所有活动 flow 的中心组件。其主要职责是: - **任务管理**: 维护一个从 `FlowId` 到 `BatchingTask` 的映射。它处理这些任务的创建、删除和检索。 - **事件分发**: 当新数据到达(通过 `handle_inserts_inner`)或当时间窗口被显式标记为脏(`handle_mark_dirty_time_window`)时,`BatchingEngine` 会识别受影响的 flow,并将信息转发给相应的 `BatchingTask`。 ### `BatchingTask` `BatchingTask` 代表一个独立的、单个的数据流。每个任务都与一个 `flow` 定义相关联,并在其自己的异步循环中运行。 - **配置 (`TaskConfig`)**: 此结构体持有 flow 的不可变配置,例如 SQL 查询、源表和目标表名以及时间窗口表达式。 - **状态 (`TaskState`)**: 包含任务的动态、可变状态,最重要的是 `DirtyTimeWindows`。 - **执行循环**: 任务运行一个无限循环 (`start_executing_loop`),该循环: 1. 检查关闭信号。 2. 等待一个预定的时间间隔或直到被唤醒。 3. 基于当前的脏时间窗口集合生成一个新的查询计划 (`gen_insert_plan`)。 4. 对数据库执行查询 (`execute_logical_plan`)。 5. 清理已处理的脏窗口。 ### `TaskState` 和 `DirtyTimeWindows` - **`TaskState`**: 此结构体跟踪 `BatchingTask` 的运行时状态。它包括 `dirty_time_windows`,这对于确定需要完成哪些操作至关重要。 - **`DirtyTimeWindows`**: 这是一个关键的数据结构,用于跟踪自上次查询执行以来哪些时间窗口接收到了新数据。它存储一组不重叠的时间范围。当任务的执行循环运行时,它会参考此结构来构建一个 `WHERE` 子句,该子句仅过滤源表中的脏时间窗口。 ### `TimeWindowExpr` `TimeWindowExpr` 是一个用于处理像 `date_bin` 这样的时间窗口表达式的辅助工具。 - **求值**: 它可以接受一个时间戳并对时间窗口表达式求值,以确定该时间戳所属窗口的开始和结束。 - **窗口大小**: 它还可以从表达式中确定时间窗口的大小(持续时间)。 这对于标记窗口为脏以及在查询源表时生成正确的过滤条件都至关重要。 ## 查询执行流程 以下是批处理模式下查询执行的简化分步演练: 1. **数据摄取**: 新数据被写入源表。 2. **标记为脏**: `BatchingEngine` 收到有关新数据的通知。它使用与每个相关 flow 关联的 `TimeWindowExpr` 来确定哪些时间窗口受到新数据点的影响。然后将这些窗口添加到相应 `TaskState` 中的 `DirtyTimeWindows` 集合中。 3. **任务唤醒**: `BatchingTask` 的执行循环被唤醒,原因可能是其周期性调度,也可能是因为它被通知有大量积压的脏窗口。 4. **计划生成**: 任务调用 `gen_insert_plan`。此方法: - 检查 `DirtyTimeWindows`。 - 生成一系列 `OR` 连接的 `WHERE` 子句(例如 `(ts >= 't1' AND ts < 't2') OR (ts >= 't3' AND ts < 't4') ...`),覆盖所有脏窗口。 - 重写原始 SQL 查询以包含此新过滤器,确保只处理必要的数据。 5. **执行**: 修改后的查询计划被发送到 `Frontend` 执行。数据库处理已过滤数据的聚合。 6. **Upsert**: 结果被插入到目标表中。目标表通常定义了一个包含时间窗口列的主键,因此现有窗口的新结果将覆盖(upsert)旧结果。 7. **状态更新**: `DirtyTimeWindows` 集合中刚刚处理过的窗口被清除。然后任务返回睡眠状态,直到下一个时间间隔。 --- ## 数据流 Dataflow 模块(参见 `flow::compute` 模块)是 `flow` 的核心计算模块。 它接收 SQL 查询并将其转换为 `flow` 的内部执行计划。 然后,该执行计划被转化为实际的数据流,而数据流本质上是一个由带有输入和输出端口的函数组成的有向无环图(DAG)。 数据流会在需要时被触发运行。 目前该数据流只支持 `map`和 `reduce` 操作,未来将添加对 `join` 等操作的支持。 在内部,数据流使用 `tuple(row, time, diff)` 以行格式处理数据。 这里 `row` 表示实际传递的数据,可能包含多个 `value` 对象。 `time` 是系统时间,用于跟踪数据流的进度,`diff` 通常表示行的插入或删除(+1 或 -1)。 因此,`tuple` 表示给定系统时间的 `row` 的插入/删除操作。 --- ## Flownode(Flownode) ## 简介 `Flownode` 为数据库提供了一种简单的流处理(称为 `flow`)能力。 `Flownode` 管理 `flow`,这些 `flow` 是从 `source` 接收数据并将数据发送到 `sink` 的任务。 `Flownode` 支持 `standalone`(单机)和 `distributed`(分布式)两种模式。在 `standalone` 模式下,`Flownode` 与数据库运行在同一进程中。在 `distributed` 模式下,`Flownode` 运行在单独的进程中,并通过网络与数据库通信。 一个 flow 有两种执行模式: - **流处理模式 (Streaming Mode)**: 原始的模式,数据在到达时即被处理。 - **批处理模式 (Batching Mode)**: 一种为持续数据聚合设计的较新模式。它在离散的、微小的时间窗口上周期性地执行用户定义的 SQL 查询。目前所有的聚合查询都使用此模式。更多详情,请参阅[批处理模式开发者指南](./batching_mode.md)。 ## 组件 `Flownode` 包含了执行一个 flow 所需的所有组件。所涉及的具体组件取决于执行模式(流处理 vs. 批处理)。在较高的层面上,关键部分包括: - **Flow Manager**: 一个负责管理所有 flow生命周期的中心组件。 - **Task Executor**: flow 逻辑执行的运行时环境。在流处理模式下,这通常是一个 `FlowWorker`;在批处理模式下,它是一个 `BatchingTask`。 - **Flow Task**: 代表一个独立的、单个的数据流,包含将数据从 source 转换为 sink 的逻辑。 --- ## 分布式查询 我们知道在 GreptimeDB 中数据是如何分布的(参见“[表分片][1]”),那么如何查询呢?在 GreptimeDB 中,分布式查询非常简单。简单来说,我们只需将查询拆分为子查询,每个子查询负责查询表数据的一个部分,然后将所有结果合并为最终结果。这是一种典型的“拆分 - 合并”方法。具体来说,让我们从查询到达 `frontend` 开始。 当查询到达 `frontend` 时,它首先被解析为 SQL 抽象语法树(AST)。我们遍历 AST,并从中生成逻辑计划。顾名思义,逻辑计划只是如何“逻辑地”执行查询的“提示”,它不能被直接运行,因此我们进一步从中生成可执行的物理计划。物理计划是一种类似树形的数据结构,每个节点实际上表示查询的执行方法。一旦我们从上到下运行物理计划树,结果数据将从叶子到根流动,被合并或计算。最终,我们在根节点的输出处得到了查询的结果。 到目前为止,这只是一个典型的“volcano”查询执行模型,你可以在几乎每个 SQL 数据库中看到这种模型。那么“分布式”是在哪里发生的呢?这全部发生在一个名为“TableScan”的物理计划节点中。TableScan 是物理计划树中的一个叶子节点,它负责扫描表的数据(就像它的名称所暗示的)。当 `frontend` 即将扫描表时,它首先需要根据每个 `region` 的数据范围将表扫描拆分为较小的扫描。 [1]: ./table-sharding.md 表的所有 `region` 都有它们存储数据的范围。以下表为例: ```sql CREATE TABLE my_table ( a INT, others STRING, ts TIMESTAMP TIME INDEX, ) PARTITION ON COLUMNS (a) ( a < 10, a >= 10 AND a < 20, a >= 20 ); ``` `my_table` 表创建时被设定了 3 个分区。在 GreptimeDB 的当前实现中,将为该表创建 3 个 `region`(分区与 `region` 的比例为 1:1)。这 3 个区域将分别包含以下范围:"[-∞, 10)", "[10, 20)" 和 "[20, +∞)"。例如,如果提供了值 "42",我们将搜索这些范围,并找到包含该值的相应的 `region`(在此示例中为第 3 个 `region`)。 对于查询,我们使用“过滤器”来查找 `region`。 "过滤器"是 "WHERE" 子句中的条件。例如,查询 `SELECT * FROM my_table WHERE a < 10 AND others = 'x'`,其“过滤器”为“a < 10 AND others = 'x'”。然后我们检查这些范围,找出包含满足过滤器条件的值的所有 `region`。 > 如果某个查询没有任何过滤器,则将其视为全表扫描。 找到所需的区域后,我们只需在其中组装子扫描。通过这种方式,我们将查询拆分为子查询,每个子查询都获取表数据的一部分。子查询在 `datanode` 中执行,并在 `frontend` 中等待完成。它们的结果将合并为表扫描请求的最终返回。 下面这张图片总结了分布式查询执行的过程: ![Distributed Querying](/distributed-querying.png) --- ## Frontend(Frontend) **Frontend** 是一个无状态服务,作为 GreptimeDB 中客户端请求的入口点。它为多种数据库协议提供统一接口,并充当代理,将读写请求转发到分布式系统中的相应 Datanode。 ## 核心功能 - **协议支持**:支持多种数据库协议,包括 SQL、PromQL、MySQL 和 PostgreSQL。详见[协议][1] - **请求路由**:基于元数据将请求路由到相应的 Datanode - **查询分发**:将分布式查询拆分到多个节点 - **响应聚合**:合并来自多个 Datanode 的结果 - **认证授权**:安全和访问控制验证 ## 架构 ### 关键组件 - **协议处理器**:处理不同的数据库协议 - **目录管理器**:缓存来自 Metasrv 的元数据以实现高效的请求路由和 Schema 校验 - **分布式规划器**:将逻辑计划转换为分布式执行计划 - **请求路由器**:为每个请求确定目标 Datanodes ### 请求流程 ![request flow](/request_flow.png) ### 部署 下图是 GreptimeDB 在云上的一个典型的部署。`Frontend` 实例组成了一个集群处理来自客户端的请求: ![frontend](/frontend.png) ## 详细信息 - [表分片][2] - [分布式查询][3] [1]: /user-guide/protocols/overview.md [2]: ./table-sharding.md [3]: ./distributed-querying.md --- ## 表分片(Frontend) 对于任何分布式数据库来说,数据的分片都是必不可少的。本文将描述 GreptimeDB 中的表数据如何进行分片。 ## 分区 有关创建分区表的语法,请参阅用户指南中的[表分片](/user-guide/deployments-administration/manage-data/table-sharding.md)部分。 ## Region 在创建分区后,表中的数据被逻辑上分割。你可能会问:"在 GreptimeDB 中,被逻辑上分区的数据是如何存储的?" 答案是保存在 `Region` 当中。 每个 `Region` 对应一个分区,并保存分区的数据。所有的 `Region` 分布在各个 `Datanode` 之中。 `Metasrv` 管理 `Region` 到 `Datanode` 的路由信息。如果建表后需要调整分区布局, GreptimeDB 支持通过显式的 [repartition](/user-guide/deployments-administration/manage-data/repartition.md) 操作拆分或合并分区。 分区和 Region 的关系参见下图: ```text ┌───────┐ │ │ │ Table │ │ │ └───┬───┘ │ Range [Start, end) │ Horizontally Split Data ┌──────────────────┼──────────────────┐ │ │ │ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ │ │ │ │ │ │ Partition │ │ Partition │ │ Partition │ │ │ │ │ │ │ │ P0 │ │ P1 │ │ Px │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │ │ │ │ │ │ ┌───────┼──────────────────┼───────┐ │ Partition 和 Region 是一一对应的 │ │ │ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ │ ┌─────▼─────┐ │ │ │ │ │ │ │ │ │ │ Region │ │ Region │ │ │ Region │ │ │ │ │ │ │ │ │ │ │ R0 │ │ R1 │ │ │ Ry │ │ └───────────┘ └───────────┘ │ └───────────┘ │ │ └──────────────────────────────────┘ 可以放在同一个 Datanode 之中 ``` --- ## 立即开始 本页面介绍如何在本地环境中从源代码运行 GreptimeDB。 ## 先决条件 ### 系统和架构 目前,GreptimeDB 支持 Linux(amd64 和 arm64)、macOS(amd64 和 Apple Silicon)和 Windows。 ### 构建依赖项 - [Git](https://git-scm.com/book/en/v2/Getting-Started-The-Command-Line)(可选) - C/C++ 工具链:提供编译和链接的基本工具。在 Ubuntu 上,这可用作 `build-essential`。在其他平台上,也有类似的命令。 - Rust nightly 工具链([指南][1]) - 编译源代码 - Protobuf([指南][2]) - 编译 proto 文件 - 请注意,版本需要 >= 3.15。你可以使用 `protoc --version` 检查它。 - 机器:建议内存在 16GB 以上 或者 使用[mold](https://github.com/rui314/mold)工具以降低链接时的内存使用。 [1]: [2]: ## 编译和运行 只需几个命令即可使用以 Standalone 模式启动 GreptimeDB 实例: ```shell git clone https://github.com/GreptimeTeam/greptimedb.git cd greptimedb cargo run -- standalone start ``` 接下来,你可以选择与 GreptimeDB 交互的协议。 如果你只想构建服务器而不运行它: ```shell cargo build # --release ``` 根据构建的模式(是否传递了 `--release` 选项),构建后的文件可以在 `$REPO/target/debug` 或 `$REPO/target/release` 目录下找到。 ## 单元测试 GreptimeDB 经过了充分的测试,整个单元测试套件都随源代码一起提供。要测试它们,请使用 [nextest](https://nexte.st/index.html)。 要使用 cargo 安装 nextest,请运行: ```shell cargo install cargo-nextest --locked ``` 或者,你可以查看他们的[文档](https://nexte.st/docs/installation/pre-built-binaries/)以了解其他安装方式。 安装好 nextest 后,你可以使用以下命令运行测试套件: ```shell cargo nextest run --workspace --features pg_kvbackend,mysql_kvbackend ``` ## Docker 我们还通过 Docker 提供预构建二进制文件,可以在 [Docker Hub 上获取](https://hub.docker.com/r/greptime/greptimedb)。 --- ## How to trace GreptimeDB GreptimeDB 使用 Rust 的 [tracing](https://docs.rs/tracing/latest/tracing/) 框架进行代码埋点,tracing 的具体原理和使用方法参见 tracing 的官方文档。 通过将 `trace_id` 等信息在整个分布式数据链路上透传,使得我们能够记录整个分布式链路的函数调用链,知道每个被追踪函数的调用时间等相关信息,从而对整个系统进行诊断。 ## 在 RPC 中定义 tracing 上下文 因为 tracing 框架并没有原生支持分布式追踪,我们需要手动将 `trace_id` 等信息在 RPC 消息中传递,从而正确的识别函数的调用关系。我们使用基于 [w3c 的标准](https://www.w3.org/TR/trace-context/#traceparent-header-field-values) 将相关信息编码为 `tracing_context` ,将消息附在 RPC 的 header 中。主要定义在: - `frontend` 与 `datanode` 交互:`tracing_context` 定义在 [`RegionRequestHeader`](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/region/server.proto) 中 - `frontend` 与 `metasrv` 交互:`tracing_context` 定义在 [`RequestHeader`](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/meta/common.proto) 中 - Client 与 `frontend` 交互:`tracing_context` 定义在 [`RequestHeader`](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/common.proto) 中 ## 在 RPC 调用中传递 tracing 上下文 我们构建了一个 `TracingContext` 结构体,封装了与 tracing 上下文有关的操作。[相关代码](https://github.com/GreptimeTeam/greptimedb/blob/main/src/common/telemetry/src/tracing_context.rs) GreptimeDB 在使用 `TracingContext::from_current_span()` 获取当前 tracing 上下文,使用 `to_w3c()` 方法将 tracing 上下文编码为符合 w3c 的格式,并将其附在 RPC 消息中,从而使 tracing 上下文正确的在分布式组件之中传递。 下面的例子说明了如何获取当前 tracing 上下文,并在构造 RPC 消息时正确传递参数,从而使 tracing 上下文正确的在分布式组件之中传递。 ```rust let request = RegionRequest { header: Some(RegionRequestHeader { tracing_context: TracingContext::from_current_span().to_w3c(), ..Default::default() }), body: Some(region_request::Body::Alter(request)), }; ``` 在 RPC 消息的接收方,需要将 tracing 上下文正确解码,并且使用该上下文构建第一个 `span` 对函数调用进行追踪。比如下面的代码就将接收到的 RPC 消息中的 `tracing_context` 使用 `TracingContext::from_w3c` 方法正确解码。并使用 `attach` 方法将新建的 `info_span!("RegionServer::handle_read")`  附上了上下文消息,从而能够跨分布式组件对调用进行追踪。 ```rust ... let tracing_context = request .header .as_ref() .map(|h| TracingContext::from_w3c(&h.tracing_context)) .unwrap_or_default(); let result = self .handle_read(request) .trace(tracing_context.attach(info_span!("RegionServer::handle_read"))) .await?; ... ``` ## 使用 `tracing::instrument` 对监测代码进行埋点 我们使用 tracing 提供的 `instrument` 宏对代码进行埋点,只要将 `instrument` 宏标记在需要进行埋点的函数即可。 `instrument` 宏会每次将函数调用的参数以 `Debug` 的形式打印到 span 中。对于没有实现 `Debug` trait 的参数,或者结构体过大、参数过多,最后导致 span 过大,希望避免这些情况就需要使用 `skip_all`,跳过所有的参数打印。 ```rust #[tracing::instrument(skip_all)] async fn instrument_function(....) { ... } ``` ## 跨越 runtime 的代码埋点 Rust 的 tracing 库会自动处理埋点函数间的嵌套关系,但如果某个函数的调用跨越 runtime 的话,tracing 不能自动对这类调用进行追踪,我们需要手动跨越 runtime 去传递上下文。 ```rust let tracing_context = TracingContext::from_current_span(); let handle = runtime.spawn(async move { handler .handle(query) .trace(tracing_context.attach(info_span!("xxxxx"))) ... }); ``` 比如上面这段代码需要跨越 runtime 去进行 tracing,我们先通过 `TracingContext::from_current_span()` 获取当前 tracing 上下文,通过在另外一个 runtime 里新建一个 span,并将 span 附着在当前上下文中,我们就完成了跨越 runtime 的代码埋点,正确追踪到了调用链。 --- ## 如何在 GreptimeDB 中启用 tokio-console 本文介绍了如何在 GreptimeDB 中启用 [tokio-console](https://github.com/tokio-rs/console)。 首先,在构建 GreptimeDB 时带上 feature `cmd/tokio-console`。同时 `tokio_unstable` cfg 也必须开启: ```bash RUSTFLAGS="--cfg tokio_unstable" cargo build -F cmd/tokio-console ``` 启动 GreptimeDB,可设置 tokio console 绑定的地址,配置是 `--tokio-console-addr`。例如: ```bash greptime --tokio-console-addr="127.0.0.1:6669" standalone start ``` 这样就可以使用 `tokio-console` 命令去连接 GreptimeDB 的 tokio console 服务了: ```bash tokio-console [TARGET_ADDR] ``` "`TARGET_ADDR`" 默认是 "\"。 :::tip Note `tokio-console` 命令的安装方法参见 [tokio-console](https://github.com/tokio-rs/console)。 ::: --- ## 如何为 GreptimeDB 开发一个 gRPC SDK GreptimeDB 的 gRPC SDK 只需要处理写请求即可。读请求是标准 SQL 或 PromQL,可以由任何 JDBC 客户端或 Prometheus 客户端处理。这也是为什么所有的 GreptimeDB SDK 都命名为 "`greptimedb-ingester-`"。请确保你的 GreptimeDB SDK 遵循相同的命名约定。 ## `GreptimeDatabase` 服务 GreptimeDB 自定义了一个 gRPC 服务:`GreptimeDatabase` 。你只需要实现这个服务即可。你可以在[这里](https://github.com/GreptimeTeam/greptime-proto/blob/main/proto/greptime/v1/database.proto) 找到它的 Protobuf 定义。 `GreptimeDatabase` 有 2 个 RPC 方法: ```protobuf service GreptimeDatabase { rpc Handle(GreptimeRequest) returns (GreptimeResponse); rpc HandleRequests(stream GreptimeRequest) returns (GreptimeResponse); } ``` `Handle` 方法是一个 unary 调用:当 GreptimeDB 服务接收到一个 `GreptimeRequest` 请求后,它立刻处理该请求并返回一个相应的 `GreptimeResponse`。 `HandleRequests` 方法则是一个 "[Client Streaming RPC][3]" 方式的调用。 它可以接受一个连续的 `GreptimeRequest` 请求流,持续地发给 GreptimeDB 服务。 GreptimeDB 服务会在收到流中的每个请求时立刻进行处理,并最终(流结束时)返回一个总结性的 `GreptimeResponse`。 通过 `HandleRequests`,我们可以获得一个非常高的请求吞吐量。 ### `GreptimeRequest` `GreptimeRequest` 是一个 Protobuf 消息,定义如下: ```protobuf message GreptimeRequest { RequestHeader header = 1; oneof request { InsertRequests inserts = 2; QueryRequest query = 3; DdlRequest ddl = 4; DeleteRequests deletes = 5; RowInsertRequests row_inserts = 6; RowDeleteRequests row_deletes = 7; } } ``` `RequestHeader` 是必需,它包含了一些上下文,鉴权和其他信息。"oneof" 的字段包含了发往 GreptimeDB 服务的请求。 注意我们有两种类型的插入请求,一种是以 "列" 的形式(`InsertRequests`),另一种是以 "行" 的形式(`RowInsertRequests` )。通常我们建议使用 "行" 的形式,因为它对于表的插入更自然,更容易使用。但是,如果需要一次插入大量列,或者有大量的 "null" 值需要插入,那么最好使用 "列" 的形式。 ### `GreptimeResponse` `GreptimeResponse` 是一个 Protobuf 消息,定义如下: ```protobuf message GreptimeResponse { ResponseHeader header = 1; oneof response {AffectedRows affected_rows = 2;} } ``` `ResponseHeader` 包含了返回值的状态码,以及错误信息(如果有的话)。"oneof" 的字段目前只有 "affected rows"。 GreptimeDB 现在有很多 SDK,你可以参考[这里](https://github.com/GreptimeTeam?q=ingester&type=all&language=&sort=)获取一些示例。 --- ## Admin API Admin 提供了一种简单的方法来查看和管理集群信息,包括 metasrv 健康检测、metasrv leader 查询、数据节点心跳检测、维护模式和 Procedure Manager 控制。 Admin API 是一个 HTTP 服务,提供一组可以通过 HTTP 请求调用的 RESTful API。Admin API 简单、用户友好且安全。 本页介绍以下 API: - /health - /leader - /heartbeat - /maintenance - /procedure-manager 所有这些 API 都在父资源 `/admin` 下。 在以下部分中,我们假设你的 metasrv 实例运行在本地主机的 4000 端口。 ## /health HTTP 端点 `/health` 端点接受 GET HTTP 请求,你可以使用此端点检查你的 metasrv 实例的健康状况。 ### 定义 ```bash curl -X GET http://localhost:4000/admin/health ``` ### 示例 #### 请求 ```bash curl -X GET http://localhost:4000/admin/health ``` #### 响应 ```json OK ``` ## /leader HTTP 端点 `/leader` 端点接受 GET HTTP 请求,你可以使用此端点查询你的 metasrv 实例的 leader 地址。 ### 定义 ```bash curl -X GET http://localhost:4000/admin/leader ``` ### 示例 #### 请求 ```bash curl -X GET http://localhost:4000/admin/leader ``` #### 响应 ```json 127.0.0.1:4000 ``` ## /heartbeat HTTP 端点 `/heartbeat` 端点接受 GET HTTP 请求,你可以使用此端点查询所有数据节点的心跳。 你还可以查询指定 `addr` 的数据节点的心跳数据,但在路径中指定 `addr` 是可选的。 ### 定义 ```bash curl -X GET http://localhost:4000/admin/heartbeat ``` | 查询字符串参数 | 类型 | 可选/必选 | 定义 | |:---------------|:-------|:----------|:--------------------| | addr | String | 可选 | 数据节点的地址。 | ### 示例 #### 请求 ```bash curl -X GET 'http://localhost:4000/admin/heartbeat?addr=127.0.0.1:4100' ``` #### 响应 ```json [ [ { "timestamp_millis": 1677049348651, "id": 1, "addr": "127.0.0.1:4100", "rcus": 0, "wcus": 0, "region_num": 2, "region_stats": [], "topic_stats": [], "node_epoch": 0, "datanode_workloads": { "types": [] }, "gc_stat": null } ] ] ``` ## /maintenance HTTP 端点 集群维护模式是 GreptimeDB 中的一项安全功能,它可以临时禁用自动集群管理操作。此模式在集群升级、计划停机以及任何可能暂时影响集群稳定性的操作期间特别有用。有关更多详细信息,请参阅[集群维护模式](/user-guide/deployments-administration/maintenance/maintenance-mode.md)。 `/maintenance` 端点支持以下 HTTP 请求: - `GET /admin/maintenance` 或 `GET /admin/maintenance/status`:查询维护模式状态。 - `POST /admin/maintenance/enable`:启用维护模式。 - `POST /admin/maintenance/disable`:禁用维护模式。 响应体使用以下格式: ```json { "enabled": true } ``` ## /procedure-manager HTTP 端点 该端点用于管理 Procedure Manager 状态。有关更多详细信息,请参阅[防止元数据变更](/user-guide/deployments-administration/maintenance/prevent-metadata-changes.md)。 `/procedure-manager` 端点支持以下 HTTP 请求: - `GET /admin/procedure-manager/status`:查询 Procedure Manager 状态。 - `POST /admin/procedure-manager/pause`:暂停 Procedure Manager。 - `POST /admin/procedure-manager/resume`:恢复 Procedure Manager。 响应体使用以下格式: ```json { "status": "running" } ``` --- ## Metasrv(Metasrv) ![meta](/meta.png) ## Metasrv 包含什么 - 存储元数据(Catalog, Schema, Table, Region 等) - 请求路由器。它告诉前端在哪里写入和读取数据。 - 数据节点的负载均衡,决定谁应该处理新的表创建请求,更准确地说,它做出资源分配决策。 - 选举与高可用性,GreptimeDB 设计为 Leader-Follower 架构,只有 leader 节点可以写入,而 follower 节点可以读取,follower 节点的数量通常 >= 1,当 leader 不可用时,follower 节点需要能够快速切换为 leader。 - 统计数据收集(通过每个节点上的心跳报告),如 CPU、负载、节点上的表数量、平均/峰值数据读写大小等,可用作分布式调度的基础。 ## 前端如何与 Metasrv 交互 首先,请求路由器中的路由表结构如下(注意这只是逻辑结构,实际存储结构可能不同,例如端点可能有字典压缩)。 ```txt table_A table_name table_schema // 用于物理计划 regions region_1 mutate_endpoint select_endpoint_1, select_endpoint_2 region_2 mutate_endpoint select_endpoint_1, select_endpoint_2, select_endpoint_3 region_xxx table_B ... ``` ### 创建表 1. 前端发送 `CREATE TABLE` 请求到 Metasrv。 2. 根据请求中包含的分区规则规划 Region 数量。 3. 检查数据节点可用资源的全局视图(通过心跳收集)并为每个 Region 分配一个节点。 4. 前端创建表并在成功创建后将 `Schema` 存储到 Metasrv。 ### `Insert` 1. 前端从 Metasrv 获取指定表的路由。注意,最小的路由单元是表的路由(多个 Region),即包含该表所有 Region 的地址。 2. 最佳实践是前端首先从本地缓存中获取路由并将请求转发到数据节点。如果路由不再有效,则数据节点有义务返回 `Invalid Route` 错误,前端重新从 Metasrv 获取最新数据并更新其缓存。路由信息不经常变化,因此,前端使用惰性策略维护缓存是足够的。 3. 前端处理可能包含多个表和多个 Region 的一批写入,因此前端需要根据“路由表”拆分用户请求。 ### `Select` 1. 与 `Insert` 类似,前端首先从本地缓存中获取路由表。 2. 与 `Insert` 不同,对于 `Select`,前端需要从路由表中提取只读节点(follower),然后根据优先级将请求分发到 leader 或 follower 节点。 3. 前端的分布式查询引擎根据路由信息分发多个子查询任务并聚合查询结果。 ## Metasrv 架构 ![metasrv-architecture](/metasrv-architecture.png) ## 分布式共识 如你所见,Metasrv 依赖于分布式共识,因为: 1. 首先,Metasrv 必须选举一个 leader,数据节点只向 leader 发送心跳,我们只使用单个 Metasrv 节点接收心跳,这使得基于全局信息进行一些计算或调度变得容易且快速。至于数据节点如何连接到 leader,这由 MetaClient 决定(使用重定向,心跳请求变为 gRPC 流,使用重定向比转发更不容易出错),这对数据节点是透明的。 2. 其次,Metasrv 必须为数据节点提供选举 API,以选举“写入”和“只读”节点,并帮助数据节点实现高可用性。 3. 最后,`Metadata`、`Schema` 和其他数据必须在 Metasrv 上可靠且一致地存储。因此,基于共识的算法是存储它们的理想方法。 对于 Metasrv 的第一个版本,我们选择 Etcd 作为共识算法组件(Metasrv 设计时考虑适应不同的实现,甚至创建一个新的轮子),原因如下: 1. Etcd 提供了我们需要的 API,例如 `Watch`、`Election`、`KV` 等。 2. 我们只执行两个分布式共识任务:选举(使用 `Watch` 机制)和存储(少量元数据),这两者都不需要我们定制自己的状态机,也不需要基于 raft 定制自己的状态机;少量数据也不需要多 raft 组支持。 3. Metasrv 的初始版本使用 Etcd,使我们能够专注于 Metasrv 的功能,而不需要在分布式共识算法上花费太多精力,这提高了系统设计(避免与共识算法耦合)并有助于初期的快速开发,同时通过良好的架构设计,未来可以轻松接入优秀的共识算法实现。 ## 心跳管理 数据节点与 Metasrv 之间的主要通信方式是心跳请求/响应流,我们希望这是唯一的通信方式。这个想法受到 [TiKV PD](https://github.com/tikv/pd) 设计的启发,我们在 [RheaKV](https://github.com/sofastack/sofa-jraft/tree/master/jraft-rheakv/rheakv-pd) 中有实际经验。请求发送其状态,而 Metasrv 通过心跳响应发送不同的调度指令。 心跳可能携带以下数据,但这不是最终设计,我们仍在讨论和探索究竟应该收集哪些数据。 ``` service Heartbeat { // 心跳,心跳可能有很多内容,例如: // 1. 要注册到 Metasrv 并可被其他节点发现的元数据。 // 2. 一些性能指标,例如负载、CPU 使用率等。 // 3. 正在执行的计算任务数量。 rpc Heartbeat(stream HeartbeatRequest) returns (stream HeartbeatResponse) {} } message HeartbeatRequest { RequestHeader header = 1; // 自身节点 Peer peer = 2; // leader 节点 bool is_leader = 3; // 实际报告时间间隔 TimeInterval report_interval = 4; // 节点状态 NodeStat node_stat = 5; // 此节点中的 Region 状态 repeated RegionStat region_stats = 6; // follower 节点和状态,在 follower 节点上为空 repeated ReplicaStat replica_stats = 7; } message NodeStat { // 此期间的读取容量单位 uint64 rcus = 1; // 此期间的写入容量单位 uint64 wcus = 2; // 此节点中的表数量 uint64 table_num = 3; // 此节点中的 Region 数量 uint64 region_num = 4; double cpu_usage = 5; double load = 6; // 节点中的读取磁盘 I/O double read_io_rate = 7; // 节点中的写入磁盘 I/O double write_io_rate = 8; // 其他 map attrs = 100; } message RegionStat { uint64 region_id = 1; TableName table_name = 2; // 此期间的读取容量单位 uint64 rcus = 3; // 此期间的写入容量单位 uint64 wcus = 4; // 近似 Region 大小 uint64 approximate_size = 5; // 近似行数 uint64 approximate_rows = 6; // 其他 map attrs = 100; } message ReplicaStat { Peer peer = 1; bool in_sync = 2; bool is_learner = 3; } ``` ## Central Nervous System (CNS) 我们要构建一个算法系统,该系统依赖于每个节点的实时和历史心跳数据,应该做出一些更智能的调度决策并将其发送到 Metasrv 的 Autoadmin 单元,该单元分发调度决策,由数据节点本身或更可能由 PaaS 平台执行。 ## 工作负载抽象 工作负载抽象的级别决定了 Metasrv 生成的调度策略(如资源分配)的效率和质量。 DynamoDB 定义了 RCUs 和 WCUs(读取容量单位/写入容量单位),解释说 RCU 是一个 4KB 数据的读取请求,WCU 是一个 1KB 数据的写入请求。当使用 RCU 和 WCU 描述工作负载时,更容易实现性能可测量性并获得更有信息量的资源预分配,因为我们可以将不同的硬件能力抽象为 RCU 和 WCU 的组合。 然而,GreptimeDB 面临比 DynamoDB 更复杂的情况,特别是 RCU 不适合描述需要大量计算的 GreptimeDB 读取工作负载。我们正在努力解决这个问题。 --- ## Selector ## 介绍 什么是 `Selector`?顾名思义,它允许用户从给定的 `namespace` 和 `context` 中选择 `Item`s。有一个相关的 `trait`,也叫做 `Selector`,其定义可以在[这里][0]找到。 [0]: https://github.com/GreptimeTeam/greptimedb/blob/main/src/meta-srv/src/selector.rs 在 `Metasrv` 中存在一个特定的场景。当 `Frontend` 向 `Metasrv` 发送建表请求时,`Metasrv` 会创建一个路由表(表的创建细节不在这里赘述)。在创建路由表时,`Metasrv` 需要选择适当的 `Datanode`s,这时候就需要用到 `Selector`。 ## Selector 类型 `Metasrv` 目前提供以下几种类型的 `Selectors`: ### LeasebasedSelector `LeasebasedSelector` 从所有可用的(也就是在租约期间内)`Datanode` 中随机选择,其特点是简单和快速。 ### LoadBasedSelector `LoadBasedSelector` 按照负载来选择,负载值则由每个 `Datanode` 上的 region 数量决定,较少的 region 表示较低的负载,`LoadBasedSelector` 优先选择低负载的 `Datanode`。 ### RoundRobinSelector [默认选项] `RoundRobinSelector` 以轮询的方式选择 `Datanode`。在大多数情况下,这是默认的且推荐的选项。如果你不确定选择哪个,通常它就是正确的选择。 ## 配置 您可以在启动 `Metasrv` 服务时通过名称配置 `Selector`。 - LeasebasedSelector: `lease_based` 或 `LeaseBased` - LoadBasedSelector: `load_based` 或 `LoadBased` - RoundRobinSelector: `round_robin` 或 `RoundRobin` 例如: ```shell cargo run -- metasrv start --selector round_robin ``` ```shell cargo run -- metasrv start --selector RoundRobin ``` --- ## 贡献者指南 DeepWiki 对 GreptimeDB 的架构和实现进行了详细且清晰的描述,强烈推荐阅读: [https://deepwiki.com/GreptimeTeam/greptimedb](https://deepwiki.com/GreptimeTeam/greptimedb) ## 架构 有关 GreptimeDB 的架构和组件,请参阅用户指南中的 [架构](/user-guide/concepts/architecture.md) 文档。 有关每个组件的更多详细信息,请参阅以下指南: - [frontend][1] - [datanode][2] - [metasrv][3] [1]: /contributor-guide/frontend/overview.md [2]: /contributor-guide/datanode/overview.md [3]: /contributor-guide/metasrv/overview.md --- ## 集成测试 ## 介绍 集成测试使用 Rust 测试工具(`#[test]`)编写,与单元测试不同,它们被单独放置在 [这里](https://github.com/GreptimeTeam/greptimedb/tree/main/tests-integration)。 它涵盖了涉及多个组件的场景,其中一个典型案例是与 HTTP/gRPC 相关的功能。你可以查看 其[文档](https://github.com/GreptimeTeam/greptimedb/blob/main/tests-integration/README.md)以获取更多信息。 --- ## 测试 我们的团队进行了大量测试,以确保 GreptimeDB 的行为。本章将介绍几种用于测试 GreptimeDB 的重要方法,以及如何使用它们。 --- ## Sqlness 测试 ## 介绍 SQL 是 `GreptimeDB` 的一个重要用户接口。我们为它提供了一个单独的测试套件(名为 `sqlness`)。 ## Sqlness 手册 ### 测试文件 Sqlness 有两种类型的文件 - `.sql`:测试输入,仅包含 SQL - `.result`:预期的测试输出,包含 SQL 和其结果 `.result` 文件是预期的执行输出。如果 `.result` 文件发生变化,意味着测试结果不同,测试可能失败。你应该检查变更日志来解决问题。 你只需要在 `.sql` 文件中编写测试 SQL,然后运行测试。 ### 组织测试案例 输入案例的根目录是 `tests/cases`。它包含几个子目录,代表不同的测试模式。例如,`standalone/` 包含所有在 `greptimedb standalone start` 模式下运行的测试。 在第一级子目录下(例如 `cases/standalone`),你可以随意组织你的测试案例。Sqlness 会递归地遍历每个文件并运行它们。 ## 运行测试 与其他测试不同,这个测试工具是以二进制目标形式存在的。你可以用以下命令运行它 ```shell cargo run --bin sqlness-runner bare ``` 它会自动完成以下步骤:编译 `GreptimeDB`,启动它,抓取测试并将其发送到服务器,然后收集和比较结果。你只需要检查是否有 `.result` 文件发生变化。如果没有,恭喜你,测试通过了 🥳! ### 运行特定测试 ```shell cargo sqlness bare -t your_test ``` `-t` 或 `--test-filter` 选项接受正则表达式字符串。Sqlness 会检查格式为 `env:case` 的案例名称。 --- ## 单元测试 ## 介绍 单元测试嵌入在代码库中,通常放置在被测试逻辑的旁边。它们使用 Rust 的 `#[test]` 属性编写,并可以使用 `cargo nextest run` 运行。 GreptimeDB 代码库不支持默认的 `cargo` 测试运行器。推荐使用 [`nextest`](https://nexte.st/)。你可以通过以下命令安装它: ```shell cargo install cargo-nextest --locked ``` 然后运行测试(这里 `--workspace` 不是必须的) ```shell cargo nextest run ``` 注意,如果你的 Rust 是通过 `rustup` 安装的,请确保使用 `cargo` 安装 `nextest`,而不是像 `homebrew` 这样的包管理器,否则会弄乱你的本地环境。 ## 覆盖率 我们的持续集成(CI)作业有一个“覆盖率检查”步骤。它会报告有多少代码被单元测试覆盖。请在你的补丁中添加必要的单元测试。 --- ## Create Service 为了充分体验 GreptimeCloud 的强大功能,你需要创建一个包含身份验证数据库的服务。打开 [GreptimeCloud 控制台](https://greptime.cloud),注册并登录。然后单击 `New Service` 按钮并配置以下内容: * Service Name: 服务名称。 * Description: 有关该服务的更多信息。 * Region: 选择数据库所在的区域。 * Plan: 选择要使用的定价计划。 现在创建服务,准备向其写入一些数据。 --- ## Go(Getting-started) ## 创建服务 ## 写入数据 使用下面的命令收集系统指标数据,例如 CPU 和内存使用情况,并将其发送到 GreptimeCloud。一旦成功发送,这些指标就可以在 GreptimeCloud 控制台中查看。 该 Demo 基于 OTLP/http 采集并发送数据,源代码位于 [GitHub](https://github.com/GreptimeCloudStarters/quick-start-go). ```shell go run github.com/GreptimeCloudStarters/quick-start-go@latest -endpoint=https:///v1/otlp/v1/metrics -db= -username= -password= ``` ## 数据可视化 --- ## InfluxDB Line Protocol(Getting-started) ## 创建服务 ## 写入数据 为了通过 InfluxDB line protocol 快速开始,我们可以使用 Bash 脚本收集系统指标,例如 CPU 和内存使用情况,并将其发送到 GreptimeCloud。 源代码位于 [GitHub](https://github.com/GreptimeCloudStarters/quick-start-influxdb-line-protocol). ```shell curl -L https://raw.githubusercontent.com/GreptimeCloudStarters/quick-start-influxdb-line-protocol/main/quick-start.sh | bash -s -- -e https:///v1/influxdb/write -d -u -p ``` ## 数据可视化 --- ## Java ## 创建服务 ## 写入数据 使用下面的命令收集 jvm 运行时的指标数据,例如 CPU 和内存使用情况,并将其发送到 GreptimeCloud。一旦成功发送,这些指标就可以在 GreptimeCloud 控制台中查看。该 Demo 基于 OTLP/http 采集并发送数据,源代码位于 [GitHub](https://github.com/GreptimeCloudStarters/quick-start-java). ```shell curl -L https://github.com/GreptimeCloudStarters/quick-start-java/releases/latest/download/greptime-quick-start-java-all.jar \ --output quick-start.jar && java -jar quick-start.jar -e https:///v1/otlp/v1/metrics -db -u -p ``` ## 数据可视化 --- ## MySQL(Getting-started) ## 创建服务 ## 写入数据 为了通过 MySQL 快速开始,我们可以使用 Bash 脚本收集系统指标,例如 CPU 和内存使用情况,并通过 MySQL CLI 将数据发送到 GreptimeCloud。 源代码位于 [GitHub](https://github.com/GreptimeCloudStarters/quick-start-mysql). ```shell curl -L https://raw.githubusercontent.com/GreptimeCloudStarters/quick-start-mysql/main/quick-start.sh | bash -s -- -h -d -u -p ``` ## 数据可视化 --- ## Node.js ## 创建服务 ## 写入数据 使用下面的命令收集系统指标数据,例如 CPU 和内存使用情况,并将其发送到 GreptimeCloud。一旦成功发送,这些指标就可以在 GreptimeCloud 控制台中查看。 该 Demo 基于 OTLP/http 采集并发送数据,源代码位于 [GitHub](https://github.com/GreptimeCloudStarters/quick-start-node-js). ```shell npx greptime-cloud-quick-start@latest --endpoint=https:///v1/otlp/v1/metrics --db= --username= --password= ``` ## 数据可视化 --- ## 立即开始(Getting-started) 立即使用你熟悉的协议或语言开始! --- ## Prometheus(Getting-started) ## 创建服务 ## 写入数据 ### 如果你已经有正在运行的 Prometheus 实例 将下面的内容添加到你的 Prometheus 配置文件中。 ```yaml remote_write: - url: https:///v1/prometheus/write?db= basic_auth: username: password: ``` ### 或者你期望启动一个全新的实例 启动一个 Docker 容器,将示例数据写入 GreptimeCloud 数据库: ```shell docker run --rm -e GREPTIME_URL='https:///v1/prometheus/write?db=' -e GREPTIME_USERNAME='' -e GREPTIME_PASSWORD='' --name greptime-node-exporter greptime/node-exporter ``` :::tip NOTE 为了防止不小心退出 Docker 容器,你可能想以“detached”模式运行它:在 `docker run` 命令中添加 `-d` 参数即可。 ::: ## 数据可视化 --- ## Python ## 创建服务 ## 写入数据 在 Python 3.10+ 中使用下面的命令收集系统指标数据,例如 CPU 和内存使用情况,并将其发送到 GreptimeCloud。一旦成功发送,这些指标就可以在 GreptimeCloud 控制台中查看。 该 Demo 基于 OTLP/http 采集并发送数据,源代码位于 [GitHub](https://github.com/GreptimeCloudStarters/quick-start-python). :::tip [pipx](https://pypa.github.io/pipx/) 是一个帮助你安装和运行用 Python 编写的应用程序的工具。 ::: ```shell pipx run --no-cache greptime-cloud-quick-start -e https:///v1/otlp/v1/metrics -db -u -p ``` ## 数据可视化 --- ## Vector(Getting-started) ## 创建服务 ## 写入数据 将下方配置写在 `vector.toml` 文件中,配置内容为将 [host_metrics](https://vector.dev/docs/reference/configuration/sources/host_metrics/) 作为 Vector source,将 GreptimeCloud 作为 Vector sink destination。 ```toml [sources.in] type = "host_metrics" scrape_interval_secs = 30 [sinks.cloud] inputs = ["in"] type = "greptimedb" endpoint = ":5001" dbname = "" username = "" password = "" tls = {} new_naming = true ``` 然后使用配置文件启动 Vector: ```shell vector --config vector.toml ``` ## 数据可视化 --- ## Visualize Data 成功将数据写入服务后,你可以在 GreptimeCloud 控制台中查看数据。控制台提供了各种可视化工具,帮助你理解、监控和分析数据。 这里我们创建一个面板显示 CPU 的 95% 用量作为示例。点击 `Add Panel` 按钮,选择包含 CPU 使用数据的 `table`,然后选择 `95%` 聚合方法。 最后,点击 `Save` 按钮保存面板。现在,你可以看到新的面板并为其设置报警规则。 --- ## Alloy [Grafana Alloy](https://grafana.com/docs/alloy/latest/) 是可观测数据采集器,同时兼容 OpenTelemetry。GreptimeDB 可被配置 为 Alloy 的数据目的地。 ## Prometheus Remote Write 将 GreptimeDB 配置为 Prometheus Remote Write 目的地。 ``` // config.alloy prometheus.remote_write "greptimedb" { endpoint { url = "https:///v1/prometheus/write?db=" basic_auth { username = "" password = "" } } } ``` ## OpenTelemetry GreptimeDB 也可以被配置为 OpenTelemetry 收集器。 ``` // config.alloy otelcol.exporter.otlphttp "greptimedb" { client { endpoint = "https:///v1/otlp/" headers = { "X-Greptime-DB-Name" = "", } auth = otelcol.auth.basic.credentials.handler } } otelcol.auth.basic "credentials" { username = "" password = "" } ``` --- ## DBeaver(Integrations) [DBeaver](https://dbeaver.io/) 是一个免费、开源且跨平台的数据库工具,支持所有流行的数据库。 由于其易用性和丰富的功能集,它在开发人员和数据库管理员中非常受欢迎。 你可以使用 DBeaver 通过 MySQL Driver 连接到 GreptimeDB。 点击 DBeaver 工具栏中的“New Database Connection”按钮,以创建 GreptimeDB 的新连接。 选择 MySQL 并点击“下一步”以配置连接。 如果你还没有安装 MySQL Driver,请先安装。 接下来输入以下连接信息: - Connect by Host - Host: `` - Port: `4002` - Database: `` - 输入用户名 `` 和密码 `` 点击“Test Connection”以验证连接设置,然后点击“Finish”以保存连接。 有关 MySQL 与 GreptimeDB 交互的更多信息,请参阅 [MySQL 协议文档](https://docs.greptime.cn/user-guide/protocols/mysql)。 --- ## Fluent Bit(3) Fluent Bit 是一个轻量且快速的日志处理和转发器,可以收集、解析、过滤和转发日志和指标。Fluent Bit 是 Fluentd 项目生态系统的一部分,用 C 语言编写。它设计为内存高效且性能优越,适合在资源受限的环境中使用。 ## HTTP Fluent Bit 可以配置为使用 HTTP 协议将日志发送到 GreptimeCloud。这允许您从各种来源收集日志并将其发送到 GreptimeCloud 进行存储、分析和可视化。 ``` [OUTPUT] Name http Match * Host Port 443 Uri /v1/ingest?db=&table=&pipeline_name= Format json Json_date_key scrape_timestamp Json_date_format iso8601 Tls On compress gzip http_User http_Passwd ``` 在此示例中,使用 `http` 输出插件将日志发送到 GreptimeCloud。有关更多信息和额外选项,请参阅 [Logs HTTP API](https://docs.greptime.cn/reference/pipeline/write-log-api.md#http-api) 指南。 ## Prometheus Remote Write Fluent Bit 可以配置为使用 Prometheus Remote Write 协议将指标发送到 GreptimeCloud。这允许您从各种来源收集指标并将其发送到 GreptimeCloud 进行存储、分析和可视化。 ``` [OUTPUT] Name prometheus_remote_write Match internal_metrics Host Port 443 Uri /v1/prometheus/write?db= Tls On http_user http_passwd ``` 在此示例中,使用 `prometheus_remote_write` 输出插件将指标发送到 GreptimeCloud。有关更多信息和额外选项,请参阅 [Prometheus Remote Write](https://docs.greptime.cn/user-guide/ingest-data/for-observability/prometheus) 指南。 ## OpenTelemetry Fluent Bit 可以配置为使用 OpenTelemetry 协议将日志和指标发送到 GreptimeCloud。这允许您从各种来源收集日志和指标并将其发送到 GreptimeCloud 进行存储、分析和可视化。 ``` # 仅用于指标 [OUTPUT] Name opentelemetry Alias opentelemetry_metrics Match *_metrics Host Port 443 Metrics_uri /v1/otlp/v1/metrics Logs_uri /v1/otlp/v1/logs Traces_uri /v1/otlp/v1/traces http_User http_Passwd Log_response_payload True Tls On compress gzip # 仅用于日志 [OUTPUT] Name opentelemetry Alias opentelemetry_logs Match *_logs Host Port 443 Metrics_uri /v1/otlp/v1/metrics Logs_uri /v1/otlp/v1/logs Traces_uri /v1/otlp/v1/traces http_User http_Passwd Log_response_payload True Tls On compress gzip Header X-Greptime-Log-Table-Name "" Header X-Greptime-Log-Pipeline-Name "" Header X-Greptime-DB-Name "" ``` 在此示例中,使用 [OpenTelemetry OTLP/HTTP API](https://docs.greptime.cn/user-guide/ingest-data/for-observability/opentelemetry/) 接口。有关更多信息和额外选项,请参阅 [OpenTelemetry](https://docs.greptime.cn/user-guide/ingest-data/for-observability/opentelemetry/) 指南。 --- ## Grafana(Integrations) GreptimeDB 服务可以配置为 [Grafana 数据源](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/)。 你可以选择使用以下三个数据源之一连接 GreptimeDB 与 Grafana:GreptimeDB、Prometheus 或 MySQL。 ## GreptimeDB 数据源插件 在使用 GreptimeDB 数据源之前,需要手动安装 GreptimeDB 数据源插件。 有关更多信息,请参考 [使用 GreptimeDB 数据源文档](https://docs.greptime.cn/user-guide/integrations/grafana#greptimedb-数据源插件)。 在 Grafana 中单击 Add data source 按钮,选择 GreptimeDB 作为类型。 在 GreptimeDB server URL 中填写以下地址: ```txt https:// ``` 接下来做如下配置: - Database Name:填写数据库名称 ``,留空则使用默认数据库 `public` - 在 Auth 部分中单击 basic auth,并在 Basic Auth Details 中填写 GreptimeDB 的用户名和密码。未设置可留空: - User: `` - Password: `` 然后单击 Save & Test 按钮以测试连接。 ## Prometheus 数据源 单击 Add data source 按钮,然后选择 Prometheus 作为类型。 在 HTTP 中填写 Prometheus server URL: ```txt https:///v1/prometheus ``` 在 Auth 部分中单击 basic auth,并在 Basic Auth Details 中填写 GreptimeDB 的用户名和密码: - User: `` - Password: `` 在 Custom HTTP Headers 部分中点击 Add header: - Header: `x-greptime-db-name` - Value: `` 然后单击 Save & Test 按钮以测试连接。 ## MySQL 数据源 单击 Add data source 按钮,然后选择 MySQL 作为类型。在 MySQL Connection 中填写以下信息: - Host: `:4002` - Database: `` - User: `` - Password: `` - Session timezone: `UTC` 然后单击 Save & Test 按钮以测试连接。 注意目前我们只能使用 SQL 创建 Grafana Panel。由于时间戳数据类型的区别,Grafana 的 SQL Builder 暂时无法选择时间戳字段。 --- ## InfluxDB Line Protocol(Integrations) GreptimeCloud 提供了 [Influxdb line protocol](https://docs.influxdata.com/influxdb/cloud/reference/syntax/line-protocol/) 的 http 接口。该接口和认证与 [InfluxDB write protocol 1.x](https://docs.influxdata.com/influxdb/v1.8/guides/write_data/#write-data-using-the-influxdb-api) 兼容。更多信息请参考 GreptimeDB 的 [InfluxDB 客户端](https://docs.greptime.cn/user-guide/protocols/influxdb-line-protocol)。 - URL: `https:///v1/influxdb/write?db=` - Username: `` - Password: `` ## Telegraf 使用 Telegraf 采集数据 ``` [[outputs.influxdb_v2]] urls = ["https:///v1/influxdb"] token = ":" bucket = "" ## Leave empty organization = "" ``` 下方的 Java 代码片段展示了如何通过配置 [InfluxDB 客户端](https://github.com/influxdata/influxdb-java)连接到 GreptimeCloud: ```java final String serverURL = "https:///v1/influxdb/", username = "", password = ""; final InfluxDB influxDB = InfluxDBFactory.connect(serverURL, username, password); influxDB.setDatabase(""); ``` --- ## Kafka(3) 如果您正在使用 Kafka 或兼容 Kafka 的消息队列来传输可观测性数据,可以直接将数据写入到 GreptimeDB 中。 在这里,我们使用 Vector 作为工具,将数据从 Kafka 传输到 GreptimeDB。 ## Logs 以下是一个示例配置。请注意,您需要创建您的 [Pipeline](https://docs.greptime.cn/user-guide/logs/use-custom-pipelines/) 用于日志 解析。 ```toml # sample.toml [sources.log_mq] type = "kafka" group_id = "vector0" topics = ["test_log_topic"] bootstrap_servers = "kafka:9092" [sinks.sink_greptime_logs] type = "greptimedb_logs" inputs = [ "log_mq" ] compression = "gzip" endpoint = "https://" dbname = "" username = "" password = "" compression = "gzip" ## customize to your own table and pipeline name table = "demo_logs" pipeline_name = "demo_pipeline" ``` ## Metrics 如果您正在使用 Kafka 传输 InfluxDB 行协议格式的指标数据,您也可以直接导入它。 ```toml # sample.toml [sources.metrics_mq] type = "kafka" group_id = "vector0" topics = ["test_metric_topic"] bootstrap_servers = "kafka:9092" decoding.codec = "influxdb" [sinks.metrics_in] inputs = ["metrics_mq"] type = "greptimedb" endpoint = ":5001" dbname = "" username = "" password = "" tls = {} ``` ## 参考文档 请参考[通过 Kafka 写入数据](https://docs.greptime.cn/user-guide/ingest-data/for-observability/kafka)获取数据写入过程的详细信息。 --- ## Metabase(Integrations) [Metabase](https://github.com/metabase/metabase) 是一个用 Clojure 编写的开源 BI 工具,可以通过社区维护的数据库驱动将 GreptimeDB 添加到 Metabase。 关于插件的安装,请[查看文 档](https://docs.greptime.cn/user-guide/integrations/metabase). ## 连接信息 - 数据库类型: `GreptimeDB` - 主机名: `` - 端口: `4003` - 数据库名: `` - 用户名: `` - 密码: `` --- ## MindsDB(Integrations) [MindsDB](https://mindsdb.com/) 是一个开源的机器学习平台,使开发人员能够轻松地将 先进的机器学习能力与现有数据库集成。 使用 MindsDB 扩展,您的 GreptimeDB 实例可以开箱即用。要配置 GreptimeDB 数据库,请 运行以下 SQL: ```sql CREATE DATABASE greptime_datasource WITH ENGINE = 'greptimedb', PARAMETERS = { "host": "", "port": 4002, "database": "", "user": "", "password": "", "ssl": True }; ``` MindsDB 是许多机器学习功能的优秀门户,包括您存储在我们实例中的时间序列数据的时间序列预测。 访问 [MindsDB docs](https://docs.mindsdb.com/what-is-mindsdb) 了解更多。 --- ## MySQL(Integrations) GreptimeCloud 可以通过 MySQL 协议访问,兼容大多数标准客户端和驱动程序,其连接使用 TLS 加密。有关更多信息,请参阅 GreptimeDB 的 [MySQL 客户端](https://docs.greptime.cn/user-guide/protocols/mysql)。 要连接到 GreptimeCloud,使用以下信息: - Host: `` - Port: `4002` - Database: `` - Username: `` - Password: `` ## MySQL CLI 使用 `mysql` CLI 连接到 GreptimeCloud 服务实例。 ```shell mysql --ssl-mode=REQUIRED -u -p -h -P 4002 -A ``` ## MariaDB CLI MariaDB CLI 与原始的 MySQL 的 `ssl` 参数有些许不同: ```shell mysql --ssl -u -p -h -P 4002 -A ``` ## URL 使用以下连接字符串连接你的 JDBC 客户端。 ``` jdbc:mysql://:4002/?user=&password= ``` 如果你使用 Python 等语言的客户端,也可以复制以下 URL 进行连接 ``` mysql://:@:4002/ ``` --- ## OpenTelemetry Protocol (OTLP)(Integrations) 你可以通过 [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp) 协议原生消费 OpenTelemetry metrics, logs 和 traces。 请使用以下接口并包含必需的 header 参数: - URL:`https:///v1/otlp/` - 协议:`HTTP/protobuf` - Headers: - `X-Greptime-DB-Name`:`` - `Authentication`:``,请参考 [HTTP API 中的认证](https://docs.greptime.cn/user-guide/protocols/http#鉴权)获取更多信息 ## OpenTelemetry Collector OpenTelemetry Collector 是 OpenTelemetry 的一个与厂商无关的实现,下面是一个导出到 GreptimeDB 的示例配置。你可以使用 [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) 将指标、日志和追踪数据发送到 GreptimeDB。 ```yaml extensions: basicauth/client: client_auth: username: password: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlphttp/traces: endpoint: 'https:///v1/otlp' auth: authenticator: basicauth/client headers: x-greptime-db-name: '' x-greptime-pipeline-name: 'greptime_trace_v1' otlphttp/logs: endpoint: 'https:///v1/otlp' auth: authenticator: basicauth/client headers: x-greptime-db-name: '' # x-greptime-log-table-name: "" otlphttp/metrics: endpoint: 'https:///v1/otlp' auth: authenticator: basicauth/client headers: x-greptime-db-name: '' service: extensions: [basicauth/client] pipelines: traces: receivers: [otlp] exporters: [otlphttp/traces] logs: receivers: [otlp] exporters: [otlphttp/logs] metrics: receivers: [otlp] exporters: [otlphttp/metrics] ``` ## Grafana Alloy 如果你更倾向于使用 [Grafana Alloy](https://grafana.com/docs/alloy/latest/) 的 OpenTelemetry 导出器,可以使用如下配置来发送你的数据。 一个简单的配置示例如下: ``` otelcol.exporter.otlphttp "greptimedb" { client { endpoint = "https:///v1/otlp/" headers = { "X-Greptime-DB-Name" = "", } auth = otelcol.auth.basic.credentials.handler } } otelcol.auth.basic "credentials" { username = "" password = "" } ``` ## 了解更多 请参考 GreptimeDB 用户指南中的 [OpenTelemetry Protocol 文档](https://docs.greptime.com/user-guide/ingest-data/for-observability/opentelemetry/) 以获取更多关于使用 GreptimeDB 和 OpenTelemetry 的信息。 --- ## PostgreSQL(Integrations) GreptimeCloud 支持用 PostgreSQL v3 协议访问 GreptimeDB。大多数标准客户端和驱动程序在协议级别上兼容,且连接使用 TLS 加密。 请注意,我们在 GreptimeDB 中不使用 Postgres 的 SQL 方言,因此可能有一些不支持的语句。 有关更多信息,请参考 GreptimeDB 的[Postgresql 文档](https://docs.greptime.cn/user-guide/protocols/postgresql)。 要使用 Postgres 协议连接到 GreptimeCloud,请使用以下信息: - Host: `` - Port: `4003` - Database: `` - Username: `` - Password: `` ## `psql` 使用 PostgreSQL 自带的默认 CLI 工具: ``` shell psql -h -p 4003 -U -d -W ``` ## Postgres 连接字符串 使用以下连接字符串与兼容的客户端库(如 psycopg、rust-postgres 等)连接。 ``` host= port=4003 dbname= user= password= ``` ## URL 在你的 Postgres JDBC 客户端使用以下 URL。 ``` jdbc:postgresql://:4003/?user=&password=&ssl=true ``` 如果你使用 Python 等语言的数据库客户端,也可以通过这个 URL 连接到服务 ``` postgresql://:@:4003/ ``` ## Postgres 外部表 将 GreptimeCloud 实例配置外 Postgres 外部数据源。注意依据你的配置修改下方的服务 器名和用户名。 ```sql CREATE SERVER greptimedb FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '', dbname '', port '4003'); CREATE USER MAPPING FOR postgres SERVER greptimedb OPTIONS (user '', password ''); ``` --- ## Prometheus(3) GreptimeCloud 与 GreptimeDB 完全兼容 Prometheus。这意味着你可以无缝地将 GreptimeCloud 用作 Prometheus 存储和查询的替代品。有关更多信息,请参阅 GreptimeDB 用户指南中的 [Prometheus 文档](https://docs.greptime.cn/user-guide/clients/prometheus)。 ## Remote Write GreptimeCloud 实例可以配置为 Prometheus 的 [Remote Write 端点](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write)。 将以下部分添加到你的 prometheus 配置中: ```yaml remote_write: - url: https:///v1/prometheus/write?db= basic_auth: username: password: ``` ## Prometheus HTTP API 与 PromQL 用户可以直接通过 Prometheus HTTP API 访问数据库: - URL 根路径:`https:///v1/prometheus` - 数据库名:添加 HTTP 头 `x-greptime-db-name`,值 `` - 认证:HTTP Basic 认证,使用数据库的用户名和密码 一个简单的例子,试用 Prometheus API 访问数据库 ```shell curl -X GET \ -H "x-greptime-db-name: " \ -u ":" \ "https:///v1/prometheus/api/v1/query?query=1" ``` GreptimeDB 支持 PromQL (Prometheus 查询语言),这意味着你可以将 GreptimeDB 作为 Prometheus 查询的替代品。有关更多详细信息,请参考 [PromQL](https://docs.greptime.cn/user-guide/clients/prometheus#prometheus-query-language)。 --- ## Go SDK GreptimeDB Go SDK 使用 gRPC 与数据库通信, 请参考 [Go SDK 文档](https://docs.greptime.com/user-guide/ingest-data/for-iot/grpc-sdks/go)查看更多 SDK 使用的相关内容。 请使用以下信息连接到 GreptimeCloud: - Host: `` - Port: `5001` - Database: `` - Username: `` - Password: `` 下方的代码片段展示了如何使用 Go SDK 建立一个 `client` 连接对象: ```go cfg := greptime.NewConfig(""). WithDatabase(""). WithPort(5001). WithInsecure(false). WithAuth("", "") cli, err := greptime.NewClient(cfg) if err != nil { panic("failed to init client") } ``` --- ## Java SDK GreptimeDB Java ingester 库使用 gRPC 协议写入数据, 请参考 [Java 库文档](https://docs.greptime.cn/user-guide/ingest-data/for-iot/grpc-sdks/java)查看更多使用内容。 请使用以下信息连接到 GreptimeCloud: - Host: `` - Port: `5001` - Database: `` - Username: `` - Password: `` 下方的代码片段展示了如何连接到数据库: ```java String database = ""; String[] endpoints = {":5001"}; AuthInfo authInfo = new AuthInfo("", ""); GreptimeOptions opts = GreptimeOptions.newBuilder(endpoints, database) .authInfo(authInfo) .tlsOptions(new TlsOptions()) .build(); GreptimeDB client = GreptimeDB.create(opts); ``` --- ## Streamlit(Integrations) Streamlit 是一套快速构建数据应用的 Python 框架,目前他也支持构建基于 GreptimeDB 的数据应用。 我们可以通过 Streamlit 的 SQL 连接来创建到 GreptimeDB 的通道。由于 GreptimeDB 兼 容 MySQL 协议,因此可以将 GreptimeDB 看作一个 MySQL 实例来进行连接。 ```python st.title('GreptimeDB Streamlit Demo') conn = st.connection("greptimedb", type="sql", url="mysql://:@:4002/") df = conn.query("SELECT * FROM ...") ``` 完成连接后,就可以直接执行 GreptimeDB 的 SQL 查询。和其他 Streamlit 的数据源一样, 结果集将被自动转换成 Pandas 格式用于其他 Streamlit 接口。 --- ## Superset(Integrations) [Apache Superset](https://superset.apache.org) 是开源的 BI 工具,用 Python 编写。 以下内容可以帮助你把 GreptimeDB 作为 Superset 的数据源。 关于插件的安装,请[查看文 档](https://docs.greptime.cn/user-guide/integrations/superset). ## 连接信息 从数据库列表中选择 `GreptimeDB`。 填写以下 URL ``` greptimedb://:@:4003/ ``` --- ## Vector(3) Vector 是高性能的可观测数据管道。 它原生支持 GreptimeDB 指标数据接收端。 通过 Vector,你可以从各种来源接收指标数据,包括 Prometheus、OpenTelemetry、StatsD 等。 GreptimeDB 可以作为 Vector 的 Sink 组件来接收指标数据。 要在 GreptimeCloud 中使用 Vector,你需要使用 Vector 版本 `0.41` 及以上。 当使用你的 GreptimeCloud 实例时,配置可以是: ```toml # sample.toml ## metrics [sources.metrics_in] type = "host_metrics" [sinks.metrics_out] inputs = ["metrics_in"] type = "greptimedb" endpoint = ":5001" dbname = "" username = "" password = "" tls = {} new_naming = true ## logs [sources.logs_in] type = "demo_logs" format = "json" [transforms.logs_json] type = "remap" inputs = ["logs_in"] source = ''' . = parse_json!(.message) ''' [sinks.logs_out] inputs = ["logs_json"] type = "greptimedb_logs" endpoint = "https://" compression = "gzip" dbname = "" username = "" password = "" table = "demo_logs" pipeline_name = "greptime_identity" healthcheck.enabled = false ``` 启动 Vector: ``` vector -c sample.toml ``` 请前往 [Vector GreptimeDB Configuration](https://vector.dev/docs/reference/sinks/greptimedb/) 查看更多配置项。 --- ## 从 InfluxDB 迁移(Migrate-to-greptimecloud) 打开 [GreptimeCloud 控制台](https://greptime.cloud) 点击 `Manage Your Data` 下的 `Connection Information`. 你可以找到 GreptimeDB URL,数据库名称,以及 token 所需的 username 和 password。 ```shell curl -X POST 'https:///v1/influxdb/api/v2/write?bucket=' \ -H 'authorization: token ' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` ```shell curl 'https:///v1/influxdb/write?db=&u=&p=' \ -d 'census,location=klamath,scientist=anderson bees=23 1566086400000000000' ``` ```toml [[outputs.influxdb_v2]] urls = ["https:///v1/influxdb"] token = ":" bucket = "" ## 留空即可 organization = "" ``` ```toml [[outputs.influxdb]] urls = ["https:///v1/influxdb"] database = "" username = "" password = "" ``` ```js 'use strict' /** @module write **/ /** 环境变量 **/ const url = 'https:///v1/influxdb' const token = ':' const org = '' const bucket = '' const influxDB = new InfluxDB({ url, token }) const writeApi = influxDB.getWriteApi(org, bucket) writeApi.useDefaultTags({ region: 'west' }) const point1 = new Point('temperature') .tag('sensor_id', 'TLM01') .floatField('value', 24.0) writeApi.writePoint(point1) ``` ```python from influxdb_client.client.write_api import SYNCHRONOUS bucket = "" org = "" token = ":" url="https:///v1/influxdb" client = influxdb_client.InfluxDBClient( url=url, token=token, org=org ) write_api = client.write_api(write_options=SYNCHRONOUS) p = influxdb_client.Point("my_measurement").tag("location", "Prague").field("temperature", 25.3) write_api.write(bucket=bucket, org=org, record=p) ``` ```go bucket := "" org := "" token := ":" url := "https:///v1/influxdb" client := influxdb2.NewClient(url, token) writeAPI := client.WriteAPIBlocking(org, bucket) p := influxdb2.NewPoint("stat", map[string]string{"unit": "temperature"}, map[string]interface{}{"avg": 24.5, "max": 45}, time.Now()) writeAPI.WritePoint(context.Background(), p) client.Close() ``` ```java private static String url = "https:///v1/influxdb"; private static String org = ""; private static String bucket = ""; private static char[] token = ":".toCharArray(); public static void main(final String[] args) { InfluxDBClient influxDBClient = InfluxDBClientFactory.create(url, token, org, bucket); WriteApiBlocking writeApi = influxDBClient.getWriteApiBlocking(); Point point = Point.measurement("temperature") .addTag("location", "west") .addField("value", 55D) .time(Instant.now().toEpochMilli(), WritePrecision.MS); writeApi.writePoint(point); influxDBClient.close(); } ``` ```php $client = new Client([ "url" => "https:///v1/influxdb", "token" => ":", "bucket" => "", "org" => "", "precision" => InfluxDB2\Model\WritePrecision::S ]); $writeApi = $client->createWriteApi(); $dateTimeNow = new DateTime('NOW'); $point = Point::measurement("weather") ->addTag("location", "Denver") ->addField("temperature", rand(0, 20)) ->time($dateTimeNow->getTimestamp()); $writeApi->write($point); ``` GreptimeCloud 控制台提供了名为 Workbench 的数据可视化工作台。 打开 [控制台](https://greptime.cloud), 在 `Manage Your Data` 下选择 `Web Dashboard`, 然后创建一个新的 Workbench 文件, 即可按需求创建图表。 ```shell for file in data.*; do curl -i --retry 3 \ -X POST "https://${GREPTIME_HOST}/v1/influxdb/write?db=${GREPTIME_DB}&u=${GREPTIME_USERNAME}&p=${GREPTIME_PASSWORD}" \ --data-binary @${file} sleep 1 done ``` --- ## 从 Prometheus 迁移(Migrate-to-greptimecloud) 有关 Prometheus 将数据写入 GreptimeDB 的配置信息,请参阅 [Remote Write](/greptimecloud/integrations/prometheus.md#remote-write) 文档。 有关使用 Prometheus 查询语言在 GreptimeDB 中查询数据的详细信息,请参阅 PromQL 文档中的 [HTTP API](/greptimecloud/integrations/prometheus.md#prometheus-http-api-与-promql) 部分。 要在 Grafana 中将 GreptimeDB 添加为 Prometheus 数据源,请参阅 [Grafana](/greptimecloud/integrations/grafana.md#prometheus-数据源) 的集成文档。 --- ## GreptimeCloud GreptimeCloud 作为完全托管 GreptimeDB 的 Serverless 云服务,为时间序列数据平台和 Prometheus 后端提供可扩展和高效的解决方案。 --- ## 账单 ## 发票 GreptimeCloud 中的每个 Service 都属于一个团队。 你可以在团队设置中的 [billing](https://console.greptime.cloud/settings/team#billing) 仪表板下为团队添加付款方式。 GreptimeCloud 按自然月收费并生成发票。 ## 用量跟踪 当前账单周期中的详细用量报告可以在 [billing](https://console.greptime.cloud/settings/team#billing) 中找到,其中包括以下项目: - Serverless 计划: - 所有 Serverless Service 设定的请求容量单位(RCU 和 WCU)之和。 - 所有 Serverless Service 使用的存储容量之和。 - Dedicated 计划: - 所有 Dedicated service 配置的专用实例数量。 - 所有专用实例使用的存储容量之和。 - 所有专用实例的负载均衡器的网络流量。 用量跟踪项目每天更新一次,通过汇总当前月份前几天的用量得出。 例如,如果你有 Service A 在 Serverless 计划中设定了 10 RCU,Service B 设定了 20 RCU, 那么 Serverless RCU 的用量在月份第二天的计算结果为 720(10 * 24 小时 + 20 * 24 小时),在第三天为 1440(720 + 720)。 ## 费用 请参考 [Serverless Plan](serverless.md#费用) 和 [Dedicated Plan](dedicated.md#费用) 了解费用计算逻辑。 --- ## Dedicated 计划 Dedicated 计划允许你购买专用的 CPU 和存储来托管 GreptimeDB。 它提供无限的数据存储和数据保留策略, 完全隔离的资源和网络, 并包括 Greptime 的 SRE 团队的支持。 如果你需要绝对地与其他用户隔离,或者需要超出 Serverless 计划的最大用量限制,那么 Dedicated 计划是你的选择。 ## 费用 请查看[价格页面](https://greptime.com/pricing)获取最新的定价信息。 ### 计算节点 在 Dedicated 计划下创建服务时,你需要配置服务模式并确定计算节点的规格。 Greptime 根据你选择的计划中指定的计算节点按小时计算费用,并按月收费。 费用计算公式: - 每小时费用:(所选计划的节点规格 * 节点数量 * 节点小时价格) - 每日费用:每小时费用之和 - 每月费用:每日费用之和 ### 网络流量 网络流量的费用将包含在你的月度账单中。 流量价格由云服务器提供商(如 AWS)决定,Greptime 不会对流量收取额外费用。 --- ## Hobby 计划 ## 简介 GreptimeCloud 提供免费的 Hobby 计划供你尝试服务。 每个团队可以在 Hobby 计划中创建最多三个服务。 Hobby 计划有以下限制: - RCU (Read Capacity Units): 每个服务 40 RCU/s。 - WCU (Write Capacity Units): 每个服务 20 WCU/s。 - 存储容量:每个服务 5GB。 - 数据保留策略:最近三个月。 :::tip 注意 计划可能会在未来更改。如果有任何问题,请联系 [feedback@greptime.cloud](mailto:feedback@greptime.cloud)。 ::: --- ## 用量和费用 此文档将帮助你了解 GreptimeCloud 的用量和费用。 - [请求容量单位](request-capacity-unit.md) - [Hobby 计划](hobby.md) - [Serverless 计划](serverless.md) - [Dedicated 计划](dedicated.md) --- ## 请求容量单位 本文档将介绍 GreptimeCloud 的请求容量单位算法。你可以前往 [GreptimeCloud 控制台](https://console.greptime.cloud/) 监控服务的使用情况。 所有对 GreptimeCloud 的请求都是以容量单位来衡量的,容量单位反映了请求的大小和复杂程度。写容量单位和读容量单位的计算方法不同,详情请见下文。 ### Write Capacity Unit (WCU) 每个写入数据到表的 API 调用都是一个写请求。WCU 是根据一次请求中插入行的总大小来计算的。一个标准的 WCU 可以写入不超过 1 KB 的行数据。对于大于 1 KB 的数据,需要额外的 WCU。 :::tip 注意 WCU 的容量可能会在未来发生变化。 ::: 每个请求的大小根据以下步骤计算: 1. 获取表结构中每个列的数据类型的大小。你可以在 [数据类型](/reference/sql/data-types.md) 文档中找到有关每个数据类型大小的详细信息。 2. 计算请求中所有列的大小之和。如果请求中不存在某列,则其大小取决于该列的默认值。如果默认值为 null,则大小为 0;否则,它是该列数据类型的大小。 3. 行数据的总和乘以要写入的行数。 这是一个具有以下表结构的 WCU 计算示例: ```shell +-------------+----------------------+------+------+---------------------+---------------+ | Column | Type | Key | Null | Default | Semantic Type | +-------------+----------------------+------+------+---------------------+---------------+ | host | String | PRI | YES | | TAG | | idc | String | PRI | YES | | TAG | | cpu_util | Float64 | | YES | | FIELD | | memory_util | Float64 | | YES | | FIELD | | disk_util | Float64 | | YES | | FIELD | | ts | TimestampMillisecond | PRI | NO | current_timestamp() | TIMESTAMP | +-------------+----------------------+------+------+---------------------+---------------+ ``` 你有一个这样的写请求: ```shell INSERT INTO system_metrics VALUES ("host1", "a", 11.8, 10.3, 10.3, 1667446797450); ``` 根据表结构中数据类型的大小,每行数据的大小为 38 字节(5+1+8+8+8+8),根据计算算法,此请求的 WCU 为 1。为了减少 WCU,可以使用批量的 `INSERT` 语句在单个语句中插入多行数据,而不是每行数据都发送一个单独的请求。例如: ```shell INSERT INTO system_metrics VALUES ("host1", "idc_a", 11.8, 10.3, 10.3, 1667446797450), ("host1", "idc_a", 80.1, 70.3, 90.0, 1667446797550), # ...... 22 rows ("host1", "idc_b", 90.0, 39.9, 60.6, 1667446798250); ``` 该请求的大小为 950 字节(38 x 25)。此请求的 WCU 为 1。如果你在单个语句中插入 40 行数据,则大小为 1520 字节(38 x 40),此请求的 WCU 为 2。 ### Read Capacity Unit (RCU) 从表中读取数据的每个 API 调用都是一个读请求。 RCU 是在服务器内存中扫描和加载的数据大小。 一个标准的读容量单位可以扫描最多 1MB 的数据。 对于扫描的数据大于 1MB,需要额外的读容量单位。 :::tip 注意 RCU 的容量可能会在未来发生变化。 ::: 假如有一个读请求扫描 2.5MB 的数据。根据计算规则该请求的 RCU 为 3。 为了降低 RCU,可以仔细设计表结构和查询请求。以下是一些建议: - 使用索引以支持在 GreptimeDB 中高效地执行查询。如果没有索引,GreptimeDB 必须扫描整个表来处理查询。如果索引与查询匹配,GreptimeDB 可以使用索引来限制扫描的数据。请考虑使用具有高区分度的列作为主键,并在 `WHERE` 子句中使用它。 - 选择使用匹配结果较少的查询。例如,时间索引字段和高区分度的标签字段上的相等匹配可以有效地限制扫描的数据大小。请注意,不等运算符 `!=` 无法做到有效查询,因为它总是会扫描所有数据。 ## 通过 HTTP 响应监控 CU 使用情况 GreptimeCloud 通过 HTTP 响应头提供 CU(Capacity Unit)使用信息,此功能能够方便地跟踪请求的 CU 消耗。例如,当使用如下命令进行写入请求时: ```bash curl -s -i -XPOST -w '\n' \ "https:///v1/influxdb/api/v2/write?db=&precision=ms&u=&p=" \ --data-binary \ 'monitor,host=127.0.0.1 cpu=0.1,memory=0.4 1667446797450 monitor,host=127.0.0.2 cpu=0.2,memory=0.3 1667446798450 monitor,host=127.0.0.1 cpu=0.5,memory=0.2 1667446798450' ``` 响应头将包括如下信息: ``` HTTP/2 204 date: Wed, 10 Apr 2024 03:29:36 GMT x-greptime-metrics: {"greptime_cloud_wcu":1} strict-transport-security: max-age=15724800; includeSubDomains access-control-allow-origin: * access-control-allow-credentials: true access-control-allow-methods: OPTIONS access-control-allow-headers: DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization access-control-max-age: 1728000 ``` 可以看到,`x-greptime-metrics` 展示了 `greptime_cloud_wcu` 的值,指示了该写入请求的消耗 WCU。类似地,对于读取请求,你可以查看 `greptime_cloud_rcu`。此功能提供了请求对 CU 利用情况的信息,有助于更好地管理并优化资源。 ## 用量统计 你可以在 [GreptimeCloud 控制台](https://console.greptime.cloud/) 查看用量。 最大 WCU 和 RCU 的使用情况将按时间范围进行聚合,并在用量图表中呈现。 --- ## Serverless 计划 Serverless 计划允许你根据需求购买请求容量,并提供 SRE 团队支持。 该解决方案提供无限的数据存储和可配置的数据保留策略, 适用于生产环境,并且可以随着业务的增长而扩展。 当创建 Serverless 计划新服务或从 Hobby 计划升级时, 你需要配置容量单元,包括: - 每秒最大 WCU (Write Capacity Unit),上限为 5000 - 每秒最大 RCU (Read Capacity Unit),上限为 5000 :::tip 注意 请查看 [请求容量单位](request-capacity-unit.md) 了解 WCU 和 RCU 的概念。 ::: ## 费用 请查看[价格页面](https://greptime.com/pricing)获取最新的定价信息。 ### WCU 和 RCU Greptime 根据你选择的计划中指定的容量单元按小时计算费用,并按月收费。 费用计算公式: - 每小时费用:(所选计划的 WCU *(WCU 每分钟价格 * 60 分钟)) + (所选计划的 RCU *(RCU 每分钟价格 * 60 分钟)) - 每日费用:每小时费用之和 - 每月费用:每日费用之和 --- ## Shared Storage Capacity ### 存储容量 GreptimeCloud 会将您的数据存储在对象存储中,例如 S3,并根据数据库中的总数据大小计算存储成本。你将按月支付所使用的服务费用。 --- ## 使用 Prometheus 和 GreptimeDB 监控 Kubernetes 指标 本指南演示如何建立一个完整的 Kubernetes 监控解决方案, 该方案使用 Prometheus 收集指标, 使用 GreptimeDB 作为长期存储后端。 ## 什么是 Kubernetes 监控 Kubernetes 监控指的是从 Kubernetes 集群中收集、分析和处理指标和日志。 它是检查容器化应用程序和基础设施的健康状况、性能和资源利用率的关键。 Kubernetes 主要监控以下信息: - **资源指标**:节点、Pod 和容器的 CPU、内存、磁盘和网络使用情况 - **集群健康**:集群组件如 kube-apiserver、etcd 和 controller-manager 的状态 - **应用程序指标**:在集群中运行的应用程序指标 - **事件和日志**:用于故障诊断的 Kubernetes 事件和容器日志 有效的监控可以帮助你: - 在问题影响用户之前检测和诊断问题 - 优化资源利用率并降低成本 - 基于历史趋势进行容量规划 - 确保 SLA 合规性 - 排查性能瓶颈 ## 架构概览 监控架构由以下组件组成: ![Kubernetes 监控架构](/k8s-metrics-monitor-architecture.drawio.svg) **组件:** - **kube-state-metrics**:导出关于 Kubernetes 对象(部署、Pod、服务等)的集群级指标 - **Node Exporter**:从每个 Kubernetes 节点导出硬件和操作系统级指标 - **Prometheus Operator**:使用 Kubernetes 自定义资源自动化 Prometheus 部署和配置 - **GreptimeDB**:Prometheus 指标的长期存储后端,具有高压缩率和查询性能 - **Grafana**:为存储在 GreptimeDB 中的指标提供仪表板和可视化 ## 前提条件 在开始之前,确保你拥有: - 一个运行中的 Kubernetes 集群(版本 >= 1.18) - 已配置 `kubectl` 以访问你的集群 - 已安装 [Helm](https://helm.sh/docs/intro/install/) v3.0.0 或更高版本 - 足够的集群资源(至少 2 个 CPU 核心和 4GB 可用内存) ## 安装 GreptimeDB GreptimeDB 被作为 Prometheus 指标的长期存储后端, 请参考[部署 GreptimeDB 集群](/user-guide/deployments-administration/deploy-on-kubernetes/deploy-greptimedb-cluster.md)文档了解如何部署。 ### 验证 GreptimeDB 的部署 部署 GreptimeDB 后,验证集群是否正常运行中。 在本指南中,我们假设 GreptimeDB 集群部署在 `greptime-cluster` 命名空间,名称为 `greptimedb`。 ```bash kubectl -n greptime-cluster get greptimedbclusters.greptime.io greptimedb ``` ```bash NAME FRONTEND DATANODE META FLOWNODE PHASE VERSION AGE greptimedb 1 2 1 1 Running v1.0.1 33s ``` 检查 Pod 状态: ```bash kubectl get pods -n greptime-cluster ``` ```bash NAME READY STATUS RESTARTS AGE greptimedb-datanode-0 1/1 Running 0 71s greptimedb-datanode-1 1/1 Running 0 97s greptimedb-flownode-0 1/1 Running 0 64s greptimedb-frontend-8bf9f558c-7wdmk 1/1 Running 0 90s greptimedb-meta-fc4ddb78b-nv944 1/1 Running 0 87s ``` ### 访问 GreptimeDB 可以将 frontend 服务的端口转发到本地来连接 GreptimeDB。 GreptimeDB 支持多种协议,其中 MySQL 协议默认使用端口 `4002`。 ```bash kubectl port-forward -n greptime-cluster svc/greptimedb-frontend 4002:4002 ``` 使用 MySQL 客户端连接 GreptimeDB: ```bash mysql -h 127.0.0.1 -P 4002 ``` ### 存储分区 为了提高查询性能并降低存储成本, GreptimeDB 会基于 Prometheus 指标标签自动创建列,并将指标存储在物理表中,默认使用的物理表名为 `greptime_physical_table`。 在上方我们部署了具有[多个 datanode 节点](#验证-greptimedb-的部署)的 GreptimeDB 集群, 你可以对表进行分区将数据分布到各个 datanode 节点上,以获得更好的可扩展性和性能。 在此 Kubernetes 监控场景中, 可以使用 `namespace` 标签作为分区键。 例如,对于 `kube-public`、`kube-system`、`monitoring`、`default`、`greptime-cluster` 和 `etcd-cluster` 等命名空间, 你可以基于命名空间的首字母创建分区方案: ```sql CREATE TABLE greptime_physical_table ( greptime_value DOUBLE NULL, namespace STRING PRIMARY KEY, greptime_timestamp TIMESTAMP TIME INDEX, ) PARTITION ON COLUMNS (namespace) ( namespace < 'f', namespace >= 'f' AND namespace < 'g', namespace >= 'g' AND namespace < 'k', namespace >= 'k' ) ENGINE = metric WITH ( "physical_metric_table" = "" ); ``` 有关 Prometheus 指标存储和查询性能优化的更多信息, 请参阅[使用 metric engine 提高效率](/user-guide/ingest-data/for-observability/prometheus.md#通过使用-metric-engine-提高效率)指南。 ### GreptimeDB 中的 Prometheus URL GreptimeDB 在 HTTP 上下文 `/v1/prometheus/` 下提供了[兼容 Prometheus 的 API](/user-guide/query-data/promql.md#prometheus-http-api), 使其能够与现有的 Prometheus 工作流程无缝集成。 你需要 GreptimeDB 服务地址来配置 Prometheus。 由于 GreptimeDB 在 Kubernetes 集群内运行,所以使用内部集群地址。 GreptimeDB frontend 服务地址遵循以下模式: ``` -frontend..svc.cluster.local: ``` 在本指南中: - GreptimeDB 集群名称:`greptimedb` - 命名空间:`greptime-cluster` - Frontend 端口:`4000` 因此服务地址为: ```bash greptimedb-frontend.greptime-cluster.svc.cluster.local:4000 ``` Prometheus 的完整 [Remote Write URL](/user-guide/ingest-data/for-observability/prometheus.md#remote-write-configuration) 为: ```bash http://greptimedb-frontend.greptime-cluster.svc.cluster.local:4000/v1/prometheus/write ``` 此 URL 包含: - **服务端点**:`greptimedb-frontend.greptime-cluster.svc.cluster.local:4000` - **API 路径**:`/v1/prometheus/write` ## 安装 Prometheus 现在 GreptimeDB 正常运行中, 我们将安装 Prometheus 收集指标并将其发送到 GreptimeDB。 ### 添加 Prometheus Community Helm 仓库 ```bash helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update ``` ### 安装 kube-prometheus-stack [`kube-prometheus-stack`](https://github.com/prometheus-operator/kube-prometheus) 是一个综合的监控解决方案,包括 Prometheus、Grafana、kube-state-metrics 和 node-exporter 组件。 此 stack 自动发现和监控所有 Kubernetes 命名空间, 收集来自集群组件、节点和工作负载的指标。 在此部署中, 我们将配置 Prometheus 使用 GreptimeDB 作为 Remote Write 目标长期存储指标数据, 并配置 Grafana 的默认 Prometheus 数据源使用 GreptimeDB。 创建一个 `kube-prometheus-values.yaml` 文件,包含以下配置: ```yaml # 配置 Prometheus 远程写入到 GreptimeDB prometheus: prometheusSpec: remoteWrite: - url: http://greptimedb-frontend.greptime-cluster.svc.cluster.local:4000/v1/prometheus/write # 配置 Grafana 使用 GreptimeDB 作为默认 Prometheus 数据源 grafana: datasources: datasources.yaml: apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://greptimedb-frontend.greptime-cluster.svc.cluster.local:4000/v1/prometheus access: proxy editable: true ``` 此配置文件为以下用途指定了[GreptimeDB 服务地址](#greptimedb-中的-prometheus-url): - **Prometheus Remote Write**:将收集的指标发送到 GreptimeDB 进行长期存储 - **Grafana 数据源**:将 GreptimeDB 配置为仪表板查询的默认 Prometheus 数据源 使用 Helm 和自定义配置文件安装 `kube-prometheus-stack`: ```bash helm install kube-prometheus prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --create-namespace \ --values kube-prometheus-values.yaml ``` ### 验证安装 检查所有 Prometheus 组件是否正在运行: ```bash kubectl get pods -n monitoring ``` ```bash NAME READY STATUS RESTARTS AGE alertmanager-kube-prometheus-kube-prome-alertmanager-0 2/2 Running 0 60s kube-prometheus-grafana-78ccf96696-sghx4 3/3 Running 0 78s kube-prometheus-kube-prome-operator-775fdbfd75-w88n7 1/1 Running 0 78s kube-prometheus-kube-state-metrics-5bd5747f46-d2sxs 1/1 Running 0 78s kube-prometheus-prometheus-node-exporter-ts9nn 1/1 Running 0 78s prometheus-kube-prometheus-kube-prome-prometheus-0 2/2 Running 0 60s ``` ### 验证监控状态 使用 [MySQL protocol](#访问-greptimedb) 查询 GreptimeDB,验证 Prometheus 指标是否已写入。 ```sql SHOW TABLES; ``` 你应该能看到为各种 Prometheus 指标创建的表名。 ```sql +---------------------------------------------------------------------------------+ | Tables | +---------------------------------------------------------------------------------+ | :node_memory_MemAvailable_bytes:sum | | ALERTS | | ALERTS_FOR_STATE | | aggregator_discovery_aggregation_count_total | | aggregator_unavailable_apiservice | | alertmanager_alerts | | alertmanager_alerts_invalid_total | | alertmanager_alerts_received_total | | alertmanager_build_info | | ...... | +---------------------------------------------------------------------------------+ 1553 rows in set (0.18 sec) ``` ## 使用 Grafana 进行可视化 Grafana 包含在 kube-prometheus-stack 中, 并预配置了 Prometheus 作为数据源的仪表盘。 ### 访问 Grafana 将 Grafana 服务的端口转发到本地以访问 Web 界面: ```bash kubectl port-forward -n monitoring svc/kube-prometheus-grafana 3000:80 ``` ### 获取管理员凭证 使用 kubectl 检索登录使用的 admin 密码: ```bash kubectl get secret --namespace monitoring kube-prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo ``` ### 登录 Grafana 1. 打开浏览器并导航到 [http://localhost:3000](http://localhost:3000) 2. 使用以下凭证登录: - **用户名**:`admin` - **密码**:从上一步检索到的密码 ### 查看预配置的仪表板 登录后,导航到**仪表板**以探索预配置的 Kubernetes 监控仪表板: - **Kubernetes / Compute Resources / Cluster**:集群范围的资源利用率概览 - **Kubernetes / Compute Resources / Namespace (Pods)**:按命名空间分解的资源使用情况 - **Kubernetes / Compute Resources / Node (Pods)**:节点级资源监控 - **Node Exporter / Nodes**:详细的节点硬件和操作系统指标 ![Grafana Dashboard](/k8s-prom-monitor-grafana.jpg) ## 总结 你现在部署了完整的 Kubernetes 监控解决方案, 使用 Prometheus 收集指标,使用 GreptimeDB 提供高效的长期存储。 该解决方案使你能够: - 实时监控集群和应用程序健康状况 - 存储指标以进行历史分析和容量规划 - 使用 Grafana 创建丰富的可视化和仪表板 - 使用 PromQL 和 SQL 查询指标 有关 GreptimeDB 和 Prometheus 集成的更多信息,请参阅: - [Prometheus 集成](/user-guide/ingest-data/for-observability/prometheus.md) - [在 GreptimeDB 中查询数据](/user-guide/query-data/overview.md)