hadoop DataNode实现分析
在前面说hadoop整体实现的时候, 说过DataNode的需要完成的首要任务是K-V存储。
第二个功能是 完成和namenode 通信 ,这个通过IPC 心跳连接实现。此外还有和客户端 其它datanode之前的信息交换。
第 三个功能是 完成和客户端还有其它节点的大规模通信,这个需要直接通过socket 协议实现。
下面开始分析源代码,看看DataNode是如何实现这些功能的。
分析代码采取自定向下的分析方式, 看看代码中做了啥,然后分析这些代码的作用。
首先看Datanode实现的接口。
- public class DataNode extends Configured
- implements InterDatanodeProtocol, ClientDatanodeProtocol, FSConstants,
- Runnable, DataNodeMXBean {
它实现了 InterDatanodeProtocol, ClientDatanodeProtocol, 这两个重要接口。 作用和之前分析haoop IPC的时候提到过, 为了是客户端 和其它datanode节点远程调用本dataNode节点方法的时候,提供方法实际运行的对象。
我们可以看到它并没有实现和datanode的接口,因为datanode是主动和nameNode联系,nameNode从来不会主动调用dataNode上的方法。
在main 方法中主要 通过一系列调用创建了datanode对象。
之后datanode的初始化工作主要由 startDataNode()来完成, 这是一个很复杂的方法,我们来一点一点的分析。
- void startDataNode(Configuration conf,
- AbstractList<File> dataDirs, SecureResources resources
- ) throws IOException {
- if(UserGroupInformation.isSecurityEnabled() && resources == null)
- throw new RuntimeException("Cannot start secure cluster without " +
- "privileged resources.");
- // connect to name node
- this.namenode = (DatanodeProtocol)
- RPC.waitForProxy(DatanodeProtocol.class,
- DatanodeProtocol.versionID,
- nameNodeAddr,
- conf);
- 这个是通过反射获取同dataNode节点通信的代理对象
- // get version and id info from the name-node
- NamespaceInfo nsInfo = handshake(); //立刻与名字节点通信
- StartupOption startOpt = getStartupOption(conf);
- assert startOpt != null : "Startup option must be set.";
- storage.recoverTransitionRead(nsInfo, dataDirs, startOpt);
- // adjust
- this.dnRegistration.setStorageInfo(storage);
- // initialize data node internal structure
- this.data = new FSDataset(storage, conf);
- // 创建数据存储KV 的对象 这个后面还要再细分析。
- }
- this.threadGroup = new ThreadGroup("dataXceiverServer");
- this.dataXceiverServer = new Daemon(threadGroup,
- new DataXceiverServer(ss, conf, this));
- this.threadGroup.setDaemon(true); // 创建流接口服务器 DataXServer 这个需要后面再分析
- ipcServer = RPC.getServer(this, ipcAddr.getHostName(), ipcAddr.getPort(),
- conf.getInt("dfs.datanode.handler.count", 3), false, conf, //创建IPC服务器。
- blockTokenSecretManager);
- }
上面代码分析中我们留了两个之后还要分析的方法,现在来看一下。
第一个是FsdataSet.
我们需要考虑的问题是 hadoop以64M大小为单位作为一个文件的大小 存储在linux 文件系统 上。 当文件多了,就有一个效率问题,同一个文件夹下有过多的文件
和文件目录过深都不利于检索速度(这个与linux文件系统inode结构有关,这里暂不讨论这个) 。所以我们这里要设计一个结构 需要创建文件夹 但文件夹目录不能过深。
此外 hadoop 还考虑了一个优化问题,如果一个datanode节点上插有多块硬盘的话,怎么提高并行吞吐量。好,有了这些我们来看具体实现。
一个FSdir对于着一个存储目录,一个FSVolume 对应着一个用户配置的数据目录(应该为一个磁盘最好) FsVolumeSet存储着所有的FSVolume对象。
在FsDataSet中海油一个最重要的成员变量,volumeMap 就是这个成员变量存储了 每一个Block 和它对应的存储路径等信息。
- HashMap<Block,DatanodeBlockInfo> volumeMap = new HashMap<Block, DatanodeBlockInfo>();;
第二个是 DataXServer
当往数据节点中填入数据或者数据节点之间做负载均衡的时候显然无法 使用Hdoop IPC 因为hadoop的IPC 在socket之上封装了方法的调用,如果在这之上封装一个大规模数据传输的方法,显然效率上不如直接用socket通信。
- ServerSocket ss;
- if(secureResources == null) {
- ss = (socketWriteTimeout > 0) ?
- ServerSocketChannel.open().socket() : new ServerSocket();
- Server.bind(ss, socAddr, 0);
- } else {
- ss = resources.getStreamingSocket();
- }
- ss.setReceiveBufferSize(DEFAULT_DATA_SOCKET_SIZE);
- //初始化处理类dataXceiverServer
- this.threadGroup = new ThreadGroup("dataXceiverServer");
- this.dataXceiverServer = new Daemon(threadGroup, new DataXceiverServer(ss, conf, this));
- this.threadGroup.setDaemon(true); // auto destroy when empty
DataXceiverServer 是个线程 我们看一下它的ruan方法
- Socket s = ss.accept();
- s.setTcpNoDelay(true);
- new Daemon(datanode.threadGroup,
- new DataXceiver(s, datanode, this)).start();
我们再看一下 DataXceiver的run方法
- public void run() {
- DataInputStream in=null;
- try {
- in = new DataInputStream(
- new BufferedInputStream(NetUtils.getInputStream(s),
- SMALL_BUFFER_SIZE));
- short version = in.readShort();
- if ( version != DataTransferProtocol.DATA_TRANSFER_VERSION ) {
- throw new IOException( "Version Mismatch" );
- }
- boolean local = s.getInetAddress().equals(s.getLocalAddress());
- byte op = in.readByte();
- // Make sure the xciver count is not exceeded
- int curXceiverCount = datanode.getXceiverCount();
- if (curXceiverCount > dataXceiverServer.maxXceiverCount) {
- throw new IOException("xceiverCount " + curXceiverCount
- + " exceeds the limit of concurrent xcievers "
- + dataXceiverServer.maxXceiverCount);
- }
- long startTime = DataNode.now();
- switch ( op ) {
- case DataTransferProtocol.OP_READ_BLOCK:
- readBlock( in );
- datanode.myMetrics.addReadBlockOp(DataNode.now() - startTime);
- if (local)
- datanode.myMetrics.incrReadsFromLocalClient();
- else
- datanode.myMetrics.incrReadsFromRemoteClient();
- break;
- case DataTransferProtocol.OP_WRITE_BLOCK:
- writeBlock( in );
- datanode.myMetrics.addWriteBlockOp(DataNode.now() - startTime);
- if (local)
- datanode.myMetrics.incrWritesFromLocalClient();
- else
- datanode.myMetrics.incrWritesFromRemoteClient();
- break;
- case DataTransferProtocol.OP_REPLACE_BLOCK: // for balancing purpose; send to a destination
- replaceBlock(in);
- datanode.myMetrics.addReplaceBlockOp(DataNode.now() - startTime);
- break;
- case DataTransferProtocol.OP_COPY_BLOCK:
- // for balancing purpose; send to a proxy source
- copyBlock(in);
- datanode.myMetrics.addCopyBlockOp(DataNode.now() - startTime);
- break;
- case DataTransferProtocol.OP_BLOCK_CHECKSUM: //get the checksum of a block
- getBlockChecksum(in);
- datanode.myMetrics.addBlockChecksumOp(DataNode.now() - startTime);
- break;
- default:
- throw new IOException("Unknown opcode " + op + " in data stream");
- }
- } catch (Throwable t) {
- LOG.error(datanode.dnRegistration + ":DataXceiver",t);
- } finally {
- LOG.debug(datanode.dnRegistration + ":Number of active connections is: "
- + datanode.getXceiverCount());
- IOUtils.closeStream(in);
- IOUtils.closeSocket(s);
- dataXceiverServer.childSockets.remove(s);
- }
- }
重点在这句
- byte op = in.readByte();
应该是根据流中的事先约定 来 第一个字节 来决定是
hadoop DataNode实现分析的更多相关文章
- hadoop源码分析(2):Map-Reduce的过程解析
一.客户端 Map-Reduce的过程首先是由客户端提交一个任务开始的. 提交任务主要是通过JobClient.runJob(JobConf)静态函数实现的: public static Runnin ...
- Hadoop启动脚本分析
Hadoop启动脚本分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 能看到这篇博客的你估计对Hadoop已经有一个系统的了解了,最起码各种搭建方式你应该是会的,不会也没有关系, ...
- Hadoop源码分析之数据节点的握手,注册,上报数据块和心跳
转自:http://www.it165.net/admin/html/201402/2382.html 在上一篇文章Hadoop源码分析之DataNode的启动与停止中分析了DataNode节点的启动 ...
- 4. hadoop启动脚本分析
4. hadoop启动脚本分析 1. hadoop的端口 ``` 50070 //namenode http port 50075 //datanode http port 50090 //2name ...
- 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 ...
- Hadoop DataNode不能正常工作的原因
在把Hadoop环境搭建成功,并且也Hadoop的各个组件都正常工作.在重启过几次Hadoop后发现DataNode不能正常工作,打开Hadoop 的后台http://localhost:50030和 ...
- hadoop编程:分析CSDN注冊邮箱分布情况
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jdh99/article/details/37565825 hadoop编程:分析CSDN注冊邮箱分 ...
- hadoop datanode 和 tasktracker起不来
本篇文章主要介绍了"hadoop datanode 和 tasktracker起不来.",主要涉及到hadoop datanode 和 tasktracker起不来.方面的内容,对 ...
- 【Hadoop】Hadoop DataNode节点超时时间设置
hadoop datanode节点超时时间设置 datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间 ...
随机推荐
- 异步等待的 Python 协程
现在 Python 已经支持用协程进行异步处理.但最近有建议称添加协程以全面完善 Python 的语言结构,而不是像现在这样把他们作为生成器的一个类型.此外,两个新的关键字---异步(async)和等 ...
- 浅谈javascript中的数据类型和引用类型
1.概述 javascript中有五种简单数据类型和一种复杂数据类型. 分别是:undefind, null, number, string ,boolean ----简单数据类型 ...
- HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)
题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都 ...
- ***百度统计图表Echarts的php实现类,支持柱形图、线形图、饼形图
/** * 百度数据统计图表echart的PHP实现类 * * 原作者: * @author: chenliujin <liujin.chen@qq.com> * @since 2013- ...
- POJ 1144 Network(Tarjan)
题目链接 题意 : 找出割点个数. 思路 : Tarjan缩点,u是割点的充要条件是:u要么是具有两个以上子女的深度优先生成树的根,要么不是根,而有一个子女v满足low[v]>=dfn[u]. ...
- OpenCV4Android开发之旅(一)----OpenCV2.4简介及 app通过Java接口调用OpenCV的示例
转自: http://blog.csdn.net/yanzi1225627/article/details/16917961 开发环境:windows+ADT Bundle+CDT+OpenCV-2 ...
- 14.spark RDD解密
开篇:spark各种库,sparksql,sparkmachicelearning,等这么多库底层都是封装的RDD.意味着 1:RDD本身提供了通用的抽象, 2:spark现在有5个子框架,sql,S ...
- redis资料汇总
redis资源比较零散,引用nosqlfan上的文章,方便大家需要时翻阅.大家看完所有的,如果整理出文章的,麻烦知会一下,方便学习. 1.Redis是什么? 十五分钟介绍 Redis数据结构 Redi ...
- Java7编程高手进阶读书笔记--final学习
这段时间终于有了一些自己的时间,在网上淘了一本书把java学习下,顺便记下每日的学习心得 工作快两年多了,才知道基础的东西永远看的时候都有一个新的体验,今天中午看了下final,把自己炒的代码贴在这以 ...
- Linux基础--例行工作
1.仅进行一次的工作排程--at at的工作情况其实是这样的: 1)先找寻/etc/at.allow这个档案,写在这个档案中的使用者才能使用at,没有在这个档案中的使用者则不能使用at(即使没有写在a ...