介绍
Hadoop分布式文件系统(HDFS)设计的运行环境是商用的硬件系统。他和现存的其他分布式文件系统存在很多相似点。不过HDFS和其他分布式文件系统的区别才是他的最大亮点,HDFS具有高容错的特性并且可以部署在廉价硬件,HDFS提供对应用数据的高吞吐访问,适用于数据量大的应用系统。HDFS放松了POSIX的要求以允许文件系统数据的流访问。
远景和目标
硬件故障
硬件故障是常态而不是异常情况,一个HDFS实例可能会使用成百上千的服务器,每个服务器保存整个文件系统的一部分数据,事实上,整个系统由大量组件构成,每个组件都存在较高的错误率,意味着HDFS中总存在失效的组件。因此检测故障并且快速自动恢复是HDFS的核心构筑目标。重点是高吞吐数据访问而不是低延迟数据范文,
流式数据访问
HDFS中运行的应用存在对数据集进行流访问的需求。他们不是运行在普通文件系统上的一般用途的应用,HDFS更多的是为批量处理需求而设计,并非用于用户的交互需求。POSIX强加了许多硬性要求,但这些要求对针对HDFS开发的应用并不需要。POSIX语法在几个关键领域已经被拓展以增加数据吞吐效率。
大数据集
HDFS上运行的应用有大数据集,一个典型的HDFS文件大小在GB到TB之间,因此HDFS被调整为可支持大文件。它应该提供高带宽并且能够支持一个集群缩放到上百节点,应该能够支撑千万级别量文件的单独实例场景。
简单一致性模型
HDFS应用需要的是一次写入多次读取(write-once-read-many)的文件访问模型,一个文件一旦被创建、写入、关闭后,除非再次追加或者截断,该文件都不需要被修改。HDFS支持向文件中追加内容,但是不能实时执行该更新,这个预置条件简化了数据一致性问题并且提高了数据访问吞吐量。MapReduce和网络爬虫应用和HDFS的数据模型能够完美匹配。
移动计算比移动数据更节省成本
应用调用的计算如果离所依赖的操作数据近,则应用小类更高,并且应用的数据量越庞大,效率优势表现更明显,这样能降低网络拥堵,提高系统整体吞吐量。HDFS的假设是迁移计算服务到数据存储位置附近比将数据移动到应用运行的地方更好。HDFS提供接口支持应用将自身移动到数据存储的位置。
跨异构硬件和软件平台的可移植性
HDFS被设计为易于在平台间移植, 该特性有助于HDFS作为大应用集合的可选平台广泛传播。
NameNode和DataNodes
HDFS是主从结构,一个HDFS集群包括一个单独的NameNode,一个主服务用于管理namespace和调节客户端的文件访问,另外包括一些DataNode(通常集群中的一个节点就是一个DataNode),DataNode用于管理所运行的节点上的存储数据。HDFS暴露一个文件系统的命名空间并且允许用户将数据存入文件,在文件系统内部一个文件会被切分成一个或多个块,这些快被存储在一个DataNode的集合。NameNode执行文件系统namespace的操作如打开、关闭、重命名文件/目录,并且提供块到DataNode的映射关系。DataNode负责为文件系统客户端的读/写请求提供服务,并且根据NameNode发送的指令执行块创建、删除和复制。
NameNode和DataNode是运行在商用机上的软件,这些机器通常运行的是GNU/Linux操作系统。HDFS使用Java开发,任何支持java的机器都能运行NameNode和DataNode软件,使用高可移植性的java语言意味着HDFS可以广泛的部署在各种机器上。一种典型的部署方式是将NameNode部署在一台指定机器上,其他机器每一台运行一个DataNode应用实例,这种结构并不排除在一台机器上部署多个DataNode实例的情况,但是实际部署过程中这种情况很罕见。
集群中独立部署NameNode极大地简化了系统结构,NameNode是HDFS元数据的仲裁人和仓库,HDFS系统被设计为用户的数据不会流经NameNode.
HDSF的Namespace
HDFS支持传统的层级文件组织结构,用户或者应用可以创建目录并把文件存入这些目录,文件系统namespace的层次结构和现存大部分文件系统类似,用户可以创建和删除文件,将文件从一个目录移到另一个目录,或者重命名文件。HDFS支持用户限额和访问控制,HDFS不支持硬链接和软连接,然而HDFS体系不限制对这些特性的扩展实现。
NameNode维护文件系统的namespace,对于文件系统namespace或者namespace属性的任何变更都会被记录在NameNode,应用程序可以指定一个HDFS所维护文件的备份数,一个文件的拷贝数被称为该文件的复制因子,复制因子信息存储在NameNode。
数据赋值
HDFS被设计为在大集群中的机器间可靠的保存超大文件,他把每个文件作为块序列存储,一个文件的每个块都会被复制以保证容错能力,每个文件的块大小和复制因子都是可配置的,一个文件的所有块,除了最后一个块,其他大小一样,HDFS支持可变长度块能力添加到append和行同步后,用户可以可以不需要将最后一个块填充到配置的块大小而开始一个新块,应用可以指定一个文件的复制数,复制因子可以在文件创建时设置,创建后也可以修改。HDFS一次写入并且在同一时间严格控制只能有一个写入者,NameNode根据块复制做所有决定,NameNode周期性收到来自集群中DataNode的心跳和Blockreport,收到心跳意味着DataNode运行正常,一个Blockreport包含一个DataNode上所有块信息列表。
备份存放位置:婴儿第一步
备份存放位置对HDFS的可靠性和性能非常重要,备份存放位置的优化将HDFS区别于其他分布式文件系统,这个特性需要许多调试和经验。这种对机架敏感的备份存储位置策略的目的是提高数据可靠性和可用性和网络带宽使用率,当前对于备份位置选择是朝着这些方向努力的第一步。实现该策略的短期目标是在线上系统先验证,了解他的运行状况,为测试和发现更多先进的策略提供基础。
运行在一群计算机上的庞大HDFS实例通常会横跨许多机架,位于不同机架的两个节点通信必须经过交换机,大多数情况下同一个机架内机器间带宽要大于不同机架设备间的。
NameNode通过Hadoop机架意识的进程检测每个DataNode所属的机架id,一个简单但不是最好的策略是把备份放到同一个机架,这可以防止数据丢失并且允许读数据操作能够充分利用多个机架的带宽。
通常情况下,当复制因子是3的时候HDFS的选址策略是一份备份放在本地机架一个节点上,另一份备份放在本地机架的另一个节点上,剩下的一个放在不同机架的一个节点上,这个策略能够减少机架间的写流量,因此能提升数据写效率,机架故障几率远 比单个节点故障低,这个策略不会对数据可靠性和可用性的保障产生影响。但是他降低了读数据时的总体网络带宽使用率因为一个块被放置在两个独立机架而不是三个。使用这个策略,一个文件的块将不会平均的分布在各个机架,1/3的备份在一个节点上,2/3的备份在一个机架上,另外1/3均匀分布在剩余机架,这个策略提高了写效率同时不会压缩数据可靠性和读效率。
当前,这里介绍的默认的副本存放策略正在使用中。
副本选择
为了最大程度减少全局带宽消耗和数据读延时,HDFS尝试使用距离数据读取者最近的一个副本来满足去请求,如果在同一个机架上存在一个副本作为读节点,则那个副本会被选择满足读请求,如果HDFS集群扩展到多个数据中心,则相比于远程副本,寄存在本地数据中心的副本将被优先使用。
安全模式
NameNode启动时会进入特殊状态叫安全模式。处于安全模式时NameNode不会进行数据块(block)复制,仅接受DataNode的心跳和数据块上报(Blockreport)消息。一条数据块上报消息包含了一个DataNode所维护的数据块信息列表。每一个块都有指定的最小的备份数,只有当指定的最小备份数的备份块信息都注册到NameNode时,该块才被认为是安全复制成功。当可配置百分比的安全复制的数据块登记到NameNode后,NameNode退出安全模式,NameNode会再次检查是否存在数据块不足指定备份数,如果存在,NameNode会复制这些数据块到其他DataNode。
文件系统Metadata的持久化
HDFS的namespace存储在NameNode上,NameNode使用被称作编辑日志(EditLog)的交互日志持久化记录发生在文件系统metadata的每个变更。例如在HDFS上创建一个新文件会引发NameNode插入一条记录到编辑日志(EditLog)来说明这个事件。类似的,改变一个文件的复制因子将触发一条新记录被插入到EditLog。NameNode使用所在的本机文件系统中的一个文件存储EditLog。整个文件系统的namespace,包括块到文件的映射和文件系统的属性配置,都存储在一个叫做FsImage的文件,FsImage也被作为一个文件存储在NameNode本机文件系统。
NameNode保存了整个文件系统的namespace和块射的快照在内存。关键的metadata项数据结构被设计的很紧凑,这样的话拥有4GB内存的NameNode很轻松就能支持大量的文件和目录。NameNode启动时,他会从硬盘读取FsImage和EditLog,然后将EditLog中的交互记录都恢复到内存中FsImage映像并把内存中的最新版本会写到硬盘中的新FsImage文件。然后他会截断就EditLog,因为他的交互已经体现到持久化的FsImage文件。这个处理过程被称作检查点(checkpoint),在当前实现中,检查点只在NameNode启动时出现。我们正在继续努力,希望在不久的将来能够支持周期性的检查点。
DataNode以文件的形式在本地文件系统中存储HDFS数据。DataNode没有HDFS文件的概念,它将每个HDFS数据块存储在本地文件系统的一个独立文件中,DataNode不会再一个相同的目录下创建所有的文件,相反他使用启发的方式确定目录下最优的文件数并且适时创建子目录。在一个目录下创建所有文件并不是最好的选择,因为本地文件系统可能不能高效的支持一个目录下有大量文件的场景。当DataNode启动时,它会扫描本机文件系统,获取所有HDFS数据块列表并将报告发送给NameNode(这就是Blockreport),每个数据块都响应地绑定一个本地文件。
通信协议
所有的HDFS通信协议都分层在TCP/IP协议顶层。客户端回合NameNode机器上的TCP端口简历连接,它和NameNode的交互基于ClientProtocol。DataNode和NameNode的交互使用DataNode协议。RCP的抽象概念包装了客户端协议和DataNode协议,按照设计,NameNode不会发起任何RPC请求,它仅仅回应DataNode和client发起的RPC请求。
健壮性
HDFS的主要目的是可靠的存储数据,甚至在故障的情况下也要保证可靠性。三种常见的故障累心格式NameNode故障、DataNode故障和网络中断。
数据磁盘故障,心跳和重复制
每个DataNode会周期性发送心跳消息到NameNode,网络中断会导致一部分DataNode会失去和NameNode的连接,NameNode通过心跳消息缺失来检测断连场景。NameNode会把近期没有心跳的DataNode标识为死亡,并且不会再转发心的IO请求给这些节点,死亡节点上注册的任何数据对HDFS都不再可用。DataNode的死亡可能导致一些块的实际复制因子低于他们配置的值。NameNode会持续跟踪哪些块需要复制并且在必要的时候随时触发复制。重复制的需求量可能因为很多原因而增加:一个节点可能会不可访问,一个备份可能失效,一个DataNode的硬盘可能故障或者一个文件的复制因子可能被提高。
判断DataNode死亡的超时时间要谨慎的设置偏长一点(默认是超过10分钟)以防止DataNode状态震荡导致的复制风暴。用户通过性能敏感的高负载配置,可以将DataNode的数据过期周期调短,防止过期节点被读取或者写入。
集群重均衡
HDFS架构兼容数据重均衡方案,如果一个DataNode上的空闲磁盘空间低于指定的阈值,一个均衡方案可能会自动将数据从这个DataNode移动到另一个上面。在一些突发情况下,特定文件可能访问量可能突然增加,一个均衡方案可能自动创建附加的备份并且再均衡集群中的其他数据。这些类型的数据均衡方案目前还没有实现。
数据完整
从DataNode上取到的数据块在到达时可能已经损坏,因为存储设备故障,网络故障或者是软件缺陷等种种原因,这种损坏是有可能发生的。HDFS客户端软件实现了针对HDFS文件内容校验和的校验,当客户端创建一个HDFS文件,他会计算文件每一个块的校验和并且将这些校验和存储在同一个HDFS命名空间下的一个独立的隐藏文件。当客户端取回数据时,它会验证从每个DataNode收到的数据和存储在关联的校验和文件中的校验和匹配性,如果不匹配客户端会尝试从另一个存有相同块的DataNode上取回数据。
Metadata磁盘故障
FsImage和EditLog是HDFS的核心数据结构,这些问题的损坏会导致HDFS实例失效,因为这个原因,NameNode可以配置为支持维护多份FsImage和EditLog,对FsImage或EditLog的任何修改都会导致每一个FsImage和EditLog备份的同步更新,对于FsImage和EditLog多份拷贝的同步更新可能降低NameNdoe每秒可以支持的命名空间操作速率。然而这个退化是可以接收的,因为即使HDFS本质上非常数据密集型的,他们不是元数据密集型。当一个NameNode重启是,它选择最新的兼容的FsImage和EditLog使用。
快照
快照支持存储数据在特定时刻的一份副本,快照的作用可能就是及时将一个损坏的HDFS实例回滚到以前已知可用的点。
数据组织
数据块
HDFS被设计为支持超大文件,适用HDFS的应用都是需要处理大数据集的,这些应用写入一次数据但是读取一次或者多次并且要求这些读操作需要达到流速度。HDFS在文件上支持write-once-read-many 语法,HDFS使用的一个典型的块大小是128MB。这样一个HDFS文件会被切分成128MB的块,如果有可能,每个块会寄存在不同的DataNode。
平台
客户端发送的创建文件的请求不会直接到达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可以一边从管道(pipeline)接收数据一边同事将数据通过管道转发给下一个DataNode。这样,数据从一个DataNode流水线到下一个。
无障碍
HDFS可以从应用程序以多种不同方式访问,最原始的,HDFS提供了一个FileSystem JAVA API供应用使用。一个JAVA API的C语言包装器和REST API也可以使用,另外,HTTP浏览器也可以用来浏览HDFS上的文件,通过使用NFS网关,HDFS可以挂载为客户端本地文件系统的一部分。
FS Shell
HDFS允许用户数据以文件和目录的形式组织,它提供了一个FS shell的命令行接口供用户操作HDFS里的数据。这个命令行语法集和用户已经熟悉的其他shell的非常相似。这里是一些简单的操作/指令 对:
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的namespace。这允许用户使用浏览器导航HDFS的namespace并且查看文件内容。