文章目录
一、简介
在大数据场景下,HBase的存储引擎选择的是LSM树(日志结构合并树Log-Structured Merge-Tree),LSM树会将写入操作处理为一次顺序写,HDFS擅长的正是顺序写。
- LSM树主要目标是快速建立索引
- LSM树通过磁盘的顺序写来实现最好的写性能
- LSM树的索引由两部分组成:一部分是内存部分,一部分是磁盘部分,内存部分一般采用跳跃表维护一个有序的Key-Value集合;磁盘部分一般由多个内部KeyValue有序的文件组成。
二、KeyValue 存储格式
- keyLen、valueLen、rowkeyLen、familyLen存储的都是各自的长度
- rowkeyBytes、familyBytes、qualifierBytes存储的分别是rowkey、列族、属性的值
- timestamp:表示timestamp对应的long值
- type:表示这个KeyValue操作的类型,HBase有Put、Delete、DeleteColumn、DeleteFamily等等,这表明LSM树内存储的不只是数据,而是每一次操作记录。
比较KeyValue大小:依次比较rowKeyBytes、familyBytes、qualifierBytes、timestamp(越大越靠前),即依次比较rowkey,列族,属性,时间戳。
LSM树的索引结构
一个LSM树主要由内存部分和磁盘部分构成,内存部分是一个ConcurrentSkipListMap,Key就是上文提到的key,value是一个字节数组。数据写入时先写入 MemStore,一旦内存占用超过一定阈值时,把内存部分数据导出,形成一个有序的数据文件,存储在磁盘上(Flush过程)。
flush时会先把当前写入的 MemStore 设为 Snapshot,不再允许新的写入操作写入这个 Snapshot 的 MemStore。另开一个内存空间作为 MemStore,让后面的数据写入。一旦 Snapshot 的 MemStore 写入完毕,对应的内存空间就可以释放。
注意
在数据写入过程中,LSM树全部都是磁盘的顺序写,磁盘的顺序写操作性能和延迟远好于磁盘随机写。因此LSM树是对写入极为友好的索引结构,能将磁盘的写入宽带利用到极致。
compact:优化读操作
随着数据的不断写入,内存中的数据也会不断刷写到磁盘中导致磁盘中的文件越来越多。如果这时候要读取数据的话,则需要将大量的磁盘文件进行多路归并,之后才能读到所需的数据(因为LSM树记录的是一个数据的操作,这个数据可能是增加、修改、删除操作,相同的key的数据中type可能不同,timestamp也不同,只有将他们全局综合起来,选出最合适的版本返回),因此磁盘文件越多,在读取的时候随机读的次数也越多,从而影响读操作的性能。
如何优化
设置一定策略将选中的多个 hfile 进行多路归并,合成一个文件
major compact
将所有的 hfile 一次性多路归并成一个文件。合并之后只有一个文件,这样读取性能最高;但是合并所有的文件可能需要很长的时间并消耗大量的IO宽带,因此major compact操作不宜频繁使用,适合周期性操作。
minor compact
只选中少数的hfile,多路归并为一个文件。好处就是进行局部的compact,通过少量的 IO 减少文件个数,提升读取操作的性能,适合高频率操作;缺点是只合并了局部数据,对于全局删除的数据,无法在合并中完全删除。然而 Major Compact 能完全清理 delete 操作,保证数据的最小化。
总结
LSM树的索引结构本质是将写入操作全部转化成磁盘的顺序写入,极大提高了写入操作的性能。但是如果需要读取数据的话,需要将磁盘中的 hfile 文件归并读取,这非常消耗IO资源。因此HBase中通过 Compaction 来降低文件个数,提高读取性能。由于HDFS只支持文件的顺序写,HDFS擅长的场景是存储大文件而非小文件,所以上层选择LSM树这种索引结构是最合适的。