datanode进程的分析(一)

来源:互联网 发布:杭州淘宝城三期商业 编辑:程序博客网 时间:2024/05/09 07:41

数据存储结点主类。

首先启动一系列服务端口,如接收数据的端口,web server访问端口等。

然后调用startDataNode()函数去做以下事情。

启动DN的数据接收服务守护线程DataXceiverServer

循环判断是否需要更新,如参数发生变化了,则需要重新初始化DN

然后再发送心跳,发送最近接收的block,报告DN当前的block列表给NN

报告DN当前的所有block列表的时间间隔相对要长很多,默认是1个小时报告一次。

 

run()

dataXceiverServer.start();

while (shouldRun) {

       startDistributedUpgradeIfNeeded();

       offerService();

    

}

 

offerService()

也是一个循环,首先会计算是否到了心跳时间。

到了下一次心跳时间,则远程调用NN的发送心跳函数sendHeartbeat,会返回相应的值。然后处理返回的值。

当下一次心跳还没到时,则向NN报告最近收到的block

然后,再向NN报告当前所有的blocks。处理NN返回的值。

如果数据块扫描线程没有启动,则启动它。

每次与NN通信时,都会返回DatanodeCommand命令,然后DN调用processCommand()函数去处理这些命令。

while (shouldRun) {

      try {

        long startTime = now();       

        if (startTime - lastHeartbeat > heartBeatInterval) {

          lastHeartbeat = startTime;

         DatanodeCommand[] cmds = namenode.sendHeartbeat(dnRegistration,

                                                      data.getCapacity(),

                                                      data.getDfsUsed(),

                                                       data.getRemaining(),

                                                      xmitsInProgress.get(),

                                                      getXceiverCount());

         myMetrics.heartbeats.inc(now() - startTime);

          //LOG.info("Justsent heartbeat, with name " + localName);

          if(!processCommand(cmds))

            continue;

        }

       reportReceivedBlocks();

       DatanodeCommand cmd = blockReport();

       processCommand(cmd);

 

        // start blockscanner

        if (blockScanner != null && blockScannerThread == null &&

            upgradeManager.isUpgradeCompleted()){

          LOG.info("StartingPeriodic block scanner.");

          blockScannerThread = new Daemon(blockScanner);

          blockScannerThread.start();

        }

        long waitTime = heartBeatInterval - (System.currentTimeMillis()- lastHeartbeat);

        synchronized(receivedBlockList) {

          if (waitTime > 0&& receivedBlockList.size() == 0) {

            try {

              receivedBlockList.wait(waitTime);

            } catch(InterruptedException ie) {

            }

          }

        } // synchronized

      }

    } // while(shouldRun)

  } // offerService

 

 

sendHeartbeat()

心跳的时间间隔为参数,默认为3S

this.heartBeatInterval = conf.getLong("dfs.heartbeat.interval", HEARTBEAT_INTERVAL) * 1000L;

 

 

processCommand()

NN中收到的命令有以下:

  final static int DNA_UNKNOWN = 0;    // unknown action  

  final static int DNA_TRANSFER = 1;   // transfer blocks to another datanode

  final static int DNA_INVALIDATE = 2; // invalidateblocks

  final static int DNA_SHUTDOWN = 3;   // shutdown node

  final static int DNA_REGISTER = 4;   // re-register

  final static int DNA_FINALIZE = 5;   // finalize previous upgrade

  final static int DNA_RECOVERBLOCK = 6;  // request a block recovery

  final static int DNA_ACCESSKEYUPDATE = 7;  // update access key

 

block传送给其他的DN,则调用BlockSender类将block传送给其他DN

标识无效的block,调用FSDataset类中的方法去标识数据块状态。

恢复block

关闭DN

重新注册DN

完成升级。

 

private booleanprocessCommand(DatanodeCommand cmd) throws IOException {

    if (cmd == null)

      return true;

    final BlockCommand bcmd =cmd instanceof BlockCommand? (BlockCommand)cmd: null;

 

    switch(cmd.getAction()) {

    case DatanodeProtocol.DNA_TRANSFER:

      // Send a copy of ablock to another datanode

     transferBlocks(bcmd.getBlocks(), bcmd.getTargets());

     myMetrics.blocksReplicated.inc(bcmd.getBlocks().length);

      break;

    case DatanodeProtocol.DNA_INVALIDATE:

      //

      // Some localblock(s) are obsolete and can be

      // safelygarbage-collected.

      //

      BlocktoDelete[] = bcmd.getBlocks();

      try {

        if (blockScanner != null) {

          blockScanner.deleteBlocks(toDelete);

        }

        data.invalidate(toDelete);

      } catch(IOException e) {

       checkDiskError();

        throw e;

      }

     myMetrics.blocksRemoved.inc(toDelete.length);

      break;

    case DatanodeProtocol.DNA_SHUTDOWN:

      // shut down thedata node

      this.shutdown();

      return false;

    case DatanodeProtocol.DNA_REGISTER:

      // namenoderequested a registration - at start or if NN lost contact

      LOG.info("DatanodeCommandaction: DNA_REGISTER");

      if (shouldRun) {

        register();

      }

      break;

    case DatanodeProtocol.DNA_FINALIZE:

      storage.finalizeUpgrade();

      break;

    case UpgradeCommand.UC_ACTION_START_UPGRADE:

      // start distributed upgrade here

     processDistributedUpgradeCommand((UpgradeCommand)cmd);

      break;

    case DatanodeProtocol.DNA_RECOVERBLOCK:

     recoverBlocks(((BlockRecoveryCommand)cmd).getRecoveringBlocks());

      break;

    case DatanodeProtocol.DNA_ACCESSKEYUPDATE:

      LOG.info("DatanodeCommandaction: DNA_ACCESSKEYUPDATE");

      if (isAccessTokenEnabled) {

        accessTokenHandler.setKeys(((KeyUpdateCommand)cmd).getExportedKeys());

      }

      break;

    default:

      LOG.warn("UnknownDatanodeCommand action: " + cmd.getAction());

    }

    return true;

  }

 

 

reportReceivedBlocks()

DN类中有二个变量。

privateLinkedList<Block> receivedBlockList = newLinkedList<Block>();

  privateLinkedList<String> delHints = newLinkedList<String>();

最近收到的blocks

当完整的接收到一个block时,会将block信息添加到这个队列里。

 

 

blockReport()

报告数据块列表的时间间隔参数,默认为60 * 60 * 1000;

this.blockReportInterval =

      conf.getLong("dfs.blockreport.intervalMsec", BLOCKREPORT_INTERVAL);

调用FSDataSet类中的getBlockReport()方法来获得正确状态的数据块列表。在该类中专门有个变量来保存数据块列表。

ReplicasMap volumeMap = new ReplicasMap();

同样,当block完成到某个状态后,都会block添加到这个队列中。

同时返回给NN的,finalized状态的block列表。

未完,待续。