大话LSM Tree

http://f.dataguru.cn/thread-24939-1-1.html

首先请大家自己解读下下面两句话的含义:
任何一种排序算法都是在一定的问题背景下提出来的。 ——XXX大学的数据结构老师
没有完美的犯罪   ——XXX神探
平衡是系统设计的一种美   ——我是这么想的

内存的高效性是lsm的结构基础,我们在访问数据的时候速度肯定是内存大于磁盘的,这样的话为什么不全用内存呢?原因大家自己考虑下就行了,所以权衡下来还是需要用硬盘的,那么为了实现数据的快速插入和查询,存储应该怎么设计呢?学过oracle的同学都应该知道,要使一个表对查询的响应比较快,那么最主要的手段就是索引,但是索引多了就会影响数据插入的速度,这也是一种平衡,下面我们将分析lsm,看看它是设计了个完美的解决方案吗?

在讨论这个问题之前,让我们看下lsm tree解决了什么问题:
答案就是减少数据频繁的插入、修改、删除操作所需要的磁盘I/O次数

学过数据结构的同学都知道Btree树是很多索引的优先选择结构,b tree树访问的时间复杂度接近Logm(N/2),我们可以计算下,在成百上千的索引节点下,即使索引十几亿的数据,那么树的深度也不会很深的,应该是10以内吧,再加上对于lru算法的支持,可以很明显的减少io,那为什么hbase不用这个结构呢,答案就是本文开头的几句话。
因为hbase中数据插入是比较随机的或者说是无序的,在查询数据的时候回到索引上,也就是对于某个叶子节点的访问是很随机的,这个场景很重要,那么我们根据这个具体场景分析一下b+树,因为查询是随机的,那么也就是说我们上次调入内存的数据可能很久以后都不会被访问,所以lru算法失去了它的价值,主要的系统开销变成了访问B+树的io了,内存的命中率很低,对于插入数据来说道理是一样的。

下面我们再看看lsm tree是怎么做的:
lsm构造许多小的结构,每个结构在内存里排序一下构成内部有序,查询的时候对每个小结构就可以采用二分法高效的查找定位,我们都知道有序的东西查找起来速度肯定比无序的快,如果只是这么设计肯定不能达到快速插入和查询的目的,lsm还引入了Bloom filter和小树到大树的排序。
Bloom Filter是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合。Bloom Filter的这种高效是有一定代价的:在判断一个元素是否属于某个集合时,有可能会把不属于这个集合的元素误认为属于这个集合(false positive)。因此,Bloom Filter不适合那些“零错误”的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter通过极少的错误换取了存储空间的极大节省。
关于Bloom filter的详细请大家自己google。
Bloom filter在lsm中的作用就是判断要查询的数据在哪个内存部件中,或者要插入的数据应该插入到哪个内存部件中。
小树到大树的排序是为了节约内存,做开发的同学应该都明白内存中宝贵,同时也是为了恢复,因为我们知道hbase的delete和update其实都是insert,这都是由lsm的特点决定的,新的数据会被写到磁盘新的位置上去,这样就保证了旧记录不会被覆盖,在系统crash后的恢复过程会很有用,只要按日志顺序恢复就ok了。
说了半天没说什么是lsm tree:
LSM-Tree通过使用一个基于内存的组件C0和一至多个基于磁盘的(C1, C2, …, CK)组件算法,对索引变更进行延迟及批量处理,并通过归并的方式高效的将更新迁移到磁盘。

下面我们看一下两组件算法的具体实现:
如下图
1.png 
当我们进行插入操作的时候,首先向日志文件中写入一个用于恢复该插入的日志记录,然后去写这条记录,把这个记录的索引放在c0树上,一段时间之后,把这个索引节点放到c1树上,对于数据的检索现在c0上,然后在c1上,这是肯定会命中的,由于内存的限制,所以c0不能太大,这就要求一定大小时要把c0中的某些连续节点merge到c1上,如下图
2.png 
磁盘上的c1是类似于b-树的结构,这个结构也被优化过,针对磁盘的块属性和访问的顺序性做了专门的优化。那么c0树是b-树吗?
相信很多人关心,当然也是贯性思维,其实不是的,因为为了能快速删除节点(为了merge)和查询,设计成b树是没有必要的,普通的avl也可以的。

多组件算法其实和两组件的类似,因为2-n从来就不是个问题,图如下:
3.png 
论坛中也有很多同学用了上面的这几幅图,说的也是很详细的,可以仔细阅读下,我在这里不费口舌了。


下面讨论下lsm tree的插入和删除:
插入的时候先生成唯一值来确保索引的唯一,生成的规则很大程度上决定了查询的规则,然后写日志,最后批量把数据写入硬盘,批量有两个含义就是延迟和合并。
删除其实也是批量的思想,就是先写日志,然后标记延迟、最后合并的时候清除。

lsm tree之所以能够做批量得意于它的日志设计。
任何的算法都有它适用的具体场景,或是具体的问题域,所以更多的时候我们是把各种算法进行综合使用,来达到我们预期的效果,也就是说组合的优势是扬长避短,同时我们也应该各有取舍。

在写本文的时候也看了网上很多这方面的文章,很多同学说lsm tree适用于写入远大于读取的场景,我觉得这个问题是相对的,从设计角度上讲,这也是一种平衡,但是从性能角度讲,lsm tree结构的搜索会比b-tree慢吗?怎么衡量呢?这也是个问题,所以我在文章开头定义了高速读写的特性给lsm tree的原因。

由于本人技术和能力有限,文章中的描述难免有不妥之处,如有发现请指正,因为这无论是对我还是对大家都有帮助 呵呵。


个人总结:这个Write OP Log ahead 在分布式中被广泛应用,比如levelDB, GFS, bigtable等。

看起来整个架构就是归并合并的路子,从内存到硬盘。但是实现细节还需要学习。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值