Skip to content

Commit 62082ae

Browse files
committed
chore: publish zh 0.17
1 parent b240d14 commit 62082ae

File tree

320 files changed

+40697
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

320 files changed

+40697
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
keywords: [数据持久化, 索引机制, SST 文件, 倒排索引]
3+
description: 介绍了 GreptimeDB 的数据持久化和索引机制,包括 SST 文件格式、数据持久化过程和倒排索引的实现。
4+
---
5+
6+
# 数据持久化与索引
7+
8+
与所有类似 LSMT 的存储引擎一样,MemTables 中的数据被持久化到耐久性存储,例如本地磁盘文件系统或对象存储服务。GreptimeDB 采用 [Apache Parquet][1] 作为其持久文件格式。
9+
10+
## SST 文件格式
11+
12+
Parquet 是一种提供快速数据查询的开源列式存储格式,已经被许多项目采用,例如 Delta Lake。
13+
14+
Parquet 具有层次结构,类似于“行组 - 列-数据页”。Parquet 文件中的数据被水平分区为行组(row group),在其中相同列的所有值一起存储以形成数据页(data pages)。数据页是最小的存储单元。这种结构极大地提高了性能。
15+
16+
首先,数据按列聚集,这使得文件扫描更加高效,特别是当查询只涉及少数列时,这在分析系统中非常常见。
17+
18+
其次,相同列的数据往往是同质的(比如具备近似的值),这有助于在采用字典和 Run-Length Encoding(RLE)等技术进行压缩。
19+
20+
<img src="/parquet-file-format.png" alt="Parquet file format" width="500"/>
21+
22+
## 数据持久化
23+
24+
GreptimeDB 提供了 `storage.flush.global_write_buffer_size` 的配置项来设置全局的 Memtable 大小阈值。当数据库所有 MemTable 中的数据量之和达到阈值时将自动触发持久化操作,将 MemTable 的数据 flush 到 SST 文件中。
25+
26+
27+
## SST 文件中的索引数据
28+
29+
Apache Parquet 文件格式在列块和数据页的头部提供了内置的统计信息,用于剪枝和跳过。
30+
31+
<img src="/column-chunk-header.png" alt="Column chunk header" width="350"/>
32+
33+
例如,在上述 Parquet 文件中,如果你想要过滤 `name` 等于 `Emily` 的行,你可以轻松跳过行组 0,因为 `name` 字段的最大值是 `Charlie`。这些统计信息减少了 IO 操作。
34+
35+
36+
## 索引文件
37+
38+
对于每个 SST 文件,GreptimeDB 不但维护 SST 文件内部索引,还会单独生成一个文件用于存储针对该 SST 文件的索引结构。
39+
40+
索引文件采用 [Puffin][3] 格式,这种格式具有较大的灵活性,能够存储更多的元数据,并支持更多的索引结构。
41+
42+
![Puffin](/puffin.png)
43+
44+
目前,倒排索引是 GreptimeDB 第一个支持的单独索引结构,以 Blob 的形式存储在索引文件中。
45+
46+
47+
## 倒排索引
48+
49+
在 v0.7 版本中,GreptimeDB 引入了倒排索引(Inverted Index)来加速查询。
50+
51+
倒排索引是一种常见的用于全文搜索的索引结构,它将文档中的每个单词映射到包含该单词的文档列表,GreptimeDB 把这项源自于搜索引擎的技术应用到了时间序列数据库中。
52+
53+
搜索引擎和时间序列数据库虽然运行在不同的领域,但是应用的倒排索引技术背后的原理是相似的。这种相似性需要一些概念上的调整:
54+
1. 单词:在 GreptimeDB 中,指时间线的列值。
55+
2. 文档:在 GreptimeDB 中,指包含多个时间线的数据段。
56+
57+
倒排索引的引入,使得 GreptimeDB 可以跳过不符合查询条件的数据段,从而提高扫描效率。
58+
59+
![Inverted index searching](/inverted-index-searching.png)
60+
61+
例如,上述查询使用倒排索引来定位数据段,数据段满足条件:`job` 等于 `apiserver``handler` 符合正则匹配 `.*users``status` 符合正则匹配 `4..`,然后扫描这些数据段以产生满足所有条件的最终结果,从而显着减少 IO 操作的次数。
62+
63+
### 倒排索引格式
64+
65+
![Inverted index format](/inverted-index-format.png)
66+
67+
GreptimeDB 按列构建倒排索引,每个倒排索引包含一个 FST 和多个 Bitmap。
68+
69+
FST(Finite State Transducer)允许 GreptimeDB 以紧凑的格式存储列值到 Bitmap 位置的映射,并且提供了优秀的搜索性能和支持复杂搜索(例如正则表达式匹配);Bitmap 则维护了数据段 ID 列表,每个位表示一个数据段。
70+
71+
72+
### 索引数据段
73+
74+
GreptimeDB 把一个 SST 文件分割成多个索引数据段,每个数据段包含相同行数的数据。这种分段的目的是通过只扫描符合查询条件的数据段来优化查询性能。
75+
76+
例如,当数据段的行数为 1024,如果查询条件应用倒排索引后,得到的数据段列表为 `[0, 2]`,那么只需扫描 SST 文件中的第 0 和第 2 个数据段(即第 0 行到第 1023 行和第 2048 行到第 3071 行)即可。
77+
78+
数据段的行数由引擎选项 `index.inverted_index.segment_row_count` 控制,默认为 `1024`。较小的值意味着更精确的索引,往往会得到更好的查询性能,但会增加索引存储成本。通过调整该选项,可以在存储成本和查询性能之间进行权衡。
79+
80+
81+
## 统一数据访问层:OpenDAL
82+
83+
GreptimeDB 使用 [OpenDAL][2] 提供统一的数据访问层,因此,存储引擎无需与不同的存储 API 交互,数据可以无缝迁移到基于云的存储,如 AWS S3。
84+
85+
[1]: https://parquet.apache.org
86+
[2]: https://github.com/datafuselabs/opendal
87+
[3]: https://iceberg.apache.org/puffin-spec
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
keywords: [Metric 引擎, 逻辑表, 物理表, DDL 操作]
3+
description: 介绍了 Metric 引擎的概念、架构及设计,重点描述了逻辑表与物理表的区别和批量 DDL 操作的实现。
4+
---
5+
6+
# Metric 引擎
7+
8+
## 概述
9+
10+
`Metric` 引擎是 GreptimeDB 的一个组件,属于存储引擎的一种实现,主要针对可观测 metrics 等存在大量小表的场景。
11+
12+
它的主要特点是利用合成的物理宽表来存储大量的小表数据,实现相同列复用和元数据复用等效果,从而达到减少小表的存储开销以及提高列式压缩效率等目标。表这一概念在 `Metric` 引擎下变得更更加轻量。
13+
14+
## 概念
15+
16+
`Metric` 引擎引入了两个新的概念,分别是逻辑表与物理表。从用户视角看,逻辑表与普通表完全一样。从存储视角看,物理 Region 就是一个普通的 Region。
17+
18+
### 逻辑表
19+
逻辑表,即用户定义的表。与普通的表都完全一样,逻辑表的定义包括表的名称、列的定义、索引的定义等。用户的查询、写入等操作都是基于逻辑表进行的。用户在使用过程中不需要关心逻辑表和普通表的区别。
20+
21+
从实现层面来说,逻辑表是一个虚拟的表,它并不直接读写物理的数据,而是通过将读写请求映射成对应物理表的请求来实现数据的存储与查询。
22+
23+
### 物理表
24+
物理表是真实存储数据的表,它拥有若干个由分区规则定义的物理 Region。
25+
26+
## 架构及设计
27+
28+
`Metric` 引擎的主要设计架构如下:
29+
30+
![Arch](/metric-engine-arch.png)
31+
32+
在目前版本的实现中,`Metric` 引擎复用了 `Mito` 引擎来实现物理数据的存储及查询能力,并在此之上同时提供物理表与逻辑表的访问能力。
33+
34+
在分区方面,逻辑表拥有与物理表完全一致的分区规则及 Region 分布。这是非常自然的,因为逻辑表的数据直接存储在物理表中,所以分区规则也是一致的。
35+
36+
在路由元数据方面,逻辑表的路由地址为逻辑地址,即该逻辑表所对应的物理表是什么,而后通过该物理表进行二次路由取得真正的物理地址。这一间接路由方式能够显著减少 `Metric` 引擎的 Region 发生迁移调度时所需要修改的元数据数量。
37+
38+
在操作方面,`Metric` 引擎仅对物理表的操作进行了有限的支持以防止误操作,例如通过禁止写入物理表、删除物理表等操作防止影响用户逻辑表的数据。总体上可以认为物理表是对用户只读的。
39+
40+
为了提升对大量表同时进行 DDL(Data Definition Language,数据操作语言)操作时性能,如 Prometheus Remote Write 冷启动时大量 metrics 带来的自动建表请求,以及前面提到的迁移物理 Region 时大量路由表的修改请求等,`Metric` 引擎引入了一些批量 DDL 操作。这些批量 DDL 操作能够将大量的 DDL 操作合并成一个请求,从而减少了元数据的查询及修改次数,提升了性能。
41+
42+
除了物理表的物理数据 Region 之外,`Metric` 引擎还额外为每一个物理数据 Region 创建了一个物理的元数据 Region,用于存储 `Metric` 引擎自身为了维护映射等状态所需要的一些元数据。这些元数据包括逻辑表与物理表的映射关系,逻辑列与物理列的映射关系等等。
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
keywords: [Datanode, gRPC 服务, HTTP 服务, Heartbeat Task, Region Manager]
3+
description: 介绍了 Datanode 的主要职责和组件,包括 gRPC 服务、HTTP 服务、Heartbeat Task 和 Region Manager。
4+
---
5+
6+
# Datanode
7+
8+
## Introduction
9+
10+
`Datanode` 主要的职责是为 GreptimeDB 存储数据,我们知道在 GreptimeDB 中一个 `table` 可以有一个或者多个 `Region`,
11+
`Datanode` 的职责便是管理这些 `Region` 的读写。`Datanode` 不感知 `table`,可以认为它是一个 `region server`
12+
所以 `Frontend``Metasrv` 按照 `Region` 粒度来操作 `Datanode`
13+
14+
![Datanode](/datanode.png)
15+
16+
## Components
17+
18+
一个 datanode 包含了 region server 所需的全部组件。这里列出了比较重要的部分:
19+
20+
- 一个 gRPC 服务来提供对 `Region` 数据的读写,`Frontend` 便是使用这个服务来从 `Datanode` 读写数据。
21+
- 一个 HTTP 服务,可以通过它来获得当前节点的 metrics、配置信息等
22+
- `Heartbeat Task` 用来向 `Metasrv` 发送心跳,心跳在 GreptimeDB 的分布式架构中发挥着至关重要的作用,
23+
是分布式协调和调度的基础通信通道,心跳的上行消息中包含了重要信息比如 `Region` 的负载,如果 `Metasrv` 做出了调度
24+
决定(比如 Region 转移),它会通过心跳的下行消息发送指令到 `Datanode`
25+
- `Datanode` 不包含物理规划器(Physical planner)、优化器(optimizer)等组件(这些被放置在 `Frontend` 中),用户对
26+
一个或多个 `Table` 的查询请求会在 `Frontend` 中被转换为 `Region` 的查询请求,`Datanode` 负责处理这些 `Region` 查询请求
27+
- 一个 `Region Manager` 用来管理 `Datanode` 上的所有 `Region`s
28+
- GreptimeDB 支持可插拔的多引擎架构,目前已有的 engine 包括 `File Engine``Mito Engine`
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
keywords: [Python 脚本, 数据分析, CPython, RustPython]
3+
description: 介绍了在 GreptimeDB 中使用 Python 脚本进行数据分析的两种后端实现:CPython 和嵌入式 RustPython 解释器。
4+
---
5+
6+
# Python 脚本
7+
8+
## 简介
9+
10+
Python 脚本是分析本地数据库中的数据的便捷方式,
11+
通过将脚本直接在数据库内运行而不是从数据库拉取数据的方式,可以节省大量的数据传输时间。
12+
下图描述了 Python 脚本的工作原理。
13+
`RecordBatch`(基本上是表中的一列,带有类型和元数据)可以来自数据库中的任何地方,
14+
而返回的 `RecordBatch` 可以用 Python 语法注释以指示其元数据,例如类型或空。
15+
脚本将尽其所能将返回的对象转换为 `RecordBatch`,无论它是 Python 列表、从参数计算出的 `RecordBatch` 还是常量(它被扩展到与输入参数相同的长度)。
16+
17+
![Python Coprocessor](/python-coprocessor.png)
18+
19+
## 两种可选的后端
20+
21+
### CPython 后端
22+
23+
该后端由 [PyO3](https://pyo3.rs/v0.18.1/) 提供支持,可以使用您最喜欢的 Python 库(如 NumPy、Pandas 等),并允许 Conda 管理您的 Python 环境。
24+
25+
但是使用它也涉及一些复杂性。您必须设置正确的 Python 共享库,这可能有点棘手。一般来说,您只需要安装 `python-dev` 包。但是,如果您使用 Homebrew 在 macOS 上安装 Python,则必须创建一个适当的软链接到 `Library/Frameworks/Python.framework`。有关使用 PyO3 crate 与不同 Python 版本的详细说明,请参见 [这里](https://pyo3.rs/v0.18.1/building_and_distribution#configuring-the-python-version)
26+
27+
### 嵌入式 RustPython 解释器
28+
29+
可以运行脚本的实验性 [python 解释器](https://github.com/RustPython/RustPython),它支持 Python 3.10 语法。您可以使用所有的 Python 语法,更多信息请参见 [Python 脚本的用户指南](/user-guide/python-scripts/overview.md).
30+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
keywords: [查询引擎, DataFusion, 逻辑计划, 物理计划]
3+
description: 介绍了 GreptimeDB 的查询引擎架构,基于 Apache DataFusion 构建,涵盖逻辑计划、物理计划、优化和执行过程。
4+
---
5+
6+
# Query Engine
7+
8+
## 介绍
9+
10+
GreptimeDB 的查询引擎是基于[Apache DataFusion][1](属于[Apache Arrow][2]的子项目)构建的,它是一个用 Rust 编写的出色的查询引擎。它提供了一整套功能齐全的组件,从逻辑计划、物理计划到执行运行时。下面将解释每个组件如何被整合在一起,以及在执行过程中它们的位置。
11+
12+
![Execution Procedure](/execution-procedure.png)
13+
14+
入口点是逻辑计划,它被用作查询或执行逻辑等的通用中间表示。逻辑计划的两个主要来源是:1. 用户查询,例如通过 SQL 解析器和规划器的 SQL;2. Frontend 的分布式查询,这将在下一节中详细解释。
15+
16+
接下来是物理计划,或称执行计划。与包含所有逻辑计划变体(除特殊扩展计划节点外)的大型枚举的逻辑计划不同,物理计划实际上是一个定义了在执行过程中调用的一组方法的特性。所有数据处理逻辑都包装在实现该特性的相应结构中。它们是对数据执行的实际操作,如聚合器 `MIN``AVG` ,以及表扫描 `SELECT ... FROM`
17+
18+
优化阶段通过转换逻辑计划和物理计划来提高执行性能,现在全部基于规则。它也被称为“基于规则的优化”。一些规则是 DataFusion 原生的,其他一些是在 GreptimeDB 中自定义的。在未来,我们计划添加更多规则,并利用数据统计进行基于成本的优化 (CBO)。
19+
20+
最后一个阶段"执行"是一个动词,代表从存储读取数据、进行计算并生成预期结果的过程。虽然它比之前提到的概念更抽象,但你可以简单地将它想象为执行一个 Rust 异步函数,并且它确实是一个异步流。
21+
22+
当你想知道 SQL 是如何通过逻辑计划或物理计划中表示时,`EXPLAIN [VERBOSE] <SQL>` 是非常有用的。
23+
24+
## 数据表示
25+
26+
GreptimeDB 使用 [Apache Arrow][2]作为内存中的数据表示格式。它是面向列的,以跨平台格式,也包含许多高性能的基础操作。这些特性使得在许多不同的环境中共享数据和实现计算逻辑变得容易。
27+
28+
## 索引
29+
30+
在时序数据中,有两个重要的维度:时间戳和标签列(或者类似于关系数据库中的主键)。GreptimeDB 将数据分组到时间桶中,因此能在非常低的成本下定位和提取预期时间范围内的数据。GreptimeDB 中主要使用的持久文件格式 [Apache Parquet][3] 提供了多级索引和过滤器,使得在查询过程中很容易修剪数据。在未来,我们将更多地利用这个特性,并开发我们的分离索引来处理更复杂的用例。
31+
32+
## 拓展性
33+
34+
<!-- 在 GreptimeDB 中扩展操作非常简单。有两种方法可以做到:1. 通过 [Python Coprocessor][4] 接口;2. 像 [这样][5] 实现你的算子。 -->
35+
36+
在 GreptimeDB 中扩展操作非常简单。你可以像 [这样][5] 实现你的算子。
37+
38+
## 分布式查询
39+
40+
参考 [Distributed Querying][6].
41+
42+
[1]: https://github.com/apache/arrow-datafusion
43+
[2]: https://arrow.apache.org/
44+
[3]: https://parquet.apache.org
45+
[4]: python-scripts.md
46+
[5]: https://github.com/GreptimeTeam/greptimedb/blob/main/docs/how-to/how-to-write-aggregate-function.md
47+
[6]: ../frontend/distributed-querying.md
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
keywords: [存储引擎, Mito, LSMT, 数据模型, Region]
3+
description: 详细介绍了 GreptimeDB 的存储引擎架构、数据模型和 region 的概念,重点描述了 Mito 存储引擎的优化和组件。
4+
---
5+
6+
# 存储引擎
7+
8+
## 概述
9+
10+
`存储引擎` 负责存储数据库的数据。Mito 是我们默认使用的存储引擎,基于 [LSMT][1](Log-structured Merge-tree)。我们针对处理时间序列数据的场景做了很多优化,因此 mito 这个存储引擎并不适用于通用用途。
11+
12+
## 架构
13+
下图展示了存储引擎的架构和处理数据的流程。
14+
15+
![Architecture](/storage-engine-arch.png)
16+
17+
该架构与传统的 LSMT 引擎相同:
18+
19+
- [WAL][2]
20+
- 为尚未刷盘的数据提供高持久性保证。
21+
- 基于 `LogStore` API 实现,不关心底层存储介质。
22+
- WAL 的日志记录可以存储在本地磁盘上,也可以存储在实现了 `LogStore` API 的分布式日志服务中。
23+
- Memtable
24+
- 数据首先写入 `active memtable`,又称 `mutable memtable`
25+
-`mutable memtable` 已满时,它将变为只读的 `immutable memtable`
26+
- SST
27+
- SST 的全名为有序字符串表(`Sorted String Table`)。
28+
- `immutable memtable` 刷到持久存储后形成一个 SST 文件。
29+
- Compactor
30+
- `Compactor` 通过 compaction 操作将小的 SST 合并为大的 SST。
31+
- 默认使用 [TWCS][3] 策略进行合并
32+
- Manifest
33+
- `Manifest` 存储引擎的元数据,例如 SST 的元数据。
34+
- Cache
35+
- 加速查询操作。
36+
37+
[1]: https://en.wikipedia.org/wiki/Log-structured_merge-tree
38+
[2]: https://en.wikipedia.org/wiki/Write-ahead_logging
39+
[3]: https://cassandra.apache.org/doc/latest/cassandra/operating/compaction/twcs.html
40+
41+
## 数据模型
42+
43+
存储引擎提供的数据模型介于 `key-value` 模型和表模型之间
44+
45+
```txt
46+
tag-1, ..., tag-m, timestamp -> field-1, ..., field-n
47+
```
48+
49+
每一行数据包含多个 tag 列,一个 timestamp 列和多个 field 列
50+
- `0 ~ m` 个 tag 列
51+
- tag 列是可空的
52+
- 在建表时通过 `PRIMARY KEY` 指定
53+
- 必须包含一个 timestamp 列
54+
- timestamp 列非空
55+
- 在建表时通过 `TIME INDEX` 指定
56+
- `0 ~ n` 个 field 列
57+
- field 列是可空的
58+
- 数据按照 tag 列和 timestamp 列有序存储
59+
60+
## Region
61+
62+
数据在存储引擎中以 `region` 的形式存储,`region` 是引擎中的一个逻辑隔离存储单元。`region` 中的行必须具有相同的 `schema`(模式),该 `schema` 定义了 `region` 中的 tag 列,timestamp 列和 field 列。数据库中表的数据存储在一到多个 `region` 中。

0 commit comments

Comments
 (0)