2021SC@SDUSC
Hadoop源码分析(九)——Datanode实现(1)
Datanode分析
Hadoop 中关于 Datanode 的代码被放在了 org.apache.hadoop.hdfs.server.Datanode 中,主要的三个类是 Datanode、 FSDataSet 和 DataBlockScanner。其中,Datanode 类就是一个 Datanode 运行实例的抽象,FSDataSet 类 用来表示Datanode节点上关于磁盘配置的信息和一些处理接口,而DataBlockScanner类是一个线程, 用来不断检查该Datanode上的blocks信息。当Datanode启动的时候,会初始化许多的信息,如和 Namenode通信的Socket信息,从Hadoop配置文件中读取的配置信息,并利用这些配置信息初始化该 Datanode类的instance。每个Datanode中都会有多个内部线程在循环作一些操作,其中有一个为 DataTransfer,用来向其他Datanode传输block数据。
Datanode启动过程中同样会把这个线程启动。启动Datanode时,同样还会将DataBlockScanner 线程启动,这个线程用来keep track Datanode上的block和更新信息。Datanode中还保存了一个 FSDataset的实例,它用来记录当前Datanode上关于磁盘的配置信息,以及这些磁盘或者路径下中保 存的HDFS分布式文件系统中的信息。通过对Hadoop配置文件的读取,Datanode也会初始化这个 FSDataset类的instance» Datanode本身也是一个线程类,它的run。中会间歇调用一个服务方法: offerService(),这个方法里记录处理的就是Datanode的核心处理逻辑。
这当中的处理包括:每隔3秒钟向namenode发送一次自己的heartbeat信息,这些信息被namenode 接收到以后会根据对该 Heartbeat的分析向 Datanode返回一个 Datanode需要的操作 (DatanodeCommand ),并根据从namenode返回的这个 DatanodeCommand来作自己相应的操作<, 然后 会检查本Datanode是否接收到新的block,并作相应的处理,然后检查上一次向namenode进行block report的时间,如果超过一定的时间(默认为1小时)就向namenode发送一次block report,以便让 namenode上记录的信息保持更新。每一次接收到来自namenode的操作信息(DatanodeCommand), Datanode都会作相应的操作。
1.Block数据块
Block所在的包为org.apache.hadoop.hdfs.protocol. Block是HDFS文件系统的最小组成单元,它通 过一个long整数被唯一的标识。默认情况下,数据Block的大小为64MB。Block实现了 Writable接口, 从而可以实现序列化,同时也实现了 Comparable接口,说明它可以比较大小。Block的源代码如下:
1.1成员变量
private long blockid;
//该变量代表数据块的唯一标示符Id。
private long numBytes;
//该变量代表组成块的字节数。
private long generationStamp;
//该变量代表此数据块的生成标记,从1000L开始。
1.2 成员方法
static long filename2id(String name) {
return Long.parseLong(name.substring("blk_".length()));
}
该方法用于将块文件名转化成块的ID。
public static boolean isBlockFilename(File f) {
String name = f.getName();
if ( name.startsWith( "blk_" ) &&
name.indexOf( "." ) < 0 ) {
return true;
} else {
return false;
}
}
该方法用于判断一个文件是否为块文件,块文件的命名规则是以“blk_”开头,后面跟块Id即一个 长整数,而且名称中不含有“.”。
Block中的其他方法都是与上面的成员变量相对应的set和get方法,以及Writable接口和Comparable 接口的实现方法。
2 DatanodeID类
DatanodelD 所在的包为 org.apache.hadoop.hd&protocol,该类用于唯一标识一个 Datanode。Datanode 的源代码如下:
2.1 成员变量
public String name;
//该变量使用主机名:端口号的格式来表示Datanode的ID名称。
public String storagelD;
//该变量代表存储介质ID。不同的集群会有不同的存储介质ID.
protected int infoPort;
//该变量代表infbserver服务器运行时所使用的的端口号。
public int ipcPort;
//该变量代表ipcserver服务器运行时所使用的的端口号。NameNode和Datanode进行连接时,或者是 Datanode之间通讯的时候会使用这个端口号。
2.2 成员方法
这个类主要定义了这个Datanode的HostName、Port, infoPort和ipcPort这些变量相关的set和get 方法。
public int hashCode() {
return name.hashCode()^ storageID.hashCode();
}
hashCode 是通过 name.hashCode()与 storagelD.hashCode()直接的异或来生成的。
public int compareTo(DatanodelD that) {
return name.compareTo(that.getName());
}
当进行两个DatanodelD的比较的时候,主要是比较他们的name.
public void updateRegInfo(DatanodeID nodeReg) {
name = nodeReg.getName();
infoPort = nodeReg.getInfoPort();
ipcPort = nodeReg.getIpcPort();
}
从该方法可以看出DatanodelD对象的域的更新只能更新它的Name和它的infoPort两项内容,而 storagelD是不可更新的。