本系列的前四章曾经对 clickhouse 的存储引擎设计的思维进行了具体解读,本章将向读者残缺地介绍 clickhouse 存储引擎的存储模型及工作机制。
文件组织
在大部分的 DBMS 中,数据库实质上就是一个由各种子目录和文件组成的文件目录,clickhouse 当然也不例外。clickhouse 默认数据目录在 / var/lib/clickhouse/data 目录中。所有的数据库都会在该目录中创立一个子文件夹。下图展现了 clickhouse 对数据文件的组织。
clickhouse 目录构造
每一个数据库都会在 clickhouse 的 data 目录中创立一个子目录,clickhouse 默认携带 default 和 system 两个数据库。default 顾名思义就是默认数据库,system 是存储 clickhouse 服务器相干信息的数据库,例如连接数、资源占用等。
上图展现了 clickhouse 通过官网提供的入门教程操作后,导入的数据库的文件模式。能够看到,在 tutorial 文件夹中,建设了两个子目录,每个子目录为即为一张数据表。进入 hits_v1 目录后又能看到两个子目录和一个文本文件。
分区目录
分区目录下的子目录和文件的含意如下:
目录名 | 类型 | 阐明 |
201403_1_10_2 | 目录 | 分区目录 一个或多个,因为分区 + LSM 生成的 |
detached | 目录 | 通过 DETACH 语句卸载后的表分区寄存地位 |
format_version.txt | 文本文件 | 纯文本,记录存储的格局 |
分区目录形成
分区目录的形成,依照 分区 ID_最小数据块编号_最大数据块编号_层级形成。在本例中,分区 ID 是 201403, 最小数据块编号是 1,最大数据库编号是 10,层级是 2。数据块编号从 1 开始自增,新创建的数据库最大和最小编号雷同,当产生合并时会将其批改为合并的数据块编号。同时每次合并都会将层级减少 1。对于合并的详情能够查看本系列的番外篇——LSM。
分区 ID 由用户在创立表时制订,容许用户创立多个分区键,每个分区键之间用‘-’相连。在本例中只应用了一个分区键,即工夫字段,依照年月分区。分区的益处在于进步并发度和减速局部查问。
### 数据目录
进入分区目录后,就能看到数据实在存储的数据目录的构造了。
### columns.txt
该文件是一个文本文件,存储了表构造信息,能够用文本编辑关上。
### count.txt
该文件也是一个文本文件,存储了该分区下的行数。能够用文本文件关上。在用户执行 select count(_) from xxx 时实质上就是间接返回了该文件的内容,而不须要遍历数据。因而 clickhouse 的 count(_) 的速度十分快。
同时,这边也比照一下 MySQL 和 PostgreSQL 的实现,在上述两个关系型数据库中,其罕用的存储引擎,都没有应用 clickhouse 的这种计划。读者们是否答复出为了 MySQL 或 pg 要舍弃简略的计划而应用遍历么?
这个问题的答案是因为事务的可见性,MySQL 和 pg 都是用 MVCC 机制的事务控制技术,这意味着对于不同事务中执行 select count(*) 的后果是不同的,对于 A 事务中执行的 insert 或 delete,对于本事务中是可见的,也就是说在本事务中执行的 count 是计算了 insert 和 delete 影响的。而对于 B 事务,在 A 事务提交前,是不能看到 A 事务中对数据的操作的。因而 AB 两个事务中执行的 count 后的后果可能是不同的。如果应用 clickhouse 的计划,就无奈实现上述需要。而 clickhouse 则不须要反对事务,因而应用了绝对简略的计划。
### primary.idx
主键索引,详情请参考本系列第四章。
### checksums.txt
二进制文件,校验和。用于疾速校验数据是否被篡改。、
### default_compression_codec.txt
新版本减少的一个文件,在旧版本时无。该文件是一个文本文件,存储了数据文件中应用的压缩编码器。clickhouse 提供了多种压缩算法供用户抉择,默认应用 LZ4。
### [column].mrk3
列的标记文件,详情请参考本系列第四章。
### [column].bin
真正存储数据的数据文件。下一节将对其对深入分析。每一列都会生成一个独自的 bin 文件。
### skp_idx_[column].idx
跳数索引,在应用了二级索引时会生成。否则这不生成
### skp_idx_[column].mrk
跳数索引标记文件,在应用了二级索引时会生成。否则这不生成
本节具体介绍 clickhouse 中存储引擎的文件组织。将一张表拆解到具体的目录和文件中,读者应该能对 clickhouse 的存储系统有了初步理解。下一节将向读者展现如何读懂数据文件。
数据组织
—-
本节将向读者展现如何读取 bin 文件。因为 bin 文件是二进制文件,在读取时须要借助工具,无奈应用文本文件进行读取。在 windows 操作系统下倡议应用 winhex,mac 零碎举荐 hex friend。
### 数据文件构造
数据文件构造
上图展现了一个 bin 文件的构造。bin 文件应用小端字节序存储。bin 文件中按 block 为单位排列数据,每个 block 文件有 16 字节校验和,1 字节压缩形式,4 字节压缩后大小和 4 字节的压缩前大小组成。每个 block 起始地址由如下公式确定:
1. offset(n)=offset(n-1)+25 + 压缩后大小(n>=2)
2. offset(1)=0
### 校验和
前 16 为测验和区域用于疾速验证数据是否残缺。
### 压缩形式
默认为 0x82。clickhouse 共反对 4 种压缩形式,别离为 LZ4(0x82)、ZSTD(0x90)、Multiple(0x91)、Delta(0x92)。
### 压缩后大小
存储在 data 区域的数据的大小。须要根据此大小计算下一个 BLOCK 的偏移量。
### 压缩前大小
data 区域存储的数据在压缩前的大小。能够根据此计算压缩比。
### data 区
data 区存储数据,大小为头信息第 18~21 字节示意的大小。拿到 data 区数据后,因为是压缩后的,因而无奈间接辨认,须要依照压缩形式进行解压缩后,能力辨认。
example
——-
下图是通过 clickhouse 通过官网提供的入门教程指引操作后,应用二进制阅读器关上 hits_v1 表的 UserAgent.bin 文件的截图,曾经对头信息进行了色彩标记。
通过读取头信息,咱们晓得该数据库是应用 LZ4 算法压缩,压缩后大小为 0x000049AC 即 18860 字节。压缩前大小为 0x00010000 即 65536 字节,压缩比约为 1:3.4≈29%。图中显示的是 AC490000,因为 clickhouse 应用小端字节序,因而理论为 0x000049AC。
接着,咱们从 data 区起始地址开始复制 18860 字节的压缩后数据,将其通过 LZ4 算法解压,能够失去原始数据,如下图所示。解压缩程序的源码曾经上传到 github, 读者能够拜访该仓库,自行下载试验。github 地址:cfcz48/lz4compress (github.com)
解压后的原始数据
接下来,咱们通过查问 columns.txt,能够看出 UserAgent 列是 UInt8 的数据类型,也就是说每个数据时无符号的 8 位整数。因而联合上一步失去的原始数据,每 8 位即为一行数据。例如 0x04 示意十进制的 4。即上图中的原始数据为 4。下图展现了前 20 位原始数据解码后的后果:
前 20 位解码后后果
咱们在用 SQL 查问前 20 位数据,看看是否统一:
总结
—
本章对 clickhouse 的存储引擎的文件组织进行了具体地阐明,并给出了一个例子,不便读者了解。下一章将为读者具体介绍数据插入的过程。