Hdfs-源码解析(3)

datanode和namenode之间的心跳机制

Hadoop中,通过datanode定期向namenode发送心跳信息,来确定datanode的有效性。对于超时未收到心跳信息的datanode,将被视为失效,将其从系统中移除。从代码中可以看出,超时的时间限制:

ClassFSNameSystem{

    ……

    long heartbeatInterval =conf.getLong("dfs.heartbeat.interval", 3) * 1000;

    this.heartbeatRecheckInterval =conf.getInt(

        "heartbeat.recheck.interval",5 * 60 * 1000); // 5 minutes

    this.heartbeatExpireInterval = 2 *heartbeatRecheckInterval +

      10 * heartbeatInterval;

 

private booleanisDatanodeDead(DatanodeDescriptor node) {

    return (node.getLastUpdate() <

            (now() - heartbeatExpireInterval));

  }

……

}

从代码中可以看出dfs.heartbeat.interval和heartbeat.recheck.interval配置项单位是毫秒。Namenode在 2*(heartbeat.recheck.interval)+ 10* dfs.heartbeat.interval之后,认为datanode失效,默认值是10分30秒。

Datanode是一个runnable对象,启动的时候,做为一个daemon运行。Datanode启动之后,会连接namenode,并每隔dfs.heartbeat.interval毫秒,发送一次心跳,默认为3秒:

public classDataNode extends Configured

    implements InterDatanodeProtocol,ClientDatanodeProtocol, FSConstants,

    Runnable, DataNodeMXBean {

……

public voidofferService() throws Exception {

while(shouldRun) {

      try {

        long startTime = now();

        if (startTime - lastHeartbeat >heartBeatInterval) {

          lastHeartbeat = startTime;

          /*调用远程Namenode的方法*/

          DatanodeCommand[] cmds =namenode.sendHeartbeat(dnRegistration,

                                                      data.getCapacity(),

                                                      data.getDfsUsed(),

                                                       data.getRemaining(),

                                                      xmitsInProgress.get(),

                                                      getXceiverCount());

          myMetrics.addHeartBeat(now() -startTime);

          //LOG.info("Just sent heartbeat, withname " + localName);

          if (!processCommand(cmds))

            continue;

        }

……

}

这个代码段中的namenode,是一个DatanodeProtocol对象。

publicDatanodeProtocol namenode = null;

在datanode启动的时候,namenode对象被初始化。初始化的同时,连接到namenode服务器:

// connect toname node

    this.namenode = (DatanodeProtocol)

      RPC.waitForProxy(DatanodeProtocol.class,

                      DatanodeProtocol.versionID,

                       nameNodeAddr,

                       conf);

从代码中可以看出,datanode中的namenode对象,是namenode在Datanode端的一个代理。Datanode使用这个代理调用了namenode中的sendHeartbeat方法,该方法调用handleHeartbeat对心跳信息进行处理,更新心跳信息列表。

在FSNamesystem类中的HeartbeatMonitor子类,是一个runnable的对象,在namenode启动的时候,将这个对象启动为一个线程,负责定期检查接收到的心跳信息,检查哪些datanode已经失效,将失效的datanode从系统中移除。

心跳机制的总体流程:datanode发起,调用namenode中的远程方法处理,HeartbeatMonitor线程负责维护。

ClassFSNamesystem{

  class HeartbeatMonitor implements Runnable {

public voidrun() {

      while (fsRunning) {

        try {

          long now = now();

          if (lastHeartbeatCheck +heartbeatRecheckInterval < now) {

            heartbeatCheck();

            lastHeartbeatCheck = now;

          }

……

        try {

          Thread.sleep(5000);  // 5 seconds

        } catch (InterruptedException ie) {

        }

      }

    }

}

  void heartbeatCheck() {

    if (isInSafeMode()) {

      //安全模式下不做心跳检测

      return;

    }

    boolean allAlive = false;

    while (!allAlive) {

      boolean foundDead = false;

      DatanodeID nodeID = null;

 

      //取第一个失效的datanode

      synchronized(heartbeats) {

        for (Iterator<DatanodeDescriptor>it = heartbeats.iterator();

             it.hasNext();) {

          DatanodeDescriptor nodeInfo =it.next();

          if (isDatanodeDead(nodeInfo)) {

            foundDead = true;

            nodeID = nodeInfo;

            break;

          }

        }

      }

 

      //申请fsnamesystem锁,删除失效的datanode

      if (foundDead) {

        synchronized (this) {

          synchronized(heartbeats) {

            synchronized (datanodeMap) {

              DatanodeDescriptor nodeInfo =null;

              try {

                nodeInfo = getDatanode(nodeID);

              } catch (IOException e) {

                nodeInfo = null;

              }

              if (nodeInfo != null &&isDatanodeDead(nodeInfo)) {

                NameNode.stateChangeLog.info(…);

                removeDatanode(nodeInfo);

              }

            }

          }

        }

      }

      allAlive = !foundDead;

    }

  }

 

private void removeDatanode(DatanodeDescriptornodeInfo) {

    synchronized (heartbeats) {

      if (nodeInfo.isAlive) {

        updateStats(nodeInfo, false);

        从heartbeats中移除

        heartbeats.remove(nodeInfo);

        更新datanode状态

        nodeInfo.isAlive = false;

      }

    }

 

    for (Iterator<Block> it =nodeInfo.getBlockIterator(); it.hasNext();) {

      删除该节点存储的block信息

      removeStoredBlock(it.next(), nodeInfo);

    }

    unprotectedRemoveDatanode(nodeInfo);

    clusterMap.remove(nodeInfo);

 

    if (safeMode != null) {

      safeMode.checkMode();

    }

  }

  更新块到datanode的映射关系。如果将被移除的块仍然有效,可能触发块复制任务。

  synchronized void removeStoredBlock(Blockblock, DatanodeDescriptor node) {

    NameNode.stateChangeLog.debug("BLOCK*NameSystem.removeStoredBlock: "

                                  +block +" from "+node.getName());

    if (!blocksMap.removeNode(block, node)) {

     NameNode.stateChangeLog.debug("BLOCK* NameSystem.removeStoredBlock:"

                                   +block+" has already been removed from node "+node);

      return;

    }

    一个块可能因为datanode失效被删除。如果这个块仍然有效,检查是否需要被复制,如果需要,将这个块放入需要复制的列表里。

    INode fileINode =blocksMap.getINode(block);

    if (fileINode != null) {

      decrementSafeBlockCount(block);

      updateNeededReplications(block, -1, 0);

    }

 

    从冗余列表里删除被删除的块信息,使块不可访问。

    Collection<Block> excessBlocks =excessReplicateMap.get(node.getStorageID());

    if (excessBlocks != null) {

      if (excessBlocks.remove(block)) {

        excessBlocksCount--;

       NameNode.stateChangeLog.debug("BLOCK* NameSystem.removeStoredBlock:"

            + block + " is removed fromexcessBlocks");

        if (excessBlocks.size() == 0) {

         excessReplicateMap.remove(node.getStorageID());

        }

      }

    }

   

    // Remove the replica from corruptReplicas

   corruptReplicas.removeFromCorruptReplicasMap(block, node);

  }

 

  void decrementSafeBlockCount(Block b) {

    if (safeMode == null) // mostly true

      return;

    safeMode.decrementSafeBlockCount((short)countNodes(b).liveReplicas());

  }

 

  刷新需要备份的块列表

  synchronized voidupdateNeededReplications(Block block,

                        int curReplicasDelta,int expectedReplicasDelta) {

    得到当前的副本数量。

    NumberReplicas repl = countNodes(block);

    int curExpectedReplicas =getReplication(block);

    将块放入需要更新的块列表中。

    neededReplications.update(block,

                             repl.liveReplicas(),

                             repl.decommissionedReplicas(),

                             curExpectedReplicas,

                              curReplicasDelta,expectedReplicasDelta);

  }

 

}

 

classSafeModeInfo {

 

    将相应的安全备份数量减1,并检查系统中块的安全备份数量是否降低到阀值,如果低于阀值,系统将进入安全模式。

    synchronized void decrementSafeBlockCount(shortreplication) {

      if (replication == safeReplication-1)

        this.blockSafe--;

      checkMode();

    }

    private void checkMode() {

      当安全的block数比例降至安全值以下,进入安全模式

      if (needEnter()) {

        enter();

        reportStatus("STATE* Safe modeON.", false);

        return;

      }

      //如果安全模式关闭,或者配置文件中的阀值设置为小于0的值,则退出安全模式。

      if (!isOn() ||                           // safe mode is off

          extension <= 0 || threshold <=0) {

        this.leave(true);

        return;

      }

      如果之前安全块数量已经低于阀值,系统处于安全模式,则直接返回。

      if (reached > 0) {

        reportStatus("STATE* Safe modeON.", false);

        return;

      }

      启动一个线程,监控安全块数量。

      reached = now();

      smmthread = new Daemon(newSafeModeMonitor());

      smmthread.start();

      reportStatus("STATE* Safe modeextension entered.", true);

    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值