第 4 章 HDFS 的读写流程(面试重点)

4.1 HDFS 写数据流程(面试重点)

4.1.1 剖析文件写入

image.png

  1. 请求和检查:
    • 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
  2. NN应答请求
    • NameNode 返回是否可以上传。
  3. Block往哪里传
    • 客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。
  4. NN应答存储位置
    • NameNode 返回 3 个 DataNode 节点(默认为三个副本),分别为 dn1、dn2、dn3。
      • 一个是client所处的节点(既本地节点)
        • 节点距离最近(节点距离为0),上传数据速度最快
      • 一个是另一个机架的随机一个节点
        • 物理上远离第一个节点(节点距离为4),保证数据的可靠性
      • 一个是与第二个节点相同机架的另一个节点
        • 既不选择和第二个副本同一个节点,也不选择另一个机架,而是同机架的不同节点(节点距离为2)是传输效率和数据安全的折衷考虑

image.png

  1. 请求DN连接
    • 客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3,将这个通信管道建立完成
      • 相对于和所有待上传的 dn 建立关系,客户端只和一个 dn 建立关系,客户端就只需要维持一个传输通道,减少了很多的工作量
      • 然后再一串串地逐级建立传输关系,每个机器都不会有太繁重的传输通道维持压力
  2. DN应答
    • dn1、dn2、dn3 逐级应答客户端。
  3. 传送Black到DN
    1. 客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以 Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3;
    2. dn1 每传一个 packet 会放入一个应答队列等待应答。
  4. 重复完成后续的Black
    • 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行 3-7 步)。

      4.1.2 网络拓扑-节点距离计算

      在 HDFS 写数据的过程中,NameNode 会选择距离待上传数据最近距离的 DataNode 接收数据。
      那么这个最近距离怎么计算呢?
      节点距离:两个节点到达最近的共同祖先的距离总和。
      距离计算示例
  • 将各个节点做成树形图
  • 数两个节点的最近共同祖先,各自的树枝之和

image.png
image.png
image.png

4.1.3 副本存储节点选择(基于节点距离远中近)

  1. 机架感知说明
  2. 源码说明
    • Crtl + n 查找 BlockPlacementPolicyDefault,在该类中查找 chooseTargetInOrder 方法。
  3. Hadoop3.1.3 副本节点选择
    • 一个是client所处的节点(既本地节点)
      • 节点距离最近(节点距离为0),上传数据速度最快
    • 一个是另一个机架的随机一个节点
      • 物理上远离第一个节点(节点距离为4),保证数据的可靠性
    • 一个是与第二个节点相同机架的另一个节点
      • 既不选择和第二个副本同一个节点,也不选择另一个机架,而是同机架的不同节点(节点距离为2)是传输效率和数据安全的折衷考虑

image.png

4.2 HDFS 读数据流程(面试重点)

image.png

  1. 客户端通过 DistributedFileSystem 向 NameNode 请求下载文件,NameNode 通过查询元数据,找到文件块所在的 DataNode 地址。
    • NN 是 HDFS 的文件管理者,客户端只有
  2. 挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据。
  3. DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校验)。
  4. 客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。
  5. 各个Block的读取,一定是串行读,进行追加拼接

    第 5 章 NameNode 和 SecondaryNameNode

    5.1 NN 和 2NN 工作机制

    NameNode 中的元数据的存储位置

  • 存储在内存
    • 优点:数据的读写速度快
    • 缺点:数据可靠性差,断电丢失数据
  • 存储在磁盘
    • 优点:数据可靠性高,断电数据不丢失
    • 缺点:数据的读写速度慢
  • 使用的方案
    • 平时所访问的数据,进行的写数据,都是直接操作的内存,也即 NN 工作时,所有读写的元数据都是存储在内存中的
    • 同时还有一份备份的文件落地在磁盘上,进行定期同步,以供 NN 重启时,可以从磁盘中读取数据到内存中,恢复断电前的内存元数据
  • 数据同步方案
    • 磁盘中的历史备份文件为:FsImage
    • 记录两次备份中间数据操作日志的文件:Edits
    • Edits 文件两次备份中间数据操作日志
      • 每当Client请求写操作需要更改NN元数据时,就会先将写日志写入当前的 Edits 文件,然后再操作内存中的元数据
    • 同步时机:每隔一小时,由 2NN 代为合并并推送替代旧 FsImage
      • 不定时同步,会导致 Edits 积累的操作过多,断电、停机后启动恢复元数据时间过长
      • 2NN 代为合并:NN 节点需要检索元数据,此时再承担合并的功能,会负载大,效率低,因此引入一个新的节点SecondaryNamenode,专门用于 FsImage 和 Edits 的合并

image.png

第一阶段:NameNode 启动

(1)第一次启动 NameNode 格式化后,创建 Fsimage 和 Edits 文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode 记录操作日志,更新滚动日志。
(4)NameNode 在内存中对元数据进行增删改。

第二阶段:Secondary NameNode 工作

(1)Secondary NameNode 询问 NameNode 是否需要 CheckPoint。直接带回 NameNode是否检查结果。

  • 默认一小时询问一次,或者 Edits 文件存满了(一百万条操作日志)(2NN 每隔一分钟都去NN检查 Edits 满了没)

(2)Secondary NameNode 请求执行 CheckPoint。
(3)NameNode 滚动正在写的 Edits 日志。也即创建一个新的文件来记录现在以及以后的 Edits 日志
(4)将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode。
(5)Secondary NameNode 加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件 fsimage.chkpoint。
(7)拷贝 fsimage.chkpoint 到 NameNode。
(8)NameNode 将 fsimage.chkpoint 重新命名成 fsimage。

5.2 Fsimage 和 Edits 解析

5.2.1 Fsimage 和 Edits 概念

NameNode 被格式化之后,将在/opt/module/hadoop-3.1.3/data/tmp/dfs/name/current目录中产生如下文件
image.png

  1. Fsimage文件
    • HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息
  2. Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中。
  3. seentxid文件保存的是一个数字,就是最后一个edits的数字
    • 用于指向最新的,还没有进行同步的 Edits 文件
    • 因此,这个数字之前的 Edits 文件的操作,都是已经被同步到 Fsimage 中的
  4. 每次NameNode启动的时候都会进行两个操作,以保证内存中的元数据信息是最新的、同步的,
    1. 将Fsimage文件读入内存:已经落到磁盘的元数据重新读到内存中
    2. 加载Edits里面的更新操作:还没有来得及同步到磁盘的数据,读取其操作日志,在内存中计算,写入到内存的元数据中
  5. 因此,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并

    5.2.1 查看 Fsimage 和 Edits 文件

    Fsimage 和 Edits 文件都不能正常通过 cat 命令进行查看,会乱码,需要通过各自的特定命令进行解析成 xml 文件查看

    ovi 查看 Fsimage 文件

    1. hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径
    1. [haniel@hdp02 current]$ pwd
    2. /opt/module/hadoop-3.1.3/data/dfs/name/current
    3. [haniel@hdp02 current]$ hdfs oiv -p XML -i
    4. fsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml
    5. [haniel@hdp02 current]$ cat /opt/module/hadoop-3.1.3/fsimage.xml
    从文件可以看出,Fsimage 中没有记录块所对应 DataNode
  • 也即:落地到磁盘的元数据,并无记录块(Block)所处的 DN,从Fsimage无法得知每个Block在集群的位置
  • 该信息是 DN 每隔一段时间上报给 NN 并写入到内存中的

原因:

  • Block 在 DN 中的位置信息并不是固定的,具有实时性,会过期,不适合持久化存储

    oei 查看 Edits 文件

    1. hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径
    1. [haniel@hdp02 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop3.1.3/edits.xml
    2. [haniel@hdp02 current]$ cat /opt/module/hadoop-3.1.3/edits.xml

    NameNode 如何确定下次开机启动的时候合并哪些 Edits?

  • 从 seen_txid 文件中获取最新的一个Edits 文件(也即还没有被2NN合并并推送的)

    5.3 CheckPoint 时间设置

    1)通常情况下,SecondaryNameNode 每隔一小时执行一次合并操作。
    [hdfs-default.xml]

    1. <property>
    2. <name>dfs.namenode.checkpoint.period</name>
    3. <value>3600s</value>
    4. </property>

    2)一分钟检查一次Edits的操作次数,当操作次数达到 1 百万时,SecondaryNameNode 执行一次合并操作

    1. <property>
    2. <name>dfs.namenode.checkpoint.txns</name>
    3. <value>1000000</value>
    4. <description>操作动作次数</description>
    5. </property>
    6. <property>
    7. <name>dfs.namenode.checkpoint.check.period</name>
    8. <value>60s</value>
    9. <description> 1 分钟检查一次操作次数</description>
    10. </property>

    第 6 章 DataNode

    6.1 DataNode 工作机制

    image.png

  1. 一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,
    • 数据本身
    • 数据的元数据包括数据块的长度,块数据的校验和,以及时间戳(版本控制用)
  2. DataNode 启动后向 NameNode 注册,通过后,周期性(6 小时)的向 NameNode 上报所有的块信息

    • 配置信息

      • DN 向 NN 汇报当前解读信息的时间间隔,默认 6 小时;

        1. <property>
        2. <name>dfs.blockreport.intervalMsec</name>
        3. <value>21600000</value>
        4. <description>Determines block reporting interval in milliseconds.</description>
        5. </property>
      • DN 扫描自己节点块信息列表的时间,默认 6 小时

        1. <property>
        2. <name>dfs.datanode.directoryscan.interval</name>
        3. <value>21600s</value>
        4. <description>Interval in seconds for Datanode to scan data directories and reconcile the difference between blocks in memory and on the disk. Support multiple time unit suffix(case insensitive), as described in dfs.heartbeat.interval.
        5. </description>
        6. </property>
  3. DN 发给 NN 的心跳是每 3 秒一次,该心跳返回给 DN 结果带有 NameNode 给该 DataNode 的命令,如复制块数据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳,则认为该节点不可用。

    1. 设置参数见 6.3
  4. 集群运行中可以安全加入和退出一些机器。

    6.2 数据完整性(通过校验对比)

    思考:如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理 DataNode 节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?
    如下是 DataNode 节点保证数据完整性的方法。
    (1)当 DataNode 读取 Block 的时候,它会计算 CheckSum
    (2)如果计算后的 CheckSum,与 Block 创建时值不一样,说明 Block 已经损坏。
    (3)Client 读取其他 DataNode 上的 Block。
    (4)常见的校验算法 crc(32),md5(128),sha1(160)
    (5)DataNode 在其文件创建后周期验证 CheckSum

    6.3 掉线时限(10min + 30s)参数设置

  5. DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信

  6. NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长
  7. HDFS默认的超时时长为10分钟+30秒
    • 由两个参数来确定:心跳时间(3s) 和 心跳复检时间(5min),计算公式为:TimeOut = 2 dfs.namenode.heartbeat.recheck-interval + 10 dfs.heartbeat.interval = 10min + 30s
      1. <property>
      2. <name>dfs.namenode.heartbeat.recheck-interval</name>
      3. <value>300000</value>
      4. </property>
      5. <property>
      6. <name>dfs.heartbeat.interval</name>
      7. <value>3</value>
      8. </property>