深入HBase——数据结构与算法

引入

通过前面的文章,我们对HBase已经有了基本认识,下面我们从HBase最核心的算法和数据结构进一步深入HBase。

HBase的一个列簇(Column Family)本质上就是一棵LSM树(Log-Structured Merge-Tree)​。LSM树分为内存部分和磁盘部分。内存部分是一个维护有序数据集合的数据结构。一般来讲,内存数据结构可以选择平衡二叉树、红黑树、跳跃表(SkipList)等维护有序集的数据结构,这里由于考虑并发性能,HBase选择了表现更优秀的跳跃表。磁盘部分是由一个个独立的文件组成,每一个文件又是由一个个数据块组成。并且为了避免不必要的IO耗时,还可以在磁盘中存储一些额外的二进制数据,这些数据用来判断对于给定的key是否有可能存储在这个数据块中,这个数据结构称为布隆过滤器(Bloom Filter)​

下面我们就深入介绍一下提到的核心数据结构与算法:

  • LSM树(Log-Structured Merge-Tree)
  • 跳跃表(SkipList)
  • 布隆过滤器(Bloom Filter)​

LSM树(Log-Structured Merge-Tree)

LSM树本质上和B+树一样,是一种磁盘数据的索引结构。但和B+树不同的是,LSM树的索引对写入请求更友好。因为无论是何种写入请求,LSM树的索引结构本质都会将其全部转化成磁盘的顺序写入,而HDFS擅长的正是顺序写(且HDFS不支持随机写)​,因此基于HDFS实现的HBase能极大提高写入操作的性能,但这种设计对读取操作是非常不利的,因为需要在读取的过程中,通过归并所有文件来读取所对应的KV,这是非常消耗IO资源的。因此,在HBase中设计了异步的compaction来降低文件个数,达到提高读取性能的目的。由于HDFS只支持文件的顺序写,不支持文件的随机写,而且HDFS擅长的场景是大文件存储而非小文件,所以上层HBase选择LSM树这种索引结构是最合适的。

原理

LSM树是一种用于存储和管理数据的数据结构,特别适用于写入密集型的工作负载。它的设计灵感来自于日志结构文件系统。LSM树的核心思想是将写操作集中到一个内存中的有序数据结构(如MemTable),待数据积累到一定数量后,将这些数据批量写入到磁盘上的有序文件中。这种设计能够显著提高写操作的性能,因为将随机写转换为顺序写,能够减少磁盘的寻道时间。

结构

LSM树的索引一般由两部分组成,一部分是内存部分,一部分是磁盘部分。内存部分一般采用跳跃表来维护一个有序的KeyValue集合。磁盘部分一般由多个内部KeyValue有序的文件组成。

KeyValue存储格式

在HBase为例,这个字节数组串设计如下图所示,字节数组主要分为以下几个字段:

其中Rowkey、Family、Qualifier、Timestamp、Type这5个字段组成KeyValue中的key部分。

  • keyLen:占用4字节,用来存储KeyValue结构中Key所占用的字节长度。
  • valueLen:占用4字节,用来存储KeyValue结构中Value所占用的字节长度。
  • rowkeyLen:占用2字节,用来存储rowkey占用的字节长度。
  • rowkeyBytes:占用rowkeyLen个字节,用来存储rowkey的二进制内容。
  • familyLen:占用1字节,用来存储Family占用的字节长度。
  • familyBytes:占用familyLen字节,用来存储Family的二进制内容。
  • qualifierBytes:占用qualifierLen个字节,用来存储Qualifier的二进制内容。
    注意,HBase并没有单独分配字节用来存储qualifierLen,因为可以通过keyLen和其他字段的长度计算出qualifierLen。
    代码如下:
qualifierLen=keyLen -2B - rowkeyLen -1B - familyLen -8B -1B
  • timestamp:占用8字节,表示timestamp对应的long值。
  • type:占用1字节,表示这个KeyValue操作的类型,HBase内有Put、Delete、Delete Column、DeleteFamily,等等。注意,这是一个非常关键的字段,表明了LSM树内存储的不只是数据,而是每一次操作记录。

Value部分直接存储这个KeyValue中Value的二进制内容。所以,字节数组串主要是Key部分的设计。

注意:

在HBase中,timestamp越大的KeyValue,排序越靠前。因为用户期望优先读取到那些版本号更新的数据。

通常来说,在LSM树的KeyValue中的Key部分,有3个字段必不可少:

  • Key的二进制内容。
  • 一个表示版本号的64位long值,在HBase中对应timestamp;这个版本号通常表示数据的写入先后顺序,版本号越大的数据,越优先被用户读取。甚至会设计一定的策略,将那些版本号较小的数据过期淘汰(HBase中有TTL策略)​。
  • type,表示这个KeyValue是Put操作,还是Delete操作,或者是其他写入操作。本质上,LSM树中存放的并非数据本身,而是操作记录。这对应了LSM树(Log-Structured Merge-Tree)中Log的含义,即操作日志。

多路归并

现在有K个文件,其中第i个文件内部存储有Ni个正整数(这些整数在文件内按照从小到大的顺序存储)​,如何设计一个算法将K个有序文件合并成一个大的有序文件?

在排序算法中,有一类排序算法叫做归并排序,里面就有大家熟知的两路归并实现。现在相当于K路归并,因此可以拓展一下,思路类似。对每个文件设计一个指针,取出K个指针中数值最小的一个,然后把最小的那个指针后移,接着继续找K个指针中数值最小的一个,继续后移指针……直到N个文件全部读完为止。

核心实现代码如下:


                
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄雪超

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值