随着使用数据库的深度和理解能力的提升,有一个问题硬件的提升,与数据量的变化是否对数据库底层的架构有冲击。 我们公认的BTREE B+TREE 是否还能面对现在的硬件的变化。
BTREE 到底是为那种硬件逻辑来服务的,这点是需要搞清楚的
在MYSQL 中使用的B+TREE的改进版中底层的数据也是有指针的,便于数据顺序的读取和查找。但在怎样写入一次数据,需要分两次写入,这是B+TREE本身结构所需要的。
在数据的读取中,磁头读取数据的速度是非常快的,纳秒基本上服务器级别的磁盘是可以达到的,但慢在磁头的移动,最近忘记哪家公司了,希捷还是西数发明了双向磁头,宣称数据读取的速度提高了200%. 所以B+TREE 要解决的主要问题就是我们的传统磁盘的性能问题,通过优化数据结构来提高一次数据的尽量不要偏移磁头,一次磁头能读取的数据越多,越准确越好。
所以无论是ORACLE ,SQL SERVER ,PG , MONGODB , MYSQL 的数据块的索引均都支持 B+TREE的类型,并且有点数据库就仅仅有这一种数据结构。
时代不同了,SSD 已经很多年了,虽然价格和传统磁盘相比还是太高,但你敢说你最近两年内买的笔记本上没有他的身影。硬件的变化并不是和部分人想的,仅仅是系统性能的提高,数据的读取的效率提高。
硬件推动的很可能是某个工作的消失,甚至是某种数据结构的淘汰。例如原先某个SQL 优化的工作,由于更换了更快的CPU ,更大的内存, SSD 磁盘系统,原先很烂的SQL 不在是问题,你优化的“事业”,就此葬送在硬件的更新换代上。
所以害死?的,并不一定是卖猪肉的,很可能是因为牛肉更便宜了。BTREE 是为传统磁盘来服务的,那SSD 磁盘对于 BTREE的方式可能并不感冒,如果你使用的SSD 磁盘, POSTGRESQL 中的某些配置文件中的某些参数都有可能要大动干戈。
Unfortunately, standard disk-based index structures such as the B-tree will effectively double the I/O cost of the transaction to maintain an index such as this in real time, increasing the total system cost up to fifty percent. Clearly a method for maintaining a real-time index at low cost is desirable. The Log-Structured Merge-tree (LSM-tree) is a disk-based data structure designed to provide low-cost indexing for a file experiencing a high rate of record inserts (and deletes) over an extended period.
LSM tree 的目的,上面的截图的文字中,BTREE 会连浪费I/O COST ,所以LSM tree 这样的数据结构为了就是,高并发的写入而准备的。
下面就引入一个Knowledge Sharing, Why LSM Tree Fast
首先我们需要确认LSM 要解决一个什么问题,更快速的写,更快速的读,并且是大量的数据的情况下。
LSM 的主体思想可以这样来表达,数据首先写入到buffer 然后当达到一个阈值的情况下,将数据顺序整理后刷新到磁盘中。(由于在内存中预先整理,所以顺序写的速度,在传统磁盘中也是很快的)
那这样的情况下,就会产生另外一个问题,读数据的困难,写是有序写入并且有内存进行批量的数据刷新,这放到哪个地方都是提升写性能的一种方式,但数据要被读取的时候,就会产生一个问题,我怎么去找到我的数据。如果顺序的去查找,那将.......
那么怎么提升读的性能就是LSM TREE 要考虑的事情,我们可以利用bloom 过滤器,bloom 过滤器常常用在大数据量中的数据排除的活动,这是Bloom 过滤器的特性(之前写过一篇关于bloom 过滤器,应该是和postgresql有关的一篇文字),这里简单的一句话bloom说你要查找的值没有,他一定没有,但如果他说有,有可能是错误,但问题是他的速度是非常快的,所以通过bloom过滤器,加上一个内存buffer 指针(保存实际的数据的物理地址,这里可以理解为index)来进行数据的读取,原则上是可以增加数据的读取的速度和准确度
并且在这个期间,是要对磁盘中的文件进行merge的,如何merge 以及 merge的 频率就会直接影响整套系统的,是更偏向于写入的性能还是读取的性能
这里稍微的小结一下,Btree 我们知道,由于数据的插入需要符合B+TREE的原理的,所以一定会有数据的空点(页面会split or merge),但LSM TREE 对数据空间的利用率要比B+TREE 干脆的多。
具体LSM tree 在磁盘上的文件的实现SSTable,相信稍微懂一点cassandra的同学对这个名词是不会陌生的,SSTABLE可以理解为是磁盘驻留的有序不可变数据结构。从结构上看,SSTable分为两部分:数据块和索引块(请看下图),数据块由按键顺序写入的唯一键/值对组成。索引块包含映射到数据块指针的键,这些键指向实际记录所在的位置。索引可能是B-tree,或者散列表来实现查询。SSTable中的每个值项都有一个与之关联的时间戳,标记了插入时间。SSTables是从键到值是持久的、有序的、不可变的映射,其中键和值都是任意的字节字符串
由于SSTable是不可变的,插入、更新或删除操作将需要重写整个文件,主要它是针对读、顺序写进行优化的,没有预留空间允许任何就地修改,用大白话讲就是这个SSTABLE 的磁盘数据存储的结构,会跟随着数据的变动不停的进行刷新合并操作。所有的Insert 操作还是Insert 操作,所有的UPDATE 操作也可以理解为insert NEW 的操作,delete 的操作也是记录一个标记,在下次文件合并的过程中,会将其去,也可以称这个过程叫压缩。(也就是一KEY VALUE数据会有多个版本)
此时会重提上面提到的两个问题,1 为什么要有时间戳的概念,时间戳的概念主要是在合并时,如有相同的数据,以时间戳最后的为准 2 合并会增加数据的顺序性,让后面的数据查找更快速。
写到这里不能不终止了,因为没有人愿意去看一篇长篇大论,并且毫无乐趣,因为一篇文字是需要点冲突点,来引起人们阅读的兴趣。
那下面的冲突点, LSM TREE 和 BTREE 之间的不同点在哪里
1 BTREE 是固定,一个页面可以从2KB - 32KB大小,具体要和磁盘的结构吻合。
2 LSM TREE 则设计是没有这样固化的概念
1 B+TREE 可以在PAGE 页内部进行修改更新,删除。
2 LSM-TREE 的操作可以理解为 insert new , append one
1 B+TREE 对数据读取的支持是高效的,尤其对于顺序读的操作,维护B+TREE的操作会不断的分裂和合并,随机的读写的操作的性能随着数据的增加,会降低
2 LSM-TREE 本身写入的特点,支持高容量的高并发的写操作,这是一个分布式系统可能更加看重的,本身读取数据的效率是随着相关索引的优化来进行改变的,理论上读的碎片也可以接近于 B+TREE。
这里就引出了另一个话题,LSM-TREE的合并操作会占用大量的CPU 和I/O ,这难道不会影响系统性能,OK, 所以及回到这篇文字的开头,一个硬件的是可能改变一个数据库的底层架构,让其在某些情况下让某些不可能,变为可能。