源码分析 | ClickHouse和他的朋友们(5)存储引擎技术进化与MergeTree

Clickhouse MergeTree 存储引擎架构总结——Clickhouse 架构篇(二) 存储引擎是ClickHouse非常重要的一个组件,MergeTree表引擎又是 Clickhouse 引擎中最流行的,同时 Clickhouse 之所以查询速度快,与它又密切相关。本文将对 Clickhouse 中的 MergeTree 表引擎架构设计进行说明,进而了解该引擎加速查询的原理,最后将列举 SQL 说明 MergeTree 表引擎的工作过程。 阅读详情

本文首发于 2020-06-22 21:55:10

《ClickHouse和他的朋友们》系列文章转载自圈内好友 BohuTANG 的博客,原文链接:
https://bohutang.me/2020/06/20/clickhouse-and-friends-merge-tree-algo/
以下为正文。

21 世纪的第二个 10 年,虎哥已经在存储引擎一线奋战近 10 年,由于强大的兴趣驱动,这么多年来几乎不放过 arXiv 上与存储相关的每一篇 paper。

尤其是看到带有 draft 的 paper 时,有一种乞丐听到“叮当”响时的愉悦。

看paper这玩意就像鉴宝,多数是“赝品”,需要你有“鉴真”的本领,否则今天是张三的算法超越xx,明儿又是王二的硬件提升了yy,让你永远跟不上节奏zz,湮灭在这些没有营养的技术垃圾中,浪费大好青春。

言归正传,接下来的3篇,跟 ClickHouse 的 MergeTree 引擎有关:
上篇介绍存储引擎的技术演进史,从”远古”的 B-tree 出发推演到目前主流的技术架构。

中篇会从存储结构介绍 MergeTree 原理 ,对 ClickHouse MergeTree 有一个深入的认识,如何合理设计来进行科学加速。

下篇会从MergeTree代码出发,看看 ClickHouse MergeTree 如何实现读、写。

本文为上篇,先来个热身,相信本篇大部分内容对大家来说都比较陌生,很少人写过。

地位

存储引擎(事务型)在一个数据库(DBMS)中的地位如何呢?

MySQL 的商业成功可以说大部分来自于 InnoDB 引擎,Oracle 收购 InnoDB 比 MySQL 早好几年呢!

20年前,能亲手撸一套 ARIES (Algorithms for Recovery and Isolation Exploiting Semantics) 规范引擎,实力还是相当震撼的,相信 Oracle 收购的不仅是 InnoDB 这个引擎,更重要的是人, InnoDB 作者在哪里,在干什么?!

Fork 出来的 MariaDB 这么多年一直找不到自己的灵魂,在 Server 层磨磨蹭蹭可谓是江河日下,只能四处收购碰碰运气,当年 TokuDB 战斗过的 commit 依在,但这些已经是历史了。

另,WiredTiger 被 MongoDB 收购并使用,对整个生态所起的作用也是无可估量的,这些发动机引擎对于一辆汽车是非常重要的。

有人问道,都已经 2020 年了,开发一个存储引擎还这么难吗?不难,但是造出来的未必有 RocksDB 好用?!

如大家所见,很多的分布式存储引擎都是基于 RocksDB 研发,可谓短期内还算明智的选择。

从工程角度来看,一个 ACID 引擎要打磨的东西非常之多,到处充斥着人力、钱力、耐心的消耗,一种可能是写到一半就停滞了(如 nessDB),还有一种可能是写着写着发现跟xx很像,沃茨法克。

当然,这里并不是鼓励大家都去基于 RocksDB 去构建自己的产品,而是要根据自己的情况去做选择。

B-tree

首先要尊称一声大爷,这个大爷年方 50,目前支撑着数据库产业的半壁江山。

50 年来不变而且人们还没有改变它的意向,这个大爷厉害的很!
鉴定一个算法的优劣,有一个学派叫 IO复杂度分析,简单推演真假便知。

下面就用此法分析下 B-tree(traditional b-tree) 的 IO 复杂度,对读、写 IO 一目了然,真正明白读为什么快,写为什么慢,如何优化。
为了可以愉快的阅读,本文不会做任何公式推导,复杂度分析怎么可能没有公式呢!

读IO分析

这里有一个 3-level 的 B-tree,每个方块代表一个 page,数字代表 page ID。

上图 B-tree 结构是内存的一个表现形式,如果我们要读取的记录在 leaf-8上,read-path 如蓝色箭头所示:
root-9 –> branch-6 –> leaf-8

下图是 B-tree 在磁盘上的存储形式,meta page 是起点:

这样读取的随机 IO (假设内存里没有 page 缓存且 page 存储是随机的)总数就是(蓝色箭头):

1(meta-10)IO + 1(root-9)IO + 1(branch-6)IO + 1(leaf-8)IO = 4次 IO,这里忽略一直缓存的 meta 和 root,就是 2 次随机 IO。
如果磁盘 seek 是 1ms,读取延迟就是 2ms。

通过推演就会发现,B-tree 是一种读优化(Read-Optimized)的数据结构,无论 LSM-tree 还是 Fractal-tree 等在读上只能比它慢,因为读放大(Read Amplification)问题。

存储引擎算法可谓日新月异,但是大部分都是在跟写优化(Write-Optimized)做斗争,那怕是一个常数项的优化那就是突破,自从 Fractal-tree 突破后再无来者了!

写IO分析

现在写一条记录到 leaf-8。

可以发现,每次写都需要先读取一遍,如上图蓝色路径所示。

假设这次写入导致 root, branch 都发生了变化,这种 in-place 的更新反映到磁盘上就是:

基本是 2 次读 IO和写 2 次写 IO+WAL fsync,粗略为 4 次随机 IO。

通过分析发现,B-tree 对写操作不太友好,随机 IO 次数较多,而且 in-place 更新必须增加一个 page 级的 WAL 保证失败回滚,简直是要命。

Write-Optimized B-tree

说到写优化,在机械盘的年代,大家的方向基本是把随机 IO 转换为顺序 IO,充分发挥磁盘的机械优势,于是出现一种 Append-only B-tree:

  1. 更新生成新的 page(蓝色)
  2. page 回写磁盘时 append only 到文件末尾
  3. 无需 page WAL,数据不 overwrite,有写放大(Write Amplification)问题,需要做空洞重利用机制

Append-only B-tree 节省了回写时的 2 次随机 IO,转换为常数级(constant)的1次顺序 IO,写性能大幅提升,总结起来就是:

随机变顺序,空间换时间

LSM-tree, Fractal-tree 等写优化算法的核心思想也是这个,只不过其实现机制不同。

LSM-trees

随着 LevelDB 的问世,LSM-tree 逐渐被大家所熟知。

LSM-tree 更像一种思想,模糊了 B-tree 里 tree 的严肃性,通过文件组织成一个更加松散的 tree。

这里不谈一个具体的 LSM-tree 是 Leveled 还是 Size-tiered,只谈大体思想。

写入

  1. 先写入内存的 C0
  2. 后台线程根据规则(Leveled/Sized)进行 merge,C0 –> C1, C1 –> C2 … CL
  3. 写入 C0 即可返回,IO 放到后台的 Merge 过程
  4. 每次 Merge 是硬伤,动作大就抖,动作小性能不好,每次 Merge 的数据流向不明确
  5. 写放大问题

读取

  1. 读取 C0
  2. 读取 C1 … CL
  3. 合并记录返回
  4. 读放大问题

Fractal-tree

终于发展到了“终极”优化(目前最先进的索引算法),Fractal-tree。
它是在 Append-only B-tree 的基础上,对每个 branch 节点增加了一个 message buffer 作为缓冲,可以看做是 LSM-tree 和 Append-only B-tree 完美合体。

相对于 LSM-tree 它的优势非常明显:
Merge 更加有序,数据流向非常分明,消除了 Merge 的抖动问题,大家一直寻找的 compaction 防抖方案一直存在的!

这个高科技目前只有 TokuDB 在使用,这个算法可以开篇新介,这里不做累述,感兴趣的可以参考原型实现 nessDB。

Cache-oblivious

这个词对于大部分人都是陌生的,不过别怕。

在存储引擎里,有一个数据结构非常非常重要,它负责 page 数据有序性维护,比如在一个 page 里怎么快速定位到我要的记录。

在 LevelDB 里使用 skiplist,但大部分引擎使用的是一个有序数组来表示,比如 [1, 2, 3, … 100],然后使用二分查找。

大概 10 年前一位内核开发者发表了一篇 <You’re Doing It Wrong>,这个小文讲了一个很有意思的事情:
数据的组织形式对性能有很大的影响,因为 CPU有 cache line。

抛开这篇文章不谈,咱们来看一张“神仙”图:

这是一个 binary-tree 的 4 种 layout 表示形式,那么哪种 layout 对 CPU cache line 最友好?

也许你已经猜对了,那就是 van Emde Boas,简称 vEB。
因为它的相邻数据“扎堆”存储,point-query 和 range-query 的 cache line 可以最大化共享,skiplist 对 cache line 是非常不友好的,还可以更快!

对于 cache oblivious 数据结构,这里有一个简单的原型实现: omt

B-tree优化魔力象限

写优化算法从原生的 B-tree 到 Append-only B-tree(代表作 LMDB),又到 LSM-tree(LevelDB/RocksDB 等),最后进化到目前最先进的 Fractal-tree (TokuDB)。

这些算法耗费了很多年才在工程上实现并被认可,研发一款存储引擎缺的不是算法而是“鉴宝”的能力,这个“宝”可能已经躺了几十年了。

其实,”科学家”们已经总结出一个 B-tree 优化魔力象限:

横坐标是写性能,纵坐标是读性能,B-tree 和 Logging 数据结构分布在曲线的两个极端。

B-tree 的读性能非常好,但是写性能差。
Logging 的写性能非常好,但是读性能差(想想我们每次写都把数据追加到文件末尾,是不是很快?但是读…)。

在它们中间有一个优化曲度(Optimal Curve)。
在这个曲度上,你可以通过增加/减少一个常数(1-epsilon)来做读和写优化组合,LSM-tree/Fractal-tree 都在这个曲度之上。

总结

本文主要讨论事务性引擎的技术演进,其中包含了 IO 复杂度分析,其实这个分析是基于一个 DAM(Disk Access Machine) 模型,这里不再展开。
这个模型要解决什么问题呢?

如果工程中涉及硬件层级关系,比如 Disk / Memory / CPU,数据在Disk,读取(以 block 为单位)到 Memory,查找计算(cache-line)在 CPU,不同介质间性能差距又非常之大,我们怎么做才能让整体性能更优的问题。

和当今的硬件相融合,这个模型也一样适用。

最后回到 ClickHouse 的 MergeTree 引擎,它只使用了本文中的部分优化,实现也比较简洁、高效,毕竟没有事务,撸起来也没啥心理负担。

随机变顺序,空间换时间, MergeTree 原理,请听下回分解。

References

[1] Cache-Oblivious Data Structures
[2] Data Structures and Algorithms for Big Databases
[3] The buffer tree: A new technique for optimal I/O-algorithms
[4] how the append-only btree works
[5] 写优化的数据结构(1):AOF和b-tree之间
[6] 写优化的数据结构(2):buffered tree
[7] 存储引擎数据结构优化(1):cpu bound
[8] 存储引擎数据结构优化(2):io bound
[9] nessDB
[10] omt


欢迎关注我的微信公众号【数据库内核】:分享主流开源数据库和存储引擎相关技术。

标题网址
GitHubhttps://dbkernel.github.io
知乎https://www.zhihu.com/people/…
思否(SegmentFault)https://segmentfault.com/u/db…
掘金https://juejin.im/user/5e9d3e…
开源中国(oschina)https://my.oschina.net/dbkernel
博客园(cnblogs)https://www.cnblogs.com/dbkernel
ClickHouse引擎详解 共同属性数据存储在磁盘上 写入时将数据追加在文件末尾 不支持突变(Mutation)操作 不支持索引(这意味着。 阅读详情

相关推荐

Logistics_Day15:ClickHouse 存储引擎

ClickHouse提供了多种不同的表引擎,表引擎可以简单理解为不同类型的表。表引擎(即表的类型)决定了:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B5VQFSQv-1641169977011)(/img/1616662005733-1622626089308.png)]文档:https://clickhouse.tech/docs/zh/engines/table-engines/1)、MergeTree引擎(合并树及系列引擎)

Maynor的博客 995

Clickhouse 存储引擎

这个引擎是在 MergeTree 的基础上,添加了”处理重复数据”的功能,该引擎和MergeTree的不同之处在于它会删除具有相同主键的重复项。特点:1使用ORDERBY排序键作为判断重复的唯一键2.数据的去重只会在合并的过程中触发3.以数据分区为单位删除重复数据,不同分区的的重复数据不会被删除4找到重复数据的方式依赖数据已经ORDER BY排好序了5.如果没有ver版本号,则保留重复数据的最后一行6.如果设置了ver版本号,则保留重复数据中ver版本号最大的数据。

qq_16803227的博客 1520

【精华收藏】ClickHouse 系统架构、存储引擎、 查询引擎原理分析

ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。

AI天才研究院 1万+

ClickHouse基础知识(四):ClickHouse 引擎详解

(2)向表中插入数据。

zuodingquan666的博客 2443

Data Structures and Algorithms for Big Databases

I/O model and cache-oblivious analysis Write-optimized data structures How write-optimized data structures can help file systems Block-replacement algorithms Indexing strategies Log-structured merge trees Bloom filters

如果使用ssms连接SQLserver的时候出现无法连接到服务器。

如果使用ssms连接SQLserver的时候出现无法连接到服务器。 Lan 2020-03-29 22:11 329 人阅读 0 条评论 标题: 连接到服务器------------------------------无法连接到...

Vastsa的博客 1万+

2021-01-13

数据分析task1 一.任务说明 二.数据集介绍 三.arxiv论文类别介绍 四.具体代码以及一定讲解 4.1导入package并读取数据 4.2定义函数 4.3数据预处理 4.4数据分析及可视化 五.总结 一.任务说明 任务主题:论文数量统计,即统计2019年全年计算机各个方向论文数量; 任务内容:赛题的理解、使用 Pandas 读取数据并进行统计; 任务成果:学习 Pandas 的基础操作; 二.数据集介绍 数据集来:[link]https://cdn.coggle.club/arxiv-metadat

weixin_54555987的博客 281

ShardingSphere-JDBC-若依框架集成(SpringBoot)

ShardingSphere基础知识、ShardingSphere-JDBC如何集成进若依框架中 使用的是若依框架前后端版本、动态数据源,可自行切换,默认数据源为达梦8代理端,

编程小菜鸟的笔记 8168

源码分析 | ClickHouse和他的朋友们(6)MergeTree存储结构

本文首发于 2020-06-30 21:41:12上篇的 存储引擎技术进化与MergeTree 介绍了存储算法的演进。存储引擎是一个数据库的底盘,一定要稳和动力澎湃。接下来我们将一起来探索下 ClickHouse MergeTree 列式存储引擎,解构下这台“跑车”最重要的部件。所有的存储引擎,无论精良与粗制滥造,最终都是要把数据回写到磁盘,来满足存储和索引目的。磁盘文件的构造可以说是算法的物理体现,我们甚至可以通过这些存储结构反推出其算法实现。所以,要想深入了解一个存储引擎,最好的入手点是它的磁盘存储结构

dbkernel 的博客 286

Feko仿真GPS微带天线学习笔记

为了优化方便,使参数变量化,所以定义几个变量在CADFEKO左侧浏览器中如图所示定义变量,如下表贴片的尺寸切角尺寸feed =-6.4馈电点距坐标原点的距离sub_w=45基板的宽度sub_d=45基板的长度sub_h=5基板的高度epsR=5.6介电常数损耗角正切。

qq_36521926的博客 3992

ENVI新手避坑指南:手把手教你搞定遥感影像的坐标系转换(附ArcGIS对比)

本文详细解析ENVI与ArcGIS在遥感影像坐标系转换中的关键差异与实战技巧,特别针对新手常见问题提供避坑指南。从基础概念到高级操作,涵盖定义投影、UTM转换等核心步骤,并对比两种软件的处理精度与效率,帮助用户高效完成遥感影像处理任务。

weixin_42531925的博客 380

ClickHouse源码简析

ClickHouse源码简析

driftingman的专栏 1787

芯片设计中的setup和hold检查:为什么你的电路会跑飞?

本文深入解析了芯片设计中Setup与Hold检查的核心原理,它们是确保电路可靠运行的“黄金窗口”。通过剖析触发器物理本质、时序路径公式及检查方法,解释了Setup违例(数据太慢)和Hold违例(数据太快)如何导致电路“跑飞”,并提供了从RTL优化到物理实现的实战修复策略与协同优化技巧。

weixin_29268267的博客 478

ClickHouse 的存储引擎

核心机制:数据按分区键(PARTITION BY)水平分割,按主键(ORDER BY)排序存储,支持高效的范围查询和聚合。预聚合优化:在后台合并分区时自动聚合数值(如 SUM、COUNT)或预计算状态(如 uniqState),加速聚合查询。去重机制:按主键合并分区时保留最新版本数据,适用于时序数据更新(如用户状态变更)。每个 part 包含列文件(.bin)、索引(.idx)和标记文件(.mrk)。优势:列式存储 + 数据压缩(如 LZ4/ZSTD),显著减少 I/O 开销。

weixin_43346403的博客 651

R语言vegan包实战:用varpart函数搞定生态学VPA分析(附完整代码与数据集)

本文详细介绍了如何使用R语言vegan包中的varpart函数进行生态学方差分解分析(VPA),包括数据准备、模型构建、结果解读和可视化呈现。通过完整的代码示例和数据集,帮助研究者理解不同环境因子对生物群落变化的相对贡献,并掌握显著性检验等高级技巧。

weixin_42525005的博客 450

PreScan快速入门到精通第二十一讲驾驶员模型之驾驶员在环

请注意,操纵杆的输出角度是以度为单位的,而方向盘执行器希望其输入是以弧度为单位的。当选择一个支持的方向盘时,PreScan会自动将按钮映射到正确的功能上(如换挡),并设置轴的正确范围(如转向角度)。该系统中的所有其他组件都是为了提供正确的按钮映射,并为所选的方向盘设置正确的范围。对于每一个额外连接的控制器,它们的ID会增加一个,例如第二个控制器的设备ID为1,第三个控制器的设备ID为2,等等。由于所有的方向盘最初放在编译表上的设备ID都是0,所以用户应该先进行正确的调整,将每个控制器设置为正确的设备ID。.

小明师兄的博客 1424

【基础篇】ClickHouse 表引擎详解

Clickhouse 表引擎(Table Engine)是一种数据库管理系统中的关键部分,负责存储数据、读取数据和处理数据查询。不同的表引擎具有不同的性能特性和适用范围。在某些数据库系统中,例如MySQL,你可以为每个表选择不同的表引擎,包括InnoDB,MyISAM,Memory等。这些表引擎在功能、性能、并发能力、恢复能力等方面都有所不同。在ClickHouse中,表引擎的选择将影响数据的存储格式、索引的使用、并发控制机制、是否支持数据复制等许多重要的方面。表引擎(即表的类型)决定了什么。

日拱一卒无有尽,功不唐捐终入海 2545

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

ClickHouse中引擎相关知识

1. 了解ClickHouse的基础架构和存储引擎。 2. 学习ClickHouse的MergeTree系列引擎,包括MergeTree、ReplicatedMergeTree、CollapsingMergeTree等。 3. 研究ClickHouse的列存储编码、数据压缩策略等。 4. 学习ClickHouse的计算引擎,包括向量化执行模型、SIMD编码、Codegen等。

lang830349821的博客 1261

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Clickhouse存储引擎的存储模型及工作机制

Clickhouse存储引擎的存储模型及工作机制 本章将向读者完整地介绍clickhouse存储引擎的存储模型及工作机制) 文件组织 在大部分的DBMS中,数据库本质上就是一个由各种子目录和文件组成的文件目录,clickhouse当然也不例外。clickhouse默认数据目录在/var/lib/clickhouse/data目录中。所有的数据库都会在该目录中创建一个子文件夹。下图展示了clickhouse对数据文件的组织。 每一个数据库都会在clickhouse的data目录中创建一个子目录,clickh

Deepexi_Date的博客 897

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

ClickHouse的介绍(基本sql操作,以及数据库引擎、表引擎、分片、副本、explain、优化、物化视图等)

ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),使用C++语言编写,主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。列式存储以下面的表为例:1)采用行式存储时,数据在磁盘上的组织结构为:好处是想查某个人所有的属性时,可以通过一次磁盘查找加顺序读取就可以。但是当想查所有人的年龄时,需要不停的查找,或者全表扫描才行,遍历的很多数据都是不需要的。2)采用列式存储时,数据在磁盘上的组织结构为:这时想查所有人的年龄只需把年龄那一列拿出来就可以了。3

迷雾总会解 4万+

ClickHouse之MergeTree引擎!

删除老数据的操作是在分区异步merge的时候进行处理,只有 同一个分区的数据才会被去重,分区间及shard间重复数据不会被 去重,所以应用侧想要获取到最新数据,需要配合argMax函数一 起使用。Summin gMergeTree 当合并SummingMergeTree表的数据片段时,ClickHouse会把所有 具有相同主键的行进行汇总,将同一主键的行替换为包含sum后的 一行记录。如果主键的组合方式使得单个键值对应于大量的行,则 可以显著的减少存储空间并加快数据查询的速度。

qq_23827347的博客 714

clickhouse表存储引擎

ClickHouse 的是其核心特性之一,不同引擎针对不同 OLAP 场景做了极致优化,决定了数据的存储方式、写入 / 查询逻辑、生命周期管理等核心行为。

bobozai86的博客 726

Clickhouse 外部存储引擎

外部存储引擎分类 MySQL引擎 PostgreSQL引擎 MongoDB引擎 JDBC引擎 ODBC引擎 Kafka引擎 RabbitMQ引擎 File引擎 URL引擎 HDFS引擎

骑个小蜗牛的博客 1994

ClickHouse存储引擎初识

本文介绍了ClickHouse中的几种主要存储引擎:MergeTree、ReplicatedMergeTree、SummingMergeTree、AggregatingMergeTree和Distributed,以及它们的工作原理、使用场景和优缺点。了解这些存储引擎有助于您根据实际需求选择合适的引擎,从而充分利用ClickHouse的强大功能。

weixin_59801183的博客 1298

ClickHouse存储引擎

对ClickHouse存储引擎的汇总

laiteng123的博客 582
上一篇: 源码分析 | ClickHouse和他的朋友们(4)Pipeline处理器和调度器
下一篇: 源码分析 | ClickHouse和他的朋友们(6)MergeTree存储结构
dbkernel
博客等级 码龄4年 60粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值