在前面说hadoop整体实现的时候, 说过DataNode的需要完成的首要任务是K-V存储。

                                

         

第二个功能是 完成和namenode 通信 ,这个通过IPC 心跳连接实现。此外还有和客户端 其它datanode之前的信息交换。

第 三个功能是 完成和客户端还有其它节点的大规模通信,这个需要直接通过socket 协议实现。

  

下面开始分析源代码,看看DataNode是如何实现这些功能的。

  

分析代码采取自定向下的分析方式, 看看代码中做了啥,然后分析这些代码的作用。

首先看Datanode实现的接口。

  1. public class DataNode extends Configured
  2.     implements InterDatanodeProtocol, ClientDatanodeProtocol, FSConstants,
  3.     Runnable, DataNodeMXBean {

它实现了 InterDatanodeProtocol, ClientDatanodeProtocol, 这两个重要接口。 作用和之前分析haoop IPC的时候提到过, 为了是客户端 和其它datanode节点远程调用本dataNode节点方法的时候,提供方法实际运行的对象。

我们可以看到它并没有实现和datanode的接口,因为datanode是主动和nameNode联系,nameNode从来不会主动调用dataNode上的方法。

在main 方法中主要 通过一系列调用创建了datanode对象。

之后datanode的初始化工作主要由 startDataNode()来完成, 这是一个很复杂的方法,我们来一点一点的分析。

  1. void startDataNode(Configuration conf,
  2.                      AbstractList<File> dataDirs, SecureResources resources
  3.                      ) throws IOException {
  4.     if(UserGroupInformation.isSecurityEnabled() && resources == null)
  5.       throw new RuntimeException("Cannot start secure cluster without " +
  6.             "privileged resources.");
  7.     // connect to name node
  8.     this.namenode = (DatanodeProtocol)
  9.       RPC.waitForProxy(DatanodeProtocol.class,
  10.                        DatanodeProtocol.versionID,
  11.                        nameNodeAddr,
  12.                        conf);
  13. 这个是通过反射获取同dataNode节点通信的代理对象
  14.     // get version and id info from the name-node
  15.     NamespaceInfo nsInfo = handshake(); //立刻与名字节点通信
  16.     StartupOption startOpt = getStartupOption(conf);
  17.     assert startOpt != null : "Startup option must be set.";
  18.       storage.recoverTransitionRead(nsInfo, dataDirs, startOpt);
  19.       // adjust
  20.       this.dnRegistration.setStorageInfo(storage);
  21.       // initialize data node internal structure
  22.       this.data = new FSDataset(storage, conf);
  23. // 创建数据存储KV 的对象 这个后面还要再细分析。
  24.     }
  25.     this.threadGroup = new ThreadGroup("dataXceiverServer");
  26.     this.dataXceiverServer = new Daemon(threadGroup,
  27.         new DataXceiverServer(ss, conf, this));
  28.     this.threadGroup.setDaemon(true); // 创建流接口服务器 DataXServer   这个需要后面再分析
  29.     ipcServer = RPC.getServer(this, ipcAddr.getHostName(), ipcAddr.getPort(),
  30.         conf.getInt("dfs.datanode.handler.count", 3), false, conf, //创建IPC服务器。
  31.         blockTokenSecretManager);
  32.      
  33.   }

上面代码分析中我们留了两个之后还要分析的方法,现在来看一下。

第一个是FsdataSet.

我们需要考虑的问题是 hadoop以64M大小为单位作为一个文件的大小 存储在linux 文件系统 上。 当文件多了,就有一个效率问题,同一个文件夹下有过多的文件

和文件目录过深都不利于检索速度(这个与linux文件系统inode结构有关,这里暂不讨论这个) 。所以我们这里要设计一个结构 需要创建文件夹 但文件夹目录不能过深。

此外 hadoop 还考虑了一个优化问题,如果一个datanode节点上插有多块硬盘的话,怎么提高并行吞吐量。好,有了这些我们来看具体实现。

一个FSdir对于着一个存储目录,一个FSVolume 对应着一个用户配置的数据目录(应该为一个磁盘最好) FsVolumeSet存储着所有的FSVolume对象。

在FsDataSet中海油一个最重要的成员变量,volumeMap 就是这个成员变量存储了 每一个Block 和它对应的存储路径等信息。

  1. HashMap<Block,DatanodeBlockInfo> volumeMap = new HashMap<Block, DatanodeBlockInfo>();;

第二个是 DataXServer

当往数据节点中填入数据或者数据节点之间做负载均衡的时候显然无法 使用Hdoop IPC 因为hadoop的IPC 在socket之上封装了方法的调用,如果在这之上封装一个大规模数据传输的方法,显然效率上不如直接用socket通信。

  1.  ServerSocket ss;
  2.     if(secureResources == null) {
  3.       ss = (socketWriteTimeout > 0) ?
  4.         ServerSocketChannel.open().socket() : new ServerSocket();
  5.       Server.bind(ss, socAddr, 0);
  6.     } else {
  7.       ss = resources.getStreamingSocket();
  8.     }
  9.     ss.setReceiveBufferSize(DEFAULT_DATA_SOCKET_SIZE);
  10. //初始化处理类dataXceiverServer
  11.    this.threadGroup = new ThreadGroup("dataXceiverServer");
  12.    this.dataXceiverServer = new Daemon(threadGroup, new DataXceiverServer(ss, conf, this));
  13.    this.threadGroup.setDaemon(true); // auto destroy when empty

DataXceiverServer 是个线程 我们看一下它的ruan方法

  1. Socket s = ss.accept();
  2.         s.setTcpNoDelay(true);
  3.         new Daemon(datanode.threadGroup,
  4.             new DataXceiver(s, datanode, this)).start();

我们再看一下 DataXceiver的run方法

  1. public void run() {
  2.     DataInputStream in=null;
  3.     try {
  4.       in = new DataInputStream(
  5.           new BufferedInputStream(NetUtils.getInputStream(s),
  6.                                   SMALL_BUFFER_SIZE));
  7.       short version = in.readShort();
  8.       if ( version != DataTransferProtocol.DATA_TRANSFER_VERSION ) {
  9.         throw new IOException( "Version Mismatch" );
  10.       }
  11.       boolean local = s.getInetAddress().equals(s.getLocalAddress());
  12.       byte op = in.readByte();
  13.       // Make sure the xciver count is not exceeded
  14.       int curXceiverCount = datanode.getXceiverCount();
  15.       if (curXceiverCount > dataXceiverServer.maxXceiverCount) {
  16.         throw new IOException("xceiverCount " + curXceiverCount
  17.                               + " exceeds the limit of concurrent xcievers "
  18.                               + dataXceiverServer.maxXceiverCount);
  19.       }
  20.       long startTime = DataNode.now();
  21.       switch ( op ) {
  22.       case DataTransferProtocol.OP_READ_BLOCK:
  23.         readBlock( in );
  24.         datanode.myMetrics.addReadBlockOp(DataNode.now() - startTime);
  25.         if (local)
  26.           datanode.myMetrics.incrReadsFromLocalClient();
  27.         else
  28.           datanode.myMetrics.incrReadsFromRemoteClient();
  29.         break;
  30.       case DataTransferProtocol.OP_WRITE_BLOCK:
  31.         writeBlock( in );
  32.         datanode.myMetrics.addWriteBlockOp(DataNode.now() - startTime);
  33.         if (local)
  34.           datanode.myMetrics.incrWritesFromLocalClient();
  35.         else
  36.           datanode.myMetrics.incrWritesFromRemoteClient();
  37.         break;
  38.       case DataTransferProtocol.OP_REPLACE_BLOCK: // for balancing purpose; send to a destination
  39.         replaceBlock(in);
  40.         datanode.myMetrics.addReplaceBlockOp(DataNode.now() - startTime);
  41.         break;
  42.       case DataTransferProtocol.OP_COPY_BLOCK:
  43.             // for balancing purpose; send to a proxy source
  44.         copyBlock(in);
  45.         datanode.myMetrics.addCopyBlockOp(DataNode.now() - startTime);
  46.         break;
  47.       case DataTransferProtocol.OP_BLOCK_CHECKSUM: //get the checksum of a block
  48.         getBlockChecksum(in);
  49.         datanode.myMetrics.addBlockChecksumOp(DataNode.now() - startTime);
  50.         break;
  51.       default:
  52.         throw new IOException("Unknown opcode " + op + " in data stream");
  53.       }
  54.     } catch (Throwable t) {
  55.       LOG.error(datanode.dnRegistration + ":DataXceiver",t);
  56.     } finally {
  57.       LOG.debug(datanode.dnRegistration + ":Number of active connections is: "
  58.                                + datanode.getXceiverCount());
  59.       IOUtils.closeStream(in);
  60.       IOUtils.closeSocket(s);
  61.       dataXceiverServer.childSockets.remove(s);
  62.     }
  63.   }

重点在这句

  1. byte op = in.readByte();

应该是根据流中的事先约定 来 第一个字节 来决定是

hadoop DataNode实现分析的更多相关文章

  1. hadoop源码分析(2):Map-Reduce的过程解析

    一.客户端 Map-Reduce的过程首先是由客户端提交一个任务开始的. 提交任务主要是通过JobClient.runJob(JobConf)静态函数实现的: public static Runnin ...

  2. Hadoop启动脚本分析

    Hadoop启动脚本分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 能看到这篇博客的你估计对Hadoop已经有一个系统的了解了,最起码各种搭建方式你应该是会的,不会也没有关系, ...

  3. Hadoop源码分析之数据节点的握手,注册,上报数据块和心跳

    转自:http://www.it165.net/admin/html/201402/2382.html 在上一篇文章Hadoop源码分析之DataNode的启动与停止中分析了DataNode节点的启动 ...

  4. 4. hadoop启动脚本分析

    4. hadoop启动脚本分析 1. hadoop的端口 ``` 50070 //namenode http port 50075 //datanode http port 50090 //2name ...

  5. Hadoop Datanode节点无法启动(All directories in dfs.data.dir are invalid)

    Hadoop Datanode节点无法启动(All directories in dfs.data.dir are invalid) java.io.IOException: All director ...

  6. Hadoop DataNode不能正常工作的原因

    在把Hadoop环境搭建成功,并且也Hadoop的各个组件都正常工作.在重启过几次Hadoop后发现DataNode不能正常工作,打开Hadoop 的后台http://localhost:50030和 ...

  7. hadoop编程:分析CSDN注冊邮箱分布情况

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jdh99/article/details/37565825 hadoop编程:分析CSDN注冊邮箱分 ...

  8. hadoop datanode 和 tasktracker起不来

    本篇文章主要介绍了"hadoop datanode 和 tasktracker起不来.",主要涉及到hadoop datanode 和 tasktracker起不来.方面的内容,对 ...

  9. 【Hadoop】Hadoop DataNode节点超时时间设置

    hadoop datanode节点超时时间设置 datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间 ...

随机推荐

  1. POJ2451 Uyuw's Concert(半平面交)

    题意就是给你很多个半平面,求半平面交出来的凸包的面积. 半平面交有O(n^2)的算法,就是每次用一个新的半平面去切已有的凸包,更新,这个写起来感觉也不是特别好写. 另外一个O(nlogn)的算法是将半 ...

  2. POJ 3281

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8577   Accepted: 3991 Descriptio ...

  3. POJ 1151 Atlantis(经典的线段树扫描线,求矩阵面积并)

    求矩阵的面积并 采用的是区间更新 #include <iostream> #include <stdio.h> #include <string.h> #inclu ...

  4. 解高次同余方程 (A^x=B(mod C),0<=x<C)Baby Step Giant Step算法

    先给出我所参考的两个链接: http://hi.baidu.com/aekdycoin/item/236937318413c680c2cf29d4 (AC神,数论帝  扩展Baby Step Gian ...

  5. POJ 1961

    #include<iostream> #include<stdio.h> #define MAXN 1000001 using namespace std; char c[MA ...

  6. 为什么toString方法可以用来区分数组和对象?

    首先大家都应该知道在javascript中只有是对象都存在toString方法,将调用该方法的值转换为字符串返回,如下: var arr = [1, 2, 3]; console.log(arr.to ...

  7. 【XJOI-NOIP16提高模拟训练9】题解。

    http://www.hzxjhs.com:83/contest/55 说实话这次比赛真的很水..然而我只拿了140分,面壁反思. 第一题: 发现数位和sum最大就是9*18,k最大1000,那么su ...

  8. Zabbix简介(第一章第一节)

    Alexei Vladishev创建了Zabbix项目,当前处于活跃开发状态,Zabbix SIA提供支持. Zabbix是一个企业级的.开源的.分布式的监控套件 Zabbix可以监控网络和服务的监控 ...

  9. 扩展 delphi 线程 使之传递参数.(给匿名线程增加参数)

    新delphi的线程TThread有了CreateAnonymousThread方法,如果再为它加一个可传递的参数不就更好了吗?代码如下: TAnonymousThreadX<T> = c ...

  10. C#之你懂得的序列化/反序列化

    前言:写此文章一方面是为了巩固对序列化的认识,另一方面是因为本人最近在面试,面试中被问到“为什么要序列化”.虽然一直在使用,自己也反复的提到序列化,可至于说为什么要序列化,还真的没想过,所以本文就这样 ...