HDFS是一个分布式文件存储系统,是 hadoop 生态中用于解决分布式存储问题的核心,是由谷歌的dfs论文催生出的分布式文件成存储解决方案。

存储模型
  • 文件线性按字节切割成(block),具有 offsetid
  • 文件与文件的 block 大小可以不一样
  • 一个文件除最后一个 block ,其他 block 大小一致
  • block 的大小依据硬盘的 I/O 特性调整
  • block 被分散存放在集群的节点中,具有 location
  • block 具有副本(replication),没有主从概念,副本不能出现在同一个节点
  • 副本是可以满足可靠性和性能的关键
  • 文件上传可以指定 block 大小和副本数,上传后只能修改副本数
  • 一次写入多次读取,不支持修改
  • 支持追加数据
  • HDFS 中的文件在物理上是分块存储(block),块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在 hadoop2.x 版本中是128M,老版本中是64M
  • 文件的各个 block 的存储管理由 DN 节点承担,DNHDFS 集群从节点,每一个 block 都可以在多个 DN上存储多个副本(副本数量也可以通过参数设置(dfs.replication),同一个 block 不会存储多份(大于1)在同一个 DN 上,因为这样没有意义
  • 文件的各个块存储在 DN的磁盘目录中(hdfs-site.xml文件中配置的(dfs.datanode.data.dir)节点的值+/current/BP-190247797-192.168.10.220-1460040893538/current/finalized)
  • hadoop中block hadoop中block.size不可以修改_hadoop中block

hadoop中block hadoop中block.size不可以修改_分布式_02

finalizedrbw 这两个目录都是用于实际存储 HDFSblock 的数据,里面包含许多block_xx 文件以及相应的.meta文件,.meta文件包含了checksum信息。

rbw 是“replica being written”的意思,该目录用于存储用户当前正在写入的数据。

数据块文件是以 blk 开头的

hadoop中block hadoop中block.size不可以修改_hdfs_03

一个是数据本身,一个是数据的元信息(.meta)。

注:设计数据块冗余度原则:一般跟数据节点一样;但是最大不要超过3,在 Hadoop 3.x 以前,会造成存储空间的极大浪费,Hadoop 3.x 以后,HDFS 纠缠码(Erasure Coding)技术,大大的节约存储的空间


架构设计
  • HDFS 是一个主从(Master/Slaves)架构
  • 由一个 NN 和一些 DN 组成
  • 面向文件包含:文件数据(data)和文件元数据(metadata)
  • NN 负责存储和管理元数据,并维护了一个层次性的文件目录树
  • DN 负责存储文件数据(block块),并提供 block 的读写
  • DNNN 维持心跳,并汇报自己持有的 block 信息(每三秒一次心跳信息带有 NNDN 的命令,周期性(一小时)的向 NN 汇报所有 block 块信息)

hadoop中block hadoop中block.size不可以修改_hadoop_04

HDFS 是设计成适应一次写入,多次读出的场景,且不支持文件的修改
(注:适合用来做数据分析,并不适合用来做网盘应用,因为,不便修改,延迟大,网络开销大,成本太高)


角色功能
NameNode(名称节点/主节点)
  • 完全基于内存存储文件元数据、目录结构、文件 block 的映射
  • 需要持久化方案保证数据可靠性
  • 提供副本放置策略
  • 管理文件系统的命名空间
  • 维护文件目录树及整个树内所有文件和目录
  • 记录各个块所在的数据节点信息(并不永久保存块的位置信息,因为这些信息会在系统启动时根据数据节点信息重建)
  • 管理数据的元信息(数据文件的 dfs.block.size+10%,block locations,dfs.replication,block count)
日志文件(edits 文件)

记录 client 执行创建,移动,修改文件的信息,同时体现了 HDFS 的最新的状态(二进制文件),它分布在磁盘上的多个文件,名称由前缀 edits 及后缀组成.后缀值是该文件包含的事务 ID,同一时刻只有一个文件处于可读写状态.为避免数据丢失,事务完成后 client 端在执行成功前,文件会进行更新和同步,当 NN 向多个目录写数据时,只有在所有操作更新并同步到每个副本之后执行才成功。

edits_inprogress_0000000000000000107 代表:正在操作的日志文件

元信息文件(fsimage 文件)

记录的是数据块的位置信息、数据块的冗余信息(二进制文件)

由于 edits 文件记录了最新状态信息,并且随着操作越多,edits 文件就会越大,把 edits 文件中最新的信息写到 fsimage 文件中就解决了 edits 文件数量多不方便管理的情况。

没有体现 HDFS 的最新状态。

每个 fsimage 文件都是文件系统元数据的一个完整的永久性的检查点。

可能产生的问题

  • 由于只有在重启时 fsimageedits 才会进行合并,得到一个新的 fsimage 文件,但是在实际生产环境中很少会重启集群.
  • NN 的重启需要花费很长时间,因为会有很多改动需要合并到 fsimage 文件上
  • 如果 NN 挂掉,fsimage 文件没有更新内容,从而丢失很多改动。

为了解决上述问题: 就引入了 Secondary NameNode


DataNode(数据节点)

负责管理和存储文件块 block

  • 基于本地磁盘存储 block (文件的形式)
  • 此处的元数据包括数据块的长度、块数据的校验和、时间戳
  • 并保存 block 的效验和数据保证 block 的可靠性
  • NN 保持心跳,汇报 block 列表状态

SecondaryNameNode(检查点节点)

职责:日志信息的合并

在非 Ha 模式下,SNN 一般是独立的节点,周期完成对 NNEditLogFsImage 合并,减少 EditLog 大小,减少 NN 启动时间。

  • 为什么引入SecondaryNameNode
  • 为什么元数据存储在NameNode在内存中?
  • 这样做有什么问题?如何解决?
  • HDFS 编辑日志文件 editlog:在NameNode节点中的编辑日志 editlog 中,记录下来客户端对 HDFS 的所有更改的记录;每次更改对应一个事务,每个事务有一个事务编号;事务编号递增
  • 作用:一旦系统出故障,可以根据 editlog 恢复元数据;
  • 但 editlog 日志大小会随着时间变的越来越大,导致系统重启,根据日志恢复元数据的时间会越来越长;
  • 为了避免这种情况,引入检查点机制checkpoint,命名空间镜像 fsimage 就是 HDFS 元数据的持久性检查点,即将内存中的元数据落磁盘生成的文件;
  • 此时,NN 如果重启,可以将磁盘中的 fsimage 文件读入内容,将元数据恢复到某一个检查点,然后再执行检查点之后记录的编辑日志 editlog ,最后完全恢复元数据。
  • 随着时间的推移,editlog 记录的日志会变多,那么当 NN 重启,恢复元数据过程中,会花越来越长的时间执行 editlog 中的每一个日志;而在 NN 元数据恢复期间,HDFS不可用。
  • 为了解决此问题,引入 SNN 辅助 NN,用来合并 fsimage 及 editlog
Checkpoint 机制

hadoop中block hadoop中block.size不可以修改_大数据_05

  • SNN 首先请求原 NN 进行 edits 的滚动,这样新的编辑操作就能够进入新的文件中
  • SNN 通过 HTTP GET 方式读取原NN中的 fsimageedits 进行备份
  • SNN 读取 fsimage 到内存中,然后执行 edits 中的每个操作,并创建一个新的统一的fsimage文件,有 ckpt 后缀
  • SNN 通过 HTTP PUT 方式将新的 fsimage 发送到原 NN
  • 原 NN 用新的 fsimage 替换旧的 fsimage,同时系统会更新 fsimage 文件到记录检查点的时间。
  • 这个过程结束后,NN 就有了最新的fsimage文件和更小的edits文件

创建检查点 checkpoint 的两大条件:

hadoop 1.x版本:

1、每隔 3600 秒(fs.checkpoint.period 参数设置最大时间间隔)

2、edits 文件达到了 64 M(fs.checkpoint.size 参数设置),即使此时没有达到period的时限也会执行 checkpoint

hadoop 2.x版本:

1、每隔 3600 秒(dfs.namenode.checkpoint.period 参数设置最大时间间隔)

2、另外,SNN 每1分钟检查一次,从上一检查点开始,edits日志文件中是否已包括100万个事务,如果是,也会创建检查点

2.x版本checkpoint相关属性(hdfs-site.xml

属性


解释

dfs.namenode.checkpoint.period

3600秒(即1小时)

The number of seconds between two periodic checkpoints.

dfs.namenode.checkpoint.txns

1000000

The Secondary NameNode or CheckpointNode will create a checkpoint of the namespace every ‘dfs.namenode.checkpoint.txns’ transactions, regardless of whether ‘dfs.namenode.checkpoint.period’ has expired.

dfs.namenode.checkpoint.check.period

60(1分钟)

The SecondaryNameNode and CheckpointNode will poll the NameNode every ‘dfs.namenode.checkpoint.check.period’ seconds to query the number of uncheckpointed transactions.


元数据持久化
  • 任何对文件系统元数据产生修改的操作,NN 都会使用一种称为 EditLog 的事务日志记录下来
  • 使用 FsImage 存储内存所有的元数据状态
  • 使用本地磁盘保存 EditLogFsImage
  • Editlog 具有完整性,数据丢失少,但恢复速度慢,并有体积膨胀风险
  • FsImage 具有恢复速度快,体积与内存数据相当,但不能实时保存,数据丢失多
  • NN 使用了 FsImage+EditLog 整合的方案;
  • 滚动将增量的 EditLog 更新到 FsImage,以保证更近时点的 FsImage 和更小的 EditLog 体积

安全模式(safe mode)
  • NN 启动后会进入一个称为安全模式的特殊状态,是 HDFS 的一种自我保护,用于检查数据块的副本率
  • 当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性和一致性。
  • NN 从所有 DN 接受心跳信号和块状态报告
  • 每当 NN 检测确认某个数据块副本数目达到这个最小值,那么该数据块就会被认为是副本安全(safely replicated)的
  • 在一定百分比(这个参数可配置)的数据块被 NN 检测确定是安全之后(加上一个额外的30秒等待时间),NN 将退出安全模式状态。
  • 接下来它会确定还有哪些数据块的副本没有达到指定数目,并将这些数据块复制到其他 DN 上。
  • HDFS 搭建时会格式化,格式化操作会产生一个空的 FsImage
  • NameNode 启动时,它从硬盘中读取 EditLogFsImage
  • 将所有 EditLog 中的事务作用在内存中的 FsImage
  • 并将这个新版本的 FsImage 从内存中保存到本地磁盘上
  • 然后删除旧的 EditLog,因为旧的 EditLog的事务都已经作用在 FsImage 上了

block 副本放置策略

2.x

  • 第一个副本:放置在上传文件的 DataNode;如果时集群外提交,则随机挑选一台磁盘不太满,CPU 不太忙的节点。
  • 第二个副本:放置在于第一个副本不同的机架的节点上。
  • 第三个副本:与第二个副本相同机架的节点。
  • 更多副本:随机节点
机架感知

将数据块保存在两个不同的机架中保证数据的安全性,但是这可能带来存取效率的问题,那么就在同一个机架中进行再次备份,这样既保证数据的安全性又解决存取效率问题。

1.x 版本副本放置策略

hadoop中block hadoop中block.size不可以修改_hadoop_06

可能产生的问题是前两个副本在同一机架当机架出现问题时会丢失两个副本

2.x 版本副本放置策略

hadoop中block hadoop中block.size不可以修改_hadoop中block_07


读写流程
写流程(write)
  • ClientNN 创建文件元数据信息
  • NN 判定元数据是否有效
  • NN 触发副本放置策略,返回元数据信息
  • ClientDN 建立 Pipeline 连接
  • Client 将块切分成 packet(64KB),并使用 chunk(512B)+ chucksum(4B)填充
  • Clientpacket 放入发送队列 dataqueue 中,并向第一个 DN 发送
  • 第一个 DN 收到 packet 后本地保存并发送给第二个 DN
  • 第二个 DN 收到 packet 后本地保存并发送给第三个 DN
  • 这一个过程中,上游节点同时发送下一个 packet
  • 生活中类比工厂的流水线:结论:流式其实也是变种的并行计算
  • HDFS 使用这种传输方式,副本数对于 Client 是透明的
  • block 传输完成,DN 们各自向 NN 汇报,同时 Client 继续传输下一个 block
  • 所以,Client 的传输和 block 的汇报也是并行的

hadoop中block hadoop中block.size不可以修改_hdfs_08

重点:NN 触发副本放置策略,Pipline 流式传输是变种的并行


读流程(read)
  • 为了降低整体的带宽消耗和读取延时,HDFS会尽量让读取程序读取离它最近的副本。
  • 如果在读取程序的同一个机架上有一个副本,那么就读取该副本。
  • 如果一个 HDFS 集群跨越多个数据中心,那么客户端也就首先读取本地数据中心的副本。
  • 语义:下载一个文件:
  • ClientNN 交互文件元数据获取 fileBlockInfo
  • NN 会按照距离策略排序返回
  • Client 尝试下载 block 并效验数据完整性
  • 语义:下载一个文件其实是获取文件的所有 block 元数据,那么子集获取某些 block 就应该成立。
  • HDFS 支持 Client 给出文件的 offset 自定义链接哪些 blockDN,自定义获取数据
  • hadoop中block hadoop中block.size不可以修改_分布式_09

  • 这个是支持计算层的分治、并行计算的核心。

HDFS 的底层原理

HDFS 的底层通信原理采用的是:RPC和动态代理对象 Proxy

RPC(Remote Procedure Call)

远程过程调用。也就是说,调用过程代码并不是在调用者本地运行,而是要实现调用者与被调用者两地之间的连接与通信。

RPC 的基本通信模型时是基于 Client/Server 进程之间相互通信模型的一种同步通信形式;它对 Client 提供了远程服务的过程抽象,其底层消息传递操作对 Client 是透明的。

RPC 中,Client 即是请求服务的调用者(Caller),而 Server 则是执行 Client 的请求而被调用的程序(Callee)。

动态代理对象

为其他对象提供一种代理以控制对这个对象的访问。

核心是使用JDKProxy

本文部分引用:
《Hadoop权威指南(第四版)》
马士兵教育 https://www.bilibili.com/video/BV1vJ411L7Rf