gpt4 book ai didi

深入理解HDFS错误恢复

转载 作者:撒哈拉 更新时间:2024-10-09 14:18:58 57 4
gpt4 key购买 nike

我们从动态的角度来看 hdfs 。

先从场景出发,我们知道 hdfs 的写文件的流程是这样的

数据以 pipeline 的方式写入 hdfs ,然后对于读取操作,客户端选择其中一个保存块副本的 DataNode 来读数据.考虑这样两个场景

  • hbase rs 在写 wal log 的时候.如果一个 rs 挂了.那么这个 rs 会转移并且通过读取 wal log 来恢复之前的状态.如果这个rs 挂的时候 ,写 wal log 的 pipeline 没有完成,那么必然这份 wal log 数据在不同的dn 上是存在差异的. 那么 hdfs 是如何保证 rs 转移后能够恢复到正确的状态?
  • 流计算写入hdfs ,如果中间 datanode 挂了.hdfs 是如何保证这个流计算程序不抛出错误,并持续运行下去的?

这里就引出了 hdfs 一个非常重要的特性就是 hdfs 写的错误恢复.对于 hdfs 的写的错误恢复.进而就需要了解三个重要概念: lease recovery, block recovery, and pipeline recovery . hdfs 的写的容错性就是由这三个概念保证的. 这三个概念也是相互关联,相互包含的.一切跟写文件有关

  • 租约恢复 在客户端可以写入 HDFS 文件之前,它必须获得租约,这本质上是一个锁。如果客户端希望继续写,则必须在约定的时间段内续租。如果租约没有明确更新或持有它的客户端死亡了,那么它就会过期。发生这种情况时,HDFS 将代表客户端关闭文件并释放租约,以便其他客户端可以写入该文件。这个过程称为租约恢复。
  • 块恢复 如果正在写入的文件的最后一个块没有传递到管道中的所有 DataNode,那么当发生租约恢复时,写入不同节点的数据量可能会不同。在租约恢复导致文件关闭之前,需要一个过程来确保最后一个块的所有副本具有相同的长度.此过程称为块恢复。块恢复仅在租约恢复过程中触发,并且在租约恢复中仅在文件的最后一个块不处于 COMPLETE 状态时才触发块恢复。
  • 管道恢复 在写入管道操作期间,管道中的某些 DataNode 可能会失败。发生这种情况时,底层的写操作不能只是失败。相反,HDFS 将尝试从错误中恢复,以允许管道继续运行并且客户端继续写入文件。从管道错误中恢复的机制称为管道恢复。

我们知道写文件,就是写 block . 上面这些错误恢复,最终的目的无非是要保证所有客户端的文件的所有 block 都能够完整的写入所有的 datanode . 所以,还得从更细致的角度去看 block,了解 block 的一些概念及语义 。

首先,把 datanode 中的 block 称之为 replica(副本) .用以区分 namenode 中的 block(块). 对于 replica ,它有如下几种状态,也对应了 replica 写入到 datanode 的一个动态过程

  • FINALIZED 当副本处于此状态时,对副本的写入完成并且副本中的数据被“冻结”(长度已确定),除非重新打开副本以进行追加。具有相同 generation stamp 的块的所有最终副本(称为 GS)应该具有相同的数据。最终副本的 GS 可能会因恢复发生而增加。
  • RBW (Replica Being Written) 这是正在写入的任何副本的状态,无论文件是为写入而创建的,还是为追加而重新打开的。 RBW 副本始终打开文件的一个块。数据仍在往副本里面写,尚未最终确定。 RBW 副本的数据(不一定是所有)对读取客户端可见。如果发生任何故障,将尝试将数据保存在 RBW 副本中。
  • RWR (Replica Waiting to be Recovered) 如果一个 DataNode 死掉并重新启动,它的所有 RBW 副本都将更改为 RWR 状态。 RWR 副本要么过时并因此被丢弃,要么将参与租约恢复中的块恢复。
  • RUR (Replica Under Recovery) 非 TEMPORARY 副本在参与租约恢复时将更改为 RUR 状态。
  • TEMPORARY 临时副本,用于块复制,由 replication monitor 或cluster balancer 来发起。它类似于 RBW 副本,只是它的数据对所有读取器客户端都是不可见的。如果块复制失败,将删除一个 TEMPORARY 副本。

以上就是 datanode 的 副本状态,接着对比一下 namenode 的块状态

  • UNDER_CONSTRUCTION 这是写入时的状态。 UNDER_CONSTRUCTION 块是打开文件的最后一个块;它的长度和 GS 仍然是可变的,并且它的数据(不一定是全部)对读者是可见的。 NameNode 中的 UNDER_CONSTRUCTION 块会跟踪管道中的合法 RBW 及 RWR 副本的位置。
  • UNDER_RECOVERY 如果一个文件的最后一个块在相应客户端的租约到期时处于 UNDER_CONSTRUCTION 状态,那么就会开始块恢复,同时它将变为 UNDER_RECOVERY 状态。
  • COMMITTED COMMITTED 意味着一个块的数据和 GS 不再可变(除非它被重新打开用以追加, 并且此时上报上来的有相同 GS/长度的 FINALIZED 副本的 DataNode 数要少于设定的最小副本数。为了服务读取请求,COMMITTED 块必须跟踪 RBW 副本的位置、GS 及其 FINALIZED 副本的长度。当客户端要求 NameNode 向文件添加新的块或关闭文件时,UNDER_CONSTRUCTION 块将更改为 COMMITTED。如果最后一个或倒数第二个块处于 COMMITTED 状态,则无法关闭文件,客户端必须进行重试。
  • COMPLETE 当 NameNode 检测到 匹配 GS/长度要求的 FINALIZED 副本数达到最小副本数的要求时,COMMITTED 块更改为 COMPLETE。只有当文件的所有块都变为 COMPLETE 时才能关闭文件。一个块可能会被强制进入 COMPLETE 状态,即使它没有最小的复制副本数 . 例如,当客户端请求一个新块时,前一个块尚未完成这种情况.

DataNode 将副本的状态保存到磁盘,但 NameNode 不会将块状态保存到磁盘。当 NameNode 重新启动时,它将先前所有打开的文件的最后一个块的状态更改为 UNDER_CONSTRUCTION 状态,并将所有其他块的状态更改为 COMPLETE.

副本和块的简化状态转换如两图所示

image

image

在上面副本/块状态转换过程中,有一个重要的判断依据,那就是 Generation Stamp(GS) 。

GS 是由 NameNode 持久维护的每个块的单调递增的 8 字节数。块和副本的 GS 主要的作用是以下

  • 检测块的陈旧副本:即,当副本 GS 比块 GS 旧时,例如,在副本中以某种方式跳过 append 操作时,可能会发生这种情况。
  • 检测 DataNode 上的过期副本,比如 datanode 死了很长时间后重新加入集群。

当发生以下任何一种情况时,需要生成一个新的 GS:

  • 创建了一个新文件
  • 客户端打开现有文件以进行 append 或 truncate
  • 客户端在向 DataNode(s) 写入数据时遇到错误并请求新的 GS
  • NameNode 启动文件的租约恢复

接下来,我们来看租约恢复,块恢复是由租约恢复触发,并且包含在租约恢复过程中的. 。

租约恢复过程是在 NameNode 上触发的.触发的场景有如下两个:当监控线程监控到租约 hard limit 到期时,或者一个客户端在 soft limit到期时尝试从另一个客户端接管租约时。租约恢复会检查由同一客户端写入的每个打开文件,如果文件的最后一个块不处于 COMPLETE 状态,则对文件执行块恢复,然后关闭文件.

下面是给定文件 f 的租约恢复过程。当客户端异常死亡时,这个客户端写入而打开的每个文件也会发生如下过程

  1. 得到 包含 f 的最后一个块的 DataNode。
  2. 将其中一个 DataNode 指定为主 DataNode p。
  3. p 从 NameNode 获取新的 GS 标记。
  4. p 从每个 DataNode 获取这个块的信息。
  5. p 计算得到这个块的最小长度。
  6. p 更新具有合法 GS 标记的 DataNode 的块, 让其更新为新的 GS 标记和最小块的长度。
  7. p 通知 NameNode 更新的结果。
  8. NameNode 更新 BlockInfo。
  9. NameNode 删除 f 的租约(其他写入者现在可以获得写入 f 的租约)。
  10. NameNode 向 edit log 提交更改。

其中步骤 3 到 7 是恢复过程中的块恢复部分.

有时,需要在硬限制到期之前强制恢复文件的租约。为此,可以使用命令强制恢复租约

hdfs debug recoverLease [-path] [-retries ] 。

由内到外,接下来,继续看外层的管道恢复 (pipeline recovery) 。

首先看写入管道(write pipeline)的流程 。

当 HDFS 客户端写入文件时,数据将作为顺序块写入。为了写入或构造一个块,HDFS 将块分成 packets(实际上不是网络数据包,而是消息;packets 实际是指带着这些消息的类),并将它们传递到写入管道中的每个 DataNode,如下图

image

写流水线分为三个阶段:

  1. 管道启动。客户端沿管道发送 Write_Block 请求,最后一个 DataNode 发送回确认。收到确认后,管道准备好写入。
  2. 数据流。数据通过管道以数据包的形式发送。客户端缓存数据,直到一个packet 数据包被填满,然后将数据包发送到管道。如果客户端调用 hflush(),那么即使一个数据包没有满,它仍然会被发送到管道并且必须得收到前一个数据包 hflush() 的确认。
  3. 关闭(finalize 副本并关闭管道)。客户端等待直到所有数据包都被确认,然后发送关闭请求。管道中的所有 DataNode 将相应的副本更改为 FINALIZED 状态并报告回 NameNode。如果配置的最小副本数量的 DataNode 报告了其相应副本的 FINALIZED 状态,则 NameNode 然后将块的状态更改为 COMPLETE。

当管道中的一个或多个 DataNode 在写入块的三个阶段中的任何一个中遇到错误时,则会启动管道恢复.

从管道启动失败中恢复 。

  1. 如果管道是为一个新块创建的,客户端会放弃该块并向 NameNode 请求一个新块和一个新的 DataNode 列表。管道为新块重新初始化。
  2. 如果创建管道 append 块操作,则客户端使用剩余的 DataNode 重建管道并增加块的 GS 标记。

从数据流失败中恢复 。

  1. 当管道中的 DataNode 检测到错误(例如,checksum 错误或写入磁盘失败)时,该 DataNode 通过关闭所有 TCP/IP 连接将自己从管道中取出。
  2. 接着客户端检测到故障,它会停止向管道发送数据,并使用剩余的 DataNode 重建新的管道。接着,该块的所有副本都被更新到一个新的 GS。
  3. 客户端使用这个新的 GS 继续发送数据包。如果发送的数据已经被某些 DataNode 接收了,他们会忽略该数据包并往管道下游传递.

从关闭失败中恢复 。

当客户端在关闭状态下检测到故障时,它会使用剩余的 DataNode 重建管道。如果副本尚未最终确定,则每个 DataNode 都会增加副本的 GS 并最终确定副本.

当一个 DataNode 坏时,它会将自己从管道中移除。在管道恢复过程中,客户端可能需要使用剩余的 DataNode 重建新的管道。 (它可能会也可能不会用新的 DataNode 替换坏的 DataNode,这取决于下文中配置的 DataNode 替换策略。)replication 监视器将负责复制块以满足配置的副本数.

失败时 datanode 的替换策略 。

在使用剩余的 DataNode 设置恢复管道时,关于是否添加额外的 DataNode 以替换坏的 DataNode 有四种可配置策略:

  1. DISABLE:禁用 DataNode 替换并在dn 上抛出错误。
  2. NEVER:当管道发生故障时,永远不替换 DataNode(通常不建议)。
  3. DEFAULT:根据以下条件替换:
    a. 假设 r 为配置的副本数。
    b. 设 n 为现已有副本数据的节点的数量。
    c. 仅当 r >= 3 且满足下面任一条件才添加新的 DataNode
    • flour(r/2) >= n
    • r > n 并且块是被 hflushed/appended
  4. ALWAYS:当现有的 DataNode 失败时,总是添加一个新的 DataNode。如果无法替换 DataNode,则会失败。

替换策略的开关为 dfs.client.block.write.replace-datanode-on-failure.enable ,值为 false 时,禁用所有策略. 。

值为 true,打开替换策略,此时通过配置 dfs.client.block.write.replace-datanode-on-failure.policy 来指定策略,默认策略为 default 。

使用 default 或 always 时,如果管道中只有一个 DataNode 成功,则错误恢复永远不会成功,客户端将无法执行写入直到超时。这种情况可以配置如下属性来解决此问题:dfs.client.block.write.replace-datanode-on-failure.best-effort 默认为false。使用默认设置,客户端将继续尝试,直到满足指定的策略。当该属性设置为 true 时,即使不能满足指定的策略(例如管道中只有一个成功的 DataNode,小于策略要求),仍然允许客户端继续来写.

租约恢复、块恢复和管道恢复对于 HDFS 容错至关重要。它们共同保证了即使存在网络和节点故障的情况下,写入到 HDFS 中是持久且一致的, 。

最后此篇关于深入理解HDFS错误恢复的文章就讲到这里了,如果你想了解更多关于深入理解HDFS错误恢复的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

57 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com