NoSql原理--LSM树

LSM树

LSM树(Log-Structured Merge Tree)存储引擎和B树一样,同样支持增、删、读、改、顺序扫描操作。而且通过批量存储技术规避磁盘随机写入问题。当然有利有弊,和B+树相比,LSM树牺牲部分读性能,用来大幅提高写性能。

LSM树设计思想:将数据的修改增量保持在内存,达到指定大小后将这些修改批量写磁盘,不过读取时稍微麻烦,需要合并磁盘中历史数据和内存中最近修改操作,所以写入性能大大提升,读取时可能需要先看是否命中内存,否则需要访问较多的磁盘文件。极端的说,基于LSM树实现的HBase的写性能比Mysql高了一个数量级,读性能低了一个数量级。

它的核心思路就是假定内存足够大,不需要每次数据更新就写入到磁盘,而先将最新数据驻留内存中,等积累后再使用归并排序方式将内存数据合并追加到磁盘队尾(因为所有待排序的树都是有序的,可以通过合并排序的方式快速合并)。

LSM树原理把一棵大树拆分成N棵小树,首先写入内存,随着小树越来越大,内存小树flush到磁盘,磁盘中的树定期可以做merge操作,合并成一棵大树,以优化读性能。

因为小树先写到内存,为防止内存数据丢失,写内存同时需要暂时持久化到磁盘,对应了HBase的MemStore和HLog
MemStore的树达到一定大小后,需要flush到HRegion磁盘中(一般是Hadoop DataNode),这样MemStore就变成了DataNode上的磁盘文件StoreFile,定期HRegionServer对DataNode的数据做merge操作,彻底删除无效空间,多棵小树在这个时机合并成大树,来增强读性能。

通常LSM-tree适用于索引插入比检索更频繁的应用系统。Bigtable在提供Tablet服务时,使用GFS存储日志和SSTable,而GFS设计初衷是希望通过添加新数据而不是重写旧数据来修改文件。LSM-tree通过滚动合并和多页块的方法推迟和批量进行索引更新,充分利用内存来存储近期或常用数据以降低查找代价,利用硬盘来存储不常用数据以减少存储代价。

  1. LSM具有批量特性,存储延迟。当写读比例很大的时候(写比读多),LSM树相比于B树有更好的性能。因为随着insert操作,为了维护B树结构,节点分裂。读磁盘的随机读写概率会变大,性能会逐渐减弱。 多次单页随机写,变成一次多页随机写,复用了磁盘寻道时间,极大提升效率。
  2. B树的写入过程:B树写入是一次原位写入的过程,首先查找对应块的位置,然后将新数据写入到刚才查找到的数据块中,然后再查找到块对应的磁盘物理位置,将数据写入。当然内存充足时,B树一部分可以缓存在内存,查找块的过程有一定概率可以在内存内完成。在上面的模式中,需要两次随机寻道(一次查找,一次原位写),才完成一次数据写入,代价还是很高。

LSM Tree优化方式:

  1. Bloom filter: 是个带随机概率的bitmap,可以快速告诉你,某一个小的有序结构里有没有指定那个数据。于是就可以不用二分查找,只需简单计算几次就能知道数据是否在某个小集合里。效率得到提升,但付出的是空间代价。
  2. compact:小树合并为大树:因为小树性能有问题,所以有个进程不断地将小树合并到大树,这样大部分的老数据查询也可以直接使用log2N的方式找到,不需进行(N/m)*log2n查询了

lsm tree,理论上,可以是内存中树的一部分和磁盘中第一层树做merge,对于磁盘中的树直接做update操作有可能会破坏物理block的连续性,但是实际应用中,一般lsm有多层,当磁盘中的小树合并成一个大树的时候,可以重新排好顺序,使得block连续,优化读性能。

hbase在实现中,是把整个内存在一定阈值后,flush到disk中,形成一个file,这个file的存储也就是一个小的B+树,因为hbase一般是部署在hdfs上,hdfs不支持对文件的update操作,所以hbase这么整体内存flush,而不是和磁盘中的小树merge update,这个设计也就能讲通了。内存flush到磁盘上的小树,定期也会合并成一个大树。整体上hbase就是用了lsm tree的思路。

猜你喜欢

转载自blog.csdn.net/weixin_40632321/article/details/83582617
LSM