概述
HDFS(Hadoop Distributed File System)是GFS的开源实现。在了解读写流程原理之前,先了解namenode、datanode、secondarynamenode三个主要角色的主要作用与职能,这有助于你更好的理解HDFS I/O流。如果你对上述组件有所了解,请直接从目录处跳转至HDFS读写原理。
专业术语
- block: 文件上传前需需要把文件切割存储,简单来说切割后的文件被称为块(block)。老版本默认64M/新版本默认128M。块太大map任务少,处理数据慢。块太(小又)多,寻址时间长,NN的压力也会激增。
- fsimage: 在NameNode启动时对整个文件系统的快照。
- editlog: NameNode启动后,对文件系统的系列操作,都会存储在editlog中。
- edit logs: 若干个editlog被称为edit logs。
- RPC: 通讯协议,client向namenode发送请求时就是使用的RPC。
HDFS 组件角色
各版本官方文档:hadoop.apache.org/docs/
1、namenode
NameNode负责:文件元数据信息的操作以及处理客户端的请求
NameNode管理:HDFS文件系统的命名空间NameSpace。
NameNode维护:文件系统树(FileSystem)以及文件树中所有的文件和文件夹的元数据信息(matedata)
维护文件到块的对应关系和块到节点的对应关系
NameNode文件:namespace镜像文件(fsimage),操作日志文件(edit log)这些信息被Cache在RAM中,当然这两个文件也会被持久化存储在本地硬盘。
NameNode记录:每个文件中各个块所在的数据节点的位置信息。
但它并不永久保存块的位置信息,因为这些信息在系统启动时由数据节点重建。
从数据节点重建:在nameNode启动时,DataNode向NameNode进行注册时发送给NameNode
NameNode元数据信息
- 文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个文件的块列表。以及列表中的块与块所在的DataNode之间的地址映射关系在内存中加载文件系统中每个文件和每个数据块的引用关系(文件、block、datanode之间的映射信息) 数据会定期保存到本地磁盘,但不保存block的位置信息而是由DataNode注册时上报和在运行时维护
NameNode文件操作
- NameNode负责文件元数据的操作 NameNode是所有HDFS元数据的仲裁程序(处理读写请求)和存储库。系统的设计方式是,用户数据永远不会流经NameNode,会询问它跟哪个DataNode联系。
NameNode副本
- 文件数据块到底存放到哪些DataNode上,是由NameNode决定的,NN根据全局情况做出放置副本的决定读取文件的时候,NN尽量让client读取离它最近的datanode上的副本,降低带宽消耗和读取时延
NameNode职责
- 全权管理数据块的复制,周期性的接受心跳和块的状态报告信息(包含该DataNode上所有数据块的列表)若接受到心跳信息,NN认为DN工作正常,如果在10分钟后还接受到不到DN的心跳,那么NN认为DN已经宕机这时候NN准备要把DN上的数据块进行重新的复制。块的状态报告包含了一个DN上所有数据块的列表,blocks report 每个1小时发送一次
NameNode容错机制
- FsImage和Editlog是NameNode的中心数据结构,这些文件的损坏会导致集群的不可用。可以设置多个FsImage和Editlog副本,但会降低NameNode每秒能够支持的命名空间事务的速率。提高对故障弹性的另一个选项是namenode启用高可用性(HA),启用2个或以上namenode节点以及将持久化状态写到本地硬盘的同时,也写入到一个远程挂载的网络文件系统(NFS)。
NameNode详解请跳转至 雾幻 的Blog
2、secondarynamenode
SecondaryNameNode有两个作用,一是镜像备份,二是日志与镜像的定期合并。两个过程同时进行,称为checkpoint.
镜像备份的作用: 数据快照。
日志与镜像定期合并的作用: 将Namenode中edits日志和fsimage合并,防止Namenode节点故障,如果从每个edit log里取到内存中,给nn的压力会很大。导致操作延迟。
1、加载编辑日志和镜像文件到内存(第一次启动NameNode格式化后,则先创建fsimage和edits文件)
2、Client对namenode(元数据)的增删改请求
3、记录操作日志,更新到滚动日志(edits.inprogress)。
4、Secondary NameNode询问NameNode是否需要chkpoint,带回是否检查结果(合并)。
5、请求执行checkpoint。
6、滚动正在写的edits.inprogress
6.1此后第3步的写入文件变更为新的edits.inprogress,旧的edits.inprogress则变为edits.004
7、SecondaryNameNode通过http get方式获取NameNode的fsimage与edits文件(在SecondaryNameNode的current同级目录下可见到 temp.check-point或者previous-checkpoint目录,这些目录中存储着从namenode拷贝来的镜像文件)
8-9、Secondary NameNode加载编辑日志和镜像文件到内存去做合并,生成新的镜像文件fsimage.chkpoint。
10、合并完成后SecondaryNameNode用http post方式发送fsimage.ckpt至NameNode,生成新的镜像文件fsimage.chkpoint。
11、NameNode将fsimage.chkpoint重新命名成fsimage。
所以,我们可以把SNN理解为一个检查点,辅助NN共同完成元数据的合并维护工作。
3、datanode
一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和(作用是为了验证文件完整性),以及时间戳。
1.DataNode 以数据的形式存储HDFS文件
2.DataNode响应HDFS客户端读写请求
3.定期(1h)向namenode汇报自身所持有的心跳信息和block(数据块)信息
HDFS读写原理
Read
2、Namenode返回所有block的位置信息以及文件副本的保存位置(datanode节点的地址),并将这些信息返回给客户端。
3、客户端通过namenode返回的信息调用FSDataOututStream方法读取最适合的副本节点(本地→同机架→数据中心)。
4、下载完成block后,客户端会通过dn存储的校验和来确保文件的完整性。
Write
1、客户端(ClientNode)向HDFS写入数据首先调用DistributedFileSystem的create方法获取输出流(FSDataOutputStream)。
2、DistributedFileSystem调用NN(namenode)的create方法发出创建文件请求。NN对准备上传的文件名称和路径做校验,确定是否拥有写权限、是否有重名文件,并将操作写入到edits文件中。
3、客户端(CN)调用FSDataOutputStream向输出流输出数据,开始写入第一个块。
4、FSDataOutputStream调用NN的addBlock方法请求第一个块要存储在哪些DN上(配置副本数为3)。 如果管道(pipeline)没有建立,则根据位置信息建立pipeline。
5、与第一个DN节点DN1建立连接(RPC协议),向其发送package。该package会保存到ackqueue确认队列中。写数据时先将数据写到一个校验块chunk中,写满512字节,对chunk计算校验和checksum值(4字节)。以带校验和的checksum为单位向本地缓存输出数据(本地缓存占9个chunk),本地缓存满了向package输入数据,一个package占64kb。当package写满后,将package写入dataqueue数据队列中。将package从dataqueue数据对列中取出,沿pipeline发送到DN1,DN1保存,然后将package发送到DN2,DN2保存,以此类推直至最后一个副本节点。
6、最后一个副本校验完成后,逆方向通过pipeline回传给客户端(DN3→DN2→DN1→CN)。客户端根据校验结果判断,“成功”则将ackqueue确认队列中的package删除;如果“失败”,则将ackqueue队列中的package取出,从新放入到dataqueue数据队列末尾,等待回滚(从新沿pipeline发送)。
7、当第一个块的所有package发送完毕,3个副本都存有block1的完整数据,则3个DN同时调用NN的blockReceivedAndDeleted方法。NameNode会更新记录内存中DataNode和block的关系。ClientNode关闭同DataNode建立的pipeline。开始执行未发送的第2个块,第3个块..........直到文件所有数据传输完成。
8、全部数据执行完成后调用FSDataOutputStream的 close 方法关闭流。
9、客户端(CN)调用NN的complete方法通知NN全部数据传输完成。