当前位置: 首页 > news >正文

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‘

相关文章:

  • webpack5 之 基础构建打包
  • STM32使用寄存器点灯实验
  • 技术对接35
  • 金仓数据库 KingbaseES 插件参考手册 plsql_pldbgapi
  • 测试面试 | 某 BAT 大厂测试开发面试真题与重点解析
  • 2022鹏城杯
  • Kubernetes学习笔记-保障集群内节点和网络安全(3)限制pod使用安全相关的特性20220828
  • [免费专栏] Android安全之利用ADT获取内存中的敏感信息
  • 网络编程必读经典书籍
  • TDengine-解决集群搭建过程中启动失败问题
  • STM32 GPIO工作原理
  • ros入门(九)----ros navigation
  • 数学建模神经网络应用,构建神经网络模型方法
  • 小程序模板报价_小程序模板价格_小程序模板使用多少钱
  • 校园跑腿小程序市场需要和功能分析!
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Golang-长连接-状态推送
  • idea + plantuml 画流程图
  • iOS | NSProxy
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • Java IO学习笔记一
  • magento 货币换算
  • PaddlePaddle-GitHub的正确打开姿势
  • python3 使用 asyncio 代替线程
  • Python中eval与exec的使用及区别
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • vue的全局变量和全局拦截请求器
  • 测试如何在敏捷团队中工作?
  • 马上搞懂 GeoJSON
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 使用API自动生成工具优化前端工作流
  • 数据可视化之 Sankey 桑基图的实现
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 阿里云API、SDK和CLI应用实践方案
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Java)【深基9.例1】选举学生会
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (三)模仿学习-Action数据的模仿
  • (四)Controller接口控制器详解(三)
  • (一)认识微服务
  • (原創) 未来三学期想要修的课 (日記)
  • .bat批处理(六):替换字符串中匹配的子串
  • .equals()到底是什么意思?
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .Net8 Blazor 尝鲜