前提
读取的过程中的寻址与大概流程其实与写入是一致的。
重点看:在内存中查找和在StoreFile上的查找过程
简述:
- 先在zookeeper中找到root表regionserver的地址
- 然后在root表中找到meta表的地址
- 在meta表中找对应要扫描的表的地址
整体扫描过程
从内存到文件
-
首先构建scanner体系,构建一个regionScanner -> storeScanner-> storeFileScanner,MemstoreScanner
这里说实话也不太明白,目前只能理解为它是一个组织扫描数据的方式,类似使用设计模式
-
然后多个scanner过滤掉一定不存在的scanner
根据时间范围和rowkey的范围
-
找到对应的每个storeFile的数据块的起点的位置(因为彼此邻近的storefile有一些重复的rowkey,但是内容不相同)
因为每个storeFile数据是被切成一个个的数据块来存储,每个数据块的开始rowkey存在索引块中
-
使用每一个定位的rowkey使用最小堆组织进行排序,然后取出数据确定是否满足条件(我理解的它应该是无法准确定位到rowkey在每一个storeFile都不一样的rowkey,但是网上的图都是这么画的。)(这里的扫描是连MemoryStore一并扫描的)
-
然后next,进行下一行
在seek key这一步:
- 先在blockcache中搜索索引定位rowkey在哪个数据块,
- 如果数据块不在blockcache中再去hfile中加载
- 最后通过二分法查找(讲道理内存中的数据结构是跳跃表,跳跃表有它自己的查询方式但不能说是二分法,应该仅仅限于文件)
最小堆的排序规则
(这里是用在scanner的排序,不是数据的排序,可以理解为)
使用hbase存储的键值对的key进行排序,这个key不是rowkey
key由以下元素组成:
-
rowkey,列族,列,时间戳,key的类型
其实就是定位一个cell的坐标
比较规则:
-
rowkey正相关,越小,key越小
-
列族正相关(怎么判断它小呢?字典排序?待考证)
-
列正相关
-
时间戳负相关,越大(新),key越小
-
key的类型
- put
- delete(删除某一行)
- delete colum (删除某一行的某一列,其他行的还是在的,不是全删了所有的列)
- delete family(类似上)
依次越来越小,根据以上规则可得以下结论:
到此其实都没说完,还有在文件的扫描过程,基本是使用二分法。