美文网首页
Block 和 Lease恢复

Block 和 Lease恢复

作者: wayyyy | 来源:发表于2022-12-11 00:42 被阅读0次

    HDFS 在文件写入过程中会有哪些异常:

    1. Client 在写入过程中,NameNode 挂了
    2. Client 在写入过程中,有 DataNode 挂了
    3. Client 在写入过程中,Client 挂了

    在讲HDFS对这几个异常处理之前,需要先明白 block 和 replica 状态转换。

    Replica
     static public enum ReplicaState {
        FINALIZED(0),
        RBW(1),
        RWR(2),
        RUR(3),
        TEMPORARY(4);
    }
    
    • RBW(Replica Being Written)状态
      这是正在写入副本的状态(无论是写入还是追加),RBW 副本始终是打开文件的最后一个块。RBW 副本的数据(不一定是全部)对客户端可见。

    • FINALIZED
      当副本处于此状态时,写入副本已完成并且副本中的数据被“冻结”(长度已确定),除非重新打开副本以进行追加。 具有相同生成戳(称为 GS 并在下面定义)的块的所有最终副本应该具有相同的数据。 作为恢复的结果,最终副本的 GS 可能会增加。

    • RWR(Replica Waiting to be Recovered)状态
      当一个DataNode在流水线传输过程中宕机,那么当他重启后,所有的之前在流水线中正在被写的RBW态Replica都会转换成RWR态。

    • RUR(Replica Under Recovery)
      租约过期后发生租约恢复和数据块恢复时所处的状态。

    • TEMPORARY
      这个状态是用来暂存Replica的,某个Block的最小备份数是3,原本有3台DataNode存有Replica,但是其中一台宕机了,那么NameNode需要把备份复制到新的一台DataNode A上,于是在A那创建了一个TEMP状态的Replica来将数据复制进去,如果复制成功那么又恢复到3个Replica了。如果A宕机,那么下次重启的时候,这个TEMP的Replica将被删除。

    image.png

    NameNode 不会持久化存储这些状态,一旦 NameNode 发生重启,它将所有打开文件的最后一个 block 设置为 UNDER_CONSTRUCTION 状态,其他则全部设置为 COMPLETE 状态。

    Replica 在 Datanode 中的状态变化

    datanode 会将不同状态的副本存储到磁盘的不同目录下,换句话说,datanode上Replica的状态是会被持久化的。在 datanode 的磁盘上,有3个子目录:

    1. rbw
      当Replica被客户端请求首次创建的时候,会被放入rbw目录
    2. current
      当一个Replica被finalized,就被移动到 current 目录
    3. tmp
      当Replica是因为复制或者均衡操作被创建的时候,会被放入tmp目录

    当数据节点重启时,tmp目录下的 replica 就被清空,rbw目录下的Replica就转变为 RWR 状态。

    • 从Init出发,一个新创建的 replica 有两种情况:
      由 Client 请求,新建的 replica 用于写入,状态为 RBW。
      由 NameNode 请求,新建的 replica 用于复制或集群间再平衡拷贝,状态为 TEMPORARY。

    • 从RBW出发,有三种情况:

      • Client 写完并关闭文件后,切换到 FINALIZED 状态。
      • replica 所在的 DataNode 发生重启,切换到 RWR 状态,重启期间数据可能过时了,可以被丢弃。
      • replica 参与 block recovery 过程,切换到 RUR 状态。
    • 从TEMPORARY出发,有两种情况:

      • 复制或集群间再平衡拷贝成功后,切换到 FINALIZED 状态。
      • 复制或集群间再平衡拷贝失败或者所在 DataNode 发生重启,该状态下的 replica 将被删除,注意这个状态状态上图未有体现。
    • 从RWR出发,有两种情况:

      • 所在 DataNode 挂了,重启后又回到 RWR 状态,自己到自己。
      • replica 参与 block recovery 过程,切换到 RUR 状态。
    • 从RUR出发,有两种情况:

      • DataNode 挂了,就变回了 RBW 状态,重启后只会回到 RWR 状态,看是否还有必要参与恢复还是过时直接被丢弃。
      • 恢复完成,切换到 FINALIZED 状态。
    • 从FINALIZED出发,有两种情况:

      • 文件重新被打开追加写入,文件的最后一个 block 对应的所有 replicas 切换到 RBW。
      • replica 参与 block recovery 过程,切换到 RUR 状态。
    Block
      static public enum BlockUCState {
        COMPLETE,
        UNDER_CONSTRUCTION,
        UNDER_RECOVERY,
        COMMITTED;
    }
    

    NN 视角 Block 有4中状态:

    • UnderConstruction状态
      这是一个块正在被写入(包括追加写)时的状态,处于该状态的长度和时间戳gs都是可变的,并且它的数据(不一定是全部)对读者可见。

    • COMMITTED 状态
      客户端在写文件时,每次请求新的数据块或者关闭文件时,都会顺带对上一个数据块进行提交操作。COMMITED 状态的数据块表明客户端已经把该数据块的所有数据都发送到了 Datanode 组成的数据流管道中。并且已经收到了下游的ACK响应,但是 Namenode 还没有收到任何一个 Datanode 汇报有 FINALIZED 副本。

    • COMPLETE
      数据块的大小和时间戳gs均不会再发生变化,而且NameNode已经至少收到一个DataNode节点汇报的FINALIZED状态的副本()。同时,该状态下的block会在NameNode内存中保存finalized状态副本replica的位置locations,而当文件的所有block都是COMPLETE状态的,文件才可以被关闭。

    • UNDER_RECOVERY
    image.png
    Block 在Namenode 中的状态变化
    • 从 Init 出发
      只有当 Client 新建或追加文件写入时新创建的 block 处于 UNDER_CONSTRUCTION 状态。

    • 从UNDER_CONSTRUCTION出发,有三种情况:

      • 当客户端发起 add block 或 close 请求,若处于 FINALIZED 状态的 replica 数量少于最小副本数要求,则切换到 COMMITTED 状态,这里 add block(Client每写一个block就会发起一个add block的操作,比如:一个文件有2个block,那么就会发起2次add block操作,所以,后面降到影响的是倒数第二个block) 操作影响的是文件的倒数第二个 block 的状态,而 close 影响文件最后一个 block 的状态。
      • 当客户端发起 add block 或 close 请求,若处于 FINALIZED 状态的 replica 数量达到最小副本数要求,则切换到 COMPLETE 状态
      • 若发生 block recovery,状态切换到 UNDER_RECOVERY。
    • 从UNDER_RECOVERY,有三种情况:
      • 0 字节长度的 replica 将直接被删除。
      • 恢复成功,切换到 COMPLETE。
      • NameNode 发生重启,所有打开文件的最后一个 block 会恢复成 UNDER_CONSTRUCTION 状态。
    • 从COMMITTED出发,有两种情况:
      若处于 FINALIZED 状态的 replica 数量达到最小副本数要求或者文件被强制关闭或者 NameNode 重启且不是最后一个 block,则直接切换为 COMPLETE 状态。
      • NameNode 发生重启,所有打开文件的最后一个 block 会恢复成 UNDER_CONSTRUCTION 状态。
    • 从 COMPLETE 出发
      只有在 NameNode 发生重启,所有打开文件的最后一个 block 会恢复成 UNDER_CONSTRUCTION 状态。 这种情况,若 Client 依然存活,有 Client 来关闭文件,否则由 lease recovery 过程来恢复。
    Client 在写入过程中,NameNode 挂了

    注意这里的先决条件是 NameNode 已经开始写入了,所以 NameNode 已经完成了对 DataNode 的分配,若写之前 NameNode 就挂了,整个 HDFS 集群是不可用的所以也无法开始写入。

    流水线写入过程中,当一个 block 写完后需向 NameNode 报告其状态,这时 NameNode 挂了,状态报告失败,但不影响 DataNode 的pipeline工作,数据先被保存下来,但最后一步 Client 写完向 NameNode 请求关闭文件时会出错,由于 NameNode 的单点特性(如果有HA则没事),所以无法自动恢复,需人工介入恢复。

    当 Client 在写入过程中,有 DataNode 挂了
    Client 在写入过程中,自己挂了

    当 Client 在写入过程中挂了后,在经过一定的超时时间后,Namenode 会收回租约并关闭文件。但在收回租约关闭文件前,需要确保文件 block 的多个副本数据一致(分布式环境下很多异常情况都可能导致存储该block的多个数据节点副本不一致),若不一致就会进入 block recovery 过程进行恢复。

    所以下面,先讲讲 block recovery 过程:
    1、获取包含文件最后一个 block 的所有 DataNodes。
    2、指定其中一个 DataNode 作为主导恢复的节点。
    3、主导节点向其他DataNode节点请求获得它们上面存储的该Block的 replica 信息。
    4、主导节点收集了包含该Block信息的所有DataNode节点上的 replica 信息后,就可以计算出那个节点上面的 replica 的长度是最小的。
    5、主导节点向其他节点发起更新,将各自 replica 更新为最小长度值(一般是pipeline流中的最后一个节点的replica的长度是最小的),保持各节点 replica 长度一致。
    6、所有 DataNode 都同步后,主导节点向 NameNode 报告更新一致后的最终结果。
    7、NameNode 更新文件 block 元数据信息,收回该文件租约,并关闭文件。


    参考资料
    1、https://zhuanlan.zhihu.com/p/328092306

    相关文章

      网友评论

          本文标题:Block 和 Lease恢复

          本文链接:https://www.haomeiwen.com/subject/hjglfdtx.html