文件系统元数据的持久性
HDFS名称空间由NameNode存储。NameNode使用名为EditLog的事务日志来持久记录文件系统元数据发生的所有更改。例如,在HDFS中创建一个新文件会导致NameNode向EditLog中插入一条记录,指出这一点。同样,更改文件的复制因子会导致将新记录插入到EditLog中。NameNode使用其本地主机OS文件系统中的文件来存储EditLog。整个文件系统名称空间(包括块到文件和文件系统属性的映射)存储在名为FsImage的文件中。FsImage也作为文件存储在NameNode的本地文件系统中。
NameNode将整个文件系统名称空间和文件Blockmap的图像保存在内存中。这个关键的元数据项目设计得很紧凑,这样一个具有4GB RAM的NameNode足以支持大量的文件和目录。当NameNode启动时,它从磁盘读取FsImage和EditLog,将EditLog中的所有事务应用到FsImage的内存中表示,并将此新版本刷新到磁盘上的新FsImage中。它可以截断旧的EditLog,因为它的事务已经被应用到持久的FsImage。这个过程被称为检查点。在当前的实现中,只有在NameNode启动时才会出现检查点。正在开展工作以支持不久的将来定期检查点。
DataNode将HDFS数据存储在本地文件系统中的文件中。DataNode没有关于HDFS文件的知识。它将每个HDFS数据块存储在本地文件系统中的单独文件中。DataNode不会在同一目录中创建所有文件。相反,它使用启发式来确定每个目录的最佳文件数量并适当地创建子目录。在同一目录中创建所有本地文件并不是最佳选择,因为本地文件系统可能无法有效地支持单个目录中的大量文件。当DataNode启动时,它扫描其本地文件系统,生成与每个本地文件相对应的所有HDFS数据块的列表,并将此报告发送给NameNode:这是Blockreport。
通信协议
所有HDFS通信协议都在TCP / IP协议之上进行分层。客户端建立到NameNode机器上可配置TCP端口的连接。它与NameNode交谈ClientProtocol。DataNode使用DataNode协议与NameNode进行通信。远程过程调用(RPC)抽象包装了客户端协议和数据节点协议。根据设计,NameNode永远不会启动任何RPC。相反,它只响应DataNode或客户端发出的RPC请求。
数据的完整性
从DataNode获取的数据块可能会损坏。由于存储设备故障,网络故障或有问题的软件,可能会发生此损坏。HDFS客户端软件对HDFS文件的内容执行校验和检查。当客户端创建HDFS文件时,它会计算文件每个块的校验和,并将这些校验和存储在同一个HDFS名称空间中的单独隐藏文件中。当客户端检索文件内容时,它会验证从每个DataNode收到的数据是否与存储在相关校验和文件中的校验和相匹配。如果不是,那么客户端可以选择从另一个具有该块的副本的DataNode中检索该块。
元数据磁盘失败
**FsImage和EditLog是HDFS的中心数据结构。这些文件的损坏可能会导致HDFS实例失效。由于这个原因,NameNode可以配置为支持维护FsImage和EditLog的多个副本。任何对FsImage或EditLog的更新都会导致每个FsImages和EditLogs同步更新。同步更新FsImage和EditLog的多个副本可能会降低NameNode每秒可支持的名称空间事务处理速度。但是,这种降级是可以接受的,因为即使HDFS应用程序本质上是非常密集的数据,它们也不是元数据密集型的。当NameNode重新启动时,它会选择最新的一致的FsImage和EditLog来使用。
另一个增加弹性以抵御故障的方法是使用多个NameNode启用高可用性,使用NFS上的共享存储或使用分布式编辑日志(称为日记)。后者是推荐的方法。**
分期
客户端创建文件的请求不会立即到达NameNode。事实上,最初HDFS客户端将文件数据缓存到本地缓冲区。应用程序写入被透明地重定向到本地缓冲区。当本地文件累积超过一个块大小的数据时,客户端会联系NameNode。NameNode将文件名插入到文件系统层次结构中,并为其分配一个数据块。NameNode用DataNode的标识和目标数据块响应客户请求。然后客户端将本地缓冲区中的数据块刷新到指定的DataNode。当文件关闭时,本地缓冲区中剩余的未刷新数据将传输到DataNode。客户端然后告诉NameNode文件已关闭。在此刻,NameNode将文件创建操作提交到持久存储中。如果NameNode在文件关闭之前死亡,则文件丢失。
在仔细考虑在HDFS上运行的目标应用程序后,采用了上述方法。这些应用程序需要流式写入文件。如果客户端在没有任何客户端缓冲的情况下直接写入远程文件,则网络速度和网络拥塞会严重影响吞吐量。这种做法并非没有先例。早期的分布式文件系统(例如AFS)使用客户端缓存来提高性能。POSIX的要求已经放宽,以实现更高的数据上传性能。
复制流水线
当客户端将数据写入HDFS文件时,首先将数据写入本地缓冲区,如前一节所述。假设HDFS文件的复制因子为3。当本地缓冲区累积大量用户数据时,客户端从NameNode中检索DataNode列表。该列表包含将承载该块的副本的DataNode。客户端然后将数据块刷新到第一个DataNode。第一个DataNode开始以小部分接收数据,将每个部分写入其本地存储库并将该部分传输到列表中的第二个DataNode。第二个DataNode反过来开始接收数据块的每个部分,将该部分写入其存储库,然后将该部分刷新到第三个DataNode。最后,第三个DataNode将数据写入其本地存储库。从而,DataNode可以从流水线中的前一个接收数据,同时将数据转发到流水线中的下一个数据。因此,数据从一个DataNode流水到下一个。