HDFS 分布式文件系统

  |   0 评论   |   0 浏览

Hadoop 是一个由 Apache 基金会开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,轻松实现大规模数据的分布式存储分布式程序的快速开发,充分利用集群的威力进行大数据的高速存储和运算。其中 Hadoop 分布式文件系统(Hadoop Distributed File System,HDFS)起着非常重要的作用,它以文件的形式为上层应用提供海量数据存储服务,并实现了高可靠性高容错性高可扩展性等特点。

HDFS 架构设计及原理

1.HDFS 的概念

HDFS 是 Hadoop 项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流式数据访问和处理超大文件的需求而开发的分布式文件系统。整个系统可以运行在由廉价的商用服务器组成的集群之上,它所具有的高容错性高可靠性高可扩展性高可用性高吞吐率等特征。

2. HDFS 产生的背景

数据量的不断增大导致数据在一个操作系统管辖的范围内存储不下,为了存储这些大规模数据,需要将数据分配到更多操作系统管理的磁盘中存储,但是这样处理会导致数据的管理和维护很不方便,所以迫切需要一种系统来管理和维护多台机器上的数据文件,这种系统就是分布式文件管理系统,而HDFS 只是分布式文件管理系统中的一种。

3.HDFS 的设计理念

HDFS 的设计理念来源于非常朴素的思想:即当数据文件的大小超过单台计算机的存储能力时,就有必要将数据文件切分并存储到由若干计算机组成的集群中,这些计算机通过网络来进行连接,而HDFS 作为一个抽象层架构在集群网络之上,对外提供统一的文件管理功能,对于用户来说感觉像在操作一台计算机一样,根本感受不到HDFS 底层的多台计算机,而且HDFS 还能够很好地容忍节点故障而不丢失任何数据。

HDFS 的核心设计目标:

(1) 支持超大文件存储。

这里的"超大文件" 指大小达到 TB(1TB = 1024GB)、PB (1PB = 1024TB)级别的文件。随着未来技术水平的发展,数据文件的规模还可以更大。

(2) 流式数据访问。

流式数据访问是 HDFS 选择的最高效的数据访问方式。

流失数据访问可以简单理解为:读取数据文件就像打开水龙头一样,可以不停地读取。因为 HDFS 上存储的数据集通常是由数据源生成或从数据源收集而来,接着会长时间在此数据集上进行各种分析,而且每次分析都会涉及该数据集的大部分甚至全部数据,所以每次读写的数据量都很大,因此对整个系统来说读取整个数据集所需要的时间要比读取第一条所需要的时间更重要,即HDFS 更重视数据的吞吐量。而不是数据的访问时间。所以HDFS 选择采用一次写入、多次读取的流式数据访问模式,而不是随机访问模式。

(3) 简单的一致性模型。

在 HDFS 中,一个文件一旦创建、写入、关闭,一般不需要再进行修改。这样就可以简单地保证数据的一致性。

(4) 硬件故障的检测和快速应对。

利用大量普通硬件构成的集群平台中,硬件出现故障是常见的问题。一般的 HDFS 系统是由数十台甚至成百上千台存储着数据文件服务器组成,大量的服务器就意味着高故障率,但是 HDFS 在设计之初已经充分考虑到这些问题,认为硬件故障是常态而不是异常,所以如何进行故障的检测和快速自动恢复也是 HDFS 的重要设计目标之一。

4. HDFS 的系统结构

整个 HDFS 系统架构是一个主从架构。一个典型的 HDFS 集群中,通常会有一个 NameNode,一个 SecondaryNameNode 和 至少一个 DataNode,而且HDFS 客户端的数量也没有限制

(1)NameNode

NameNode 是 HDFS 主从架构中的主节点,也被称为名字节点管理节点元数据节点,它管理文件系统的命名空间,维护着整个文件系统的目录树以及目录树中的所有子目录和文件。

这些信息还以两个文件的形式持久化保存在本地磁盘上,一个是命名空间镜像,也称为文件系统镜像 FSImage(File System Image,FSImage), 主要用来存储 HDFS 的元数据信息,是 HDFS元数据的完整快照。每次NameNode 启动时,默认都会加载最新的命名空间镜像文件到内存中。

还有一个文件是命名空间镜像的编辑日志(EditLog),该文件保存用户对命名空间镜像的修改信息。

(2)SecondaryNameNode

SecondaryNameNode 是 HDFS 主从架构中的备用节点,也被称为从元数据节点,主要用于定期合并 FSImage命名空间镜像的 Edit Log,是一个辅助 NameNode 的守护进程。在生产环境下,SecondaryNameNode 一般会单独地部署到一台服务器上,因为SecondaryNameNode 节点在进行两个文件合并时需要消耗大量资源。

SecondaryNameNode 要辅助 NameNode 定期地合并 FSImage 文件和 Edit Log 文件的目的如下。

FSImage 文件实际上是HDFS 文件系统元数据的一个永久性检查点(CheckPoint),但也并不是每一个写操作都会更新到这个文件中,因为 FSImage 是一个大型文件,如果频繁地执行写操作,会导致系统运行极其缓慢。

解决问题的方案就是,NameNode 将命名空间的改动信息写入命名空间的Edit Log,但是随着时间的推移,Edit Log 文件会越来越大,一旦发生故障,将需要花费很长的时间进行回滚操作,所以可以像传统的关系型数据库一样,定期地合并 FSImage 和 Edit Log。如果由NameNode 来执行合并操作的话,有NameNode 同时在为集群提供服务,所以可能无法提供足够的资源。为了彻底解决这一问题,产生了 SecondaryNameNode。 SecondaryNameNode 和 NameNode 的交互过程如下所示。

  • 1.SecondaryNameNode(即从元数据节点)引导NameNode(即元数据节点)滚动更新编辑日志,并开始将新的编辑日志写入 edits.new。
  • 2.SecondaryNameNode 将 NameNode 的 FSImage 文件(fsimage)和编辑日志Edit Log(edits)文件复制到本地的检查点目录。
  • 3.SecondaryNameNode 将 FSImage(fsimage)文件导入内存,回放编辑日志(edits),将其合并到 FSImage(fsimage.ckpt),并将新的 FSImage 文件(fsimage.ckpt)压缩后写入磁盘。
  • 4.SecondaryNameNode 将新的 FSImage 文件(fsimage.ckpt)传回NameNode。
  • 5.NameNode 在接收到新的 FSImage文件 (fsimage.ckpt)后,将 fsimage.ckpt 替换为 fsimage,然后直接加载和启用该文件。
  • 6.NameNode 将 Edit Log.new(即图中的 edits.new) 更名为Edit Log(即图中的edits)。默认情况下,该过程1h发生一次,或当编辑日志达到默认值(如 64MB)也会触发。具体触发该操作的值是可以通过配置文件配置的。

(3)DataNode

DataNode 也被称为数据节点,它是 HDFS 主从结构中的从节点,它在NameNode 的指导下完成数据的I/O操作。实际上,在DataNode 节点上,数据块就是一个普通文件,可以在 DataNode存储块的对应目录下看到(默认在 $(dfs.data.dir)/current的子目录下),块的名称是 blk_blkID

DataNode 会不断地向NameNode 汇报块报告(即各个DataNode节点会把本节点上存储的数据块的情况以“块报告”的形式汇报给NameNode)并执行来自NameNode 的指令初始化时,集群中的每个 DataNode会将本节点当前存储的块信息以块报告的形式汇报给NameNode。在集群正常工作时,DataNode仍然会定期地把最新的块信息汇报给NameNode,同时接收NameNode 的指令,比如创建、移动或删除本地磁盘的数据块等操作。

实际上,可以通过一下三点更深入地理解一下DataNode 是如何存储和管理数据块的。

1). DataNode 节点是以数据块的形式在本地Linux 文件系统上保存 HDFS 文件的内容,并对外提供文件数据访问功能。

2). DataNode 节点的一个基本功能就是管理这些保存在Linux 文件系统中的数据。

3). DataNode 节点是将数据块以 Linux 文件的形式保存在本节点的存储系统上。

(4) HDFS 客户端

HDFS 客户端便于用户和 HDFS 文件系统进行交互,HDFS 提供了非常多的客户端,包括命令行接口、JavaAPI、Thrift接口、Web 界面等。

(5)数据块

磁盘有数据块(也叫磁盘块)的概念,比如每个磁盘都有默认的磁盘块容量,磁盘块容量一般为 512 字节,这是磁盘进行数据读写的最小单位。文件系统也有数据块的概念,但是文件系统中的块容量只是磁盘块容量的整数倍,一般为几千字节。然而用户在使用文件系统时,比如对文件进行读写操作时,可以完全不需要知道数据块的细节,只需要知道相关的操作即可,因为这些底层细节对用户都是透明的。

HDFS 也有数据块(Block)的概念,但是 HDFS 的数据块比一般文件系统的数据块要大的多,它也是 HDFS 存储处理数据的最小单元。默认为 64MB 或 128MB。这里需要特别指出的是,和其他文件系统不同,HDFS 中小于一个块大小的文件并不会占据整个块的空间

那么为什么 HDFS中的数据块这么大?

HDFS 的数据块大是为了最小化寻址开销。因为如果块设置得足够大,从磁盘传输数据的时间可以明显大于定位到这个块开始位置所需要的时间。所以要将块设置尽可能大一点,但是也不能太大,因为这些数据块最终是要供上层的计算框架处理的,如果数据块太大,那么处理整个数据块所花的时间久比较长,会影响整体数据处理的时间,数据块的大小到底应该设置多少合适呢?

比如寻址时间为10ms,磁盘传输速度为100M/s,加入寻址时间占传输时间的1%,那么块的大小可以设置为100MB ,随着磁盘驱动器传输速度的不断提升,实际上数据块的大小还可以设置得更大。

5. HDFS 的优缺点

(1)HDFS 的优点(HDFS 适合的场景)

  • 1)高容错性。数据自动保存多个副本,HDFS 通过增加多副本的形式,提高了HDFS 文件系统的容错性;某一个副本丢失以后可以自动恢复。
  • 2)适合大数据处理。能够处理 GB、TB、甚至 PB 级别的数据规模;能够处理百万规模以上的文件数量;能够处理10000个以上节点的集群规模。
  • 3)流式文件访问。数据文件只能一次写入,多次读取,只能追加,不能修改;HDFS 能保证数据的简单一致性。
  • 4)可构建在廉价的机器上。HDFS 通过多副本机制,提高了整体系统的可靠性;HDFS 提供了容错和恢复机制。比如某一个副本丢失,可以通过其他副本来恢复。保证了数据的安全性和系统的可靠性。

(3) HDFS 的缺点(HDFS 不适合的场景)

  • 1)不适合低延时数据访问。比如 ms 级别的数据响应时间,这种场景 HDFS 是很难做到的。HDFS更适合高吞吐率的场景,即某一时间内写入大量的数据。
  • 2)不适合大量小文件的存储。如果有大量小文件需要存储,这些小文件的元数据的存储会占用 NameNode 大量的内存空间。这样是不可取的,因为NameNode 的内存总是有限的;如果小文件存储的寻道时间超过文件数据的读取时间,这样也是不行的,它违反了 HDFS 大数据块的设计目标。
  • 3)不适合文件写入、文件随机修改。一个文件只能有一个写操作,不允许多个线程同时进行写操作;仅支持数据的append 操作,不支持文件的随机修改。

6.HDFS 的读数据流程

  • 1)首先调用FileSystem 对象的 open() 方法, 其实获取的是一个分布式文件系统(DistributedFileSystem) 实例。
  • 2)分布式文件系统(DistributedFileSystem)通过远程过程调用(Remote Procudure Call,RPC)获得文件第一批块(Block)的位置信息(Location),同一个块按照重复数会返回多个位置信息,这些位置信息按照Hadoop 拓扑结构排序,举例客户端近的排在前面。
  • 3)前两步会返回一个文件系统数据输入流(FSDataInputStream)对象,该对象会被封装为分布式文件系统输入流(DFSInputStream)对象,DFSInputStream 可以方便地管理DataNode 和 NameNode 数据流。客户端调用read() 方法,DFSInputStream 会找出离客户端最近的 DataNode 并连接。
  • 4)数据从DataNode 源源不断地流向客户端。
  • 5)如果第一个块的数据读取完毕,就会关闭指向第一块的DataNode的连接,接着读取下一个块。这些操作对客户端来说是透明的,从客户端的角度看来只是在读一个持续不断的数据流。
  • 6)如果第一批块都读取完毕,DFSInputStream 就会去NameNode 获取下一批块的位置信息,然后继续读取,如果所有的块都读取完毕,这是就会关闭所有的流。

如果在读数据时,DFSInputStream 和 DataNode 的通信发生异常,就会尝试连接正在读取的块排序第二近的DataNode,并且会记录哪个 DataNode 发生错误,剩余的块读取时就会直接跳过该DataNode。 DFSInputStream 额会检查块数据校验和,如果发现一个坏的块,就会先报错到NameNode,然后 DFSInputStream 在其他的 DataNode 上读取该块的数据。

HDFS 读数据流程的设计就是客户户端直接连接 DataNode 来检索数据,并且NameNode 来负责为每一个块提供最优的DataNode,NameNode仅仅处理块的位置请求,这些信息都加载在NameNode 的内存中,HDFS 通过 DataNode 集群可以承受大量客户端的并发访问。

7. HDFS 的写数据流程

  • 1 ) 客户端通过调用分布式文件系统(DistributedFileSystem)的 create() 方法创建新文件。
  • 2 )DistributedFileSystem 通过 RPC 调用 NameNode 去创建一个没有块关联的新文件,创建前,Nameode 会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,NameNode会记录下新文件,否则会抛出 I/O 异常。
  • 3 ) 前两步结束后,会返回文件系统数据流出流(FSDataOutputStream)的对象,与读文件时相似,FSDataOutputStream 被封装成分布式文件系统数据输出流(DFSOutputStream)。DFSOutputStream可以协调 NameNode 和 DataNode。客户端开始写数据到 DFOutputStream,DFSOutputStream 会把数据切分成一个个小的数据包(packet),然后排成数据队列(data quene)
  • 4 ) 数据队列中的数据包首先输出到数据管道(多个数据节点组成数据管道)中的第一个DataNode中(写数据包),第一个DataNode又把数据包发送到第二个DataNode 中,依次类推。
  • 5 ) DFSOutputStream 还维护者一个队列叫响应队列(ack quene),这个队列也是由数据包组成,用于等待 DataNode 收到数据后返回响应数据包,当数据管道中的所有DataNode 都表示已经收到响应信息时, akc quene 才会吧对应的数据包移除掉。
  • 6)客户端完成写数据后,调用close() 方法关闭写入流。
  • 7)客户端通知NameNode把文件标记为已完成。然后NameNode 把文件写成功的结果反馈给客户端。此时就表示客户端已经完成了整个 HDFS 的写数据流程。

如果在写的过程中某个 DataNode 发生错误,会采取一下步骤处理。

1 ) 管道关闭

2 ) 正常的DataNode 上正在写的块会有一个新 ID(需要和 NameNode 通信),而失败的DataNode上的那个不完整的块在上报心跳会被删掉。

3 )失败的 DataNode 会被移出数据管道,块中剩余的数据包继续写入管道中的其他两个 DataNode。

4 )NameNode 会标记这个块的副本个数少于指定值,块的副本会稍后在另一个DataNode 创建。

5 )有时多个 DataNode 会失败,只要 dfs.replication.min(缺省是 1 个)属性定义的指定个数的 DataNode 写入数据成功了,整个写入过程就算成功,缺少的副本会进行异步的恢复。

注意: 客户端执行 write 操作后,写完的块才是可见的,正在写的块对客户端是不可见的,只有调用 sync() 方法,客户端才确保该文件的写操作已经全部完成,当客户端调用 close() 方法时,会默认调用 sync() 方法。

8. HDFS 的副本存放策略

HDFS 被设计成适合运行在廉价通用硬件上的分布式文件系统。它和现有的分布式文件系统有很多共同点。但同时,它和其他分布式文件系统的区别也是很明显的,即 HDFS 是一个高度容错性的系统。 HDFS 文件系统在设计之初就充分考虑到了容错问题,它的容错性机制能够很好地实现即使节点故障而数据不会丢失。这就是副本技术。

(1)副本技术概述

副本技术分布式数据复制技术,是分布式计算的一个重要组成部分。该技术允许数据在多个服务器端共享,而且一个本地服务器可以存取不同物理地点远程服务器上的数据,也可以使得所有的服务器均持有数据的副本。

通过副本技术可以有以下优点。

  • 提高系统可靠性:系统不可避免地会产生故障和错误,拥有多个副本的文件系统不会导致无法访问的情况,提高了系统的可用性。另外,系统可以通过其他完好的副本对发生错误的副本进行修复,提高了系统的容错性。
  • 负载均衡:副本可以对系统的负载量进行扩展。多个副本存放在不同的服务器上,可有效地分担工作量,从而将较大的工作量有效地分布在不同的节点上。
  • 提高访问效率:将副本创建在访问频度较大的区域,即副本在访问节点的附近,相应减小了其通信的开销,提高了整体的访问效率。

(2)HDFS 副本存放策略

HDFS 的副本策略实际上就是 NameNode 如何选择在哪个DataNode 存储副本(Replication)的问题。这里需要对可靠性、写入带宽和读取带宽进行权衡。Hadoopp 对 DataNode 存储副本有自己的副本策略,块副本存放位置的选择严重影响 HDFS的可靠性和性能。HDFS 采用机架感知(RackAwareness)的副本存放策略来提高数据的可靠性、可用性和网络带宽的利用率。

在其发展过程中,HDFS 一共有两个版本的副本策略。具体分析如下。

HDFS 运行在跨越大量机架的集群之上。两个不同机架上的节点是通过交换机实现通信的,大多数情况下,相同机架上机器减的网络带宽优于不同机架上的机器。

在开始时,每一个数据节点自检它所属的机架ID,然后在想 NameNode注册时告知自己的机架 ID。HDFS 提供接口以便很容易地挂载检测机架标识的模块。一个简单但不是最优的方式就是将副本放置在不同的机架上,这就防止了机架故障时数据的丢失,并且在读数据时可以充分利用不同机架的带宽。这个方式均匀地讲副本数据分散在集群中,这就简单地实现了组件故障时的负载均衡。然后这种方式增加了写的成本。,因为写时需要跨越多个机架传输文件块。

新版本的副本存放策略的基本思想如下

副本1 存放在Client 所在的节点上(假设Client 不在集群的范围内,则第一个副本存储节点是随机选取的。当然系统会尝试不选择那些太满或太忙的节点)。

副本2 存放在第一个节点不同机架中的一个结点中(随机选择)。

副本3 和副本2在同一个机架,随机放在不同的节点中。

假设还有很多其他的副本随机放在集群中的各个节点上。具体副本数据复制流程如下。

1 )当Client向 HDFS 文件写入数据时,一开始写入本地文件中。

2 )假设文件的副本个数设置为3,那么当 Client本地临时文件积累到一个数据块的大小时,Client 会从 NameNode 获取一个DataNode 列表用于存放副本。然后Client 开始向第一个 DataNode中传输副本数据,第一个DataNode 一小部分一小部分(4KB)地接收数据,将每一部分写入本地存储,并同一时间传输该部分到列表中的第二个DataNode节点。第二个DataNode 节点也是这样,一小部分一小部分地接收数据,写入本地存储,并同一时间传给第三个DataNode 节点。最后,第三个DataNode接收数据并存储在本地。因此,DataNode 能流水线式地从去前一个节点结束数据,并同一时间转发给下一个节点,数据以流水线的方式从一个DataNode 复制到下一个DataNode。

HDFS 的高可用(HA)

1. HA机制的产生背景

高可用(High Availability,HA),为了整个系统的可靠性,通常会在系统中部署两台或多台主节点,多台节点形成主备的关系,但是某一时刻只有一个主节点能够对外提供服务,当某一时刻检测到对外提供服务的主节点“挂”掉之后,备用主节点能够立刻接替已挂掉的主节点对外提供服务,而用户感觉不到明显的系统中断。这样对用户来说整个系统就更加的可靠和高效。

  • NameNode 机器宕机,将导致集群不可用,重启NameNode 之后才可使用。
  • 计划内的NameNode 节点软件或硬件升级,导致集群在短时间内不可用。

在 Hadoop1.0 的时代,HDFS 集群中 NameNode 存在单点故障(SPOF)时,由于NameNode保存了整个元数据信息,对于只有一个NameNode 的集群,如果NameNode 所在的机器出现意外情况,将导致整个HDFS 系统无法使用。同时 Hadoop生态系统中依赖于 HDFS的各个组件,包括 MapReduceHivePig以及HBase 等也都无法正常工作,直到NameNode重新启动。重新启动NameNode 和 其进行数据恢复的过程也会比较耗时。这些问题在给 Hadoop 的使用者带来困扰的同时,也极大地限制了Hadoop的使用场景,使得Hadoop 在很长时间内仅能用做离线存储和离线计算,无法应用到对可用性和数据一致性要求很高的在线应用场景中。

为了解决上述问题,在Hadoop2.0 中给出了 HDFS 的高可用(HA)解决方案

2.HDFS 的 HA 机制

HDFS 的 HA 通常由两个NameNode 组成,一个处于Active 状态,另一个处于 Standby状态。Active 状态的NameNode 对外提供服务,仅同步Active 状态的 NameNode的状态,以便能够在它失败时快速进行切换。

3. HDFS 的 HA 架构

NameNode 的高可用架构如下:

  • 活跃的名字节点(Active NameNode)和备用的名字节点(Standby NameNode ) : 两个名字节点形成互备,一个处于 Active 状态,为主NameNode,另外一个处于 Standby状态,为备用NameNode,只有主NameNode才能对外提供读写服务。
  • 主备切换控制器(ZKFailoverController): 主备切换控制器作为独立的进程运行,对NameNode 的主备切换进行总体控制。主备切换控制器能即时检测到NameNode 的健康状况,在主NameNode 故障时借助Zookeeper 实现自动的主备选举和切换,当然NameNode目前也支持不依赖Zookeeperd的手动主备切换。
  • Zookeeper 集群: 为主备切换控制器提供主备选举支持。
  • 共享存储系统:共享存储系统即为 JournalNode 集群(JournalNode 为存储管理EditLog 的守护进程)。共享存储系统是实现NameNode 高可用最为关键的部分,共享存储系统保存了NameNode 在运行过程中所产生的 HDFS 的元数据。主NameNode 和 备 NameNode 通过共享存储系统实现元数据同步。在进行主备切换时,新的主NameNode 在确认元数据完全同步之后才能继续对外提供服务。
  • 数据节点(DataNode):除了通过共享存储系统共享 HDFS 的元数据信息之外,主NameNode 和 备NameNode 还需要共享 HDFS 的数据块和 DataNode 之间的映射关系。DataNode 会同时向主NameNode 和 备NameNode 上报数据块的位置信息。

HDFS 的联邦机制

虽然 HDFS HA 解决了单点故障问题,但是在系统扩展性整体性能隔离性方面仍然存在问题。

  • 系统扩展性: 元数据存储在 NameNode 内存中,受内存上限的制约。
  • 整体性能: 吞吐量受单个NameNode 的影响。
  • 隔离性:一个程序可能会影响其运行的程序,如一个程序消耗过多资源导致其他程序无法顺利运行,HDFS HA 本质上还是个单名称节点。

HDFS 引入联邦机制可以解决以上3个问题。

在 HDFS 联邦中,设计了多个相互独立的NameNode(名称节点),使得 HDFS 的命名服务能够水平扩展,这些NameNode 分别进行个子命名空间和块的管理,不需要彼此协调。每个 DataNode(数据节点)要向集群中所有的NameNode 注册,并周期性地发送心跳信息和块信息,报告自己的状态。

HDFS 联邦拥有多个独立的命名空间,其中,每一个命名空间管理属于自己的一组块,属于同一个命名空间的块组成一个 "块池"。每个DataNode 会为多个块池提供块的存储,块池中的每个块实际上是存储在不同的DataNode 中。


标题:HDFS 分布式文件系统
作者:zh847707713
地址:http://lovehao.cn/articles/2021/11/17/1637139714486.html