感时花溅泪,恨别鸟惊心。
1 前言
在前文 OceanBase分布式云数据库实践 中提到了 OceanBase
的数据存储结构使用的是 LSM-tree
即日志结构合并树 (Log-Structured Merge Tree
), 随着对众多分布式数据库的了解,使用 LSM-tree
数据结构的数据库还挺多,于是便深入了解一下这个数据结构。众所周知,常用的 mysql
数据库使用的是 b+tree
这种索引结构来实现数据的快速查找,当数据量不大时,这种数据结构对数据的读写支持表现优秀,但是在大量数据时,b+tree
的数据层级会越来越高,此时数据的更新和删除会引发页分裂和页合并,严重的影响了数据的写入性能,需要在适当的时候进行索引重建,释放树结构中的空空间用于提高性能。
LSM-Tree
是一种新的分布式存储系统模型,这种架构设计将顺序写发挥到极致,诸多的数据库如 OceanBase、 HBase、 LevelDB、 PolarDB、 TiDB
都是使用 LSM-Tree
来组织数据结构。
2 基本原理
如下图所示, LSM-Tree
主要由内存数据和磁盘数据组成,在内存中有一个 memtable
和多个 immutable
组成,在磁盘中由多层级的 sstable
组成。 level
越小表示该 level
的 sstable
数据越新, level
层级越高则表示数据越旧,数据的层级 level
大小可以由系统指定。通常情况下,磁盘中的最小级数为 level0
, 但是也可以把内存中的 immutable memetable
定义为 level0
, 磁盘中的层级从 level1
开始。
WAL(write ahead log)
, WAL 是一个以追加的方式记录日志的一个机制。这个机制在数据库中是一个常用的机制,是在操作数据之前先记录日志,以便在系统宕机重启数据时进行数据的恢复。
memtable
是一个有序的数据结构(跳表、有序数组、红黑树或者二叉搜索树) ,这个结构一般是在内存中存在。
sstable
一般是一组 block
元数据组成,元数据 block
存储了 sstable
数据的描述信息,如索引、压缩信息,统计信息,bloomfilter
等信息, sstable
的信息是有序的,一旦写入不能修改。
3 lsm-tree 数据写入
在前文中已经介绍了 LSM-Tree
的基本原理,那么 LSM-Tree
是如何写入数据的呢?
当写入数据时,需要先写入一条 WAL log
日志记录,然后将数据写入内存中的 memtable
,这样写入的操作即完成了。 写入的过程和修改的过程都是一样的,删除数据时,则是写入该数据的一条删除标记。当 memtable
的大小达到设定的值(一般是 64KB)时, LSM-Tree
会把当前的 memtable
冻结成为一个不可修改的 immutable memtable
,然后创建一个新的 memtable
继续接受数据的新增、修改和删除。同时 LSM-Tree
会有一个异步线程负责将 immutable memtable
刷新(flush)到磁盘中对数据进行持久化。完成持久化后,即可将该数据对应的 WAL
日志从磁盘中删除。内存中的 immutable memtable
数量取决于 flush
操作的速度。
从数据的写入过程来看,过程比较简单且操作简便,只需要写入 WAL
日志 和内存中的 memtable
即可,WAL
日志是顺序写入的,所以写入速度很快,memtable
的结构一般是二叉搜索树,由于其数据规模小,所以其写入的速度还是很快的。对于 mysql
数据库,其写入的速度随着数据的规模变大而减慢,但是对于 LSM-Tree
结构,其写入的单元是 memtable
,所以数据的规模不影响其写入的速度。
4 lsm-tree 数据读取
了解了 LSM-Tree
的数据写入过程,如果一个数据更新过多次,那么数据将存在多个不同的 sstable
中,在查找数据时,需要按顺序从 level0 到 levelN
进行查找,直到查找到所有的数据位置,读取的数据以低级别的 sstable
为准,因为最新的修改都是在低级别的 level
中。为了提高数据读取的性能,LSM-Tree
采用了 sstable
压缩、布隆过滤器 bloomfilter
、 缓存、sstable
合并(compaction
) 等操作来提高其读数据性能。
从这个过程可以知道,其读取的数据过程比较复杂和繁琐,随着 level
层级的提高,其读取的数据也会增加。因此,LSM-Tree
支持将多个 sstable
合并成为一个新的 sstable
,在合并的过程中会物理删除被删除的数据,将多个修改合并成一个修改,这个过程和 jvm 垃圾回收算法中的标记整理算法类似,这个过程会增加磁盘IO 和 CPU 的消耗,因此该过程需要在业务低峰期进行。
5 总结
LSM-Tree
主要是牺牲部分读取性能为代价提高了写入性能,适用于时序数据库类的写多读少的场景。 LSM-Tree
主要利用磁盘顺序访问要比随机访问快的多的思想以提高写入性能。分布式数据库采用了 LSM-Tree
高效的数据写入特性,同时优化了其数据读取性能,同时充分利用了内存存储的廉价性。相比 mysql
数据库的 b+tree
数据结构,LSM-Tree
提高了分布式数据库的性价比。