HBase原理深入

目录

1.HBase读数据流程

2.HBase写数据流程

3.HBase的flush(刷写)及compact(合并)机制

3.1.Flush机制

3.2.阻塞机制

3.3.Compact合并机制

4.Region 拆分机制

4.1.拆分策略

4.2.RegionSplitPolicy的应用

5.HBase表的预分区(region)

5.1 为何要预分区? 

5.2 手动指定预分区

6.Region 合并


HBase数据模型与整体架构:https://blog.csdn.net/qq_42029989/article/details/126604310

HBase优化:https://blog.csdn.net/qq_42029989/article/details/126607734

1.HBase读数据流程

HBase读流程示意
HBase读流程示意

HBase读流程示意
HBase读流程示意

hbase表中rowkey按照字典序排序,切分region就是按照rowkey来划分

HBase读操作

  1. 首先从 zk 找到 meta表 的 region位置,然后读取 meta表 中的数据,meta表 中存储了用户表的 region信息
  2. 根据要查询的 namespace、表名 和 rowkey 信息。找到写入数据对应的 region 信息
  3. 找到这个 region 对应的 regionServer,然后发送请求
  4. 查找对应的region
  5. 先从 memstore 查找数据,如果没有,再从 BlockCache 读取 HBase上Regionserver 的内存分为两个部分: 一部分作为 Memstore,主要用来写;另外一部分作为BlockCache,主要用于读数据;
  6. 如果 BlockCache 中也没有找到,再到 StoreFile 上进行读取,从 storeFile 中读取到数据之后,不是直接把结果数据返回给客户端,而是把数据先写入到 BlockCache 中,目的是为了加快后续的查询;然后在返回结果给客户端。

2.HBase写数据流程

HBase写流程示意
HBase写流程示意
HBase写流程示意
HBase写流程示意

HBase写操作

  1. 首先从 zk 找到 meta表 的 region位置,然后读取 meta表 中的数据,meta表 中存储了用户表的 region信息
  2. 根据 namespace、表名和rowkey信息。找到写入数据对应的 region 信息
  3. 找到这个 region 对应的 regionServer,然后发送请求
  4. 把数据分别写到HLog(write ahead log)和 memstore 各一份
  5. memstore 达到阈值后把数据刷到磁盘,生成 storeFile 文件
  6. 删除 HLog 中的历史数据

3.HBase的flush(刷写)及compact(合并)机制

3.1.Flush机制

  • 当memstore的大小超过这个值的时候,会flush到磁盘,默认为128M
<property>
    <name>hbase.hregion.memstore.flush.size</name>
    <value>134217728</value>
</property

  • 当memstore中的数据时间超过1小时,会flush到磁盘
<property>
    <name>hbase.regionserver.optionalcacheflushinterval</name>
    <value>3600000</value>
</property>

  • HregionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%
<property>
    <name>hbase.regionserver.global.memstore.size</name>
    <value>0.4</value>
</property>

  • 手动flush 
flush tableName

3.2.阻塞机制

        以上介绍的是Store中memstore数据刷写磁盘的标准,但是Hbase中是周期性的检查是否满足以上标准满足则进行刷写,但是如果在下次检查到来之前,数据疯狂写入Memstore中,会出现什么问题?

        会触发阻塞机制,此时无法写入数据到Memstore,数据无法写入Hbase集群。

  • memstore中数据达到512MB

计算公式:

        hbase.hregion.memstore.flush.size * hbase.hregion.memstore.block.multiplier

        hbase.hregion.memstore.flush.size刷写的阀值,默认是 134217728,即128MB。

        hbase.hregion.memstore.block.multiplier是一个倍数,默认是4。

  • RegionServer全部memstore达到规定值

        hbase.regionserver.global.memstore.size.lower.limit是0.95

        hbase.regionserver.global.memstore.size是0.4

        堆内存总共是 16G

        触发刷写的阈值是:6.08GB

        触发阻塞的阈值是:6.4GB

3.3.Compact合并机制

在hbase中主要存在两种类型的compac合并

minor compact 小合并

  • 在将Store中多个HFile(StoreFile)合并为一个HFile

       这个过程中,删除和更新的数据仅仅只是做了标记,并没有物理移除,这种合并的触发频率很高

  • minor compact文件选择标准由以下几个参数共同决定:
<!--待合并文件数据必须大于等于下面这个值-->
<property>
    <name>hbase.hstore.compaction.min</name>
    <value>3</value>
</property>

<!--待合并文件数据必须小于等于下面这个值-->
<property>
    <name>hbase.hstore.compaction.max</name>
    <value>10</value>
</property>

<!--默认值为128m,表示文件大小小于该值的store file 一定会加入到minor compaction的store file中-->
<property>
    <name>hbase.hstore.compaction.min.size</name>
    <value>134217728</value>
</property>

<!--默认值为LONG.MAX_VALUE,表示文件大小大于该值的store file 一定会被minor compaction排除-->
<property>
    <name>hbase.hstore.compaction.max.size</name>
    <value>9223372036854775807</value>
</property>

触发条件

  • memstore flush

       在进行memstore flush前后都会进行判断是否触发compact

  • 定期检查线程

       周期性检查是否需要进行compaction操作,由参数:hbase.server.thread.wakefrequency决定,默认值是10000 millseconds

major compact 大合并

  • 合并Store中所有的HFile为一个HFile

        这个过程有删除标记的数据会被真正移除,同时超过单元格 maxVersion 的版本记录也会被删除。合并频率比较低,默认7天执行一次,并且性能消耗非常大,建议生产关闭(设置为 0),在应用空闲时间手动触发。一般可以是手动控制进行合并,防止出现在业务高峰期。

  • major compaction触发时间条件
<!--默认值为7天进行一次大合并,-->
<property>
    <name>hbase.hregion.majorcompaction</name>
    <value>604800000</value>
</property>
  • 手动触发
##使用major_compact命令
major_compact tableName

4.Region 拆分机制

        Region中存储的是大量的rowkey数据 ,当Region中的数据条数过多的时候,直接影响查询效率.当Region过大的时候.HBase会拆分Region , 这也是Hbase的一个优点 

4.1.拆分策略

HBase的Region Split策略一共有以下几种:

1)ConstantSizeRegionSplitPolicy  0.94版本前默认切分策略

        当region大小大于某个阈值(hbase.hregion.max.filesize=10G)之后就会触发切分,一个region等分为2个region。

        但是在生产线上这种切分策略却有相当大的弊端:切分策略对于大表和小表没有明显的区分。阈值(hbase.hregion.max.filesize)设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1个,这对业务来说并不是什么好事。如果设置较小则对小表友好,但一个大表就会在整个集群产生大量的region,这对于集群的管理、资源使用、failover来说都不是一件好事。

2)IncreasingToUpperBoundRegionSplitPolicy  0.94版本~2.0版本默认切分策略

        切分策略稍微有点复杂,总体看和 ConstantSizeRegionSplitPolicy 思路相同,一个region大小大于设置阈值就会触发切分。但是这个阈值并不像 ConstantSizeRegionSplitPolicy 是一个固定的值,而是会在一定条件下不断调整,调整规则和 region 所属表在当前 regionserver 上的region个数有关系。

        region split的计算公式是:
                regioncount^3 * 128M * 2,当region达到该size的时候进行split

        例如:
                第一次split:1^3 * 256 = 256MB
                第二次split:2^3 * 256 = 2048MB
                第三次split:3^3 * 256 = 6912MB
                第四次split:4^3 * 256 = 16384MB > 10GB,因00000000次split的size都是10GB了

3)SteppingSplitPolicy  2.0版本默认切分策略

        这种切分策略的切分阈值又发生了变化,相比 IncreasingToUpperBoundRegionSplitPolicy 简单了一些,依然和待分裂region所属表在当前regionserver上的region个数有关系,如果region个数等于1,切分阈值为flush size * 2,否则为MaxRegionFileSize。这种切分策略对于大集群中的大表、小表会比 IncreasingToUpperBoundRegionSplitPolicy 更加友好,小5表不会再产生大量的小region,而是适可而止。

4)KeyPrefixRegionSplitPolicy

        根据rowKey的前缀对数据进行分组,这里是指定rowKey的前多少位作为前缀,比如rowKey都是16位的,指定前5位是前缀,那么前5位相同的rowKey在进行region split的时候会分到相同的region中。

5)DelimitedKeyPrefixRegionSplitPolicy

        保证相同前缀的数据在同一个region中,例如rowKey的格式为:userid_eventtype_eventid,指定的delimiter为 _ ,则split的的时候会确保userid相同的数据在同一个region中。

6)DisabledRegionSplitPolicy

        不启用自动拆分, 需要指定手动拆分

4.2.RegionSplitPolicy的应用

Region拆分策略可以全局统一配置,也可以为单独的表指定拆分策略。

1)通过hbase-site.xml全局统一配置(对hbase所有表生效) 

<property>
    <name>hbase.regionserver.region.split.policy</name>
    <value>org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value>
</property>

2)通过Java API为单独的表指定Region拆分策略

HTableDescriptor tableDesc = new HTableDescriptor("test1");
tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, IncreasingToUpperBoundRegionSplitPolicy.class.getName());
tableDesc.addFamily(new HColumnDescriptor(Bytes.toBytes("cf1")));
admin.createTable(tableDesc);

3)通过HBase Shell为单个表指定Region拆分策略

hbase> create 'test2', {METADATA => {'SPLIT_POLICY' =>
'org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy'}},{NAME => 'cf1'}

5.HBase表的预分区(region)

5.1 为何要预分区? 

        当一个table刚被创建的时候,Hbase默认的分配一个region 给 table 。也就是说这个时候,所有的读写请求都会访问到同一个 regionServe r的同一个 region 中,这个时候就达不到负载均衡的效果了,集群中的其他 regionServer 就可能会处于比较空闲的状态。解决这个问题可以用pre-splitting,在创建table的时候就配置好,生成多个region。

  • 增加数据读写效率
  • 负载均衡,防止数据倾斜
  • 方便集群容灾调度region

        每一个region维护着startRow 与 endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。

5.2 手动指定预分区

create 'person','info1','info2',SPLITS => ['1000','2000','3000']

也可以把分区规则创建于文件中

vim split.txt

文件内容

aaa
bbb
ccc
ddd

执行

create 'student','info',SPLITS_FILE => '/root/hbase/split.txt'

6.Region 合并

Region的合并不是为了性能,而是出于维护的目的。

通过Merge类冷合并Region(需要先关闭hbase集群

需求:需要把student表中的2个region数据进行合并

student,1593244870695.10c2df60e567e73523a633f20866b4b5.

student,1000,1593244870695.0a4c3ff30a98f79ff6c1e4cc927b3d0d.

        这里通过org.apache.hadoop.hbase.util.Merge类来实现,不需要进入hbase shell,直接执行(需要先关闭hbase集群):

hbase org.apache.hadoop.hbase.util.Merge student \
student,,1595256696737.fc3eff4765709e66a8524d3c3ab42d59. \
student,aaa,1595256696737.1d53d6c1ce0c1bed269b16b6514131d0.

通过online_merge热合并Region(不需要关闭hbase集群,在线进行合并

        与冷合并不同的是,online_merge的传参是Region的hash值,而Region的hash值就是Region名称的最后那段在两个.之间的字符串部分。

需求:需要把lagou_s表中的2个region数据进行合并:
student,,1587392159085.9ca8689901008946793b8d5fa5898e06. \
student,aaa,1587392159085.601d5741608cedb677634f8f7257e000.

        需要进入hbase shell:

merge_region 'c8bc666507d9e45523aebaffa88ffdd6','02a9dfdf6ff42ae9f0524a3d8f4c7777‘

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值