一、 更改目录操作
该操作基本只和NameNode进行交互
rename/mkdir等操作
NameNode在目录树数据结构上对应位置创建新的目录节点并持久化到日志中。
delete操作以及增加副本等相对复杂的操作
NameNode标记需要删除的文件并且持久化到日志中,等到DataNode提交心跳的时会获取到删除的命令,之后DataNode执行该删除指令,此时数据才会真正的被删除。
二、读取文件操作(NameNode仅提供数据块定位请求)
Client先打开一个输入流DFSInputStream
向NameNode获取文件开始部分数据块存储的地址(返回副本所在的数据节点地址并且利用网络的拓扑信息进行简单的排序)
Client和最近的数据节点建立联系,然后读取该块的信息直到块的末端,再关闭连接
重复2,3步
读取完毕后关闭输入流
2,3步对Client是透明的,实际是由DFSInputStream来进行的,Client是仅跟DFSInputStream进行交互
在读取的时候会同时获取数据以及数据校验和进行校验数据的一致性,若是校验错误则报告给NameNode,并尝试从别的数据节点中读取另外一个副本的文件内容。让客户端来进行校验可以降低数据节点的负载,均衡各节点的计算能力
如果读取的时候数据节点发生错误,那么Client会尝试读取下一个数据块的位置并且记住故障的数据节点并不再进行尝试。
NameNode并不会一次性返回所有数据块的信息,每次仅返回一组数据块的信息
三、写文件操作
Client打开输出流DFSDataOutputStream
NameNode在文件系统的命名空间创建新文件(做一些检查)并记录到编辑日志中
DFSDataOutputStream向NameNode申请数据块(返回数据块标识、版本号等信息)
与DataNode进行连接并且开始链式写数据以及逆流ack操作
写完一个数据块就向NameNode提交数据块;若是还有数据再继续申请数据块
全部写完后Client关闭输出流
输出流通知NameNode关闭文件,完成一次正常的写文件流程
若是写的时候有数据节点故障,则
① 数据流写通道关闭
② 已经发送到管道却还没收到ack的数据会被添加到输出队列
(当作没有写过来处理从而保证任一节点故障都不会丢数据)
③ 当前正常工作的DataNode上的数据块(指正在写的这个块)会被赋予一个新的版本号并报告NameNode,故障的DataNode恢复过来的时候会因为数据块版本号跟NameNode保存的版本号不一致而被删除。
④ 数据流管道中删除错误DataNode,重新建立管道并继续写数据到正常的DataNode
只要成功写入的副本数满足dfs.replication.min(默认1)的值,则认为写操作是成功的。后续这个数据块会被复制,直到满足文件的副本系数要求。
四、数据节点启动和心跳
DataNode先跟NameNode比对版本号,检查它们之间的HDFS版本是 一致的
DataNode向NameNode进行注册,NameNode会检查该DataNode是否是该集群的成员,保证整个系统的一致性。
成功注册后DataNode会将当前管理的数据块信息上报给NameNode,帮助NameNode建立HDFS文件数据块到数据节点的映射关系
五、Secondarynamenode合并元数据
Client对文件系统的目录树进行修改的操作都会被NameNode记录在编辑日志里,保证出现故障的时候可以快速恢复。为了避免编辑日志过大导致恢复时间过长,HDFS引入了检查点机制(fsimage)
fsimage是文件系统元数据的持久性检查点
NameNode与DataNode的交互
NameNode需要只需要准备一个DatanodeCommand数组,里面存放各种操作指令。在DataNode提交心跳的时候会拉取该数组回去并且执行里面的操作指令。