一、数据单位:
block :文件上传前需要分块,这个块就是block,一般为128MB,可以修改。因为块太小:寻址时间占比过高。块太大:Map任务数太少,作业执行速度变慢。它是最大的一个单位。
packet :packet是第二大的单位,它是client端向DataNode,或DataNode的PipLine之间传数据的基本单位,默认64KB。
chunk :chunk是最小的单位,它是client向DataNode,或DataNode的PipLine之间进行数据校验的基本单位,默认512Byte,因为用作校验,故每个chunk需要带有4Byte的校验位。所以实际每个chunk写入packet的大小为516Byte。由此可见真实数据与校验值数据的比值 约为128 : 1。(即64*1024 / 512)
二、HDFS读流程
读详细步骤:
1、client跟NameNode通信,查询元数据信息,找到文件块所在的DataNode服务器。
2、就近挑选一台DataNode(就近原则,然后随机)服务器,请求建立输入流 。
3、DataNode开始发送数据,即从磁盘里面读取数据放入流,以packet为单位来校验。
4、客户端以packet为单位接收,现在本地缓存,然后写入目标文件。
5、关闭输入流。
三、HDFS写流程
写详细步骤:
1、客户端向NameNode发出写文件请求。
2、检查是否已存在文件、检查权限。若通过检查,直接先将操作写入EditLog,并返回输出流对象。(注:WAL,write ahead log,先写Log,再写内存,因为EditLog记录的是最新的HDFS客户端执行所有的写操作。如果后续真实写操作失败了,EditLog中仍会有记录)
3、NameNode返回是否可以上传。
4、client请求第一个 block(128MB的块切文件)该传输到哪些DataNode服务器上。
5、NameNode返回n个DataNode服务器,如ABC。
6、client请求最近的第一个DataNodeA节点,此后client端和多个DataNode(B、C)构成pipeline管道。
7、client向第一个DataNodeA写入一个packet,这个packet便会在pipeline里传给第二个、第三个…DataNode(B、C)。在pipeline反方向上,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点将ack发送给client。
8、当一个block传输完成之后,client再次请求NameNode上传第二个block的服务器。
9、写完数据,关闭输输出流.
10、发送完成信号给NameNode。
更通俗易懂的图:
四、DFSOutputStream内部原理
1、创建Packet
Client写数据时,会将字节流数据缓存到内部的缓冲区中,当长度满足一个Chunk大小(512B)时,便会创建一个Packet对象,然后向该Packet对象中写Chunk
的Checksum校验和数据,以及实际数据块Chunk Data,校验和数据是基于实际数据块计算得到的。每次满足一个Chunk大小时,都会向Packet中写上述数据内容,
直到达到一个Packet对象大小(64K),就会将该Packet对象放入到dataQueue队列中,等待DataStreamer线程取出并发送到DataNode节点。
2、发送Packet
DataStreamer线程从dataQueue队列中取出Packet对象,放到ackQueue队列中,然后向DataNode节点发送这个Packet对象所对应的数据
3、接收ack
发送一个Packet数据包以后,会有一个用来接收ack的ResponseProcessor线程,如果收到成功的ack,则表示一个Packet发送成功,ResponseProcessor线程会将
ackQueue队列中对应的Packet删除,在发送过程中,如果发生错误,所有未完成的Packet都会从ackQueue队列中移除掉,然后重新创建一个新的Pipeline,排除掉出错的
那些DataNode节点,接着DataStreamer线程继续从dataQueue队列中发送Packet。
参考: