最近被大佬问到一个问题,hbase查询数据在最坏的场景下须要进行几回rpc,当时就懵了..下面主要对client端代码进行分析。阅读文章和看源码更配~html
1. 从zookeeper中获取meta信息,并经过meta信息找到须要查找的table的startkey所在的region信息java
2. 和该region所在的regionserver进行rpc交互获取result数据库
3. region server查询memstore(memstore是是一个按key排序的树形结构的缓冲区),若是有该rowkey,则直接返回,若没有进入步骤4数组
4. 查询blockcache,若是有该rowkey,则直接返回,若没有进入步骤5缓存
5. 查询storefile,无论有没有都直接返回优化
hbase读数据除了直接操做hfile以外有3个入口,get(),batch()和scan(),get()相对而言就比较简单,找到对应的regionserver而后发rpc便可,batch()采用单rpc多action的策略流程和get()相似,下面主要对scan涉及的核心接口进行分析。核心接口有如下几个日志
Connection:负责和zk创建链接server
Table:负责维护相关对象htm
ResultScanner:负责给使用者遍历纾解对象
Caller:负责调用Callable
Callable:客户端和hbase交互的主要接口
默认的链接器是HConnectionImplementation,能够经过配置`hbase.client.connection.impl`修改。核心思路是基于zk的watcher,保持长链接,而后获取hbase元数据
table经过Connection.getTable()实例化,默认的实现是HTable。这个类比较简单,只是维护了针对hbase一张表所用到的对象。主要关注遍历的方法,经过HTable.getScanner()实例化一个新的ResultScanner,使用者经过ResultScanner迭代器遍历获取result数据。
client提供了4种scanner,参考HTable.getScanner(),1. ClientScanner,读取result的流程须要3次rpc,openScanner,next和closeScanner;2. 针对小量数据优化的ClientSmallScanner,和ClientScanner的区别在于,将openScanner,next和closeScanner合并到一个rpc执行,官方建议拉取的数据在64KB以内能够考虑用SmallScanner的方式;另外两个是基于reversed配置,也就是倒序遍历region,须要交换startkey和endkey的位置。ClientScanner是咱们最经常使用的Scanner,也是默认的Scanner,下面对其进行分析
ClientScanne对应的Callable是ScannerCallable,也是最典型的Callable,下面对其核心方法进行分析
prepare()方法
核心call()方法
hbase-client的scan操做整体上能够当作是两层迭代器,面向使用者的Scanner以及面向region server的Callable。Callable负责从regionserver中获取result,主要解决,Scanner负责整合result提供给使用者。这样作的思路很明显,数据大小是确定会大于内存的,经过迭代器接口,可让使用者处理完以前的result再拉取其余result,从而起到分页的效果,这操做对使用者是透明的。若是须要详细的scan日志,能够经过配置`hbase.client.log.scanner.activity`来打开开关,默认是false。
对于scan操做而言,拿ClientScanner来讲,一次“完整rpc”过程包含3次rpc,open,result和close。若是失败了,region不可用或者在split,那么client会重试新的一次“完整rpc”,那么就是6次rpc。其余操做会少一点,例如SmallClientScanner一次“完整rpc”只须要1次rpc,它把open,close集成到了一块儿。hbase在client仍是花了很多心思的。
HBase-1.3.1代码