在前面说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. HDU 1316 How Many Fibs?(java,简单题,大数)

    题目 /** * compareTo:根据该数值是小于.等于.或大于 val 返回 -1.0 或 1: public int compareTo(BigInteger val) 将此 BigInteg ...

  2. LA 3350

    The NASA Space Center, Houston, is less than 200 miles from San Antonio, Texas (the site of the ACM ...

  3. JS获取Url参数的通用方法

    //获取URL中的参数 function request(paras) { var url = location.href.replace('#', ''); var paraString = url ...

  4. Java常用类库

    System System:类中的方法和属性都是静态的. out:标准输出,默认是控制台. in:标准输入,默认是键盘. System描述系统一些信息.获取系统属性信息:Properties getP ...

  5. ruby libmysqlclient.18.dylib

    在mac 的rails环境中,如果已经确定安装了 mysql server,但是在启动rails s (服务器)的时候出现  Library not loaded: libmysqlclient.18 ...

  6. 在linux/unix中查找大文件

    在linux/unix中查找大文件,如查找大于100M文件的位置路径,查找等于10M文件的位置路径等等,下面就介绍几个实现快速查找的命令: 1. 查找指定目录下所有大于100M的文件,命令为 find ...

  7. Java-数据结构与算法-逢3减1

    1.要求:有一群人围成一圈数数,逢3退1人,要求算出最后留下来的人的下标 2.代码: package Test; public class Count3Quit1 { //要求:有一群人围成一圈数数, ...

  8. nodejs上传图片并显示的例子

    目标 1. 在浏览器地址栏输入“http://demos/start”,进入欢迎页面,页面有一个文件上传表单: 2. 选择一张图片并提交表单,文件被上传到"http://demos/uplo ...

  9. PHPCMS V9添加模板自定义全局变量

    在我们使用PHPCMS V9的制作网站模板的时候,使用全局模板变量能轻松调用,使用起来非常方便,而且可以统一修改,方便维护. 下面就来讲一下在PHPCMS V9中如何添加自定义全局变量. 修改网站sy ...

  10. 资源 之 4.4 Resource通配符路径 ——跟我学spring3

    4.4.1  使用路径通配符加载Resource 前面介绍的资源路径都是非常简单的一个路径匹配一个资源,Spring还提供了一种更强大的Ant模式通配符匹配,从能一个路径匹配一批资源. Ant路径通配 ...