Databend 是一个应用 Rust 研发、开源的、齐全面向云架构的旧式数仓,致力于提供极速的弹性扩大能力,打造按需、按量的 Data Cloud 产品体验。开源地址:https://github.com/datafusela…
前言
这篇来介绍下 Databend 底座:Fuse Engine,一个能源磅礴的列式存储引擎,Databend Fuse Engine 在设计之初社区给它的定位是: 能源要磅礴,架构要简略,可靠性要高。 在正式介绍之前,咱们先看一组“挑战数据”,Databend Fuse Engine + AWS S3,一个事务在 ~1.5 小时写入了 22.89 TB 原始数据:
mysql> INSERT INTO ontime_new SELECT * FROM ontime_new;
Query OK, 0 rows affected (1 hour 34 min 36.82 sec)
Read 31619274180 rows, 22.89 TB in 5675.207 sec., 5.57 million rows/sec., 4.03 GB/sec.
同时,在性能上要满足:
- 分布式事务:反对多个计算节点同时读、写同一份数据(存算拆散架构首先要解决的问题)
- 快照隔离:不同版本数据之间互不影响,不便做 Table Zero-Copy
- 回溯能力:可切换到任意一个版本,不便做 Time Travel
- 数据合并:合并后生成新版本数据
- 简略、强壮:关系通过文件来形容,基于这些文件即可复原出整个数据系统
从这些需要登程,你会发现 Fuse Engine 跟 Git“形似”(Git-inspired),在介绍 Fuse Engine 设计之前,咱们先来看看 Git 底层是如何工作的。
Git 工作机制
Git 解决了分布式环境下的数据版本治理(data version control)问题,它有隔离(branch)、提交(commit)、回溯(checkout),以及合并(merge)性能,基于 Git 语义齐全能够打造出一个分布式存储引擎。市面上也呈现一些基于 Git-like 思维而构建的产品,比方 Nessie – Transactional Catalog for Data Lakes 和 lakeFS。
为了更好的摸索 Git 底层工作机制,咱们抉择从数据库角度登程,应用 Git 语义来实现一系列“数据”操作。
- 首先,筹备一个数据文件
cloud.txt
,内容为:
2022/05/06, Databend, Cloud
- 把
cloud.txt
数据写到 Git 零碎:
git commit -m "Add olap.txt"
- Git 为咱们生成一个快照,Commit ID 为
7d972c7ba9213c2a2b15422d4f31a8cbc9815f71
:
git log
commit 7d972c7ba9213c2a2b15422d4f31a8cbc9815f71 (HEAD)
Author: BohuTANG <overred.shuttler@gmail.com>
Date: Fri May 6 16:44:21 2022 +0800
Add cloud.txt
- 再筹备一个新文件
warehouse.txt
2022/05/07, Databend, Warehouse
- 把
warehouse.txt
数据写到 Git 零碎
git commit -m "Add warehouse.txt"
- Git 为咱们生成一个新的快照,Commit ID 为
15af34e4d16082034e1faeaddd0332b3836f1424
commit 15af34e4d16082034e1faeaddd0332b3836f1424 (HEAD)
Author: BohuTANG <overred.shuttler@gmail.com>
Date: Fri May 6 17:41:43 2022 +0800
Add warehouse.txt
commit 7d972c7ba9213c2a2b15422d4f31a8cbc9815f71
Author: BohuTANG <overred.shuttler@gmail.com>
Date: Fri May 6 16:44:21 2022 +0800
Add cloud.txt
到此为止,Git 曾经为咱们保护了 2 个版本的数据:
ID 15af34e4d16082034e1faeaddd0332b3836f1424,版本 2
ID 7d972c7ba9213c2a2b15422d4f31a8cbc9815f71,版本 1
咱们能够依据 Commit ID 进行版本间的任意切换,也就是实现了 Time Travel 和 Table Zero-Copy 性能,那么 Git 底层是如何做到的呢?形式也比较简单,它通过引入 3 类对象文件来进行关系形容:
- Commit 文件,用于形容 tree 对象信息
- Tree 文件,用于形容 blob 对象信息
- Blob 文件,用于形容文件信息
HEAD 文件
首先,咱们须要晓得一个 HEAD 指针:
cat .git/HEAD
15af34e4d16082034e1faeaddd0332b3836f1424
Commit 文件
Commit 文件会记录跟 commit 相干的一些元数据信息,比方以后 tree 以及 parent,还有提交人等,文件门路:
.git/objects/15/af34e4d16082034e1faeaddd0332b3836f1424
文件内容:
git cat-file -p 15af34e4d16082034e1faeaddd0332b3836f1424
tree 576c63e580846fa6df2337c1f074c8d840e0b70a
parent 7d972c7ba9213c2a2b15422d4f31a8cbc9815f71
author BohuTANG <overred.shuttler@gmail.com> 1651830103 +0800
committer BohuTANG <overred.shuttler@gmail.com> 1651830103 +0800
Add warehouse.txt
Tree 文件
Tree 文件记录以后版本下所有的数据文件,文件门路:
.git/objects/57/6c63e580846fa6df2337c1f074c8d840e0b70a
文件内容:
git cat-file -p 576c63e580846fa6df2337c1f074c8d840e0b70a
100644 blob 688de5069f9e873c7e7bd15aa67c6c33e0594dde cloud.txt
100644 blob bdea812b9602ed3c6662a2231b3f1e7b52dc1ccb warehouse.txt
Blob 文件
Blob 文件是原始数据文件,同样能够通过 git cat-file
命令来查看文件内容(如果应用 Git 来治理代码,Blob 就是咱们的代码文件)。
git cat-file -p 688de5069f9e873c7e7bd15aa67c6c33e0594dde
2022/05/06, Databend, Cloud
git cat-file -p bdea812b9602ed3c6662a2231b3f1e7b52dc1ccb
2022/05/07, Databend, Warehouse
Fuse Engine
Databend Fuse Engine 在设计上,跟 Git 十分相似,它引入 3 个形容文件:
- Snapshot 文件,用于形容 Segment 对象信息
- Segment 文件,用于形容 Block 对象信息
- Block 文件,用于形容 Parquet 文件信息
咱们持续在 Fuse Engine 里进行一把方才在 Git 进行的操作。
- 首先创立一个表:
CREATE TABLE git(file VARCHAR, content VARCHAR);
- 把
cloud.txt
数据写到 Fuse Engine
INSERT INTO git VALUES('cloud.txt', '2022/05/06, Databend, Cloud');
- Fuse 为咱们生成一个新的 Snapshot ID
6450690b09c449939a83268c49c12bb2
:
CALL system$fuse_snapshot('default', 'git');
*************************** 1. row ***************************
snapshot_id: 6450690b09c449939a83268c49c12bb2
snapshot_location: 53/133/_ss/6450690b09c449939a83268c49c12bb2_v1.json
format_version: 1
previous_snapshot_id: NULL
segment_count: 1
block_count: 1
row_count: 1
bytes_uncompressed: 68
bytes_compressed: 351
- 把
warehouse.txt
数据写到 Fuse Engine
INSERT INTO git VALUES('warehouse.txt', '2022/05/07, Databend, Warehouse');
- Fuse Engine 为咱们生成一个新的 Snapshot ID
efe2687fd1fc48f8b414b5df2cec1e19
,并指向前一个 Snapshot ID6450690b09c449939a83268c49c12bb2
CALL system$fuse_snapshot('default', 'git');
*************************** 1. row ***************************
snapshot_id: efe2687fd1fc48f8b414b5df2cec1e19
snapshot_location: 53/133/_ss/efe2687fd1fc48f8b414b5df2cec1e19_v1.json
format_version: 1
previous_snapshot_id: 6450690b09c449939a83268c49c12bb2
segment_count: 2
block_count: 2
row_count: 2
*************************** 2. row ***************************
snapshot_id: 6450690b09c449939a83268c49c12bb2
snapshot_location: 53/133/_ss/6450690b09c449939a83268c49c12bb2_v1.json
format_version: 1
previous_snapshot_id: NULL
segment_count: 1
block_count: 1
row_count: 1
目前为止,Fuse Engine 为咱们生成了 2 个版本的数据:
ID efe2687fd1fc48f8b414b5df2cec1e19,版本 2
ID 6450690b09c449939a83268c49c12bb2,版本 1
是不是跟 Git 十分相似?
HEAD
跟 Git 一样,Fuse Engine 也须要一个 HEAD 作为入口,查看 Fuse Engine 的 HEAD:
SHOW CREATE TABLE git\G;
*************************** 1. row ***************************
Table: git
Create Table: CREATE TABLE `git` (
`file` VARCHAR,
`content` VARCHAR
) ENGINE=FUSE SNAPSHOT_LOCATION='53/133/_ss/efe2687fd1fc48f8b414b5df2cec1e19_v1.json'
SNAPSHOT_LOCATION
就是 HEAD,默认指向最新的快照 efe2687fd1fc48f8b414b5df2cec1e19
,那咱们如何切到 ID 为 6450690b09c449939a83268c49c12bb2
的快照数据呢?很简略,先查看以后表的 Snapshot 信息:
CALL system$fuse_snapshot('default', 'git')\G;
*************************** 1. row ***************************
snapshot_id: efe2687fd1fc48f8b414b5df2cec1e19
snapshot_location: 53/133/_ss/efe2687fd1fc48f8b414b5df2cec1e19_v1.json
format_version: 1
previous_snapshot_id: 6450690b09c449939a83268c49c12bb2
segment_count: 2
block_count: 2
row_count: 2
*************************** 2. row ***************************
snapshot_id: 6450690b09c449939a83268c49c12bb2
snapshot_location: 53/133/_ss/6450690b09c449939a83268c49c12bb2_v1.json
format_version: 1
previous_snapshot_id: NULL
segment_count: 1
block_count: 1
row_count: 1
而后创立一个新表(git_v1)并把 SNAPSHOT_LOCATION
指向相应的 Snapshot 文件:
CREATE TABLE git_v1(`file` VARCHAR, `content` VARCHAR) SNAPSHOT_LOCATION='53/133/_ss/6450690b09c449939a83268c49c12bb2_v1.json';
SELECT * FROM git_v1;
+-----------+-----------------------------+
| file | content |
+-----------+-----------------------------+
| cloud.txt | 2022/05/06, Databend, Cloud |
+-----------+-----------------------------+
Snapshot 文件
用于存储 Segment 信息,文件门路:
53/133/_ss/efe2687fd1fc48f8b414b5df2cec1e19_v1.json
文件内容:
{
"format_version":1,
"snapshot_id":"efe2687f-d1fc-48f8-b414-b5df2cec1e19",
"prev_snapshot_id":[
"6450690b-09c4-4993-9a83-268c49c12bb2",
1
],
"segments":[
["53/133/_sg/df56e911eb26446b9f8fac5acc65a580_v1.json"],
["53/133/_sg/d0bff902b98846469480b23c2a8f93d7_v1.json"]
]
... ...
}
Segment 文件
用于存储 Block 相干信息,文件门路:
53/133/_sg/df56e911eb26446b9f8fac5acc65a580_v1.json
文件内容:
{
"format_version":1,
"blocks":[
{
"row_count":1,
"block_size":76,
"file_size":360,
"location":[
"53/133/_b/ba4a60013e27479e856f739aefeadfaf_v0.parquet",
0
],
"compression":"Lz4Raw"
}
]
... ...
}
Block 文件
Fuse Engine 底层数据应用 Parquet 格局,每个文件外部有多个 Block 组成。
小结
Databend Fuse Engine 在晚期设计(2021 年 10 月)时候,需要很明确,但计划选型还是经验过一段小波折。过后,Databend 社区调研了市面上大量的 Table Format 计划(比方 Iceberg 等),过后面临的挑战是基于现有计划还是本人造一套?最终抉择研发一套简洁的、适宜本人的 Storage Engine,但数据存储格局抉择 Parquet 规范。在 Fuse Engine 里,咱们把 Parquet Footer 独自寄存,以缩小不必要的 Seek 操作,另外减少了一套更加灵便的索引机制,比方 Aggregation,Join 等都能够有本人的索引来进行减速。
欢送体验 Fuse Engine,挂上对象存储,让你体验不一样的大数据分析 https://databend.rs/doc/deploy
Databend 开源地址:https://github.com/datafusela…
对于 Databend
Databend 是一款开源、弹性、低成本,基于对象存储也能够做实时剖析的旧式数仓。期待您的关注,一起摸索云原生数仓解决方案,打造新一代开源 Data Cloud。
- Databend 文档:https://databend.rs/
- Twitter:https://twitter.com/Datafuse_…
- Slack:https://datafusecloud.slack.com/
- Wechat:Databend
- GitHub:https://github.com/datafusela…
文章首发于公众号:Databend