写流程
1.客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件, NameNode检查用户是否有写入权限并且检查目标文件是否已存在,父目录是否存在。 2.Namenode返回客户端是否可以上传。
3.如果可以上传客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。
4.NameNode根据副本放置策略返回 一个有序的 DataNode列表, 分别为 dn1、 dn2、 dn3。
5.客户端通过 FSDataOutputStream 模块请求 dn1 上传数据, dn1收到请求会继续调用dn2,然后 dn2 调用 dn3,将这个通信管道(Pipeline)建立完成(是dn1找dn2,dn2找dn3,不是客户端与dn1、dn2、dn3都建立连接)。
6.dn1、 dn2、 dn3 逐级应答客户端。
7.客户端与DataNode建立数据传输流,将数据进行分割Packet(64KB),并使用chunk(512B)+chuncksum(4B) 填充Packet,dn1 收到一个 Packet 向内存存一份,向磁盘存一份,dn1接收完第一个Packet就会传给 dn2, dn2 传给 dn3; 当dn1向dn2传送第一个Packet的同时客户端向dn1传输第二个Packet。--将数据进行分割是为了节省数据传输时间
当一个 Block 传输完成之后,DateNode各自向NameNode汇报,同时客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行 3-7 步)
如果传输过程中dn3节点宕机,不影响数据传输;如果dn2节点宕机,dn1将数据传输给dn3;如果dn1宕机,客户端与dn2建立通信;DateNode与Namenode通过心跳机制汇报block块位置,发现副本数不足,会让其中一个DateNode复制出一个DateNode。
NameNode中记录的元数据是DateNode通过心跳机制汇报的,并不是客户端标记的。
读流程
1.客户端向 NameNode 发起 RPC 请求,来确定请求文件 block 所在的位置;
2.NameNode 检查用户权限以及是否有这个文件,返回DataNode地址;
3.客户端根据就近原则从 DataNode 来读取 block.,由DateNode返回数据;
4.当读完列表的 block 后,若文件读取还没有结束,客户端会继续向 NameNode 获取下一批的 block 列表;
5.读取完一个 block 都会进行 checksum 验证,如果读取 DataNode 时出现错误,客户端会通知 NameNode,然后再从下一个拥有该 block 副本的 DataNode 继续读。
6.最终读取来所有的 block 会合并成一个完整的最终文件
read 方法是并行的读取 block 信息,不是一块一块的读取;NameNode 只是返回 Client 请求包含块的 DataNode 地址,并不是返回请求块的数据;