`
hongs_yang
  • 浏览: 61082 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

region split流程分析

阅读更多

region split流程分析

split region的发起主要通过client端调用regionserver.splitRegion或memstore.flsuh时检查并发起。

 

Client通过rpc调用regionserver的splitRegion方法

client端通过HBaseAdmin.split传入region name与split point(切分的rowkey,可以不传入),

通过meta得到此region所在的server,发起rpc请求,调用HRegionServer.splitRegion方法

 

  public SplitRegionResponse splitRegion(final RpcController controller,

      final SplitRegionRequest request) throws ServiceException {

    try {

      checkOpen();

      requestCount.increment();

从onlineRegions中拿到对应的HRegion

      HRegion region = getRegion(request.getRegion());

      region.startRegionOperation(Operation.SPLIT_REGION);

      LOG.info("Splitting " + region.getRegionNameAsString());

在做split前,先对region进行flush操作。请参见region flush流程分析

      region.flushcache();

如果client端发起split请求时指定有split的rowkey,拿到split key的值

      byte[] splitPoint = null;

      if (request.hasSplitPoint()) {

        splitPoint = request.getSplitPoint().toByteArray();

      }

设置region的splitRequest属性为true,表示有split request

如果split rowkey传入不为空,也就是指定有rowkey,设置region的explicitSplitPoint为指定的rowkey

但此值设置后不会被清空,原因后面分析

 

      region.forceSplit(splitPoint);

发起split request,到split的线程进行处理。

Region.checkSplit流程:

a.检查region是否是meta/namespace的region,如果是返回null

b.如果hbase.master.distributed.log.replay配置为true时,同时openRegion后此region还没有被replay

  region.isRecovering==true,如果是返回null

c.通过hbase.regionserver.region.split.policy配置的RegionSplitPolicy,

  默认为IncreasingToUpperBoundRegionSplitPolicy,

  也可以直接在table create时配置SPLIT_POLICY的值为class

  调用splitPolicy.shouldSplit(),此方法做如下检查流程,并返回true与false

  c.1检查region.splitRequest的值是否为true,如果是,返回true,

  c.2得到当前regionserver中此region对应的table的所有region个数,

    得到region的存储最大size,

  c.2.1取出通过table create时的属性MAX_FILESIZE来设置的region最大存储大小,

如果没有取hbase.hregion.max.filesize配置的的值,默认为10 * 1024 * 1024 * 1024L(10g)

  c.2.2取出通过table create时的MEMSTORE_FLUSHSIZE属性来设置的region memstore的大小,

如果没有取hbase.hregion.memstore.flush.size配置的值,默认为1024*1024*128L(128M)

  c.2.3通过c.2.2的值*(当前rs中此table的region个数 * 当前rs中此table的region个数)

  c.2.4取出c.2.1中得到的值与c.2.3计算出的值最小的一个,得到region最大可存储的size值

  c.3检查region中所有store中是否有reference的storefile,如果有返回false

  c.4检查region中所有store中所有的storefile的大小是否超过了c.2中得到的size大小,如果是返回true

d.如果c方法调用返回的结果是false,返回null

f.调用RegionSplitPolicy.getSplitPoint()方法返回进行split的切分rowkey

  f.1如果region.explicitSplitPoint的值不为空,返回此值

  f.2迭代region中所有的store,调用HStore.getSplitPoint()方法得到此store的split rowkey

    HStore.getSplitPoint()方法流程:

  调用this.storeEngine.getStoreFileManager().getSplitPoint();得到一个splitpoint

  通过hbase.hstore.engine.class配置storeEngine的实现类,默认为DefaultStoreEngine

  默认的storeFileManager为DefaultStoreFileManager,如果store中没有storefile,返回null

  否则得到size最大的storefile,并得到此storefile的中间rowkey,并返回此值

g.检查f中得到的rowkey是否在region中,如果不在返回null,否则返回此rowkey,到此checkSplit流程完成

 

requestSplit见下面的compactSplitThread.requestSplit(region,rowkey)流程分析

      compactSplitThread.requestSplit(region, region.checkSplit());

      return SplitRegionResponse.newBuilder().build();

    } catch (IOException ie) {

      throw new ServiceException(ie);

    }

  }

 

compactSplitThread.requestSplit(region,rowkey)流程

此方法是所有的split请求的最终执行处理程序

 

  public synchronized void requestSplit(final HRegion r, byte[] midKey) {

如果进行split操作的传入进行切分region的rowkey为null,不做split操作

    if (midKey == null) {

      LOG.debug("Region " + r.getRegionNameAsString() +

        " not splittable because midkey=null");

      return;

    }

    try {

生成一个SplitRequest执行线程,通过splits线程池执行此线程,

  线程池大小通过hbase.regionserver.thread.split配置,默认为1

      this.splits.execute(new SplitRequest(r, midKey, this.server));

      if (LOG.isDebugEnabled()) {

        LOG.debug("Split requested for " + r + ".  " + this);

      }

    } catch (RejectedExecutionException ree) {

      LOG.info("Could not execute split for " + r, ree);

    }

  }

 

SplitRequest.run方法处理流程:

  public void run() {

    if (this.server.isStopping() || this.server.isStopped()) {

      LOG.debug("Skipping split because server is stopping=" +

        this.server.isStopping() + " or stopped=" + this.server.isStopped());

      return;

    }

    try {

      final long startTime = System.currentTimeMillis();

生成一个split执行程序

      SplitTransaction st = new SplitTransaction(parent, midKey);

 

      //acquire a shared read lock on the table, so that table schema modifications

      //do not happen concurrently

      tableLock = server.getTableLockManager().readLock(parent.getTableDesc().getTableName()

          , "SPLIT_REGION:" + parent.getRegionNameAsString());

      try {

        tableLock.acquire();

      } catch (IOException ex) {

        tableLock = null;

        throw ex;

      }

 

      // If prepare does not return true, for some reason -- logged inside in

      // the prepare call -- we are not ready to split just now. Just return.

 

根据splitkey把原来的region的startkey到splitkey与current time生成一个regioninfo

根据splitkey把原来的region的splitkey到endkey与current time生成一个regioninfo

      if (!st.prepare()) return;

      try {

执行split操作,通过hbase.regionserver.fileSplitTimeout配置split file的timeout时间,默认为30000ms

在zk中的region-in-transition路径下生成一个根据此region的子路径的RegionTransition实例,

  此实例在zk上存储的值为新生成的两个hregioninfo信息,

  并设置zk中此节点的EventType为RS_ZK_REQUEST_REGION_SPLIT

  在hdfs中的此region目录下生成一个.splits目录,

  关闭当前的region,并得到当前region中所有的store与store下的storefile列表。

  从rs中的onlineRegions列表中移出此region

  迭代每一个store中的所有storefile,生成一个SplitTransaction.StoreFileSplitter实例

  通过HRegionFileSystem.splitStoreFile生成一个以splitrow结束的与一个以splitrow开头的Reference的hfile

  并存储在切分后的两个新的region的.splits/cfname/storefilename.oldregionname文件

  通过调用HRegion(oldregion).createDaughterRegionFromSplits(newregionInfo)生成两个新的HRegion实例

  并把.splits目录下的hfile文件move到newregion的目录下

  更新meta表中的信息

  生成SplitTransaction.DaughterOpener线程实例,在当前rs中直接通过openregion打开两个新的hregion实例。

  把zk中节点的transition的zk EventType从RS_ZK_REGION_SPLITTING更新到RS_ZK_REGION_SPLIT,

  通知master在regionserver中的split完成,等待master对这个消息进行处理。直到master处理完成。

        st.execute(this.server, this.server);

      } catch (Exception e) {

        if (this.server.isStopping() || this.server.isStopped()) {

          LOG.info(

              "Skip rollback/cleanup of failed split of "

                  + parent.getRegionNameAsString() + " because server is"

                  + (this.server.isStopping() ? " stopping" : " stopped"), e);

          return;

        }

        try {

          LOG.info("Running rollback/cleanup of failed split of " +

            parent.getRegionNameAsString() + "; " + e.getMessage(), e);

          if (st.rollback(this.server, this.server)) {

            LOG.info("Successful rollback of failed split of " +

              parent.getRegionNameAsString());

          } else {

            this.server.abort("Abort; we got an error after point-of-no-return");

          }

        } catch (RuntimeException ee) {

          String msg = "Failed rollback of failed split of " +

            parent.getRegionNameAsString() + " -- aborting server";

          // If failed rollback, kill this server to avoid having a hole in table.

          LOG.info(msg, ee);

          this.server.abort(msg);

        }

        return;

      }

      LOG.info("Region split, hbase:meta updated, and report to master. Parent="

          + parent.getRegionNameAsString() + ", new regions: "

          + st.getFirstDaughter().getRegionNameAsString() + ", "

          + st.getSecondDaughter().getRegionNameAsString() + ". Split took "

          + StringUtils.formatTimeDiff(System.currentTimeMillis(), startTime));

    } catch (IOException ex) {

      LOG.error("Split failed " + this, RemoteExceptionHandler.checkIOException(ex));

      server.checkFileSystem();

    } finally {

      if (this.parent.getCoprocessorHost() != null) {

        try {

          this.parent.getCoprocessorHost().postCompleteSplit();

        } catch (IOException io) {

          LOG.error("Split failed " + this,

              RemoteExceptionHandler.checkIOException(io));

        }

      }

      releaseTableLock();

    }

  }

 

master中处理region split的监听流程

通过AssignmentManager.nodeDataChange事件监听rs中对split region的值修改。

nodeDataChanged-->handleAssignmentEvent-->handleRegion

      switch (rt.getEventType()) {

      case RS_ZK_REQUEST_REGION_SPLIT:

      case RS_ZK_REGION_SPLITTING:

      case RS_ZK_REGION_SPLIT:

设置两个新的region的状态为online状态。并删除zk上的路径

        if (!handleRegionSplitting(

            rt, encodedName, prettyPrintedRegionName, sn)) {

          deleteSplittingNode(encodedName, sn);

        }

        break;

 

执行memstore的flush后的split流程分析

在每次执行完成memstore时,会进行是否需要split的检查,如果需要进行split,会发起split request操作。

 private boolean flushRegion(final HRegion region, final boolean emergencyFlush) {

 

...............................................此处省去一些代码

 

Region.checkSplit流程:

a.检查region是否是meta/namespace的region,如果是返回null

b.如果hbase.master.distributed.log.replay配置为true时,同时openRegion后此region还没有被replay

  region.isRecovering==true,如果是返回null

c.通过hbase.regionserver.region.split.policy配置的RegionSplitPolicy,

  默认为IncreasingToUpperBoundRegionSplitPolicy,

  也可以直接在table create时配置SPLIT_POLICY的值为class

  调用splitPolicy.shouldSplit(),此方法做如下检查流程,并返回true与false

  c.1检查region.splitRequest的值是否为true,如果是,返回true,

  c.2得到当前regionserver中此region对应的table的所有region个数,

    得到region的存储最大size,

  c.2.1取出通过table create时的属性MAX_FILESIZE来设置的region最大存储大小,

如果没有取hbase.hregion.max.filesize配置的的值,默认为10 * 1024 * 1024 * 1024L(10g)

  c.2.2取出通过table create时的MEMSTORE_FLUSHSIZE属性来设置的region memstore的大小,

如果没有取hbase.hregion.memstore.flush.size配置的值,默认为1024*1024*128L(128M)

  c.2.3通过c.2.2的值*(当前rs中此table的region个数 * 当前rs中此table的region个数)

  c.2.4取出c.2.1中得到的值与c.2.3计算出的值最小的一个,得到region最大可存储的size值

  c.3检查region中所有store中是否有reference的storefile,如果有返回false

  c.4检查region中所有store中所有的storefile的大小是否超过了c.2中得到的size大小,如果是返回true

d.如果c方法调用返回的结果是false,返回null

f.调用RegionSplitPolicy.getSplitPoint()方法返回进行split的切分rowkey

  f.1如果region.explicitSplitPoint的值不为空,返回此值

  f.2迭代region中所有的store,调用HStore.getSplitPoint()方法得到此store的split rowkey

    HStore.getSplitPoint()方法流程:

  调用this.storeEngine.getStoreFileManager().getSplitPoint();得到一个splitpoint

  通过hbase.hstore.engine.class配置storeEngine的实现类,默认为DefaultStoreEngine

  默认的storeFileManager为DefaultStoreFileManager,如果store中没有storefile,返回null

  否则得到size最大的storefile,并得到此storefile的中间rowkey,并返回此值

g.检查f中得到的rowkey是否在region中,如果不在返回null,否则返回此rowkey,到此checkSplit流程完成

此处主要是检查region中是否有store的大小超过了配置的指定大小,也就是对c的检查

 

      boolean shouldSplit = region.checkSplit() != null;

      if (shouldSplit) {

如果需要做split操作,发起split request

        this.server.compactSplitThread.requestSplit(region);

      } else if (shouldCompact) {

        server.compactSplitThread.requestSystemCompaction(

            region, Thread.currentThread().getName());

      }

 

...............................................此处省去一些代码

 

    return true;

  }

 

 

  public synchronized boolean requestSplit(final HRegion r) {

    // don't split regions that are blocking

a.检查hbase.regionserver.regionSplitLimit配置的split limit是否大于rs中的onlineRegions的个数

  如果不想做split操作,可以把此值设置为一个较小的值,比如1

b.迭代region下的所有store,检查hbase.hstore.blockingStoreFiles配置的store的文件个数,默认为7

  减去store中所有的storefile的个是是否大于或等于Store.PRIORITY_USER(1)

    if (shouldSplitRegion() && r.getCompactPriority() >= Store.PRIORITY_USER) {

如果需要做split操作,得到split的key,此时默认从最大的storefile的中间key开始split

      byte[] midKey = r.checkSplit();

      if (midKey != null) {

发起split request,见compactSplitThread.requestSplit(region,rowkey)流程

        requestSplit(r, midKey);

        return true;

      }

    }

    return false;

  }

0
1
分享到:
评论

相关推荐

    HBase性能深度分析

    #### 实验流程与数据分析 实验中,客户端通过Zookeeper获取RegionServer地址,持续向HBase的RegionServer发送Row数据。为直观展现性能测试结果,设计了一款基于JFreeChart的实时图表生成程序,每隔3分钟自动绘制...

    HBase应用场景原理与基本架构共40页.pdf.zip

    在扩展时,可以通过增加Region Server来提升处理能力,或者通过Split操作将大Region分割为小Region,提高查询效率。同时,合理规划Column Family,优化数据模型,也能显著提升HBase的性能。 总之,"HBase应用场景...

    RF.rar_遥感ENVI ROI操作

    6. **ROI操作流程**:通常,ROI操作包括选择ROI、定义ROI、编辑ROI、分析ROI以及导出ROI数据等步骤。在ENVI中,可以通过交互式绘图工具或导入外部形状文件来创建和编辑ROI。 7. **IDL编程技巧**:在处理遥感数据时...

    HBase权威指南中文版

    7. **Region与Split**:Region是HBase的数据分区,每个Region包含一个连续的行键范围。随着数据增长,Region会自动分裂,保持单个Region的大小在合理范围内,以确保高效查询。 8. **Zookeeper**:Zookeeper是HBase...

    HBase源码分析

    - Split操作耗时大约在10毫秒级别,对于正在进行Split操作的Region,访问请求会被抛出NotServingRegion异常。 #### 二、HBase Master启动过程解析 1. **初始化HMaster:** - 启动时,首先进行HMaster的初始化...

    03开源NewSql数据库TiDB-Deep Dive into TiDB

    支持手动 Split Region,可用于处理单 Region 热点的问题 支持打散指定 Region,用于某些情况下手动调整热点 Region 分布 增加配置参数检查规则,完善配置项的合法性较验 5.调试接口 增加 `Drop Region` 调试接口...

    HBase-Research:HBase数据库源代码学习研究(包括代码注释,文档,用于代码分析的测试用例)

    源代码中的`RegionSplitPolicy`和`RegionSplitter`类是实现这一功能的关键。 2. **MemStore与HFile**:MemStore是内存中的数据缓冲区,当达到一定阈值时会被写入磁盘形成HFile。HFile是HBase的数据文件格式,它提供...

    平台维护规范

    贵州移动可能面临海量网络管理数据的存储和分析需求,因此需要建立一套规范化的HBase平台维护流程。 - **目的**:制定此规范的目的是为了确保HBase系统能够高效、安全地运行,同时提高数据处理能力和故障恢复能力,...

    python小白实验练习题实验二题目

    - **操作**:使用 `while` 循环和 `break` 控制流程。 - **输出结果**:输出 `1 3 5`。 ### 18. 嵌套循环与累加 ```python sum_result, j = 1, 1 while j factorial = 1 for i in range(2, 2 * (j + 1)): ...

    HBASE编程指南word版

    - **后台进程**: 包括Compaction、Split等,用于优化存储结构、提升性能。 #### 四、客户端访问HBase - **本地Java客户端**: 提供了直接访问HBase的能力,性能最优。 - **REST接口**: 通过HTTP协议提供对外的服务...

    鼎利软件分割数据方法

    首先,用户需要打开鼎利软件,选择“工具”菜单,然后选择“文件分割”选项,这将弹出“split rcu file”对话框。在这个对话框中,用户需加载需要分割的数据文件。接着,设置一个时间间隔,例如每小时、每天或者...

    halcon算子解释

    9. **连接和分割算子**:`join_region`用于合并相邻区域,而`split_region`可以将一个区域分割成多个子区域。这些算子在处理复杂图像结构时不可或缺。 10. **光照补偿算子**:如`illumination_compensation`,可以...

    hbase数据可视化系统

    使用HBase的Compaction和Split机制,保持Region的平衡;并考虑使用二级索引提高查询效率。 六、总结 通过SpringBoot搭建的HBase可视化系统,使得非技术人员也能便捷地管理和操作HBase,降低了使用门槛,提高了工作...

    10大HBase常见运维工具整理小结

    6. ** hbadmin**:HBase的命令行工具,提供了诸如关闭、启动regionserver,进行Region Split和Merge等操作。它是HBase运维中的基础工具,实用性极高。 7. **HBase Shell**:HBase的交互式命令行接口,允许用户执行...

    Phoenix技术与应用

    - 加盐属性不等同于 split key,一个 bucket 可以对应多个 region。 - 过大的 salt buckets 数量可能会减少 range 查询的灵活性,并降低查询性能。 #### Phoenix 下推 - **聚合/分组下推**:将聚合运算下推到...

    Unity编辑器下重启的方法

    - 资源管理:在自动化流程中,尤其是资源依赖分析和打包过程中,要注意内存和资源的管理,避免不必要的资源占用和内存溢出。 - 编码规范:代码的编写应当遵守编程规范,例如命名、注释以及逻辑清晰等,这有助于...

    OpenCV-Python-Toturial-中文版.pdf

    Python 还被称为“胶水语言”,因为它能够轻松地与其他软件工具集成,例如可以使用 Python 调用其他软件来构建复杂的工作流程,充分发挥各软件的优势。 **为什么选择 OpenCV?** 尽管 Python 自身拥有像 PIL 这样...

    35.OpenCV图像处理入门、算数逻辑运算与图像融合(推荐).pdf

    根据提供的文件信息,本文将详细解析“35.OpenCV图像处理入门、算数逻辑运算与图像融合”的核心知识点。...这不仅有助于理解图像处理的基本流程,还为进行更复杂的图像分析提供了必要的工具和方法。

Global site tag (gtag.js) - Google Analytics