Region拆分逻辑


Table of Contents

Region拆分
拆分前提
获取拆分点
执行拆分
回滚操作

Region拆分

Region的拆分逻辑是通过CompactSplitThread线程的requestSplit方法来触发的,每当执行MemstoreFlush操作时都会调用该方法进行判断,看是否有必要对目标Region进行拆分。

拆分前提

Region可拆分的前提是需要满足如下约束条件:

  1. 目标RegionServer的线上Region数没有达到hbase.regionserver.regionSplitLimit参数阀值

    该参数的默认值为1000,达到900时RegionServer将会打印警告:Total number of regions is approaching the upper limit。

  2. StoreFile文件数量没有达到hbase.hstore.blockingStoreFiles参数阀值

    此时会优先触发整理操作(详细参考Region整理章节)

  3. 要拆分的Region不属于meta表格

    HBase不支持对meta表格中的Region做拆分操作。

  4. Region没有处于recovering状态(参考Region恢复章节)
  5. 由具体的拆分策略来做决定,通过其shouldSplit方法

    HBase对外提供了5中拆分策略,全部由RegionSplitPolicy派生而来,5中策略分别为:

    • ConstantSizeRegionSplitPolicy

      当Region中某个Store数据量达到hbase.hregion.max.filesize参数阀值时进行拆分

    • IncreasingToUpperBoundRegionSplitPolicy

      当Region中某个Store数据量达到sizeToCheck阀值时进行拆分,sizeToCheck是通过如下方法计算得出的,如果RegionServer上含有指定Table的Region数量在(0,100]之间,返回如下公式的值:

      min(hbase.hregion.max.filesize, regionCount^3 * initialSize)

      否则返回hbase.hregion.max.filesize参数值。由此可见该拆分策略是增量式的,随着Region数量的增多,拆分阀值也逐渐越大,直至达到目标上限为止。

    • DelimitedKeyPrefixRegionSplitPolicy

      拆分策略如下:如果定义rowkey时,采用‘_‘作为字段分隔符(如:userid_eventtype_eventid),则采用该策略拆分之后,能够确保具有相同userid的记录隶属于同一Region。

      该类继承至IncreasingToUpperBoundRegionSplitPolicy,其拆分前提与父类相同,只是在拆分点的获取上略有不同(参考下一章节)。

    • KeyPrefixRegionSplitPolicy

      与DelimitedKeyPrefixRegionSplitPolicy类似,只不过是选取指定长度的字符前缀来作为row的分组。

    • DisabledRegionSplitPolicy

      该策略shouldSplit方法永远返回false,表示不启用拆分功能,不对Region做任何拆分。

获取拆分点

拆分点主要是通过调用拆分策略的getSplitPoint方法来进行获取,不同的拆分策略有着不同的获取逻辑,具体如下:

  1. 如果拆分点是用过通过split命令强制声明的,返回用户指定的拆分点。
  2. 如果采用的拆分策略为ConstantSizeRegionSplitPolicy或IncreasingToUpperBoundRegionSplitPolicy,则选取Region中数据总量最大的Store,通过其getSplitPoint方法来获取切分点。

    方法在执行过程中还需要考虑StoreFileManager的实现类型:

    • 如果是DefaultStoreFileManager

      从目标Store中选择一个数据量最大的StoreFile,对其执行getFileSplitPoint方法来获取midkey作为拆分点(从根索引中读取,参考HFile存储结构)。

    • 如果是StripeStoreFileManager(采用了StripeCompaction)

      如果Store中只有一个Stripe,获取数据量最大的StoreFile,对其执行getFileSplitPoint方法来获取midKey信息作为该Region的拆分点。

      如果有多个Stripe,则试图在所有Stripe中间找到如下图所示的分隔线,使分割线左右两侧的数据总量最为接近。

      分割线确立以后,如果能满足以下约束条件,便可直接确定该Region的拆分点。

      largeSideSize / smallSideSize < 1.5

      其中largeSideSize为数据总量偏大的一方(即图中分割线左边的数据总量),smallSideSize为数据总量偏小的一方(即图中分割线右边的数据总量),而1.5是通过hbase.store.stripe.region.split.max.imbalance配置项声明的。

      拿示例图片来做说明:由于largeSideSize(3072m)/smallSideSize(2560M)=1.2,数值低于1.5,因此直接将Stripe-2的endRow作为该Region的拆分点。而如果Stripe-2的大小为20480m,那么便没有办法满足以上约束条件,这时需要进行如下处理:

      将stripe-2的一半大小划分到右侧区域(即将分割线画到如图所示位置),然后重新生成radio值。

      largeSideSize(12800) / smallSideSize(11264) = 1.14

      如果新生成的radio值比之前的radio还要大,则放弃这种处理办法,依然采用之前的处理方式,否则从stripe-2中选择数据总量最大的StoreFile,对其执行getFileSplitPoint方法来获取midkey信息,并将其作为该Region的拆分点返回。

执行拆分

Region在拆分过程中,需要HMaster和RegionServer的共同参与,中间的协调工作通过Zookeeper来实现。针对每一个待拆分的Region,RegionServer端会创建/hbase/region-intransition/{regionName}拆分节点,节点内容为RegionTransition对象,对象由以下几部分信息构成:

  • eventType

    事件类型,这里为RS_ZK_REQUEST_REGION_SPLIT,Master端会对该事件类型进行捕获,并做出相应的回调处理。

  • regionName

    表示对哪个Region执行的转换操作。

  • serverName

    目标Region部署在哪台RegionServer上。

  • payload

    装载额外的信息用于处理目标事件,这里为子Region的HRegionInfo信息。

拆分节点创建成功以后,HMaster端会进行相应的回调处理,通过监听Zookeeper的目标节点路径(参考AssignmentManager类的handleRegion方法)。在回调处理中,首先从目标拆分节点中读取出RegionTransition对象,修改其eventType属性值为RS_ZK_REGION_SPLITTING,并将该对象重新赋予目标拆分节点。随后对参与拆分操作的Region状态进行修改,将待拆分的父Region标记成SPLITTING状态,将两个新生成的子Region标记为SPLITTING_NEW,通过RegionStates类的updateRegionState方法。

与此同时,RegionServer端在创建出拆分节点以后会进入循环等待状态(代码逻辑参考ZKSplitTransactionCoordination类的waitForSplitTransaction方法),直至其eventType属性值变为RS_ZK_REGION_SPLITTING,然后开始执行如下处理:

  1. 在待拆分Region目录下创建.splits子目录来作为拆分目录。
  2. 将待拆分的Region关闭,不再提供线上服务,通过HRegion的close方法。
  3. 对Region中的storeFile进行拆分。

    假设将目标Region拆分成Split-A(存储拆分点之前的数据)和Split-B(存储拆分点之后的数据),拆分规则如下:

    首先定义如下3个变量:

    (1)firstKey:用于表示StoreFile文件的起始key;

    (2)lastKey:用于表示StoreFile文件的结束key;

    (3)splitKey:用于表示Region的拆分点。

    • 如果StoreFile满足firstKey < splitKey < lastKey,将[firstKey,splitKey]区间上的数据赋予Split-A。
    • 如果StoreFile满足firstKey < lastKey < splitKey,将整个StoreFile赋予Region-a。
    • 如果StoreFile满足splitKey < firstKey < lastKey,将整个StoreFile赋予Region-b

    Tip

    在HBase中,拆分后的StoreFile子文件是通过Reference来进行描述的,其数据内容采用protobuf进行序列化,每个Reference文件在HDFS上的存储路径为path/to/table/parentRegion/.splits/childRegion/cf/storefile.parentRegion

    拆分完成以后需要将子Region从path/to/table/parentRegion/.splits/childRegion路径移动到path/to/table/路径下。

  4. 修改meta表中Region元数据信息,通过MetaTableAccessor类的splitRegion方法

    将子Region添加到meta表格中,并将父Region标记为splitting状态(新增splitA和splitB列信息,内容为子Region的HRegionInfo)。

    Tip

    从该步骤开始起,Region拆分操作将无法回滚,一旦出错,需要将RegionServer停掉以便ServerShutdownHandler可以对目标Region的元数据进行修复,具体可参考Region状态管理章节中有关状态修复内容的介绍。

  5. 将拆分后的子Region进行启动,通过HRegion的openHRegion方法

    启动后的子Region与父Region部署在同一个RegionServer上,同时由于拆分后的子Region内部含有Reference文件,因此需要对其执行整理操作(参考Region整理章节)。

RegionServer端完成子Region的启动之后,需要将启动结果通知到HMaster端,通知逻辑同样是借助于Zookeeper来实现的,首先从Zookeeper的目标拆分节点中获取RegionTransition对象,将其eventType属性值修改为RS_ZK_REGION_SPLIT。节点状态修改后,Master端会进行如下回调处理:

(1)将父Region标记成SPLIT状态,并对其进行下线处理;

(2)对拆分后的子Region进行上线,将其标记为OPEN状态;

(3)删除Zookeeper中的拆分节点。

至此,Region的拆分逻辑成功执行,子Region开始提供线上服务。

回滚操作

Region在拆分过程中是采用事务进行管理的,如果在拆分的过程中出现了异常,可以对事务进行回滚,从而避免脏数据的产生。事务逻辑主要是通过SplitTransaction类来封装的,该类的使用模版如下:

SplitTransaction st = new SplitTransaction(conf, parent, midKey);
if (!st.prepare()) return;
try {
   st.execute(server, services);
} catch (IOException ioe) {
   try {
      st.rollback(server, services);
      return;
   } catch (RuntimeException e) {
      myAbortable.abort("Failed split, abort");
   }
}
		

可以看到回滚逻辑主要通过rollback方法来实现,方法在执行过程中会进行如下处理:

  1. 首先获取当前Region的拆分进度,以及到达该进度之前都做了哪些工作。

    Region在拆分过程中大致会经历如下几个阶段(详细的拆分过程可参考上一章节):

    (1)STARTED - 拆分逻辑被触发;

    (2)PREPARED - 执行拆分前的准备工作;

    (3)BEFORE_PRE_SPLIT_HOOK - 调用协处理器进行拆分前的拦截处理;

    (4)AFTER_PRE_SPLIT_HOOK - 协处理器处理结束;

    (5)SET_SPLITTING - Zookeeper中创建出拆分节点;

    (6)CREATE_SPLIT_DIR - 拆分目录被生成;

    (7)CLOSED_PARENT_REGION - 父Region被关闭;

    (8)OFFLINED_PARENT - 父Region被下线,不再提供线上服务;

    (9)STARTED_REGION_A_CREATION - 第一个子Region被成功创建;

    (10)STARTED_REGION_B_CREATION - 第二个子Region被成功创建;

    (11)PONR - 回滚分界点,即该阶段之前的操作可以回滚;

    (12)OPENED_REGION_A - 第一个子Region被开启;

    (13)OPENED_REGION_B - 第二个子Region被开启;

    (14)BEFORE_POST_SPLIT_HOOK - 调用协处理器进行拆分后的拦截处理;

    (15)AFTER_POST_SPLIT_HOOK - 协处理器处理结束。

    每到达一个阶段,HBase都会创建JournalEntry实体来对当前的进度进行标记,并将该实体添加到journal集合中。这样,通过journal集合便可获知当前拆分进度已经进入到了哪个阶段,然后依次向前回溯对每个阶段进行回滚即可。需要注意的是如果拆分进度到达了PONR阶段(point-of-no-return),此时将无法在执行回滚操作,只能将RegionServer停掉以便ServerShutdownHandler对Region的元数据进行修复(参考Region状态管理章节中有关状态修复的介绍)。

    针对该情况RegionServer宕掉以后将会打印如下提示信息:

    Abort; we got an error after point-of-no-return

  2. 针对当前进度之前的所有操作进行回滚。

    回滚操作是通过不断迭代来完成的,每次回滚都是针对一个具体的阶段来进行。

    (1)如果回滚时处于SET_SPLITTING阶段,删除Zookeeper中的拆分节点;

    (2)如果回滚时处于CREATE_SPLIT_DIR阶段,清理父Region下的拆分目录;

    (3)如果回滚时处于CLOSED_PARENT_REGION阶段,重新对父Region执行初始化操作;

    (4)如果回滚时处于STARTED_REGION_A_CREATION阶段,清理第一个子Region的存储目录;

    (5)如果回滚时处于STARTED_REGION_B_CREATION阶段,清理第二个子Region的存储目录;

    (6)如果回滚时处于OFFLINED_PARENT阶段,重新将父Region上线;

    (7)如果回滚时处于PONR或以后的阶段,将RegionServer停掉。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-11 00:36:04

Region拆分逻辑的相关文章

Region恢复逻辑

Table of Contents Region恢复逻辑 配置参数 Region恢复逻辑 RegionServer出现宕机以后,其上部署的Region将会被Master重新分配处理,由于在宕机前,某些Region的memStore数据可能还没有做flush操作,因此,需要对这部分数据做还原处理,还原过程通过读取HLog文件来实现. 截至到目前为止(1.0版本),HBase共对外声明了两种Region恢复策略,分别基于LOG_SPLITTING和LOG_REPLAY.其中LOG_REPLAY是从0

银行业务-Excel文件的拆分逻辑

一.问题: 随着银行业务数据量的急剧增加,原始的人力统计数据已经不能满足要求, 需要开发一款可以实现自动化数据统计的系统平台,进行数据的采集.加工.过滤.统计.预测 其中数据采集方式又以[Excel]格式为人们所熟悉,那么如何把Excel表格的数据进行持久化 ? 二.分析: 首先,需要把实体的Excel文件映射到数据库中,就要对表格进行拆分 行维度:可以分为表头行.数据行,映射到数据库中就是两张表[头表.DTL表],其中由于数据的特殊存在[DTL*表] 列维度:每一列都包含实际的数据信息,在行维

HBASE REGION SPLIT策略

hbase 0.94.0版本中,对于region的split方式引入了一个非常方便的SplitPolicy,通过这个SplitPolicy,可以主动的干预控制region split的方式.在org.apache.Hadoop.hbase.regionserver包中,可以找到这么几个自带的splitPolicy: ConstantSizeRegionSplitPolicy, IncreasingToUpperBoundRegionSplitPolicy, and KeyPrefixRegion

Hbase的region合并与拆分详解

1.region 拆分机制 region中存储的是大量的rowkey数据 ,当region中的数据条数过多的时候,直接影响查询效率.当region过大的时候.hbase会拆分region , 这也是Hbase的一个优点 . HBase的region split策略一共有以下几种: 1.ConstantSizeRegionSplitPolicy 0.94版本前默认切分策略 当region大小大于某个阈值(hbase.hregion.max.filesize=10G)之后就会触发切分,一个regio

如何计算一段程序逻辑运行时间?

-- 1 class Program 2 { 3 4 [System.Runtime.InteropServices.DllImport("Kernel32.dll")] 5 static extern bool QueryPerformanceCounter(ref long count); 6 [System.Runtime.InteropServices.DllImport("Kernel32.dll")] 7 static extern bool Query

Hbase Region Server整体架构

Region Server的整体架构 本文主要介绍Region的整体架构,后续再慢慢介绍region的各部分具体实现和源码 RegionServer逻辑架构图 RegionServer职责 1.      监听协作,通过zk来侦听master.meta位置.集群状态等信息的变化,更新本地数据. 2.      管理region的offline.online.open.close等操作,这些操作是和hmaster配合这来做的,region的状态有如下这些 offline.opening.open.

大文件拆分问题的java实践(附源码)

引子 大文件拆分问题涉及到io处理.并发编程.生产者/消费者模式的理解,是一个很好的综合应用场景,为此,花点时间做一些实践,对相关的知识做一次梳理和集成,总结一些共性的处理方案和思路,以供后续工作中借鉴. 本文将尝试由浅入深的方式表述大文件拆分的问题及不同解决方案,给出的方案不一定是最优解,也并非线上环境论证过的靠谱方式,目的只是在于通过该问题融会贯通io.多线程等基础知识理论.生产环境请慎用. 本文不会逐行讲解代码实现,而注重在方案设计及思路探讨上,但会在文末附上源码demo git地址. 问

AIX-存储管理和逻辑卷管理(下)

存储管理.LVM和文件系统(下) 导航: 管理逻辑卷 文件系统 五.管理逻辑卷 一个逻辑卷映射一个或多个物理卷,具体取决于您希望维护的数据副本的数量 单个逻辑卷副本,表示存在一个逻辑分区到物理分区的映射 添加逻辑卷 使用mklv命令创建逻辑卷,该命令指定逻辑卷的名称并定义其特征,包括要分配的逻辑分区数量(默认为128个逻辑分区) mklv命令标志: -c设置每个逻辑分区的物理分区数量 -i从标准输入读取Phsical Volume的参数 -L设置逻辑卷标签.标签大小为127个字符,如果逻辑卷将用

HBase原理和设计

一篇不错的介绍HBase基本原理的文章,转载自:http://www.sysdb.cn/index.php/2016/01/10/hbase_principle/ ,感谢原作者. 简介 HBase —— Hadoop Database的简称,Google BigTable的另一种开源实现方式,从问世之初,就为了解决用大量廉价的机器高速存取海量数据.实现数据分布式存储提供可靠的方案.从功能上来讲,HBase不折不扣是一个数据库,与我们熟悉的Oracle.MySQL.MSSQL等一样,对外提供数据的