Hadoop:HDFS 分布式文件存储系统概念详解

0. 分布式存储

0.1 分布式存储核心属性

  • 分布式存储
    • 多机器、横向扩展存储资源
    • 相对与纵向扩展,可以分布式存储理论上无上限
  • 元数据记录(文件位置索引)
    • 记录文件存储位置信息
    • 快速定位文件位置
  • 分块存储
    • 解决文件过大,单机存储不下的问题
    • 方便并行计算,提高文件处理的效率
    • 并行上传下载,提升文件传输的效率
  • 副本机制
    • 问题:部署的机器是普通机器,难免存在硬件故障,容易导致数据丢失
    • 解决:副本机制、异地备份,做数据冗余,有效保证数据安全

0.2 常见的分布式存储方案

  • HDFS / GFS
  • Ceph

1. HDFS 概念

1.1. HDFS 工作原理

  • HDFS 概念
    • HDFS 是Hadoop Distribute File System 的简称,HDFS 是 Hadoop 生态的核心。
    • 它允许文件通过网络在多台主机上分享的文件系统,可以让多台机器上的多个用户分享文件和存储空间。

      HDFS只是分布式文件管理系统中的一种。

  • HDFS 架构

    • HDFS 遵循主/从架构,由单个 NameNode(NN)、SecondaryNameNode 和多个 DataNode(DN) 组成:

    • NameNode :
      • 负责维护和管理文件系统元数据
        • 执行有关 文件系统命名 空间的操作,例如打开,关闭、重命名文件和目录等;
        • 同时还负责 集群元数据 的存储,记录着文件中各个数据块的位置信息;

          NameNode 是访问 HDFS 的唯一入口。

      • NameNode 管理元数据的方式:
        • 内存
        • 磁盘文件
          • FSimage 内存元数据镜像文件
          • edits log(Journal)日志
      • NameNode,其实就是 Master,它是一个管理者承担以下职责:
        • 管理HDFS的名称空间
        • 配置副本策略
        • 管理数据块的映射信息
        • 处理客户端读写请求

      • NameNode 是主服务器,
        • NameNode 负责管理文件系统的命名空间以及客户端对文件的访问。当客户端请求数据时,仅仅从 NameNode 中获取文件的元数据信息,具体的数据传输不经过 NameNode,而是直接与具体的 DataNode 进行交互。
        • 这里文件的元数据信息,记录了文件系统中的文件名和目录名,以及它们之间的层级关系,同时也记录了每个文件目录的所有者及其权限,甚至还记录每个文件由哪些块组成,这些元数据信息记录在文件 fsimage 中,当系统初次启动时,NameNode 将读取 fsimage 中的信息并保存到内存中。
        • 这些块的位置信息是由 NameNode 启动后从每个 DataNode 获取并保存在内存当中的,这样既减少了 NameNode 的启动时间,又减少了读取数据的查询时间,提高了整个系统的效率。
      • NameNode 并不持久化文件块的存储位置信息,这些信息会在系统启动时从 DataNode 重建。

        NameNode 所在机器通常会配置大量内存(RAM)。

    • DataNode:
      • 负责具体的数据块存储;
      • 提供来自文件系统客户端的读写请求,执行块的创建,删除等操作;
      • DateNode,其实就是 Slave,NameNode 下达命令,DateNode 执行实际的操作:
        • 存储实际的数据块
        • 执行数据块的读/写操作
      • DataNode 会定期发送心跳信息给 NameNode,告知 NameNode 当前节点存储的文件块信息。
      • 当客户端给 NameNode 发送读写请求时,NameNode 告知客户端每个数据块所在的 DataNode 信息,然后客户端直接与 DataNode 进行通信,减少 NameNode 的系统开销。
      • 当 DataNode 在执行块存储操作时,DataNode 还会与其他 DataNode 通信,复制这些块到其他 DataNode 上实现冗余。
    • Secondary NameNode
      • 从字面上来看,SecondaryNameNode 很容易被当作是 NameNode 的备份节点,其实不然。

      • NameNode 管理着元数据信息,元数据信息会定期保存到 edits 和 fsimage 文件中。
      • 其中的 edits 保存操作日志信息,在 HDFS 运行期间,新的操作日志不会立即与 fsimage 进行合并,也不会存到 NameNode 的内存中,而是会先写到 edits 中。
      • 当 edits 文件达到一定域值或间隔一段时间后触发 SecondaryNameNode 进行工作,这个时间点称为 checkpoint。
      • SecondaryNameNode 的角色就是定期地合并 edits 和 fsimage 文件,其合并步骤如下:
        • 在进行合并之前,SecondaryNameNode 会通知 NameNode 停用当前的 editlog 文件, NameNode 会将新记录写入新的 editlog.new 文件中。
        • SecondaryNameNode 从 NameNode 请求并复制 fsimage 和 edits 文件。
        • SecondaryNameNode 把 fsimage 和 edits 文件合并成新的 fsimage 文件,并命名为 fsimage.ckpto
        • NameNode 从 SecondaryNameNode 获取 fsimage.ckpt,并替换掉 fsimage,同时用 edits.new 文件替换旧的 edits 文件。
        • 更新 checkpoint 的时间。
      • 在紧急情况下,Secondary NameNode 可辅助恢复 NameNode
  • HDFS 设计目标
    • 故障检测 & 自动恢复
      • HDFS 运行在廉价普通机器上,硬件出现故障是常态,因此 故障检测 & 自动恢复 是常态;
    • 注重数据访问的 高吞吐量
      • 不太重视数据访问的反应时间
    • HDFS 支持大文件
      • 提供很高的聚合数据带宽,一个集群支持数据百个节点,支持千万级别的文件。
    • write-one-read-many
      • 一次写入,多次访问;
      • 文件一旦被写入,就不再被修改;
    • 跨平台移植
  • HDFS 适用场景
    • 大文件
    • 数据流式访问
    • 高吞吐量
    • 一次写入、多次读取
    • 低成本部署(部署在廉价PC上)
    • 高容错
  • HDFS 不适合的场景
    • 大量的小文件
    • 数据交互式访问
    • 频繁任意修改
    • 实时数据处理
    • 低延迟数据访问
    • 多用户写入
      • HDFS 只有一个写入者,而且写操作总是在文件末尾,不支持多用户写入

1.2. 分块(Block)存储机制

  • HDFS 中的文件在 物理上是分块 (Block) 存储的,可以通过配置参数 ([hdfs-site.xml文件中的]dfs.blocksize) 来设置。
  • Block 块不能设置太小,也不能设置太大,HDFS块大小的设置主要取决于磁盘的传输效率
    • HDFS的块设置太小,会增加寻址时间
      • HDFS 的块比磁盘的块大,目的是为了最小化寻址开销

        磁盘块一般 512 Bit,HDFS 每个块 64Mb。

    • HDFS的块如果设置的也不能太大。
      • Hadoop 中一个 map 任务一次通常只处理一个块中的数据,如果块过大,会导致整体任务数量过小,降低作业处理的速度。
      • 另外,在一次上传时,如果发生异常,需要重新传输,造成网络IO资源的浪费。
      • 在随机读取某部分内容时,不够灵活。
  • Hadoop 2.x 默认最小分块大小是 128M
    • 原因:寻址时间大约为 10ms,寻址时间为传输时间的 1% 为最佳(即为 10/0.01=1000ms=1s ),目前磁盘的传输率普遍为 100m/s,块的大小需要是 2的n次方,故为 128M)

1.3. 文件系统命名空间(name space)

  • HDFS 的文件系统命名空间的层次结构,支持目录和文件的创建、移动、删除和重命名等操作,支持配置用户和访问权限。
  • HDFS 不支持硬链接和软连接。
  • NameNode负责维护文件系统名称空间,记录对名称空间或其属性的任何更改。

1.4. 副本机制

  • 由于 Hadoop 被设计运行在廉价的机器上,这意味着硬件是不可靠的,为了保证容错性,HDFS 提供了数据复制机制。
  • HDFS 将每一个文件存储为一系列块,每个块由多个副本来保证容错,块的大小和复制因子可以自行配置(默认情况下,块大小是 128M,默认复制因子是 3)。

1.5. 副本机制的实现原理

  • 大型的 HDFS 实例,通常分布在多个机架的多台服务器上,不同机架上的两台服务器之间通过交换机进行通讯。
  • 在大多数情况下,同一机架中的服务器间的网络带宽、大于不同机架中的服务器之间的带宽。
  • 因此 HDFS 采用 机架感知 副本放置策略,对于常见情况,当复制因子为 3 时,HDFS 的放置策略是:
    • 在写入程序位于 Datanode 上时,就优先将写入文件的一个副本放置在该 Datanode 上,否则放在随机 Datanode 上,在另一个远程机架上的任意一个节点上放置另一个副本,并在该机架上的另一个节点上放置最后一个副本。
    • 此策略可以减少机架间的写入流量,从而提高写入性能。

1.6. 副本的选择

  • 为了最大限度地减少带宽消耗和读取延迟,HDFS 在执行读取请求时,优先读取距离读取器最近的副本。

    节点距离:两个节点到达最近的共同祖先的距离总和。

  • 如果在与读取器节点相同的机架上存在副本,则优先选择该副本。
  • 如果 HDFS 群集跨越多个数据中心,则优先选择本地数据中心上的副本。

2. HDFS 的稳定性

2.1. 心跳机制

  • 每个 DataNode 定期向 NameNode 发送心跳消息,如果超过指定时间没有收到心跳消息,则将 DataNode 标记为死亡。
  • NameNode 不会将任何新的 IO 请求转发给标记为死亡的 DataNode,也不会再使用这些DataNode上的数据。
  • 由于数据不再可用,可能会导致某些块的复制因子小于其指定值,NameNode会跟踪这些块,并在必要的时候进行重试复制。

2.2. 数据的完整性

  • 由于存储设备故障等原因,存储在 DataNode 上的数据块也会发生损坏。
  • 为了避免读取到已经损坏的数据而导致错误,HDFS提供了数据完整性校验机制来保证数据的完整性,具体操作如下:
    • 当客户端创建 HDFS 文件时,它会计算文件的每个块的校验和,并将校验和存储在同一HDFS命名空间下的单独的隐藏文件中。
    • 当客户端检索文件内容时,它会验证从每个DataNode接收的数据是否与存储在关联校验和文件中的校验和匹配。
    • 如果匹配失败,则证明数据已经损坏,此时客户端会选择从其他DataNode获取该块的其他可用副本。

2.3. 元数据的磁盘故障

  • FsImage 和 EditLog 是 HDFS 的核心数据,这些数据的意外丢失可能会导致整个 HDFS 服务不可用。
  • 为了避免这个问题,可以配置 NameNode 使其支持 FsImage 和 EditLog 多副本同步,这样 FsImage 或 EditLog 的任何改变都会引起每个副本 FsImage 和 EditLog 的同步更新。

2.6. 支持快照

  • 快照支持在特定时刻存储数据副本,在数据意外损坏时,可以通过回滚操作恢复到健康的数据状态。

3. HDFS 特点

3.1 高容错

  • 副本机制: 由于HDFS 采用数据的多副本方案,所以部分硬件的损坏不会导致全部数据的丢失。

3.2 高吞吐量

  • HDFS设计的重点是支持高吞吐量的数据访问,而不是低延迟的数据访问。

3.3 大文件支持

  • HDFS适合于大文件的存储,文档的大小应该是是GB到TB级别的。

3.3 简单一致性模型

  • HDFS 更适合于一次写入多次读取(write-once-read-many)的访问模型。
  • 支持将内容追加到文件末尾,但不支持数据的随机访问,不能从文件任意位置新增数据。

3.4 跨平台移植性

  • HDFS具有良好的跨平台移植性,这使得其他大数据计算框架都将其作为数据持久化存储的首选方案。

4. HDFS 文件写入流程

4.1. Pipeline 管道

  • 通过 pipeline 管道,客户端将数据块写入第一个数据节点,第一个节点保存后再复制到第二个节点,第二个节点保存后再复制到第三个节点。

问题:DataNode 采用 pipeline 传输,而不是用拓扑式传输的原因是什么?

答案:以管道的形式,顺序沿着一个方向传输,这样能够充分利用每台机器的带宽,避免网络瓶颈和高延迟的连接,最小化推送所有数据的延时。

4.2. ACK 应答响应

  • ACK (Acknowledge character)即是确认字符,在数据通信中,接收方发给发送方的一种传输类控制字符。表示发来的数据已确认接收无误;
  • 在HDFS pipeline管道传输数据的过程中,传输的反方向会进行ACK校验,确保数据传输安全。

4.3. 核心概念–默认 3 副本存储策略

  • 默认副本存储策略是由 BlockPlacementPolicyDefault 指定。
  • 第一块副本:优先客户端本地,否则随机
  • 第二块副本:不同于第一块副本的不同机架。
  • 第三块副本:第二块副本相同机架不同机器。

4.4. 文件写入流程

  • 客户端在向 NameNode 发送写请求之前,先将数据写入本地的临时文件中。
  • 待临时文件块达到系统设置的块大小时,开始向 NameNode 请求写文件。
  • 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 收到请求后会进行校验:
    • 校验是否有写权限;
    • 校验路径下是否有同名文件;
  • NameNode 在此步骤中会检查集群中每个 DataNode 状态信息,获取空闲的节点,并在检查客户端权限后创建文件;
  • NameNode 返回是否可以上传(如果校验失败,会直接报错,如果成功会给客户端返回一个信号,表示可以上传);
  • 客户端请求第一个 Block 块上传到哪几个 DataNode 节点上;
  • NameNode 返回 3 个 DataNode 节点,dn1、dn2、dn3;
  • 客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用dn2,然后 dn2 调用 dn3,将这个通信管道建立完成;
  • dn1、dn2、dn3逐级应答客户端;
  • 客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以 Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3,dn1 每传一个 Packet 会放入一个应答队列等待应答;
  • 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行3-7步)。
  • 最小复制块由 dfs.namenode.replication.min 指定,默认值是 1。

    如果 pipeline 传输失败,只要有一个副本上传成功,系统就会自动找其他机器继续复制。如果一个副本都没穿成功,则上传失败。

5. HDFS 读数据流程

  • 客户端通过 Distributed FileSystem 向 NameNode 请求下载文件,NameNode 通过查询元数据信息,获取文件块所在的 DataNode 节点地址;
  • 挑选一台 DataNode 服务器(就近原则),请求读取数据;
  • DataNode 开始传输数据给客户端(从磁盘里读取 数据输入流,以Packet为单位来做校验);
  • 客户端以 Packet 为单位接受,先在本地缓存,然后写入目标文件。

6. 常用命令一览表