`
hongs_yang
  • 浏览: 61329 次
  • 性别: 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
分享到:
评论

相关推荐

    停车场管理系统c语言.docx

    问题描述: 停车场内只有一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在停车场的最北端),若车场内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入; 当停车场内某辆车要离开时,在它之后开入的车辆必须先退出车场为它让路,待该辆车开出大门外,其它车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。试为停车场编制按上述要求进行管理的模拟程序。 1.基本要求 (1)以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。 (2)每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码及到达或离去的时刻,对每一组输入数据进行操作后的输出数据为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车离去;则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。 (3)栈以顺序结构实现,队列以链表实现。 2.重点难点 重点:针对停车场问题的特点,利

    精选毕设项目-人民好公仆小程序(生活+便民+政务).zip

    精选毕设项目-人民好公仆小程序(生活+便民+政务)

    精选毕设项目-相册;处理用户信息.zip

    精选毕设项目-相册;处理用户信息

    精选毕设项目-喵喵小说.zip

    精选毕设项目-喵喵小说

    精选毕设项目-图片预览带后端.zip

    精选毕设项目-图片预览带后端

    精选项目-爱靓女带后台.zip

    精选项目-爱靓女带后台

    法院综合安全监管平台解决方案PPT(53页).pptx

    在科技与司法的交响曲中,智慧法院应运而生,成为新时代司法服务的新篇章。它不仅仅是一个概念,更是对法院传统工作模式的一次深刻变革。智慧法院通过移动信息化技术,为法院系统注入了强大的生命力,有效缓解了案多人少的矛盾,让司法服务更加高效、便捷。 立案、调解、审判,每一个阶段都融入了科技的智慧。在立案阶段,智慧法院利用区块链技术实现可信存证,确保了电子合同的合法性和安全性,让交易双方的身份真实性、交易安全性得到了有力见证。这不仅极大地缩短了立案时间,还为后续审判工作奠定了坚实的基础。在调解阶段,多元调解服务平台借助人工智能、自然语言处理等前沿技术,实现了矛盾纠纷的快速化解。无论是矛盾类型的多元化,还是化解主体的多元化,智慧法院都能提供一站式、全方位的服务,让纠纷解决更加高效、和谐。而在审判阶段,智能立案、智能送达、智能庭审、智能判决等一系列智能化手段的应用,更是让审判活动变得更加智能化、集约化。这不仅提高了审判效率,还确保了审判质量的稳步提升。 更为引人注目的是,智慧法院还构建了一套完善的执行体系。移动执行指挥云平台的建设,让执行工作变得更加精准、高效。执行指挥中心和信息管理中心的一体化应用,实现了信息的实时传输和交换,为执行工作提供了强有力的支撑。而执行指挥车的配备,更是让执行现场通讯信号得到了有力保障,应急通讯能力得到了显著提升。这一系列创新举措的实施,不仅让执行难问题得到了有效解决,还为构建诚信社会、保障金融法治化营商环境提供了有力支撑。智慧法院的出现,让司法服务更加贴近民心,让公平正义的阳光更加温暖人心。

    西门子1200与3台台达DTK温控器通讯程序 功能:实现西门子1200 PLC对3台台达DTK温控器进行485通讯控制,在触摸屏上设定温度,读取温度 器件:西门子12

    西门子1200与3台台达DTK温控器通讯程序 功能:实现西门子1200 PLC对3台台达DTK温控器进行485通讯控制,在触摸屏上设定温度,读取温度 器件:西门子1200 1214DC DC DC.昆仑通态TPC7062Ti ,西门子KTP700 Basic PN,台达DTK 4848V12温控器。 说明:的是程序,带详细注释程序,西门子触摸屏程序,PLC设置和温控器设置,接线说明书。 #SIEMENS 西门子

    机械设计电阻绕线焊线一体机sw18全套技术资料100%好用.zip

    机械设计电阻绕线焊线一体机sw18全套技术资料100%好用.zip

    VB6编写的上位机采集2路温度 并形成曲线图 还可查看历史数据

    VB6编写的上位机源码,可实时显示曲线图,带有数据库,可以进行历史数据的保存 及 查看历史采集数据。

    精选毕设项目-新浪读书.zip

    精选毕设项目-新浪读书

    jQuery+Slick插件实现游戏人物轮播展示切换特效源码.zip

    jQuery+Slick插件实现游戏人物轮播展示切换特效源码是一款通过背景图片的切换来显示不同的人物效果,轮播效果通过slick幻灯片插件来制作。效果非常棒,有需要的朋友可以直接下载使用,适应各大网站

    精选毕设项目-地图查找附件.zip

    精选毕设项目-地图查找附件

    (蛐蛐voc数据)农作物病虫害识别目标检测数据集,VOC格式,蛐蛐数据集,纯手动标注,用来进行目标检测代码训练的数据

    (蛐蛐voc数据)农作物病虫害识别目标检测数据集,VOC格式,蛐蛐数据集,纯手动标注,用来进行目标检测代码训练的数据。

    MATLAB Simulink仿真模型 双馈风机并网频率控制仿真模型,利用下垂控制与惯性控制结合的综合惯性控制,实现电力系统的频率稳定,两台同步发电机组,具体参数可自行调节,频率波形比较可利用matl

    MATLAB Simulink仿真模型 双馈风机并网频率控制仿真模型,利用下垂控制与惯性控制结合的综合惯性控制,实现电力系统的频率稳定,两台同步发电机组,具体参数可自行调节,频率波形比较可利用matlab工作区画出。

    科研项目结题报告的撰写指南:结构、内容与注意事项

    一、结题报告的类型及主要结构 结题报告是一种专门用于科研课题结题验收的实用性报告类文体,也叫研究报告。它是研究者在课题研究结束后对科研课题研究过程和研究成果进行客观、全面、实事求是的描述,是课题研究所有材料中最主要的材料,也是科研课题结题验收的主要依据。   一篇规范、合格的结题报告,需要回答好3个问题:一是“为什么要选择这项课题进行研究?”二是“这项课题是怎样进行研究的?”三是“课题研究取得哪些研究成果?”  基本结构大致包括以下部分: 第一个问题 “为什么要选择这项课题进行研究?”  1.课题提出的背景;2.课题研究的意义(包括理论意义和现实意义,这个部分也可以合并归入“课题提出的背景”部分);第二个问题“这项课题是怎样进行研究的?”3.文献综述;4.课题研究的理论依据;5.课题研究的目标;6.课题研究的主要内容;7.课题研究的对象;8.课题研究的方法;9. 课题研究的主要过程(研究的步骤);   除了第9部分外,从第1到第8部分在填报课题立项申报表、在制定课题研究方案、在开题报告中,都有要求,内容基本相同。到了撰写结题报告时,只须稍作适当修改就可以了。而第9部分,则需要通过对

    1+X网络安全应急响应之应急准备:构建高效安全的应急响应体系

    内容概要:本文档重点讲述了网络安全应急响应的各项准备工作,涵盖了‘1+X’网络安全应急响应的职业技能等级证书概述、应急响应的基础知识、应急响应组织的建立、风险评估与改进、应急响应预案的制定以及详细的应急响应计划处置样例。文中详细介绍了各级职业技能的要求和任务,尤其关注如何未雨绸缪,制定完善的应急预案以应对潜在的网络安全风险;同时也探讨了如何在网络安全事件发生时,采取及时有效的应急处置措施。 适合人群:从事或有兴趣进入网络安全领域的从业人员,尤其是准备考取‘1+X’网络安全应急响应职业技能等级证书的相关人员。 使用场景及目标:帮助读者了解网络安全应急响应的基本概念及其在整个国家安全框架中的重要地位;指导读者学会如何建立健全高效的应急响应组织结构,如何进行全面的风险评估以及如何编制切实可行的应急预案;通过实例剖析,增强读者应对突发网络安全事件的能力。文档的目标在于提升读者在不同层面的专业技能,包括但不限于系统备份、日志分析、安全漏洞修复等方面的能力。 阅读建议:此文档结构清晰,内容详尽,非常适合有一定基础的技术从业者参考学习。建议读者逐章节深入了解,特别是关注自身岗位对应的技能细分类别。此外,结合实例深入理解和练习如何进行应急处置是非常有价值的,有助于提升自身的实战能力。

    电动汽车动力系统匹配计算模型:输入整车参数及性能要求,一键生成驱动系统的扭矩功率峰值转速等参数 2、整车动力经济性计算模型:包含NEDC WLTC CLTC工况,输入整车参数可生成工况电耗、百公里电

    电动汽车动力系统匹配计算模型:输入整车参数及性能要求,一键生成驱动系统的扭矩功率峰值转速等参数。 2、整车动力经济性计算模型:包含NEDC WLTC CLTC工况,输入整车参数可生成工况电耗、百公里电耗、匀速工况续航、百公里电耗等信息。 实际项目中使用的计算仿真模型. 两个模型打包

    chromedriver-linux64_122.0.6254.0.zip

    chromedriver-linux64_122.0.6254.0

    SRS构型七自由度冗余机械臂运动学建模全套matlab代码 代码主要功能: 1. 基于臂角参数化方法求解机械臂在给定末端位姿和臂角下的关节角度; 2. 求解机械臂在给定末端位姿下的有效臂角范围

    SRS构型七自由度冗余机械臂运动学建模全套matlab代码 代码主要功能: [1]. 基于臂角参数化方法求解机械臂在给定末端位姿和臂角下的关节角度; [2]. 求解机械臂在给定末端位姿下的有效臂角范围,有效即在该区间内机械臂关节角度不会超出关节限位; [3]. 以避关节限位为目标在有效臂角区间内进行最优臂角的选取,进而获取机械臂在给定末端位姿下的最优关节角度。 购前须知: 1. 代码均为个人手写,主要包含运动学建模全套代码; 2. 代码已经包含必要的注释; 包含原理推导文档,不包含绘图脚本以及urdf;

Global site tag (gtag.js) - Google Analytics