Hadoop 源代码分析(一七)DataNode

周围的障碍扫清以后,我们可以开始分析类DataNode。类图如下:
Hadoop 源代码分析(一七)DataNode_第1张图片 

publipublic class DataNode extends Configured
implements InterDatanodeProtocol, ClientDatanodeProtocol, FSConsta nts, Runnable
上面给出了DataNode 的继承关系,我们发现,DataNode 实现了两个通信接口,其中ClientDatanodeProtocol 是用于和Client
交互的,InterDatanodeProtocol,就是我们前面提到的DataNode 间的通信接口。ipcServer(类图的左下方)是DataNode 的
一个成员变量,它启动了一个IPC 服务,这样,DataNode 就能提供ClientDatanodeProtocol 和InterDatanodeProtocol 的能
力了。
我们从main 函数开始吧。这个函数很简单,调用了createDataNode 的方法,然后就等着DataNode 的线程结束。createDataNode
首先调用instantiateDataNode 初始化DataNode,然后执行runDatanodeDaemon。runDatanodeDaemon 会向NameNode 注册,如
果成功,才启动DataNode 线程,DataNode 就开始干活了。
初始化DataNode 的方法instantiateDataNode 会读取DataNode 需要的配置文件,同时读取配置的storage 目录(可能有多个,
看storage 的讨论部分),然后把这两参数送到makeInstance 中,makeInstance 会先检查目录(存在,是目录,可读,可写),
然后调用:
new DataNode(conf, dirs);
接下来控制流就到了构造函数上。构造函数调用startDataNode,完成和DataNode 相关的初始化工作(注意,DataNode 工作线
程不在这个函数里启动)。首先是初始化一堆的配置参数,什么NameNode 地址,socket 参数等等。然后,向NameNode 请求配
置信息(DatanodeProtocol.versionRequest),并检查返回的NamespaceInfo 和本地的版本是否一致。
正常情况的下一步是检查文件系统的状态并做必要的恢复,初始化FSDataset(到这个时候,上面图中storage 和data 成员变
量已经初始化)。
然后,找一个端口并创建DataXceiverServer(run 方法里启动),创建DataBlockScanner(根据需要在offerService 中启动,
只启动一次),创建DataNode 上的HttpServer,启动ipcServer。这样就结束了DataNode 相关的初始化工作。
在启动DataNode 工作线程前,DataNode 需要向NameNode 注册。注册信息在初始化的时候已经构造完毕,包括DataXceiverServer
端口,ipcServer 端口,文件布局版本号等重要信息。注册成功后就可以启动DataNode 线程。
DataNode 的run 方法,循环里有两种选择,升级(暂时不讨论)/正常工作。我们来看正常工作的offerService 方法。offerService
也是个循环,在循环里,offerService 会定时向NameNode 发送心跳,报告系统中Block 状态的变化,报告DataNode 现在管理
的Block 状态。发送心跳和Block 状态报告时,NameNode 会返回一些命令,DataNode 将执行这些命令。
心跳的处理比较简单,以heartBeatInterval 间隔发送。
Block 状态变化报告,会利用保存在receivedBlockList 和delHints 两个列表中的信息。receivedBlockList 表明在这个
DataNode 成功创建的新的数据块,而delHints,是可以删除该数据块的节点。如在DataXceiver 的replaceBlock 中,有调用:
datanode.notifyNamenodeReceivedBlock(block, sourceID)
这表明,DataNode 已经从sourceID 上接收了一个Block,sourceID 上对应的Block 可以删除了(这个场景出现在当系统需要
做负载均衡时,Block 在DataNode 之间拷贝)。
Block 状态变化报告通过NameNode.blockReceived 来报告。
Block 状态报告也比较简单,以blockReportInterval 间隔发送。
心跳和Block 状态报告可以返回命令,这也是NameNode 先DataNode 发起请求的唯一方法。我们来看一下都有那些命令:
DNA_TRANSFER:拷贝数据块到其他DataNode
DNA_INVALIDATE:删除数据块(简单方法)
DNA_SHUTDOWN:关闭DataNode(简单方法)
DNA_REGISTER:DataNode 重新注册(简单方法)
DNA_FINALIZE :提交升级(简单方法)
DNA_RECOVERBLOCK:恢复数据块
拷贝数据块到其他DataNode 由transferBlocks 方法执行。注意,返回的命令可以包含多个数据块,每一个数据块可以包含多
个目标地址。transferBlocks 方法将为每一个Block 启动一个DataTransfer 线程,用于传输数据。
DataTransfer 是一个DataNode 的内部类,它利用我们前面介绍的OP_WRITE_BLOCK 写数据块操作,发送数据到多个目标上面。
恢复数据块和NameNode 的租约(lease)恢复有关,我们后面再讨论。

你可能感兴趣的:(hadoop,datanode)