概述
Hadoop分布式文件系统(HDFS)是一种分布式文件系统,用于在普通商用硬件上运行。它与现有的分布式文件系统有许多相似之处。然而,与其他分布式文件系统的区别很大。HDFS具有高度的容错能力,旨在部署在低成本的硬件上。HDFS提供对应用程序数据的高吞吐量访问,适用于具有大数据集的应用程序。HDFS放宽了一些POSIX要求,以便对文件系统数据进行流式访问。HDFS最初是作为Apache Nutch Web搜索引擎项目的基础架构构建的。HDFS是Apache Hadoop Core项目的一部分。
设想和目标
硬件容错
硬件故障很常见而不例外。HDFS实例可以由数百或数千台服务器机器组成,每台服务器存储部分文件系统的数据。事实上,有大量的组件,并且每个组件具有不一定的故障概率,这意味着HDFS的某些组件总是不起作用的。因此,故障检测和快速自动恢复是HDFS的核心架构。
流数据访问
在HDFS上运行的应用程序需要对其数据集进行流式访问。HDFS不是用于提供普通应用访问的文件系统。HDFS的设计更多用于批量处理,而不是用户的交互式使用。重点是数据访问的高吞吐量,而不是数据访问的低延迟。POSIX施加了许多难于为HDFS定位的应用程序所需的硬要求。POSIX语义在几个关键领域已被交易,以提高数据吞吐率。
大数据集
在HDFS上运行的应用程序具有较大的数据集。HDFS中的典型文件大小为千兆字节。因此,HDFS被调整为支持大文件。它应该提供高聚合数据带宽并扩展到单个集群中的数百个节点。它应该在一个实例中支持数千万个文件。
简单一致性模型
HDFS数据访问模式为一次写入多次读取。文件一旦创建、写入和关闭后,除了追加和截断,文件内容不再变化。将内容附加到文件的末尾是受支持的,但不能随意更新。该假设简化了数据一致性问题,并实现了高吞吐量数据访问。MapReduce应用程序或Web爬虫程序应用程序与此模型完美匹配。
“移动计算比移动数据便宜”
如果应用程序能够很近德运行在其需要的数据,则应用程序所请求的计算效率更高【应用处理本机数据比远程数据更快】。当数据集很大时,这一点尤其如此。这样可以最大限度地减少网络拥塞并提高系统的整体吞吐量。假设通常更好地将计算迁移到更接近数据位置的位置,而不是将数据移动到应用程序运行的位置。HDFS为应用程序提供接口,使其更接近数据所在的位置。
跨越异构硬件和软件平台的可移植性
HDFS被设计为可以从一个平台轻松地移植到另一个平台。这有助于HDFS作为大型应用程序的首选平台。
NameNode DataNodes
HDFS具有主/从结构。HDFS集群包含单一的NameNode作为master服务器,用于管理文件系统命名空间,并调节客户端对文件的访问。此外,还有一些DataNodes,通常是集群中每个节点的一个,它们管理连接到运行的节点的存储。HDFS公开了文件系统命名空间,并允许将用户数据存储在文件中。在内部,文件被分割成一个或多个块,并且这些块被存储在一组DataNodes中。NameNode执行文件系统命名空间操作,如打开,关闭和重命名文件和目录。它还确定块到DataNodes的映射。DataNodes负责从文件系统的客户端提供读取和写入请求。DataNode还可以根据NameNode的指示执行块创建,删除和复制。
NameNode和DataNode是用于在商用机上运行的软件。这些机器通常运行GNU / Linux操作系统(OS)。HDFS使用Java语言构建;任何支持Java的机器都可以运行NameNode或DataNode软件。高度可移植的Java语言的使用意味着HDFS可以部署在广泛的机器上。典型的部署具有仅运行NameNode软件的专用机器。集群中的每个其他计算机都运行DataNode软件的一个实例。该架构并不排除在同一台机器上运行多个DataNodes,而是在很少出现的实际部署中。
集群中单个NameNode的存在大大简化了系统的体系结构。NameNode是所有HDFS元数据的仲裁器和存储库。该系统的设计方式使得用户数据不会流经NameNode。
文件系统命名
HDFS支持传统的分层文件组织。用户或应用程序可以创建目录并将文件存储在这些目录中。文件系统命名空间层次结构与大多数其他现有文件系统类似;可以创建和删除文件,将文件从一个目录移动到另一个目录,或者重命名文件。HDFS支持用户配额和访问权限。HDFS不支持硬链接或软链接。然而,HDFS架构并不排除实现这些功能。
NameNode维护文件系统命名空间。文件系统名称空间或其属性的任何更改都由NameNode记录。应用程序可以指定应由HDFS维护的文件的副本数。文件的副本数称为该文件的复制因子。该信息由NameNode存储。
数据复制
HDFS设计用于在大型集群中的机器之间可靠地存储非常大的文件。它将每个文件存储为一系列块。复制文件的块以进行容错。块大小和复制因子是可配置的每个文件。【hdfs-site.xml dfs.block.size dfs.replication】
除了最后一个块之外的文件中的所有块都是相同的大小,而用户可以在将可变长度块的支持添加到追加和hsync之后启动一个新的块,而不会将最后一个块填充到配置的块大小。
应用程序可以指定文件的副本数。可以在文件创建时指定复制因子,稍后更改。HDFS中的文件是一次写入(除了附加和截断之外),并且在任何时候都有一个作者。
NameNode做出关于块复制的所有决定。它周期性地从集群中的每个DataNode接收到一个心跳和一个阻塞报告。收到心跳意味着DataNode正常运行。Blockreport包含DataNode上所有块的列表。
复本安置:第一步
复制品的放置对于HDFS的可靠性和性能至关重要。优化复制放置将HDFS与大多数其他分布式文件系统区分开来。这是一个需要大量调整和体验的功能。机架感知复制放置策略的目的是提高数据可靠性,可用性和网络带宽利用率。目前的复制放置政策的实施是朝这个方向努力的第一步。实施这一政策的短期目标是在生产系统上进行验证,更多地了解其行为,并为更复杂的政策进行测试和研究奠定基础。
大型HDFS实例在通常分布在多个机架上的计算机集群上运行。不同机架中的两个节点之间的通信必须经过交换机。在大多数情况下,同一机架中的机器之间的网络带宽大于不同机架中的机器之间的网络带宽。
NameNode通过Hadoop机架意识【http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/RackAwareness.html】中概述的过程来确定每个DataNode所属的机架ID。一个简单但不是最优的策略是将副本放在独特的机架上。这可以防止整个机架发生故障时丢失数据,并允许在读取数据时使用多个机架的带宽。该策略在集群中均匀分配副本,这使得轻松平衡组件故障时的负载。但是,这种策略会增加写入的成本,因为写入需要将块传输到多个机架。
对于常见情况,当复制因子为3时,HDFS的放置策略是将一个副本放在本地机架中的一个节点上,另一个在本地机架上的另一个节点上,最后在不同机架中的不同节点上。该策略可以减少机架间的写入流量,这通常会提高写入性能。机架故障的机会远小于节点故障的机会;此政策不影响数据的可靠性和可用性保证。然而,它确实减少了在读取数据时使用的总体网络带宽,因为块仅放置在两个独特的机架中,而不是三个。使用此策略,文件的副本不会均匀分布在机架中。三分之一的副本在一个节点上,三分之二的副本在一个机架上,另外三个是均匀分布在剩余的机架上。此策略可改善写入性能,而不会影响数据的可靠性或读取性能。
如果复制因子大于3,则随机确定第4个和以后副本的位置,同时保持每个机架的副本数量低于上限(基本为(复制1)/机架2))。
由于NameNode不允许DataNodes具有相同块的多个副本,所以创建的副本的最大数目是当时的DataNodes的总数。
在将存储类型和存储策略【http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/ArchivalStorage.html】的支持添加到HDFS之后,除了上述的机架感知之外,NameNode还会将策略考虑在副本位置。NameNode首先根据机架识别选择节点,然后检查候选节点是否具有与文件关联的策略所需的存储。如果候选节点没有存储类型,则NameNode将查找另一个节点。如果在第一个路径中找不到足够的放置副本的节点,则NameNode将在第二个路径中查找具有备用存储类型的节点。
此处描述的当前,默认的复制放置策略是一项正在进行的工作。
复本选择
为了最大限度地减少全局带宽消耗和读取延迟,HDFS会尝试从最接近读卡器的副本获取读取请求。如果在与读取器节点相同的机架上存在副本,则该副本优选满足读取请求。如果HDFS群集跨越多个数据中心,则驻留在本地数据中心的副本优先于任何远程副本。
安全模式
在启动时,NameNode进入一个称为Safemode的特殊状态。NameNode处于Safemode状态时,不会复制数据块。NameNode从DataNodes接收心跳和Blockreport消息。Blockreport包含DataNode承载的数据块列表。每个块具有指定的最小数量的副本。当使用NameNode检入数据块的最小副本数时,块被认为是安全复制的。在可配置百分比的安全复制数据块使用NameNode(加上另外30秒)之后,NameNode退出Safemode状态。然后,它确定仍然具有少于指定数量的副本的数据块(如果有)的列表。NameNode然后将这些块复制到其他DataNodes。
持久化文件系统元数据
元数据信息
1.EditLog
2.FsImage
HDFS命名空间由NameNode存储。NameNode使用名为EditLog的事务日志持续记录文件系统元数据发生的每个更改。例如,在HDFS中创建一个新文件会导致NameNode将一个记录插入到EditLog中。类似地,更改文件的复制因子将导致将新记录插入到EditLog中。NameNode使用其本地主机OS文件系统中的文件来存储EditLog。整个文件系统命名空间(包括将块映射到文件和文件系统属性)存储在一个名为FsImage的文件中。FsImage作为文件存储在NameNode的本地文件系统中。
检查点
checkpoint 用于合并EditLog至FsImage,FsImage是文件系统最新的元数据,但不直接更新FsImage,而是定时合并EditLog至FsImage
NameNode将整个文件系统命名空间和文件Blockmap的映像保存在内存中。当NameNode启动或检查点由可配置的阈值触发时,它从磁盘读取FsImage和EditLog,将所有来自EditLog的事务应用到FsImage的内存中表示,并将该新版本刷新为保存到硬盘作为新的FsImage。它可以截断旧的EditLog,因为它的事务已被应用到永久的FsImage。这个过程称为检查点。检查点的目的是通过拍摄文件系统元数据的快照并将其保存到FsImage来确保HDFS具有文件系统元数据的一致视图。即使阅读FsImage也是有效的,直接对FsImage进行增量编辑是不正确的。我们不用修改每个编辑的FsImage,而是在Editlog中保持编辑。在检查点期间,Editlog中的更改应用于FsImage。可以在给定的时间间隔(dfs.namenode.checkpoint.period)上以秒为单位触发检查点,或在给定数量的文件系统事务已累积(dfs.namenode.checkpoint.txns)后触发。如果这两个属性都被设置,则要达到的第一个阈值触发一个检查点。
真实数据的存储
DataNode将HDFS数据存储在本地文件系统中的文件中。DataNode不了解HDFS文件。它将HDFS数据的每个块存储在其本地文件系统中的单独文件中。DataNode不会在同一目录中创建所有文件。相反,它使用启发式方法来确定每个目录的最佳文件数,并适当地创建子目录。在同一目录中创建所有本地文件并不是最佳的,因为本地文件系统可能无法在单个目录中有效地支持大量文件。当DataNode启动时,它将扫描其本地文件系统,生成与每个这些本地文件对应的所有HDFS数据块的列表,并将此报告发送到NameNode。该报告称为Blockreport。
通信协议
所有HDFS通信协议分层在TCP / IP协议之上。客户端与NameNode机器上配置TCP端口建立连接。利用ClientProtocol协议与NameNode进行通信。DataNode使用DataNode协议与NameNode进行通信。远程过程调用(RPC)抽象包含客户端协议和数据节点协议。按照设计,NameNode从不启动任何RPC。相反,它只响应DataNodes或客户端发出的RPC请求。
稳定性
HDFS的主要目标是即使存在故障也能够可靠地存储数据。三种常见的故障类型是NameNode故障,DataNode故障和网络分区
数据磁盘故障,心跳和重新复制
每个DataNode定期向NameNode发送一个心跳信息。网络分区可能导致DataNodes的一个子集与NameNode失去连接。NameNode通过不存在心跳消息来检测此情况。NameNode将DataNodes标记为没有最近的Heartbeats死机,并且不会向其转发任何新的IO请求。任何已注册到死亡数据节点的数据不再适用于HDFS。DataNode死亡可能导致某些程序段的复制因子低于其指定值。NameNode不断跟踪哪些块需要复制,并在必要时启动复制。重复复制的必要性可能由于许多原因:DataNode可能变得不可用,副本可能会损坏,DataNode上的硬盘可能会失败,或者可能会增加文件的复制因素。
标记DataNodes死机的超时保守长(默认为10分钟以上),以避免DataNodes的状态拍摄引起的复制风暴。用户可以设置更短的间隔,将DataNodes标记为过时,并通过配置读取和/或写入性能敏感工作负载来避免过时的节点。
集群再平衡
HDFS架构与数据重新平衡方案兼容。如果DataNode上的可用空间低于某个阈值,则方案可能会自动将数据从一个DataNode移动到另一个DataNode。在特定文件需求突然增加的情况下,方案可能会动态创建其他副本并重新平衡群集中的其他数据。这些类型的数据重新平衡计划尚未实施。
数据的完整性
从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来使用。
快照
快照支持在特定时刻存储数据副本。快照功能的一个用法可能是将损坏的HDFS实例回滚到先前已知的好时间点。
数据组织
数据块
HDFS旨在支持非常大的文件。与HDFS兼容的应用程序是处理大型数据集的应用程序。这些应用程序只写一次数据,但它们读取一次或多次,并要求这些读取在流速下满足。HDFS支持对文件的一次读取多语义。HDFS使用的典型块大小是128 MB。因此,将HDFS文件切成128 MB块,如果可能,每个块将驻留在不同的DataNode上。
分阶段
创建文件的客户端请求不会立即到达NameNode。实际上,最初,HDFS客户端将文件数据缓存到本地缓冲区中。应用程序写入被透明地重定向到本地缓冲区。当本地文件累积超过一个块大小的数据时,客户端将连接NameNode。NameNode将文件名插入到文件系统层次结构中,为其分配一个数据块。NameNode使用DataNode和目标数据块的标识响应客户端请求。然后客户端将数据块从本地缓冲区刷新到指定的DataNode。关闭文件时,本地缓冲区中剩余的未刷新数据将传输到DataNode。客户端然后告诉NameNode该文件是关闭的。此时,NameNode将文件创建操作提交到持久存储。如果NameNode在文件关闭之前死机,该文件将丢失。
上述方法在仔细考虑了在HDFS上运行的目标应用程序后才采用。这些应用程序需要流式写入文件。如果客户端直接写入远程文件而没有任何客户端缓冲,网络速度和网络拥塞就会大大影响吞吐量。这种做法并非没有先例。早期的分布式文件系统,例如AFS使用客户端缓存来提高性能。POSIX要求已放宽,以实现更高性能的数据上传。
复制管道
当客户端将数据写入HDFS文件时,首先将其数据写入本地缓冲区,如上一节所述。假设HDFS文件的复制因子为3。当本地缓冲区累积一大批用户数据时,客户端将从NameNode中检索一个DataNodes列表。该列表包含将承载该块的副本的DataNodes。然后,客户端将数据块刷新到第一个DataNode。第一个DataNode开始以小部分接收数据,将每个部分写入其本地存储库,并将该部分传输到列表中的第二个DataNode。第二个DataNode又开始接收数据块的每个部分,将该部分写入其存储库,然后将该部分刷新到第三个DataNode。最后,第三个DataNode将数据写入本地存储库。因此,DataNode可以在流水线中接收来自前一个数据的数据,并且同时将数据转发到流水线中的下一个数据。因此,数据从一个DataNode流水线到下一个。
访问能力
HDFS可以从应用程序以许多不同的方式访问。本来,HDFS提供了一个FileSystem Java API,供应用程序使用。此Java API和REST API的C语言包装器也可用。另外,HTTP浏览器还可以用来浏览HDFS实例的文件。通过使用NFS网关,HDFS可以作为客户端本地文件系统的一部分进行安装。
FS Shell
HDFS允许以文件和目录的形式组织用户数据。它提供了一个名为FS shell的命令行接口,可让用户与HDFS中的数据进行交互。该命令集的语法类似于用户已经熟悉的其他shell(例如bash,csh)。以下是一些示例操作/命令对:
Action | Command |
---|---|
Create a directory named /foodir | bin/hadoop dfs -mkdir /foodir |
Remove a directory named /foodir | bin/hadoop fs -rm -R /foodir |
View the contents of a file named /foodir/myfile.txt | bin/hadoop dfs -cat /foodir/myfile.txt |
FS shell针对需要使用脚本语言与存储数据进行交互的应用程序。
DFSAdmin
DFSAdmin命令集用于管理HDFS集群。这些是仅由HDFS管理员使用的命令。以下是一些示例操作/命令对:
Action | Command |
---|---|
Put the cluster in Safemode | bin/hdfs dfsadmin -safemode enter |
Generate a list of DataNodes | bin/hdfs dfsadmin -report |
Recommission or decommission DataNode(s) | bin/hdfs dfsadmin -refreshNodes |
浏览器
典型的HDFS安装配置Web服务器以通过可配置的TCP端口公开HDFS命名空间。这允许用户浏览HDFS命名空间,并使用Web浏览器查看其文件的内容。
空间管理
文件删除和取消删除
如果启用垃圾箱配置,FS Shell删除的文件不会立即从HDFS中删除。相反,HDFS将其移动到垃圾目录(每个用户在/user/<username>/.Trash下都有自己的垃圾文件目录)。只要文件保留在垃圾箱中,文件可以快速恢复。
大多数最近删除的文件被移动到当前垃圾桶目录(/user/<username>/.Trash/Current),并且在可配置的时间间隔内,HDFS创建检查点(在/ user / <username> /。垃圾桶/ <date>下)对于当前垃圾目录中的文件,并在旧的检查点过期时删除它们。请参阅FS shell关于检查垃圾的清除命令。
Trash生命周期到期时,Namenode从HDFS命名空间中删除该文件。删除文件会导致与文件关联的块被释放。请注意,在用户删除文件的时间与HDFS中可用空间相应增加的时间之间可能会有明显的时间延迟。
以下是一个示例,显示如何从FS Shell从HDFS中删除文件。我们创建了2个文件(test1&test2)
$ hadoop fs -mkdir -p delete/test1$ hadoop fs -mkdir -p delete/test2$ hadoop fs -ls delete/Found 2 itemsdrwxr-xr-x - hadoop hadoop 0 2015-05-08 12:39 delete/test1drwxr-xr-x - hadoop hadoop 0 2015-05-08 12:40 delete/test2
我们要删除文件test1。下面的描述显示文件已被移至垃圾桶目录。
$ hadoop fs -rm -r delete/test1Moved: hdfs://localhost:9820/user/hadoop/delete/test1 to trash at: hdfs://localhost:9820/user/hadoop/.Trash/Current
现在我们将使用skipTrash选项删除该文件,该选项不会将文件发送到Trash。它将从HDFS中完全删除。
$ hadoop fs -rm -r -skipTrash delete/test2Deleted delete/test2
我们现在可以看到垃圾邮件目录只包含文件test1。
$ hadoop fs -ls .Trash/Current/user/hadoop/delete/Found 1 items\drwxr-xr-x - hadoop hadoop 0 2015-05-08 12:39 .Trash/Current/user/hadoop/delete/test1
所以文件test1进入垃圾箱,文件test2被永久删除。
降低复制因子
当文件的复制因子减少时,NameNode选择可以删除的多余副本。下一个Heartbeat将此信息传输到DataNode。DataNode然后删除相应的块,并且相应的可用空间出现在群集中。再次,在完成setReplication API调用和集群中可用空间的外观之间可能会有时间延迟。
References
Hadoop .
HDFS source code: