对于使用Hbase,通常情况下是Hbase客户端到Hbase服务端再到HDFS客户端这么一个路径,所以使用Hbase时需要对Hbase客户端有较好的理解。实际上,由于Hbase的复杂性以及Region的定位设计在客户端上(hbase:meta元数据表缓存在客户端上用于定位region),导致Hbase客户端并不足够轻量级。

Hbase客户端实现:

        Hbase提供了多种语言的客户端,由于Hbase是通过Java语言实现的,所以非Java语言需要先访问ThriftServer,然后通过JavaHbase客户端请求Hbase集群。另外Shel(hbase-shell)l客户端实质是用JRuby(java编写的Ruby解析器)调用官方客户端。

访问客户端主要有以下介个步骤:

        1、获取集群的Configuration对象(HDFS,Kafka这些也都有COnfiguration对象)。一般需要3个配置文件:hbase-site.xml,core-site.xml,hdfs-site.xml.在maven项目中,直接放在resource文件夹下面即可。

        2、通过Configuration初始化Connection。Connection是Hbase客户端进行一切操作的基础,维持了客户端到整个集群的连接。如果一个集群中存在2个Master和5个RegionServer,那么一般来说,这个Connection会维持一个到ActiveMaster的TCP连接和5个到RegionServer的Tcp连接。从这个情况可以看出,一个请求会被分布在5个Regionserver的其中一个之上,所以Hbase连接没有必要使用连接池对连接进行管理。另外Connection还缓存了Meta信息(hbase:meta),可以更方便的找到数据。

        3、通过Connection初始化Table,一个轻量级对象,实现了所有需要的API操作(增删改查)。本质上同一个Connection创建的Table都是会共享Connection的资源,包括连接,配置信息,线程池,Meta缓存。

        4、通过Table进行操作。

定位Meta表:

        Hbase客户端又一个很重要的过程,定位Meta表。由于Hbase一张表kennel由多个Region构成,而这些Region又可能分布在不同的RegionServer上,在通过客户端查询时,都需要先找到数据在那个Region,再到对应的服务器上找数据。所以Hbase内部维护了一张特殊的表:hbase:meta。这个表专门存放集群的所有Region信息。hbase:meta中的hbase指的是命名空间,可以根据不同的业务设置不同的名称,meta指的是hbase表名。

        hbase:meta只有一个名为Info的列簇,而且只有一个Region,这样可以保证meta表多次操作的原子性,因为Hbase本质只支持Region级别的事物。表内主要存储以下信息:

rowkey

一个rowkey对应一个region,主要由

        TableName(业务表名)

        StartRow(region区间起始rowkey)

        Timestamp(region创建时间戳)

        EncodedName(以上字段的MD5Hex值)

info:regioninfo

主要存储4个信息:EncodedName,RegionName,Region的StartRow和StopRow

info:seqnumDuringOpen存储Region打开时的sequenceId
info:serverregion存储在哪个RegionServer上
info:serverstartcodeRegionServer启动的TiimeStamp

        hbase:meta作为最为核心的表,当大量请求同时放过来时,因为只有一个Region,很快就会成为热点Region并且无法承担这么大的压力。所以Hbase会将hbase:meta缓存在客户端上。

        hbase:meta缓存在客户端MetaCache的缓存中,调用Hbase时,会在MetaCache中查找rowkey对应的Region,有以下几种情况:

        1、region信息为空,说明缓存中没有这个rowkey所在region的任何信息。在首次查找时,需要先读取zookeeper中/hbase/meta-regioen-server的Znode用来确定hbase:meta所在的RegionServer,之后进行查询,新的信息存放在缓存中。

        2、region信息不为空,但是调用RPC请求后发现并不在这个RegionServer上。这说明缓存中的信息已经过期,重新查询更新缓存信息。通常这种情况发生在不regionserver宕机或者region迁移,这种情况也很少出现。

        3、region信息不为空且信息在对应的RegionServer上。这种为大多数的情况。直接通过缓存信息就能定位到对应的服务器查询数据。

Hbase Sacan操作:

        Hbase的Scan时比较复杂的RPC操作。通常table.getScanner(sacn)获取到Scanner,通过scanner.next()就能拿到一个result。

        1、用户每次next,都会尝试在cache对列中拿result

        2、如果缓存队列为空,则会发起一次RPC请求当前scanner后续的result数据。

        3、客户端获取到结果后,通过scanResultCache重组,结果放在cache对列中。

为什么需要对结果进行重组?这是因为为了避免当前RPC请求耗尽资源,对结果实现了多维度的限制,这样用户得到的数据可能就不是一行完整的数据了。

        Scanner包含几个重要概念:

caching每次缓存数据最多放caching个result到缓存中
batch用户result中最多含有一行数据中的batch个cell。如果一行数据包括5个cell,batch为2的情况下,用户会拿到3个result,cell个数为2,2,1
allowPartial允许一行部分cell的result,设置这个会跳过重组,直接将Result返回        
maxResultSize单次RPC操作最多拿maxResultSIze字节的结果集

本文为《Hbase原理与实践》读书心得,感兴趣的可以阅读原书。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐