美文网首页HBase
Hbase 读取流程

Hbase 读取流程

作者: ZYvette | 来源:发表于2021-08-30 14:50 被阅读0次

    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

    相关文章

      网友评论

        本文标题:Hbase 读取流程

        本文链接:https://www.haomeiwen.com/subject/naauiltx.html