zoukankan      html  css  js  c++  java
  • HDFS Maintenance State

    前言


    初一看文章标题,很多人可能比较奇怪“HDFS Maintenance”是什么意思,“HDFS包含”的意思?首先Maintenance这个形似Maintain的单词可不是什么包含的意思,它的解释是维护,维修。那么HDFS Maintenance具体是什么意思呢,HDFS处于维护状态?说起维护状态,我们不禁可以联想到HDFS RollingUpgrad,没错,RollingUpgrade确实与HDFS的维护有点关联。确切地说,HDFS的RollingUpgrade是HDFS Maintenance功能的一个使用场景。下面给大家介绍一下社区目前在开发的这个feature。

    HDFS Maintenance的缘来


    HDFS Maintenance的提出源自于HDFS Upgrade Domain(升级域)的提出。HDFS升级域是方便于集群做大规模滚动升级之类的操作而提出的HDFS升级域的相关内容可查阅笔者的另外一篇文章:HDFS升级域:Upgrade Domain。在HDFS升级域的讨论与实现过程中,社区提出了DataNode的Maintenance(维护状态)。Maintenance状态是一类新的状态,HDFS现有的状态有以下几种,看完大家可能就知道这是什么意思了。

    • Live(In Sevice)
    • Decommissioning
    • Decommissioned
    • Dead

    这些状态我们在NameNode的WebUI界面上也能直接看到。那么问题来了,上面4种是否是完美的呢?答案显然不是,如果我们仔细进行分析的话,上面状态的划分不够灵活。在这样的情况下,DataNode不是处于服务状态,就是处于Out of Service状态。而一旦处于Out of Service状态,接下来就会导致replication操作,使集群副本数满足副本系数的要求。所以这里会引出一个问题,我们是否能够定义一个新的状态,使得我们对DataNode的操作能尽可能地对集群没有影响,并能够快速的恢复回去呢?这就是DataNode Maintenance状态的缘由。

    DataNode Maintenance状态的定义


    与Decommission下线状态类似,Maintenance状态同样有2个细分状态,Enter_Maintenance和In_Maintenance状态。Enter_Maintenance表示的意思是正在进入Maintenance状态。而In_Maintenance表示目前已为Maintenance状态。为什么这里还会有进入Maintenance这样的状态呢?其实大家可以拿Decommission过程与此过程做一个比较。我们在执行下线操作时,为了满足集群副本数的要求,会有一个Decommissioning的状态,此时集群会做replication操作。同理,Enter_Maintenance状态也会做这样的事情,但是它与Decommission过程的目的略有不同。Enter_Maintenance是为了保证集群内有至少满足1个副本以上的数据副本,来保证数据的可用性。比如说当进入Maintenance状态的节点拥有集群中唯一的某块副本时,这时就会做一次replication操作。从一定程度上而言,Maintenance情况下需要满足的最低副本数应比Decommission过程要低,理论上只要存在一个即可。所以如果我们集群都是默认3副本的情况时,那么进入Maintenance状态,基本不会有replication操作了。

    如果DataNode处于Maintenance状态了,HDFS对DataNode的节点是怎样处理的呢?主要有以下几点主要影响:

    • 集群内不会触发replicate此节点内的块数据。
    • DataNode将不接收来自DFSClient端的读写请求。以往DataNode如果处于Out of Service的状态,就会抛出很多的异常。
    • DataNode将不会被选为block的存储节点。
    • Balancer/Mover操作也将避免移动此节点上的数据。

    所以从这里我们可以看到,Maintenance状态的DataNode就是处于一个“维护”的状态,它并不等同于Dead、Decommissioned状态,它能够主动地让NameNode知道自己的状态,并能够随时快速的切换回服务状态。

    HDFS Maintenance功能的使用场景


    介绍完Maintenance状态的定义之后,我们再来看看它的使用场景。

    首先HDFS Maintenance的提出源自于HDFS 升级域的讨论。所以毫无疑问,在滚动升级的过程中,HDFS Maintenance可以起到很大的帮助。这样的话,当每次进行批量rolling upgrade操作的时候,就能够快速进行服务状态的切换,而不用担心操作时间过长导致集群进行replication操作了。

    第二个使用场景是DataNode服务的快速切换。在很多情况下,当节点本身出现软件或者硬件层面的问题时,这时我们可能会对其进行临时的停止操作来进行软、硬件的故障恢复操作。这个时候我们就可以使DataNode进入Maintenance状态。在这里,我们可以把DataNode Maintenance理解为DataNode背后的一道开关。

    HDFS Maintenance的核心实现


    在HDFS-7877上,原作者提交了此功能的patch。笔者对其也进行了学习,给我的感觉是HDFS Maintenance的引入好比在各个操作方法入口上加了一道开关。这里的开关可以具象的理解为if(datanode.inService())的判断。主要在下面几个场景代码中做了处理。

    第一处,在调用BlockManager#createLocatedBlock获取块信息的时候做了处理,这步操作会在每次的读请求中被调用。代码改动如下:

    private LocatedBlock createLocatedBlock(final BlockInfoContiguous blk, final lon
    
         final int numNodes = blocksMap.numNodes(blk);
         final boolean isCorrupt = numCorruptNodes == numNodes;
    -    final int numMachines = isCorrupt ? numNodes: numNodes - numCorruptNodes;
    +    int numMachines = isCorrupt ? numNodes: numNodes - numCorruptNodes;
    +    numMachines -= numberReplicas.inMaintenanceReplicas() +
    +        numberReplicas.deadEnteringMaintenanceReplicas();
         final DatanodeStorageInfo[] machines = new DatanodeStorageInfo[numMachines];
         int j = 0;
         if (numMachines > 0) {
           for(DatanodeStorageInfo storage : blocksMap.getStorages(blk)) {
             final DatanodeDescriptor d = storage.getDatanodeDescriptor();
             final boolean replicaCorrupt = corruptReplicas.isReplicaCorrupt(blk, d);
    +        // Don't pick IN_MAINTENANCE or dead ENTERING_MAINTENANCE states.
    +        if (d.isInMaintenance() || (d.isEnteringMaintenance() && !d.isAlive)) {
    +          continue;
    +        }

    第二处,在Rereplication过程和普通写请求中的选出目标放置节点的方法过程中,进行了过滤处理,主要集中在下面2个方法。

    DatanodeDescriptor chooseSourceDatanode(Block block,
             corrupt += countableReplica;
           else if (node.isDecommissionInProgress() || node.isDecommissioned())
             decommissioned += countableReplica;
    +      else if (node.isEnteringMaintenance()) {
    +        enteringMaintenance += countableReplica;
    +        if (!node.isAlive) {
    +          deadEnteringMaintenance += countableReplica;
    +        }
    +      } else if (node.isInMaintenance())
    +        inMaintenance += countableReplica;
           else if (excessBlocks != null && excessBlocks.contains(block)) {
             excess += countableReplica;
           } else {
    @@ -1638,7 +1682,7 @@ else if (excessBlocks != null && excessBlocks.contains(block)) {
           if ((nodesCorrupt != null) && nodesCorrupt.contains(node))
             continue;
           if(priority != UnderReplicatedBlocks.QUEUE_HIGHEST_PRIORITY 
    -          && !node.isDecommissionInProgress() 
    +          && !node.isDecommissionInProgress() && !node.isEnteringMaintenance()
               && node.getNumberOfBlocksToBeReplicated() >= maxReplicationStreams)
           {

    下面是选择副本放置位置的时候,做了目标存储节点类别的判断。

    @@ -764,9 +764,9 @@ private boolean isGoodTarget(DatanodeStorageInfo storage,
         }
    
         DatanodeDescriptor node = storage.getDatanodeDescriptor();
    -    // check if the node is (being) decommissioned
    -    if (node.isDecommissionInProgress() || node.isDecommissioned()) {
    -      logNodeIsNotChosen(storage, "the node is (being) decommissioned ");
    +    // check if the node is in service
    +    if (!node.isInService()) {
    +      logNodeIsNotChosen(storage, "the node isn't in service");
           return false;
         }

    第三处,Balancer/Mover操作的时候,需要过滤掉处于Maintenance状态的节点。

    由于Balancer/Mover工具在运行的时候,都会调用Dispatcher init方法来执行初始化节点的操作,来过滤掉exclude,decommissioned这类的节点。所以我们在这里只需多加一类判断即可。

    首先是Dispatcher的init初始化方法。

      /** Get live datanode storage reports and then build the network topology. */
      public List<DatanodeStorageReport> init() throws IOException {
        final DatanodeStorageReport[] reports = nnc.getLiveDatanodeStorageReport();
        final List<DatanodeStorageReport> trimmed = new ArrayList<DatanodeStorageReport>(); 
        // create network topology and classify utilization collections:
        // over-utilized, above-average, below-average and under-utilized.
        for (DatanodeStorageReport r : DFSUtil.shuffle(reports)) {
          final DatanodeInfo datanode = r.getDatanodeInfo();
          // 此处判断节点是否需要过滤
          if (shouldIgnore(datanode)) {
            continue;
          }
          trimmed.add(r);
          cluster.add(datanode);
        }
        return trimmed;
      }

    然后我们进入shouldIgnore方法。

    private boolean shouldIgnore(DatanodeInfo dn) {
         final boolean decommissioned = dn.isDecommissioned();
         // ignore decommissioning nodes
         final boolean decommissioning = dn.isDecommissionInProgress();
    +    // ignore nodes in maintenance
    +    final boolean inMaintenance = dn.isInMaintenance();
    +    // ignore nodes entering maintenance
    +    final boolean enteringMaintenance = dn.isEnteringMaintenance();
         // ignore nodes in exclude list
         final boolean excluded = Util.isExcluded(excludedNodes, dn);
         // ignore nodes not in the include list (if include list is not empty)
         final boolean notIncluded = !Util.isIncluded(includedNodes, dn);
    
    -    if (decommissioned || decommissioning || excluded || notIncluded) {
    +    if (decommissioned || decommissioning || excluded || notIncluded ||
    +        inMaintenance || enteringMaintenance) {
           if (LOG.isTraceEnabled()) {
             LOG.trace("Excluding datanode " + dn + ": " + decommissioned + ", "
    -            + decommissioning + ", " + excluded + ", " + notIncluded);
    +            + decommissioning + ", " + excluded + ", " + notIncluded + ", "
    +            + inMaintenance + ", " + enteringMaintenance);
           }
           return true;
         }

    从以上3处的处理我们可以看到,Maintenance状态的处理与原有的Decommission状态的处理极为相似。当然上述只是笔者简单分析了几处,更多的实现还是建议读者自行阅读原patch代码,上面还有Enter_Maintenance状态时进行最小副本数的判断逻辑。

    HDFS Maintenance状态转化图


    DataNode Maintenance状态同样支持多种状态之间的转换,下面是原设计中的状态转化图。




    HDFS Maintenance状态转换图

    本文的内容就是如此,希望大家读完后有所收获。HDFS Maintenance功能预计发布在Hadoop 2.9.0的版本中,目前还在开发中。笔者目前也在关注这个Feature,希望也能贡献自己的一份力吧。

    参考资料


    [1].https://issues.apache.org/jira/browse/HDFS-7877
    [2].https://issues.apache.org/jira/secure/attachment/12709388/Supportmaintenancestatefordatanodes-2.pdf
    [3].https://issues.apache.org/jira/secure/attachment/12709387/HDFS-7877-2.patch

  • 相关阅读:
    mysql练习
    导航 开发 常用 官方网址 办公 政府 网站 url
    Yii 数据库 连接 Error Info: 向一个无法连接的网络尝试了一个套接字操作。
    xampp Apache Access forbidden! Error 403 解决方法
    MySQL 没有密码 初始化 设置 用户名
    Apache 虚拟机 vhosts C:WINDOWSsystem32driversetchosts
    js 返回上一页 链接 按钮
    MySQL concat concat_ws group_concat 函数(连接字符串)
    PHP的UTF-8中文转拼音处理类(性能已优化至极致)
    原生JavaScript实现金额大写转换函数
  • 原文地址:https://www.cnblogs.com/bianqi/p/12183694.html
Copyright © 2011-2022 走看看