原创文档,转载请将原文url地址标明
前面两篇文档我们重点研究了datanode的启动及工作过程中的源代码,对源代码做了注释工作,本篇文档将总结前面两篇文档,我们将绘制整个工作过程的流程图,通过流程图大家可以较清楚的了解相关工作过程,结合前面的文档自己去实际研究一下代码能够更清楚的了解datanode的工作过程。
hadoop 相关视频下载地址: http://pan.baidu.com/share/link?shareid=223046310&uk=3073578852
引言,hadoop代表一种全新的编程思想,基于hadoop有很多衍生项目,充分利用他们
为我们服务是非常必要的,同时hadoop又是一个复杂系统,若能理解他的工作原理对
我们将有非常大的帮助,我们在这里以hadoop的0.1.0版本为基础逐步分析他的基本工作
原理、结构、思路等等,希望通过这个能帮助我们理解生产中的hadoop系统。 时间有限,
经验不足,疏漏难免,在这里仅仅分享一些心得,希望对大家能起到一个抛砖引玉的作用吧,
有问题请大家给我留言或者评论等,这样也能对我的工作有莫大的帮助。
感谢您阅读这篇文章!
一.Datanode的启动过程及总体工作流程
本部分我们重点研究datanode启动流程,以及功过过程中的线程关系,下一节我们研究具体工作线程的关系。
上图是datanode启动及工作过程中的流程图,图中带有阴影区域的地方是线程或者线程组。
从上图可以看出,主要分成为:
左侧主线程,系统启动等等代码均在这里
数据线程,负责数据接收等相关任务, 主线程中datanode对象构造函数内部创建的一个线程对象
任务线程,负责datanode工作过程中相关任务调度,namenode通信等,由主线程中runandwait函数中创建的线程对象
另外, 数据线程及任务线程共同共同构成一对,每个datanode中配置的dir目录均构成一对相关线程
下面我们重点介绍一下上图中重点的工作流程,大家可以先看图,然后再看描述,也可以先看描述,在看图,总之图要与描述相互参照,慢慢理解,重在一个“悟”。
1. 用户激发启动,main函数被调用
2. 创建匿名配置文件 (上一篇文章中代码注释中已经添加了必要的注释)
3. 运行runandwait函数
4. 取得用户的数据目录列表(以下步骤中大部分操作都是在runandwait函数进行的,我们这里仅仅给出示意的描述,没有严格遵循一下规范之类的)
5. 创建一个datanode节点对象(节点对象创建过程中发生了很多过程,我们先简单带过,稍后再介绍)
6. 给这datanode对象创建一个线程对象来同namenode等进行通信,状态维护等等,这个对象同上一步的datanode对象是相互关联的。
7. 重复5,6两个步骤,知道没有数据目录为止
8. 循环等待datanode的任务线程的结束
9. 若是全部线程结束主程序退出
下面我们重点介绍一下datanode创建过程中都发生了什么
1. 对目录进行相关检查
2. 创建namenode对象的代理对象(注意:强调一下是 Namenode对象的 代理对象,程序通过反射机制进行的相关处理,我们将在后面几篇文章专门介绍这个代理及通信机制,届时欢迎读者观看,更欢迎读者提出自己的建议以及文章的疏漏,在此先感谢了!)
3. 本地数据操作对象的创建,程序通过这个对象具体操作本地文件等,相关情况我们后面在行讨论。
4. 创建数据的接收及发送线程(数据监听线程),线程对象付给当前datanode对象
经过了上面两个主要过程后,系统中已经存在了若干组线程,他们相互协作共同完成datanode的工作任务。
分别是:
主线程,完成系统初始化工作,启动完毕后基本功能已经完成,等待退出。
数据监听线程, 负责数据接收与发送
任务线程,负责datanode的相关任务工作等。
这个几个线程的具体工作,我们在下面的一部分将详细介绍。
二.Datanode各工作线程流程
1. 数据监听线程DataXceiveServer
如下图
红色区域是这个这个线程的执行部分,在红色区域中的区域1的循环语句,程序会一直循环下去,直到应该退出为止,然后每次都执行下面的语句。
区域2(绿色的部分),系统开始等待接收一个用户的请求,若是没有用户的请求这个函数就会阻塞到这里,这个非常重要呀。
当系统中有用户请求到来时,会返回一个新的socket对象,程序会执行下一个语句。
在区域3中,程序创建一下新的对象用来在新创建的socket上接收数据请求等待,程序创建完成这个对象,立即开始这个线程。
最后这个线程就继续返回while语句,然后继续等待accept语句的返回(用户的请求到来)
2. 数据接收线程DataXceiver
这个线程设计datanode中实际进行数据操作的线程,是非常重要的一个过程。
相关过程如下:
1)读取请求的数据,获取操作类型
2)判断操作类型,分为3个分支。我们分别进行介绍
OP_WRITE_BLOCK分支,这个分支是最复杂,也是最重要的一个分支
3)程序进入这个分支后,做了一些准备工作,赋值工作,最后 从输入流中读取目标对象信息targets[0...n]这个对象开发于0,结束n, 其中0是当前对象(程序下面在传递信息给下一个节点时,开始于1,因此这样依次类推,每次减一,最后一定有一个最后的节点,没有了下一个目标,循环可以结束)。
4)通过socket连接到下一个目标对象
5)传递操作数,信息及目标对象给下一个节点(从1开始,因此相当于减一啦)
6)传输数据块(仅此一块,因此hadoop中数据块都比较大,若是太小,频繁的网络连接开销也太大啦),并记录操作结果
7)写数据块到本地
8)创建namenode的回报信息,添加信息到队列中,并发出通知,这个非常重要,这个通知消息,然另外一个正在等待线程开始工作,那个线程立即将相关信息向namenode进行了汇报工作。
9)返回汇总信息给客户端
10)线程结束,重要!这个线程执行完这个分支后就退出了,不进行其他工作,更没有循环!!!
OP_READ_BLOCK 或者 OP_READSKIP_BLOCK 分支
11)从客户端读取需要读取的信息描述
12)读取本地数据返回给客户端。
13)退出线程
默认分支
若是程序才操作码中无法找到相关信息,则打印提示信息,抛出异常,然后退出
从上面线程可以看出,这个接受线程是一次性的,用完就扔了,因此若是频繁创建就效率非常低了,因此提高hadoop的块大小是非常必要,小文件是很浪费的。
3. 任务线程run
如上图,run函数中主要就是一句反复调用offerService()函数的语句,知道被通知需要退出为止。
offerService函数主要流程如下:
1. 等待receivedBlockList对象的锁
2. 判断是否到了应该发送心跳给namenode,若是到达则发送
3. 判断是否需要回报块信息给namenode了,若是需要进行汇报,汇报后顺便获取本地孤立块等,然后进行删除
4. 新接收到块信息汇报给namenode
5. 块命令获取,从namenode节点处获取命令,然后根据命令指示进行操作,主要是删除,传输之类的工作。
6. 释放锁,等待有事件通知到来,若是没有,定时时间到后,系统返回步骤1继续执行。
以上我们是对hadoop的datanode工作过程的一个基本汇总描述,通过这个流程图以及前面的相关源代码分析希望能对读者了解datanode有更好的帮助。
下一篇文档我们将研究一下客户端上传一个文件到hadoop系统中的过程,通过这个过程我们将加固了解datanode的工作过程。
之后我们将了解datanode及namenode的通信过程。
参考文章
Hadoop源代码分析 之Datanode工作原理(5)—–拷贝文件过程总结
Hadoop源代码分析 之Datanode工作原理(4)—–拷贝本地文件到hadoop的过程
Hadoop源代码分析 之Datanode工作原理(3)—–datanode工作过程总结
Hadoop源代码分析 之Datanode工作原理(2)—–datanode基本工作过程
Hadoop源代码分析 之Datanode工作原理(1)—–datanode启动过程代码分析
Hadoop源代码分析 之hadoop配置及启动(4)—–启动过程汇总
Hadoop源代码分析 之hadoop配置及启动(3)—–classpath与hadoop主要组件启动过程
Hadoop源代码分析 之hadoop配置及启动(2)—–classpath与启动shell脚本
Hadoop源代码分析 之hadoop配置及启动(1)—–classpath与配置文件
Hadoop源代码分析 之hadoop源代码项目(1)—–创建eclipse下java项目
Hadoop源代码分析 之环境配置(1)—–hadoop虚拟机配置
Hadoop源代码分析 之概念介绍(2)—–初学者眼中的hadoop