阅读 107

Hbase 读取流程

Hbase 读取复杂原因:

主要基于两个方面的原因:

  • 一是因为HBase一次范围查询可能会涉及多个Region、多块缓存甚至多个数据存储文件(HFile);
  • 二是因为HBase中更新操作以及删除操作的实现都很简单。
    插入&删除: 没有更新原始数据,而是通过时间戳属性新增版本。
    删除:只是插入deleted标签。在Major Compact的时候删除真正数据。
    读取过程需要根据版本进行过滤,对已经标记删除的数据也要进行过滤。

读流程步骤:

  • Client-Server读取交互逻辑
  • Server端Scan框架体系
  • 过滤淘汰不符合查询条件的HFile
  • 从HFile中读取待查找Key。

1. Client-Server读取交互逻辑

Client首先会从ZooKeeper中获取元数据hbase:meta表所在的RegionServer,然后根据待读写rowkey发送请求到元数据所在RegionServer,获取数据所在的目标RegionServer和Region(并将这部分元数据信息缓存到本地),最后将请求进行封装发送到目标RegionServer进行处理。

  • hbase的读取请求分为get和scan,而get实际是最简单的一次scan。

  • client-server端将scan没有使用一次rpc,原因:
    •大量数据传输会导致集群网络带宽等系统资源短时间被大量占用,严重影响集群中其他业务。
    •客户端很可能因为内存无法缓存这些数据而导致客户端OOM。


    image.png
  • 一次大的scan操作会拆分为多个RPC请求。每个RPC是一次next请求,分会规定数量的结果。每次next()操作,客户端先检查本地缓存,没有就发一次RPC请求给服务器,然后缓存到本地。

  • 单次RPC caching大小默认是Integer.MAX_VALUE。设置过大可能因为一次获取到的数据量太大导致服务器端/客户端内存OOM;设置太小会导致一次大scan进行太多次RPC,网络成本高。

  • 对于一张表列过大,可以通过setBatch方法设置一次RPC请求的数据列数量。

  • 客户端还可以通过setMaxResultSize方法设置每次RPC请求返回的数据量大小(不是数据条数),默认是2G。

2 Server端Scan框架体系

  • 一次scan可能会同时扫描一张表的多个Region。客户端会根据hbase:meta元数据将扫描的起始区间[startKey, stopKey)进行切分,切分成多个互相独立的查询子区间,每个子区间对应一个Region。

  • HBase中每个Region都是一个独立的存储引擎,因此客户端可以将每个子区间请求分别发送给对应的Region进行处理。下文会聚焦于单个Region处理scan请求的核心流程。

  • RegionServer接收到客户端的get/scan请求之后做了两件事情:首先构建scanner iterator体系;然后执行next函数获取KeyValue,并对其进行条件过滤。

image.png

image.png
  1. 构建Scanner Iterator体系
    1)过滤淘汰部分不满足查询条件的Scanner。
    主要过滤策略有:TimeRange过滤、Rowkey Range过滤以及布隆过滤器


    image.png

    2)每个Scanner seek到startKey

  • 根据HFile索引树定位目标Block


    image.png
  • BlockCache中检索目标Block
    Block缓存到Block Cache之后会构建一个Map,Map的Key是BlockKey,Value是Block在内存中的地址。其中BlockKey由两部分构成——HFile名称以及Block在HFile中的偏移量。BlockKey很显然是全局唯一的。根据BlockKey可以获取该Block在BlockCache中内存位置,然后直接加载出该Block对象。如果在BlockCache中没有找到待查Block,就需要在HDFS文件中查找。
  • HDFS文件中检索目标Block


    image.png

    根据文件索引提供的Block Offset以及Block DataSize这两个元素可以在HDFS上读取到对应的Data Block内容。

为什么HDFS的Block设计为128M,而HBase的Block设计为64K ?
1. HDFS Block 为128M,因为 主要存储文件,Block太小,会导致Block元数据(Block所在DataNode位置、文件与Block之间的对应关系等)庞大。因为HDFS元数据都存储在NameNode上,大量的元数据很容易让NameNode成为整个集群的瓶颈。
2. HBase的缓存策略是缓存整个Block,如果Block设置太大会导致缓存很容易被耗尽,尤其对于很多随机读业务,设置Block太大会让缓存效率低下。

  • 从Block中读取待查找KeyValue

3)KeyValueScanner合并构建最小堆
最小堆管理Scanner可以保证取出来的KeyValue都是最小的,这样依次不断地pop就可以由小到大获取目标KeyValue集合,保证有序性。

执行next函数获取KeyValue并对其进行条件过滤

1)检查该KeyValue的KeyType是否是Deleted/DeletedColumn/DeleteFamily等
2)检查该KeyValue的Timestamp是否在用户设定的Timestamp Range范围
3)检查该KeyValue是否满足用户设置的各种filter过滤器
4)检查该KeyValue是否满足用户查询中设定的版本数

总结: 读取过程中,是先根据TimeRange,Rowkey Range,bloomfilter判断数据是否在对应文件,再将文件中的数据读取出来,判断是否删除,是否符合用户条件。

读取过程总结:

  1. 客户端: 将scan 转变为多次next请求。将请求转变为发送对应region(读zk,读meta找到对应region)的请求
  2. 服务器端:过滤掉不符合查询条件的hfile,读取符合条件的hfile,构建最小堆
    (1)过滤hfile方式:TimeRange,RowKey,bloomfiler
    (2) hfile索引树定位目标block
    (3)检索block: blockcache中检索、hdfs文件中检索block
  3. 获取keyvalue,next过滤:
    (1)keytype判断是否删除
    (2)timestamp判断timerange
    (3) 判断用户filter
    (4) 判断版本号
image.png

作者:ZYvette

原文链接:https://www.jianshu.com/p/4af53bc0df5b

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐