四、HBase读写流程及Coprocessor

HBase读写流程

HBase写入流程

HBase采用LSM树架构,天生适用于写多读少的应用场景。HBase对数据的update、delete是写入操作。

HBase写入流程的三个阶段

在这里插入图片描述

  • 客户端处理阶段:根据集群元数据表hbase:meta定位写入数据所在的RegionServer,将请求发送给对应的RegionServer;
  • Region写入阶段:首先写入到WAL(HLog),再写入到MemStore;
  • MemStore Flush阶段:当MemStore超过阈值时,将数据异步flush到HFile。
客户端处理阶段
  1. client提交put后,autoflush=true(HBase默认),client直接提交给RegionServer处理;设置autoflush=false,client将写入数据缓存到本地缓冲区,本地缓冲区大小超过一定阈值(默认为2M)才会提交;
  2. 在提交之前,HBase会在client缓存的元数据表hbase:meta中根据rowkey找到它们归属的RegionServer;
    • 缓存中有,直接发送请求到RegionServer;
    • 缓存中没有,先去zookeeper中获取hbase:meta表所在的RegionServer,然后向该RegionServer查询rowkey所在的RegionServer以及Region信息;client将结果缓存到本地;
Region写入阶段

数据写入Region的流程可以抽象为两步:追加写入HLog,随机写入MemStore

MSLAB内存管理方式

MemStore本地分配缓存(MemStore-Local Allocation Buffer,MSLAB)

MemStoreLAB会申请一个2M大小的Chunk数组,同时维护一个Chunk偏移量(初始为0);

数据data写入Chunk数组,Chunk偏移量移动data.length;

Chunk数组写满后,再申请一个新的Chunk数组;

MemStore Chunk Pool

MSLAB存在的问题,一个Chunk写满之后,系统会重新申请一个新的Chunk(新建Chunk对象会在JVM新生代申请新内存,如果申请比较频繁会导致JVM新生代Eden区满掉,触发YGC。)

MemStore Chunk Pool的核心思想:chunk循环利用,系统不需要申请新的Chunk

在这里插入图片描述

1)Acquire locks:HBase中使用行锁用以保证写入的原子性,要么更新成功,要么更新失败;

2)Update LATEST_TIMESTAMP timestamps:更新所有待写入KeyValue的时间戳为当前系统时间;

3)Build WAL edit:在内存中构建WALEdit对象,一次写入操作中所有KeyValue会构建成一条WALEdit记录;

4)Append WALEdit To WAL:将步骤3中构造在内存中的WALEdit记录顺序写入HLog中,此时不需要执行sync操作;

5)Write back to MemStore:写入WAL之后再将数据写入MemStore;

6)Release row locks:释放行锁;

7)Sync wal:HLog真正sync到HDFS,在释放行锁之后执行sync操作是为了尽量减少持锁时间,提升写性能。如果sync失败,执行回滚操作将MemStore中已经写入的数据移除;

8)结束写事务:更新操作才会对其他读请求可见,更新才实际生效。

MemStore Flush阶段

随着数据的不断写入,MemStore中存储的数据达到阈值,会将MemStore中的数据写入文件形成HFile。

MemStore Flush触发条件
  • MemStore级别限制:当Region中任意一个MemStore的大小达到了上限(hbase.hregion.memstore.flush.size,默认128MB),会触发MemStore刷新。
  • Region级别限制:当Region中所有MemStore的大小总和达到了上限(hbase.hregion.memstore.block.multiplier*hbase.hregion.memstore.flush.size),会触发MemStore刷新。
  • RegionServer级别限制:当RegionServer中MemStore的大小总和超过低水位阈值hbase.regionserver.global.memstore.size.lower.limit*hbase.regionserver.global.memstore.
  • size,RegionServer开始强制执行flush,先flush MemStore最大的Region,再flush次大的,依次执行。如果此时写入吞吐量依然很高,导致总MemStore大小超过高水位阈值hbase.regionserver.global.memstore.size,RegionServer会阻塞更新并强制执行flush,直至总MemStore大小下降到低水位阈值。
  • 当一个RegionServer中HLog数量达到上限(可通过参数hbase.regionserver.maxlogs配置)时,系统会选取最早的HLog对应的一个或多个Region进行flush。
  • HBase定期刷新MemStore:默认周期为1小时,确保MemStore不会长时间没有持久化。为避免所有的MemStore在同一时间都进行flush而导致的问题,定期的flush操作有一定时间的随机延时。
  • 手动执行flush:用户可以通过shell命令flush’tablename’或者flush’regionname’分别对一个表或者一个Region进行flush。
MemStore Flush执行流程

整个flush过程分为三个阶段

  1. prepare阶段:将MemStore中当前数据集做一个快照snapshot,再新建一个接收新写入的数据;
  2. flush阶段:将prepare阶段生成的snapshot持久化为临时文件,涉及磁盘IO,相对耗时;
  3. commit阶段:将flush阶段生成的临时文件移到指定的ColumnFamily目录下,最后再清空prepare阶段生成的snapshot

系统定期刷新MemStore、手动执行flush操作、触发MemStore级别限制、触发HLog数量限制以及触发Region级别限制等不会对业务读写产生太大影响,只会阻塞对应Region上的写请求,且阻塞时间较短。

RegionServer级别flush会对用户请求产生较大的影响,系统会阻塞所有落在该RegionServer上的写入操作,直至MemStore中数据量降低到配置阈值内。

BulkLoad功能

使用BulkLoad将HDFS数据批量导入到HBase

影响Locality
如果用户生成HFile所在的HDFS集群和HBase所在HDFS集群是同一个,则MapReduce生成HFile时,能够保证HFile与目标Region落在同一个机器上,可以保证了locality。

先通过MapReduce任务在HDFS集群A上生成HFile,再通过distcp工具将数据拷贝到HDFS集群B上去,没法保证locality,需要跑完Bulkload之后手动执行major compact,来提升locality。

HBase读取流程

Client-Server读取交互逻辑

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

所有读取操作都可以认为是一次scan操作,get请求也是一种scan请求(scan的条数为1)。HBase会将一次大的scan操作拆分为多个RPC请求,每个RPC请求称为一次next请求,每次只返回规定数量的结果。

单次RPC请求的数据条数由参数caching设定,默认为Integer.MAX_VALUE。每次RPC请求获取的数据都会缓存到客户端,该值设置过大可能会因为一次获取到的数据量太大导致服务器端/客户端内存OOM;而设置太小会导致一次大scan进行太多次RPC,网络成本高。

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

Coprocessor

大多数情况下,通过调用HBase提供的读写API或者使用Bulkload功能基本上可以满足日常的业务需求。在部分特殊应用场景下,使用Coprocessor可以大幅提升业务的执行效率。比如,业务需要从HBase集群加载出来几十亿行数据进行求和运算或是求平均值运算,调用HBase API将数据全部扫描出来在客户端进行计算,势必有下列问题:

  • 大量数据传输可能会成为瓶颈,导致整个业务的执行效率受限于数据的传输效率。
  • 客户端内存可能会无法存储如此大量的数据而OOM。
  • 大量数据传输可能将集群带宽耗尽,严重影响集群中其他业务的正常读写。

将客户端的计算代码迁移到RegionServer服务器端执行,就能很好地避免上述问题。

Coprocessor分类

HBase Coprocessor分为两种:Observer和Endpoint

在这里插入图片描述

Observer Coprocessor

Observer Coprocessor提供钩子使用户代码在特定事件发生之前或者之后执行(钩子函数)

使用Observer Coprocessor的最典型案例是在执行put或者get等操作之前检查用户权限。

在当前HBase系统中,提供了4种Observer接口:

  • RegionObserver,主要监听Region相关事件,比如get、put、scan、delete以及flush等。

  • RegionServerObserver,主要监听RegionServer相关事件,比如RegionServer启动、关闭,或者执行Region合并等事件。

  • WALObserver,主要监听WAL相关事件,比如WAL写入、滚动等。

  • MasterObserver,主要监听Master相关事件,比如建表、删表以及修改表结构等。

Endpoint Coprocessor

Endpoint Coprocessor允许将用户代码下推到数据层执行。上文提到的计算一张表(设计大量Region)的平均值或者求和,可以使用Endpoint Coprocessor将计算逻辑下推到RegionServer执行。

Observer Coprocessor执行对用户来说是透明的,只要HBase系统执行了get操作,对应的preGetOp就会得到执行,不需要用户显式调用preGetOp方法;而Endpoint Coprocessor执行必须由用户显式触发调用。

Coprocessor加载

用户定义的Coprocessor可以通过两种方式加载到RegionServer:一种是通过配置文件静态加载;一种是动态加载。

静态加载:hbase-site.xml配置,Coprocessor代码放到HBase lib目录,重启HBase集群;

动态加载:不需要重启集群

详情参照官网
erver:一种是通过配置文件静态加载;一种是动态加载。

静态加载:hbase-site.xml配置,Coprocessor代码放到HBase lib目录,重启HBase集群;

动态加载:不需要重启集群

详情参照官网

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值