HDFS Client如何从Datanode读取block
Datanode中包含DataXceiverServer。DataXceiverServer是一个socket server,负责接收client发起的socket连接。DataXceiverServer接收到一个socket连接后,启动一个线程DataXceiver,由DataXceiver具体负责该scoket的处理。DataXceiver从client读取client想要进行操作的操作码。如果操作码是OP_READ_BLOCK,则DataXceiver负责读取该block,并将其发送给client。
读取block数据传输格式
Client为了从Datanode读取block,按照一定的格式向Datanode发送指令及其他一些数据,具体的格式如下:
? operator:byte Client所需要的操作,读取一个block、写入一个block等等? version:short Client所需要的数据与Datanode所提供数据的版本是否一致
? blockId:long 所要读取block的blockId
? generationStamp:long 所需要读取block的generationStamp
? startOffset:long 读取block的的起始位置
? length:long 读取block的长度
? clientName:String Client的名字
? accessToken:Token Client提供的验证信息,用户名密码等
读取过程
DataXceiver首先按照上面的数据格式依次读取各变量。读取完成后,如果需要进行访问控制,则根据Client提供的accessToken进行验证。验证通过后,产生一个BlockSender实例blockSender,通过blockSender进行数据的读取与传输。这里有一个需要注意的地方,HDFS在保存文件的时候有几个非常重要的概念:一个文件由多个block构成。HDFS在进行block读写的时候是以packet为单位进行的。每一个packet由若干个chunk组成。Chunk是进行数据校验的基本单位,对每一个chunk生成一个校验和并将校验和进行存储(在默认情况下一个chunk的大小是512byte,生成的校验和是4byte)。在读取一个block的时候,数据传输的基本单位是packet,每个packet由若干个chunk组成。
为了读取一个block,首先从block的.meta文件中读取block的版本号、校验类型等,并生成相应的校验工具类。Meta文件的格式如下所示:
? version:short 所保存block的版本号
? checksumType:int 校验码的类型,要么没有校验码,要么是CRC32校验码(CHECKSUM_NULL、CHECKSUM_CRC32)
? bytesPerChecksum:int 表示这么校验和是由多少byte的源数据计算而来
? checksum:每一个chunk的校验和
这里有一个需要注意的地方,当读取数据的时候读取的起始位置必行是一个chunk的起始位置,如果client读取的起始位置不是chunk的起始位置,那么必须回退到chunk的起始位置开始读取。确定好位置后,Datanode以packet为单位依次发送block的数据,packet的具体格式如下图所示:
? packetLen:int packet的长度,包括数据、数据的校验等等
? offset:long packet在block中的偏移量
? sequenceNum:long 该packet在这次block读取时的序号
? isLastPacket:byte packet是否是最后一个
? dataLen:int 该packet所包含block数据的长度,纯数据不包括校验和其他
? checksum:该packet每一个chunk的校验和,有多少个chunk就有多少个校验和
? data:该packet所包含的block数据