引子
最近一两年里,每次做分布式数据库的内容分享活动时,总是会提及现在数据库的两个重要的存储结构,B-TREE和LSM-TREE。因为,我觉得作为数据库的存储根基,无论是要选型,或者是用好一个数据库,清楚这两的差别和各自特点,都特别重要。但是几乎每一次都只能提一下,哪种数据库用了哪个存储。再多就是稍微介绍LSM-TREE的写入友好。对于有些朋友,正面临二选一项目抉择时,这点信息显然是不够的。于是他们会想要知道,更多二者差异细节,以及到底哪一种适合自己的系统。可惜我总是只能遗憾讲个大概,并解释要彻底讲清楚的话,整个分享就只能光讲这个可能时间还不太够。然而,我还是觉得每次都含含糊糊的过去,未免也有点耍流氓的感觉。总得找个机会,把这里面一些有意思的内容拿出来罗列一下。适逢国庆宅家,想想也是时候把这个坑给填一填了。
当然,本文并不打算从0开始介绍LSM-TREE,那样篇幅也太冗长了。本文默认各位读者具有一点B-TREE和LSM-TREE的基础背景知识。
背景板-分布式关系型数据库
其实,抛开分布式数据库来纯写这两个存储引擎,似乎要更加简明一点。但是,这样的话实用性不太行。单机版LSM-TREE数据库有排名在100名左右的ROCKSDB,LEVELDB。它们被划分为KEY-VALUE类型,而且它们通常不会直接出现在我们的视野,也极少直接被使用在项目中。然而,基于LSM-TREE的分布式数据库则是非常常见的,比如这些:
甚至可能有些人,是有用分布式数据库的需求,才去学习和理解LSM-TREE的(比如说我就是先要使用CASSANDRA)。不过带上分布式的这个背景,未免多少会使得存储结构差异比对,变得不那么纯粹。因为分布式数据库嘛,总是带来了一些额外的开销。比如说数据库层面的SQL解析到分布式执行计划产生。再比如说分布式的场景下,分布式事务、全局时间戳获取等等。不过这个还是可以大致对比一下基于B树的分布式数据库情况来说明一下。但就具体到每一个数据库的话,因为各个数据库的具体实现方式各有不同,实际情况就得看某一个具体的数据库还做了些什么额外的动作,再把它附加上去。
还有关系型也算是一个重要背景。因为有些特殊项目场景、特殊的数据格式,使用某种数据库或者存储结构时快得飞起,然而却缺乏了一般通用性。其实,像REDIS和CASSANDRA这样的数据库已经非常的热门,使用范围也非常的广。但是我们在项目中使用这些数据库,也还是充当某种功能性的角色比较多,我们很难把它做成系统的主数据库。尤其是那些有历史包袱迁移而来的系统。无论如何,关系型模型,基本上还是我们见到的主要情况。
所以我准备在分布式和关系型的数据库大背景下,以最为常见的几种数据访问形态来描述一下,这样就更加具有真实的参考性价值。先摊开来数据库的主要操作都做了些什么。然后再套几个经典的案例场景进去看看。这样子的话,围绕着分布式关系型数据库来展开这两颗树的内容,也就更贴近大家现实使用这两存储结构的实际需求,起码我感觉上是如此。
在开始眼花缭乱的各种操作叙述之前,我们可以先草率的做一点假定。比如说,我们SQL的响应时长,认为是最关键的性能指标。比如说,我们认为内存中的操作比较快,对性能的影响稍微小一些。而磁盘操作比较慢,比较可能影响交易时长。再比如,异步动作,基本不怎么影响交易性能。这些假定虽然草率,但是我认为这可以使我们对一些数据库操作的性能开销,有一些更粗暴而直观的感性认知。
LSM-TREE之优势的写
写友好,几乎是LSM-TREE的标志性特点,那么我们就从写流程开始。先来个经典的LSM-TREE的图。
STEP 1 WAL日志写入(Write Ahead Log)。*磁盘操作。
这个步骤基本上各个数据库都有,有各种各样的叫法。比如说Innodb的Redo log,Cassandra 的Commit logs。但是,作用都是一样的,在数据库宕机之后,这份日志可以保证数据的恢复。而这个日志,都是以顺序写入的方式不断追加。所以,感觉上,这部分开销应该是非常的接近的。
我觉得MYSQL的BINLOG也可以放在这里提一下,从严格意义上来说,BINLOG不属于存储引擎而是属于MYSQL,它与B-TREE这个存储结构没有必然关系。功能上来看,我觉得它有点接近某些数据库的归档日志。它开销是显然有的,但是我觉得应该把这笔账算在高可用的头上去。
STEP 2 树数据结构维护。
有观点说B-TREE至少要写两