背景
我们知道hbase是一个kv数据库,数据是有序存放的,对于get和小范围的scan操作性能极佳,然后由于hbase中一张表的数据量非常庞大,其内部是使用多个文件来存储数据的,那么hbase是怎么保证对于客户端scan操作时返回的记录是表范围内的有序记录呢?
Hbase Scan操作流程图
首先对于一张大表A,假设有两个列簇,Hbase会把大表A分成多个Region,每个Region区域就是A表的数据水平切分,也就是比如0-100行的记录在Region1,100-200行的记录在Region2的意思,然后对于每个Region的数据会再次进行垂直划分,也就是再次按照列簇划分成两个Store,每个Store对象就是对应那个Region底下的不同列簇的数据,最后Store会使用多个HFile文件+Memstore内存区域组成的LSM结构存储数据,当客户端进行Scan操作请求时,Hbase是怎么保证返回的数据是表范围内有序的呢?毕竟底层存储时有多个HFile文件+Memstore内存区域组成,每个HFile内部和Memstore内部虽然都是有序的,但是他们之间并不是有序的,也就是并不是说HFile1的数据一定都是小于HFile2的数据的,Hbase只是保证每个文件在表范围内是局部有序的。
下面我们来看一下Hbase是如何把内部存储的多个局部有序的HFile文件和Memstore内存区域转换成为表范围内有序的数据返回的:
总结
其实原理就是利用一个最小堆把数据先组合起来,这个最小堆就是表级别的有序的记录列表,其实有些同学就想问了,hbase内部不会真的每次只从每个HFile和Memstore中获取一个key来创建最小堆吧?这样效率也太低了吧。其实不是的,Hbase内部比如每个HFile和Memstore会获取比如100个记录,假设有两个HFile和一个Memstore的话,这个最小堆的数量会是300个,那你获取就有疑惑了?那什么时候会从某个HFile或者Memstore中获取下一个100行的记录?答案就是当最小堆的最小的那个元素是某个HFile或者Memstore的前一批的最大的元素时。