编程相关

HDFS 数据块和副本状态转换

2022-12-04  本文已影响0人  wayyyy

HDFS 中文件的存储方式是将文件block进行切分,默认一个 block 64MB(这个值在hadoop2.x中是128M)。若文件大小超过一个 block 的容量(64M)就会被切分为多个 block,这些block会根据存储策略存储在不同的 DataNode 上。

image.png

一个文件至少由一个或多个 block 组成,而一个 block 仅属于一个文件。

Block 或者 Replica 的状态

文件在HDFS里进行读取和存储的时候大都是以block的形式存在和表现。每个文件都可能会有很多个block,每个block又会根据配置存在多个备份。

在NN(NameNode)的视角,将其称为Block,在DN(DataNode)的视角将其称为Replica。

Block 或者 Replica 在NN中和DN中随着操作以及各种异常场景,会有多种状态,这些状态因不同的操作或者事件而触发和转变。

Replica
 static public enum ReplicaState {
    FINALIZED(0),
    RBW(1),
    RWR(2),
    RUR(3),
    TEMPORARY(4);
}
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 状态。

Block
  static public enum BlockUCState {
    COMPLETE,
    UNDER_CONSTRUCTION,
    UNDER_RECOVERY,
    COMMITTED;
}

NN 视角 Block 有4中状态:

image.png
Block 在Namenode 中的状态变化

Block,BlockInfo,BlocksMap 相关类

Block

Block 类用来唯一标识Namenode 中的数据块,是HDFS 数据块最基本的抽象接口。
Block 类定义了三个字段:

blockId    // 唯一标识
numBytes    // numBytes 是这个数据块的大小
generationStamp    // 数据块的时间戳 

其他包括序列化,反序列化的方法。

BlockInfo
image.png

BlockInfo 类扩展至 Block类,是 Block类的补充和完善。

private BlockCollection bc;
private Object[] triplets;

bc 是 类型,记录了该HDFS文件的INode 对象的引用。
triplets保存了这个Block 副本存储在哪些数据节点上,triplets[] 这个数组的长度是3*replication,replication表示数据块的备份数。
现在我们假设replication=3,这个数组存储的数据如下:

image.png

也就是说,triplets包含的信息:

BlockInfo 中定义的方法大都是维护 这个数据结构。

BlockInfoUnderConstruction类

HDFS在加载fsimage时,如果当前加载的文件处于正在构建状态,则将该INodeFile的最后一个数据块设置为 BlockInfoUnderConstruction,表面最后一个数据块正在构建中,而其他的数据块均为正常的 BlockInfo 。

BlocksMap

HDFS为了解决通过blockId快速定位BlockInfo的问题,所以引入了BlocksMap,BlocksMap底层通过GSet(本质是一个链式解决冲突的哈希表)实现。

在HDFS集群启动过程,DataNode会进行BR(BlockReport,其实就是将DataNode自身存储的数据块上报给NameNode),根据BR的每一个Block计算其HashCode,之后将对应的BlockInfo插入到相应位置逐渐构建起来巨大的BlocksMap。

BlocksMap 实现比较简单,主要是维护了 Block -> BlockInfo 的映射关系。

private final int capacity
private final GSet<Block, BlockInfo> blocks

Generation Stamp

GS ( Generation Stamp ) :

GS 这是 NameNode 维护的一个类似版本标签的全局唯一标识,他是一个8字节的整数,当一个NameNode格式化文件系统的时候,这个标识被初始化为1。

以下的事件能够让GS+1:

  1. 当客户端请求NameNode创建一个新的文件。
  2. 当客户端请求NameNode打开一个文件来以便向里面追加(append)内容或者删减内容(truncate)。
  3. 当客户端在流水线工作过程中失败,需要恢复流水线,客户端回向NameNode讨要一个新的GS。
  4. NameNode以客户端的名义续租(Lease Recovery) ,GS + 1后将被写入到NameNode的日志记录里。

可以简单理解,GS 是HDFS维护的文件系统的版本标签。当某些退出DataNode集群很久的节点加入时,根据GS可以识别出他们是否是旧的节点。

BGS

BGS用来标记一个Block(以及他的Replica)的版本,用来以区分Replica是否过期。

当客户端需要写入或者追加时,都需要调用 addBlock 获取一个新的Block,NameNode会为这个Block打上一个新的BGS。新BGS产生方式很简单,NameNode将现在的GS + 1就得到了新的BGS(NameNode同时要把 + 1后的GS写到日志里)。



参考资料
1、https://www.codercto.com/a/47336.html
2、https://lausaa.github.io/2021/06/08/PipelineOfHDFS/
3、https://www.cnblogs.com/lqlqlq/p/12314057.html

上一篇下一篇

猜你喜欢

热点阅读