HDFS架构

HDFS(Hadoop Distributed File System)是一个运行在商用机器上面的分布式文件系统,其设计思想来自于google著名的Google File System论文。

HDFS的设计目标:为何产生HDFS?

由于数据量的急剧增大,原有的单机多磁盘因为速度,存储量等原因,已经远远无法满足要求,HDFS应运而生。
HDFS解决的痛点:
1. 高容错性:HDFS设计运行在成百上千的机器上,任何一台机器都有可能随时发生损坏,这要求HDFS能够随时应对机器故障。
2. 流式数据访问:HDFS适用于批处理而非用户即时交互;高吞吐量而非低数据访问延迟;运行的应用程序对其数据集能够进行流式访问。
3. 适合大数据量:适合GB或者TB级别的数据存储;在单个集群中,有上百个节点提供服务。
4. HDFS适合一次写多次读的模型。MapReduce和网络爬虫适合这种模型。
5. 认为数据的移动比计算的移动代价更小。必要情况下,HDFS提供了将应用程序移动到数据所在位置的接口。
6. 适用于多种硬件和软件平台。HDFS使用Java写成,可在任意安装了JVM的机器上运行。

NameNode和DataNode

HDFS是一个Master/Slave架构。一个HDFS集群包含了一个活动的NameNode和若干个DataNode。

  • NameNode负责管理DataNode,处理客户端的读写服务,如执行打开,关闭和重命名等任务(但是实际的数据流并不经过NameNode);处理确定数据块到具体DataNode节点的映射。
  • DataNode负责处理客户端的读写请求,在NameNode的统一调度下,进行数据块的创建,删除和复制。

HDFS读写流程

  1. 读过程

    • HDFS客户端通过DistributedFileSystem(HDFS中API里面的一个对象)对NameNode发送Read请求,同时将用户信息和文件名等信息发送给NameNode,NameNode返回给客户端FSDataInputStream,以及文件包含的block及其所在的DataNode位置。
    • HDFS客户端通过FSDataInputStream按顺序读取DataNode中的block信息(它会选择负载最低或者离客户端最近的一个DataNode读取block)
    • 读取完毕,将FSDataInputStream关闭。
  2. 写过程

    • HDFS客户端通过DistributedFileSystem对NameNode客户端发送Write请求,同时将文件要保存的位置,文件名,用户信息发送给NameNode,NameNode返回给客户端FSDataOutputStream,以及文件要写入哪些DataNode(选择负载较低的DataNode)
    • 通过FSDataOutputStream进行写操作,在写文件之前就对文件拆分成block,第一个写操作写在负载较低的DataNode上,并将该block复制到其他DataNode上。
    • 所有block副本复制完成反馈给FSDataOutputStream,FSDataOutputStream关闭。
    • 通过DistributedFileSystem更新NameNode中元数据。
      备注:客户端创建文件请求事实上并没有立即发送给NameNode,事实上,在开始阶段HDFS客户端会将文件数据缓存到本地的一个临时文件,应用程序的写操作会透明的重定向到该临时文件,当这个临时文件累积的数据量达到一个block大小时,客户端才会向NameNode发送Write请求。

文件系统命名空间

HDFS支持传统的层次化的文件结构。命名空间由目录,文件和块组成,它支持所有与命名空间相关的文件系统的操作,如创建,删除,修改和列出文件和目录。

数据复制(Data Replication)

HDFS被设计通过集群存储超大的文件,它将文件存储为大小相等的块,每个块都有副本以容错,应用程序可以指定备份的数量。在HDFS中,同一时间只允许一个writer写入。
NameNode定时收到来自集群中DataNode的心跳包和块报告(Heartbeat and Blockreport)。HeartBeat用来表明DataNode正常工作,而Blockreport用来指示该DataNode中block列表。

block副本放置策略

副本的存放是HDFS可靠性和性能的关键。优化的副本存放策略是HDFS区别于其他分布式文件系统的重要特性。HDFS采用一种称为机架感知(rack-wise)的策略。HDFS实例一般运行在跨越多个机架的集群上,不同机架上的两台机器通讯需要通过交换机。在大多数情况下,副本系数(一个block的副本数量)为3,HDFS的存放策略是将一个副本存放到本地机架的节点上,一个副本放在同一机架的不同节点上,另一个副本存放在不同机架的节点上。这种策略既减少了机架间的数据传输,提高了写操作的效率,也有效防止了整个机架失效时数据的丢失。

副本选择

为了降低整体的宽带消耗和读取延迟,HDFS会尽量让应用程序读取离它最近的副本。

安全模式

  • NameNode启动时,会进入称为安全状态的特殊状态。它首先将映像文件(fsimage)载入内存,并执行编辑日志(edit)中的各项操作。一旦内存中成功建立文件系统元数据映射,则创建一个新的fsimage文件和一个空的edit。
  • 在安全模式中,NameNode对于客户端是只读的,只可以显示目录,文件内容等。在此阶段NameNode会搜集DataNode的报告,当block达到设定的最小副本数时,就认为该block是"安全"的,当一定比例的block达到“安全”的标准时,安全模式结束。当检测到副本数不足的block时,该block将被复制,直到达到最小副本数。系统中block的位置不是NameNode维护的,而是以块列表存储在DataNode中。

文件系统元数据的持久化

  • Metadata是存储在NameNode上的元数据信息,它存储在磁盘上的文件名为fsimage。并且,有个名为Edits的文件,记录对metadata的操作日志。例如,在HDFS中创建一个文件,NameNode就会在Edits中插入一条记录表示。总体来说,fsimage和edit文件记录了文件系统目录树,文件中包含哪些块,块到DataNode的映射,block存放在哪些DataNode上。
  • NameNode在内存中保存着整个文件系统的命名空间和文件对block的映射(Blockmap)。这个关键的元数据结构设计的很紧凑,当NameNode启动时,它从硬盘中读取Edits和Fsimage,将所有Edits的事务文件作用在内存中的Fsimage上,并将这个新版本的Fsimage从内存中保存到本地磁盘上,然后删除旧的Edits,这个过程称为检查点(checkpoint)。

通信协议

所有的HDFS通讯协议建立在TCP/IP协议之上,客户端通过TCP端口连接到NameNode,通过ClientProtocol协议与NameNode交互;DataNode通过DatanodeProtocol与NameNode交互。ClientProtocol和DatanodeProtocol都是基于TCP/IP的远程过程调用(Remote Procedure Call,RPC)。值得注意的是,NameNode不会主动发起RPC,它只会响应来自客户端或者NameNode的RPC。

数据错误,心跳检测和重新复制(Re-Replication)

为了确定DataNode正常工作,需要DataNode周期性向NameNode发送心跳信号HeartBeat,NameNode将近期不再发送心跳信号的DataNode标记为脱机(dead),并不会在将新的IO请求发送给它,任何存储在dead datanode的数据不再有效。DataNode的dead有可能使得某些block的副本数量低于设定值,NameNode检测到它们后,就会启动复制操作。

数据完整性

HDFS通过校验和(checksum)确保数据的完整。客户端从DataNode获取文件内容后,都会校验获取的数据的checksum和DataNode中存储的checksum是否相同,如果不同,客户端可以选择从别的DataNode中获取该block的副本。

元数据磁盘损坏

Fsimage和Edits是HDFS的核心数据,如果这些数据损坏,整个HDFS的实例也就失效了。因此,HDFS可配置成维持多个Fsimage和Edits的副本,任何对Fsimage和Edits的修改都要同步到它们的副本上。这种同步操作会降低HDFS处理命名空间的速度,但是代价是可接受的。当HDFS重启时,它会选取最近的完整的Fsimage和Edits启动。

快照机制

HDFS快照是文件系统的只读时间点副本。HDFS快照文件记录block列表和文件大小,并不对datanode中的块复制。利用快照,可以使HDFS在数据损坏时恢复到过去一个已知正确的时间点。

数据组织

  • 数据块
    当客户端发送write请求后,NameNode返回DataNode标识符和目标数据块给客户端,客户端将文件上传至指定的DataNode中,当文件关闭后,客户端向NameNode报告文件已关闭,NameNode才会将文件创建操作提交到日志中存储,如果NameNode在文件关闭前失效,文件将丢失。
  • 流水线复制策略
    当客户端向第一个DataNode传输数据,第一个DataNode以每段4KB接受数据,并同时向列表中第二个DataNode传输该部分数据,第二个DataNode存储该部分数据后,也同时向第三个DataNode传输该部分数据...因此,DataNode能够流水线式从前一个节点接受数据,并同时转发给下一个节点。

HDFS缺点

  • 不适合低延迟的数据访问:HDFS设计目标是批处理,而不是用户交互使用,重点在于数据访问的高吞吐量而非数据访问的低延迟。
  • 不适合小文件存储:小文件会占用NameNode的大量内存,文件读取时,其寻道时间反而会超过读取时间。
  • 无法并发写入,文件随即修改:一个文件同时只能有一个writer,而且仅仅支持追加和截断。