HDFS 的体系架构采用主从结构,一个 HDFS 集群由一个单一的 Namenode和多个 Datanode 组成,Namenode 是 HDFS 的主服务器,主要负责管理文件系统的元数据。Datanode 负责存储文件的数据块。下面具体描述 Namenode 和 Datanode的功能。
Namenode 的功能主要有以下几点:
(1) 管理元数据和数据块
Namenode 也可以称为元数据节点,它的主要功能就是管理文件的元数据信息。
HDFS 中文件的元数据信息包括命名空间、文件到数据块的映射、数据块到数据节点的
映射三部分。Namenode 还会对文件的数据块进行管理,包括创建新数据块、复制数据
块、移除无效数据块以及回收孤立数据块等内容。
(2) 持久化元数据
为了加快元数据的访问,Namenode 一般将文件的元数据存储在内存中,但为了元数据的安全性,Namenode 还会将元数据持久化到硬盘中(fsImage)。Namenode 将元数据的修改操作记录在事务日志中(EditLog),事务日志一般存储在Namenode 节点的硬盘中。Namenode 将元数据信息存储在 FsImage 文件中,持久化的元数据信息包括文件属性、文件到数据块的映射,而数据块到数据节点的映射是在文件按系统启动时 Datanode 汇报给 Namenode的,因此并不需要将这些信息持久化。
(3) 处理请求
Namenode 还负责处理客户端和Datanode 的请求。Namenode 启动后会监听客户端和 Datanode 的请求,对请求进行处理后返回结果。客户端的请求通常包括文件和目录的创建、读写、重命名、删除,打开目录、移动目录等等。Datanode 的请求一般包括数据块信息的汇报、心跳响应、出错信息等等。
(4) 管理 Datanode
Datanode 节点会定时向Namenode节点发送心跳信息,Namenode通过心跳信息检测失效或已恢复的 Datanode。
Datanode 的功能主要包括以下几个方面:
(1) 数据块的读写
Datanode 存储了文件的数据块,但它不记录数据块到文件的映射,这些信息是记录在 Namenode 中的。因此,客户端不能直接与 Datanode 打交道,它必须通过 Namenode 获取文件的数据块信息和位置后,才能与 Datanode 联系进行文件的读写操作。
(2) 向NameNode 报告状态。
每个 Datanode 节点会定时向Namenode 发送心跳信息和数据块状态报告,Namenode 收集这些信息以了解集群的 Datanode 节点的状态和数据块状态。如果Namenode 发现某个 Datanode 节点失效,就会执行数据块的复制,将失效节点上的数据块通过其它副本复制到一个正常的 Datanode 中,保证数据块的副本数达到指定的数量。
(3) 执行数据的流水线复制
在创建文件时,客户端从 Namenode 节点获取到文件数据块的存储位置,包括数据块副本的存放位置,客户端不会将数据块直接复制到每个副本存放的Datanode 节点中,而是会进行数据块的流水线复制。客户端将数据块复制到第一个 Datanode 节点上,第一个节点将数据块复制到第二个节点中,第二个节点又向第三个节点复制,直到复制的数据块的数量达到系统指定的数据块副本数量。在进行流水线复制当中,每个节点不是等到整个数据块复制完成才向下一个节点复制,而是同时进行。
HDFS集群的单一的 Namenode 节点的结构在某种程度上简化了系统的架构。HDFS 只有一个 NameNode,这个 NameNode 节点保存着文件系统所有的元数据信息,可以通过全局的信息精确定位数据块的位置并进行复制决策。
二、元数据维护
在 Namenode 节点内存中,保存有三种类型的元数据信息,它们是文件命名空间、文件到数据块的映射、数据块到数据节点的映射。为了提高系统的可靠性,通常要将元数据的修改操作保存在磁盘中,以便在 Namenode 宕机时可以将元数据恢复。在 HDFS中,通常是将文件命名空间和文件到数据块的映射的修改操作记录并保存在硬盘中,系统重启时通过日志文件将这两种元数据加载到内存中。对于数据块到数据节点的映射关系,系统并没有将它们进行持久化,这是由于数据块的存放位置不固定且经常发生发生变化,对其持久化没有实际意义。
Namenode 并没有对数据块到Datanode 的映射关系进行持久化,而是在系统启动时从 Datanode 获得,启动后通过 Datanode 的心跳响应信息定期更新。在 HDFS 集群中,对某个 Datanode 发生失效的概率是很低的,但当集群中 Datanode 节点的数量通常达到数千个,发生节点失效的概率变得很大,节点失效已成为系统的常态,集群会频繁发生 Datanode 的加入、离开、宕机或重启,因此,只有 Datanode 自身才能确定其本地磁盘中的数据块位置信息,因而不需要将该信息持久化到 Namenode 中。而且,也不用去维护 Namenode 与 Datanode 的一致性问题。
EditLog 中保存了元数据的修改的历史记录,因而它发挥着非常重要的作用。EditLog不但对元数据信息进行持久化,还对元数据的修改顺序的逻辑时间线进行记录,而逻辑时间是对文件和数据块进行查找确认的唯一标示。因此,EditLog 存储的安全性和可靠性十分重要。为了防止系统丢失客户端对文件系统最近几次操作的记录,系统应该保证在客户端对元数据的修改操作之前将操作信息记录到 EditLog 中。为了保证数据的一致性,Namenode 在重启时会根据磁盘中的元数据信息(FsImage)和 EditLog 快速地进行数据恢复。
Namenode服务器在启动时,会进行检查点操作。在 HDFS 现在的版本的实现中,Namenode 只在启动时创建一个检查点,在以后的版本中,Namenode 可能会进行周期性地检查点创建。
Secondary Namenode 并不仅仅是 Namenode 的一个备份,SecondaryNamenode 的作用是和 FsImage,EditLog 分不开的。NameNode 将对文件系统的改动追加保存到本地文件系统上的一个日志文件(EditLog)。当一个 NameNode 启动时,它首先从一个映像文件(FsImage)中读取 HDFS 的状态,接着应用日志文件中的 edits 操作。然后它将新的HDFS 状态写入(FSImage)中,并使用一个空的 edits 文件开始正常操作。因为 NameNode只有在启动阶段才合并 FsImage 和 Edits,所以久而久之日志文件可能会变得非常庞大,特别是对大型的集群。日志文件太大的另一个副作用是下一次 NameNode 启动会花很长时间。
Secondary NameNode 定期合并 FsImage 和 Edits 日志,生成新的检查点,将Edits 日志文件大小控制在一个限度下。同时Secondary Namenode也可以作为namenode的备份存在,从而保证元数据的安全。