大数据培训:Hadoop HDFS 实现原理
一、HDFS 体系结构
1.1 HDFS 简介
Hadoop 分布式文件系统 (HDFS) 是运行在通用硬件(commodity hardware)上的分布式文件系统(Distributed File System)。
它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。
HDFS 是一个高度容错性的系统,适合部署在廉价的机器上。
HDFS 能提供高吞吐量的数据访问,大数据培训机构非常适合大规模数据集上的应用。
HDFS 放宽了一部分 POSIX 约束,来实现流式读取文件系统数据的目的。
HDFS 在最开始是作为 Apache Nutch 搜索引擎项目的基础架构而开发的。
HDFS 是 Apache Hadoop Core 项目的一部分。
1.2 HDFS 设计原则
HDFS 设计之初就非常明确其应用场景,适用于什么类型的应用,不适用什么应用,有一个相对明确的指导原则。
1.2.1 设计目标
存储非常大的文件:这里非常大指的是几百 M、G、或者 TB 级别。实际应用中已有很多集群存储的数据达到 PB 级别。根据 Hadoop 官网,Yahoo!的 Hadoop 集群约有 10 万颗 CPU,运行在 4 万个机器节点上。更多世界上的 Hadoop 集群使用情况,参考 Hadoop 官网.
采用流式的数据访问方式: HDFS 基于这样的一个假设:最有效的数据处理模式是一次写入、多次读取数据集经常从数据源生成或者拷贝一次,然后在其上做很多分析工作
分析工作经常读取其中的大部分数据,即使不是全部。因此读取整个数据集所需时间比读取第一条记录的延时更重要。
运行于商业硬件上: Hadoop 不需要特别贵的、reliable 的(可靠的)机器,可运行于普通商用机器(可以从多家供应商采购) ,商用机器不代表低端机器。在集群中(尤其是大的集群),节点失败率是比较高的 HDFS 的目标是确保集群在节点失败的时候不会让用户感觉到明显的中断。
1.2.2 HDFS 不适合的应用类型
有些场景不适合使用 HDFS 来存储数据。下面列举几个:
1)低延时的数据访问
对延时要求在毫秒级别的应用,不适合采用 HDFS。HDFS 是为高吞吐数据传输设计的,因此可能牺牲延时 HBase 更适合低延时的数据访问。
2)大量小文件
文件的元数据(如目录结构,文件 block 的节点列表,block-node mapping)保存在 NameNode 的内存中, 整个文件系统的文件数量会受限于 NameNode 的内存大小。
经验而言,一个文件/目录/文件块一般占有 150 字节的元数据内存空间。如果有 100 万个文件,每个文件占用 1 个文件块,则需要大约 300M 的内存。因此十亿级别的文件数量在现有商用机器上难以支持。
3)多方读写,需要任意的文件修改
HDFS 采用追加(append-only)的方式写入数据。不支持文件任意 offset 的修改。不支持多个写入器(writer)。
1.3. HDFS 核心概念
1.3.1 Blocks
物理磁盘中有块的概念,磁盘的物理 Block 是磁盘操作最小的单元,读写操作均以 Block 为最小单元,一般为 512 Byte。文件系统在物理 Block 之上抽象了另一层概念,文件系统 Block 物理磁盘 Block 的整数倍。通常为几 KB。
Hadoop 提供的 df、fsck 这类运维工具都是在文件系统的 Block 级别上进行操作。
HDFS 的 Block 块比一般单机文件系统大得多,默认为 128M。
HDFS 的文件被拆分成 block-sized 的 chunk,chunk 作为独立单元存储。比 Block 小的文件不会占用整个 Block,只会占据实际大小。例如, 如果一个文件大小为 1M,则在 HDFS 中只会占用 1M 的空间,而不是 128M。
HDFS 的 Block 为什么这么大?
是为了最小化查找(seek)时间,控制定位文件与传输文件所用的时间比例。假设定位到 Block 所需的时间为 10ms,磁盘传输速度为 100M/s。如果要将定位到 Block 所用时间占传输时间的比例控制 1%,则 Block 大小需要约 100M。
但是如果 Block 设置过大,在 MapReduce 任务中,Map 或者 Reduce 任务的个数 如果小于集群机器数量,会使得作业运行效率很低。
Block 抽象的好处
block 的拆分使得单个文件大小可以大于整个磁盘的容量,构成文件的 Block 可以分布在整个集群, 理论上,单个文件可以占据集群中所有机器的磁盘。
Block 的抽象也简化了存储系统,对于 Block,无需关注其权限,所有者等内容(这些内容都在文件级别上进行控制)。
Block 作为容错和高可用机制中的副本单元,即以 Block 为单位进行复制。
1.3.2 Namenode & Datanode
整个 HDFS 集群由 Namenode 和 Datanode 构成 master-worker(主从)模式。Namenode 负责构建命名空间,管理文件的元数据等,而 Datanode 负责实际存储数据,负责读写工作。
Namenode
Namenode 存放文件系统树及所有文件、目录的元数据。元数据持久化为 2 种形式:
namespcae image
edit log
但是持久化数据中不包括 Block 所在的节点列表,及文件的 Block 分布在集群中的哪些节点上,这些信息是在系统重启的时候重新构建(通过 Datanode 汇报的 Block 信息)。
在 HDFS 中,Namenode 可能成为集群的单点故障,Namenode 不可用时,整个文件系统是不可用的。HDFS 针对单点故障提供了 2 种解决机制:
1)备份持久化元数据
将文件系统的元数据同时写到多个文件系统, 例如同时将元数据写到本地文件系统及 NFS。这些备份操作都是同步的、原子的。
2)Secondary Namenode
Secondary 节点定期合并主 Namenode 的 namespace image 和 edit log, 避免 edit log 过大,通过创建检查点 checkpoint 来合并。它会维护一个合并后的 namespace image 副本, 可用于在 Namenode 完全崩溃时恢复数据。
1.4 主从架构
HDFS 采用 master/slave 架构。
一个 HDFS 集群是由一个 Namenode 和一定数目的 Datanodes 组成。
Namenode 是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。
集群中的 Datanode 一般是一个节点一个,负责管理它所在节点上的存储。HDFS 暴露了文件系统的名字空间,用户能够以文件的形式在上面存储数据。
从内部看,一个文件其实被分成一个或多个数据块,这些块存储在一组 Datanode 上。Namenode 执行文件系统的名字空间操作,比如打开、关闭、重命名文件或目录。它也负责确定数据块到具体 Datanode 节点的映射。Datanode 负责处理文件系统客户端的读写请求。在 Namenode 的统一调度下进行数据块的创建、删除和复制。
1、数据块 Block
最小存储单元,默认 128MB,适合大文件存储,减少寻址和内存开销。
2、NameNode
文件系统命名空间,含目录、文件的数据块索引,索引存储在内存中,文件越多占用内存越大。同时存储命名空间镜像文件(FsImage)与编辑日志文件(EditLog),文件的变更先写入日志文件中。Hadoop 2.X 版本引入 HA 功能,通常通过 Journal Nodes 保持多主间 EditLog 同步。再加入 ZKFailoverController 进行主备切换操作(也可人工切换)。
3、DataNode
数据存储节点,执行数据块的创建、删除、复制等操作。
4、Secondary NameNode
由于 NameNode 合并 EditLog 和 FsImage 非常耗时,特别在大型集群中。故增加一个 Secondary NameNode 负责定时从 NameNode 获取(HTTP)EditLog 并且合并到 FsImage 中,耗时的合并工作完成后将新的 FsImage 传回 namenode。
1.5. hdfs 元数据的持久化
HDFS 的命名空间是由名字节点来存储的。
1.5.1.EditLog
名字节点使用叫做 EditLog 的事务日志来持久记录每一个对文件系统元数据的改变,如在 HDFS 中创建一个新的文件,名字节点将会在 EditLog 中插入一条记录来记录这个改变。
类似地,改变文件的复制因子也会向 EditLog 中插入一条记录。名字节点在本地文件系统中用一个文件来存储这个 EditLog。
1.5.2.FsImage
整个文件系统命名空间,包括文件块的映射表和文件系统的配置都存在一个叫 FsImage 的文件中,FsImage 也存放在名字节点的本地文件系统中。
FsImage 和 Editlog 是 HDFS 的核心数据结构。这些文件的损坏会导致整个集群的失效。因此,名字节点可以配置成支持多个 FsImage 和 EditLog 的副本。任何 FsImage 和 EditLog 的更新都会同步到每一份副本中。
1.6 数据复制
HDFS 被设计成能够在一个大集群中跨机器可靠地存储超大文件。它将每个文件存储成一系列的数据块,除了最后一个,所有的数据块都是同样大小的。为了容错,文件的所有数据块都会有副本。每个文件的数据块大小和副本系数都是可配置的。应用程序可以指定某个文件的副本数目。副本系数可以在文件创建的时候指定,也可以在之后改变。
HDFS 中的文件都是一次性写入的,并且严格要求在任何时候只能有一个写入者。
Namenode 全权管理数据块的复制,它周期性地从集群中的每个 Datanode 接收心跳信号和块状态报告(Blockreport)。接收到心跳信号意味着该 Datanode 节点工作正常。块状态报告包含了一个该 Datanode 上所有数据块的列表。
HDFS 采用一种称为机架感知(rack-aware)的策略来改进数据的可靠性、可用性和网络带宽的利用率。
大型 HDFS 实例一般运行在跨越多个机架的计算机组成的集群上,不同机架上的两台机器之间的通讯需要经过交换机。在大多数情况下,同一个机架内的两台机器间的带宽会比不同机架的两台机器间的带宽大。
通过一个机架感知的过程,Namenode 可以确定每个 Datanode 所属的机架 id。一个简单但没有优化的策略就是将副本存放在不同的机架上。这样可以有效防止当整个机架失效时数据的丢失,并且允许读数据的时候充分利用多个机架的带宽。这种策略设置可以将副本均匀分布在集群中,有利于当组件失效情况下的负载均衡。但是,因为这种策略的一个写操作需要传输数据块到多个机架,这增加了写的代价。
在大多数情况下,副本系数是 3,HDFS 的存放策略是将一个副本存放在本地机架的节点上,一个副本放在同一机架的另一个节点上,最后一个副本放在不同机架的节点上。这种策略减少了机架间的数据传输,这就提高了写操作的效率。机架的错误远远比节点的错误少,所以这个策略不会影响到数据的可靠性和可用性。于此同时,因为数据块只放在两个(不是三个)不同的机架上,所以此策略减少了读取数据时需要的网络传输总带宽。在这种策略下,副本并不是均匀分布在不同的机架上。三分之一的副本在一个节点上,三分之二的副本在一个机架上,其他副本均匀分布在剩下的机架中,这一策略在不损害数据可靠性和读取性能的情况下改进了写的性能。
二、HDFS 主要流程
2.1 客户端的读取
1、调用 DistributedFileSystem.open 打开文件(底层调用 DFSClient.open)并创建 HdfsDataInputStream。
2、通过调用 DFSClient.getBlockLocations 获取数据块所在的 datanode 节点列表,根据排序规则选择一个 datanode 建立连接获取数据块,当此数据块读取完毕后,再次向 namenode 获取下一个数据块。依次循环。
2.2 客户端写入流程
1、通过调用 DistributedFileSystem.create 在底层调用 DFSClient.create 发送通知 namenode 创建文件。
2、获取输出流后就可以调用 DFSOutputStream 写数据,空文件时就会调用 Clientprotocol.addBlock 向 Namenode 申请一个数据块并返回 LocatedBlock,此对象包含该数据块的所有节点信息,后续即可往其中一节点 write 数据。
2.3 HA 切换流程
Hadoop 2.X 之前版本 NN 存在单点故障,HA 功能提供一个 active NN 与一个 standby NN,命名空间实时同步。Active NN 修改命名空间时同时通知多数的 Quorum Journal Nodes(JNS),standby NN 监听 JNS 中的 editlog 变化,并与自身的命名空间合并,当发生切换时,需要等待 standby 合并 JNS 上的所有 editlog 后才会进行切换。
ZKFailoverController 会实时监控 NN 的状态,如果 active NN 处于不可用状态则进行自动主备切换,不需要人工干预,当然管理员也可用 DFSHAAdmin 命令进行手工切换。
三、NameNode
3.1 文件目录树
HDFS 命名空间在内存中以树结构存储,目录与文件抽象为 INode 节点,目录为 INodeDirectory,文件为 INodeFile。目录有 List<INode> children 存储子目录或文件(内部使用二分法做检索),HDFS 命名空间存储在本地系统 FsImage 文件中,启动时加载,与此同时 NN 会定期合并 fsimage 与 editlog,editlog 操作类为 FSEditLog。
INodeFile 主要成员变量:
private long header = 0L; # 文件头信息
private BlockInfoContiguous[] blocks; # 数据块与数据节点关系
3.2 数据块管理
1、NameNode 启动时从 fsimage 加载文件与数据块之前的关系,数据块存储在哪些节点上具体是由 datanode 启动时向 NN 上报数据块信息时才能构建。
2、BlockMap 在 NN 中存储数据块与节点的关系,该关系则由 DN 上报时更新。
3.3 数据节点管理
1、添加和撤销 DN:HDFS 提供的 dfs.hosts 可配置 include 和 exclude,如果节点下线则配置 exclude 并执行 dfsadmin -refreshNodes 后 NN 开始进行撤销,下线的节点数据会复制到其他节点上,此时 DN 则处于正在被撤销状态,复制完毕后 DN 状态则变成已撤销。
2、DN 启动需要向 NN 握手、注册于上报数据块,并定期发送心跳包。
3.4 NN 的启动与停止
1、NN 启动由 NameNode 类的 main 方法执行,并调用 createNameNode 方法进行初始化。调用 FSNamesystem.loadFromDisk 进行 fsimage 与 editlog。
2、NN 的停止则是通过启动时注册 JVM 的 ShutdownHook,当 JVM 退出时调用,并输出一些退出日志。
四、数据节点 DN
HDFS 2.X DN 使用 Federation 架构,可配置多个命名空间,每个命名空间在 DN 中对应一个池。DN 的启动由 DataNode 类的 main 方法执行。
1、DataBlockScanner 扫描数据块并检查校检和是否匹配。
2、DirectoryScanner 定时扫描内存元数据与磁盘是否有差异,如有则更新内存。
3、IPCServer 为 RPC 服务端,接收 Client、NN、DN 的 RPC 请求。
4、DataXceiverServer 用于流式数据传输。
4.1 DN 磁盘存储与读写
1、DFSStorage 管理数据块,管理磁盘存储目录(dfs.data.dir),dfs.data.dir 可定义多个存储目录,不同目录磁盘异构。
2、DataTransferProtocol 定义了基于 TCP 流的数据访问接口,包含 Sender 和 Receiver,流程如下图:
文章来源:hdfs
评论