原创文章,转载请指明出处并保留原文url地址
hadoop 相关视频下载地址: http://pan.baidu.com/share/link?shareid=223046310&uk=3073578852
前一文章中,我们重点讨论了hadoop shell脚本拷贝本地文件到hadoop文件系统(hdfs)的工作过程,我们重点针对拷贝的源代码进行了研究,主要研究了本地文件拷贝的初始化过程,文件拷贝过程。本篇文档我们通过汇总相关工作的序列图来从图形化方式分析相关工作过程。
引言,hadoop代表一种全新的编程思想,基于hadoop有很多衍生项目,充分利用他们
为我们服务是非常必要的,同时hadoop又是一个复杂系统,若能理解他的工作原理对
我们将有非常大的帮助,我们在这里以hadoop的0.1.0版本为基础逐步分析他的基本工作
原理、结构、思路等等,希望通过这个能帮助我们理解生产中的hadoop系统。 时间有限,
经验不足,疏漏难免,在这里仅仅分享一些心得,希望对大家能起到一个抛砖引玉的作用吧,
有问题请大家给我留言或者评论等,这样也能对我的工作有莫大的帮助。
感谢您阅读这篇文章!
一.文件拷贝总体过程
管理员在hadoop客户端机中,启动hadoop shell,拷贝本地文件到hadoop集群时,系统经历了大概下面几个阶段。
1. 系统初始化过程,这个过程中shell客户端根据本地配置文件初始化本次jvm进程的相关信息,从classpath中寻找到配置文件,获取namenode等具体信息,本地相关信息等,然后,启动main函数,调用里面功能创建一系列文件服务对象等。
2. 系统初始化完成后,读取文件系统数据,然后循环写入数据对象中,数据对象将数据先缓存在内存中,到达一定数据后将数据输出到本地临时文件中,当文件大小尺寸到达文件块尺寸时,启动dfsclient中的流输出对象,对象相同namenode沟通获取块信息(元信息)等,然后连接datanode节点通过网络将数据传输过去(datanode中相关流程在前一文章中已经研究过了),循环将全部数据传输完。
3. 最后文件结束后系统启动close功能,将内存中数据包括crc等数据刷新到网络上,同时清理本地相关临时文件等等。
二.初始化阶段
下图是hadoop shell在文件拷贝中初始化阶段的创建过程,图中内容比较多,为了绘图方便,大部分名称都采用简写,图中附上一个对照关系表供参考。
下图采用近似uml序列图方式绘制,但不是规范的uml序列图,同时也不完全拘泥于序列图的规范,核心就是让读者能看明白图中内容(uml相关可以参考http://www.iigrowing.cn/?s=uml)。
一)图示介绍
图中如下图示的含义如下:
1. 表示java中一个类的某个对象实例,一般用类名代表,但其实是实例对象。
2. 图中箭头表示一次调用,并且是一次阻塞式调用(被调用对象的相关函数若是没有返回,则调用者将一直等待返回)。图中箭头方向代表调用方向 ,例如A对象调用B的方法,就是 A--->B(A调用B)
3. 图中虚线箭头代表调用的返回,箭头的方向表示从被调用者到调用者的返回。
4. 图中蓝色竖条代表被调用函数的执行时间,从上到下表示调用开始、调用结束。
5. 图中折线箭头表示对象内部函数调用, 新的蓝色竖条表示新的调用生命周期。
6. 图中调用箭头上面的文字用来描述调用的相关信息,主要表示调用的方法等信息,或者调用函数功能等,这里用法同标准序列图有些出入,但是基本相同。
7. 图中<init>一般代表java中类(对象)的构造函数
8. 程序调用顺序从上 至下 进行。读者读图时需要从上至下进行,沿着箭头方向进行阅读。
上图是hadoop shell上传文件到hdfs过程,主要是初始化过程,下面我们来了解一下相关过程。
二)图形内容概括
如上图,我们用带阴影矩形标识出了3个区域
区域1:数据输出流对象创建,这个区域中各个调用主要围绕创建java流对象创建,创建出对象主要是保证上传数据文件对象的数据读取写入等各种操作,包括网络等流操作。
区域2:校验文件流对象创建区域,这里面也创建了一些流对象,但是这流对象是对上面数据文件数据进行校验的,这些校验信息形成一块独立的流对象,单独作为文件存储在hdfs中(这个版本是这样的,后续版本情况我没有去验证,稍后验证了在补充到文档中)。
区域3:数据工作区域,这里进行数据输出到远程服务器等工作,这里内容已经省略,详情见下一幅图形及解释。
三)流程内容解释
下面的解释需要读者参照上面图形进行慢慢理解,同时解释仅仅是一个处略的解释,详细情况请参考相关源代码。
1. 首先用户从命令行数输入命令, hadoop脚本调用java的dfsshell类的main行数,程序从这里开始执行。
2. main函数调用dfsshell的copyFromLocal函数
3. copyFromLocal函数调用DistributedFileSystem类(一个实例对象)的copyFromLocalFile函数(图中对象比较多采用简写办法DistributedFileSystem为dfs,其他对照参考对照)
4. dfs的copyFromLocalFile中调用doFromLocalFile函数
5. doFromLocalFile函数,调用create函数,create又调用另一个重载的函数
6. 最后在create函数中 创建FSDataOutputStream(FSDOS)对象
7. 最后在FSDOS的构造函数中创建summer对象
8. 在summer对象的构造函数中间接调用DFSClient及DFSClint内部类DFSOS对象,这个对象负责具体的同namenode及datanode进行通信等工作
9. DFSOS对象创建完成后,返回到summber构造函数中
10. summer构造函数中继续上面相似流程,创建下面校验对象(这里省略几个针对crc的FSDataOutputStream$buffer及FSDataOutputStream$PositionCache对象的创建过程,内容比较多,也比较烦了,只好省略不重要的内容了)
11. FSDataOutputStream$summer
对象创建完成后,系统会将FSDataOutputStream$summer
对象作为参数创建FSDataOutputStream$PositionCache对象,
12. FSDataOutputStream$PositionCache对象创建完成后作为参数创建FSDataOutputStream$buffer对象
13. 最后创建过程完成
14. 创建完成后,程序进行数据写入工作,详情见下节
三.数据写入过程
下图是hadoop shell程序写入数据到hdfs时序列图
一)图形内容概括
如上图,整个图形根据不同矩形阴影区域,可以分5个区域,相关情况如下:
1. 左侧垂直区域, 这个区域是程序员最容易看到也容易看清楚的一个区域, hadoop通过一个抽象的FileSystem对象将系统客户端代码同server代码进行了封装。当shell代码采用FileSystem系统分布式实现方式时,shell操作就是hdfs文件系统,当FileSystem实现的是本地文件系统操作的对象就是本地的普通文件。这样简化了shell的设计,开发人员可以专注一个方面的开发不用在关心复杂的网络通信等。
2. 右侧最上面区域1,是初始化区域,由于本图是shell进行文件拷贝的序列图,为了保持完整性我们保留大部分拷贝过程等,同时根据本图需要重点表现情况针对不同过程进行了省略或者简化。本区域是个初始化过程,较为详细过程在上面图中已经表达,读者可以去参考。
3. 右侧上面区域2, 是校验和写入区域,校验和写入过程中有个区域工作过程同写入正常数据类似(总体思路是类似,具体代码实现不同),我们省略了过程,相关过程读者感兴趣自己去看源代码。
4. 右侧上面区域3, 这个是本文重点,这里是具体数据写入过程,包括数据读取,数据写入内存缓存,然后写入网络,包括如何同namenode及datanode通信过程等,我们稍后会给出详细解释。
5. 右侧最下面区域, 这个区域是系统关闭代码区域,系统在关闭过程中清理了内存的缓存,临时文件,同namenode及datanode通信等,这个过程也包括了一个同上面数据写入区域类似的过程,这里面也省略了,读者感兴趣可以执行研究。
二)数据写入过程解释
前面main函数调用、初始化等过程等在前面一节已经有了介绍我们不在多言。我们直接从数据写入开始。
1. 读取数据 (in.read(buf)),in是输入流,在初始化过程已经创建完毕
2. 调用fsdos(FSDataOutputStream)对象的write(x,x,x)(代表有三个参数的重载函数版本,x省略了具体情况,读者去阅读源码吧)写入数据
3. 调用FSDataOutputStream$buffer对象相应写入函数(这里面其实是调用buffer对象的父对象的函数,我们为了简化记做buffer对象)
4. 调用FSDataOutputStream$PositionCache对象的write函数
5. 调用FSDataOutputStream$summer对象的writer(x,x,x)函数
6. 在FSDataOutputStream$summer对象的writer函数内计算校验和,写入校验和到对象中,写入先是写入内存对象中,当内存对象满或者达到一定条件后,写入临时文件以及根据网络配置情况传输到网络上的hdfs中,这个过程也相对较为省略了,请读者自己研究源码了,看懂了数据写入过程在看那个过程非常类似,比较容易看懂因此省略了)
7. 校验和写入完毕后,写入数据到DFSOS(DFSClient$DFSOutputStream)对象中
8. DFSOS(DFSClient$DFSOutputStream)首先将数据写入内存缓存
9. 数据条件满足时,写入临时文件中
10.当数据写满了一块数据后,调用endblock函数
11.endblock函数处理临时文件等,然后调用nextblockoutputstream函数
12.在nextblockoutputstream函数中,首先同namenode进行沟通来创建文件(若是首次通信),或者添加一块数据,最后获取块的元信息
13.根据块的元信息连接datanode节点
14.传输数据到datanode节点
15.处理传输后相关逻辑
17.最后程序依次返回调用函数处,然后程序继续读取下一部分数据重复上面过程,直到数据都发送完毕
18.程序关闭阶段,关闭阶段处理了内存中的缓存数据,处理本地临时文件等
19.程序最后返回给用户一个执行情况结果。
以上是hadoop shell上传文件到datanode过程的一个总结,请结合前面文章慢慢了解工作过程。若是有时间请下载相关虚拟机及eclipse项目调试整个过程,读者会获取更多理解。
参考文章
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