2021-12-05 datanode存储相关(一):storage管理

基于源码hadoop-3.3.0

1 概述

众所周知,dn主要是用来存储hadoop集群中的具体的数据的。但实际上,Datanode还是需要保存一部分Datanode自身的元数据的, 这些元数据是通过Datanode磁盘存储上的一些文件和目录来保存的。

Datanode可以定义多个存储目录保存数据块,Datanode的多个存储目录存储的数据块并不相同,并且不同的存储目录可以是异构的, 这样的设计可以提高数据块IO的吞吐率[比如多块磁盘]。

1.1 实际存储

下面看一个实际中的存储:

我们简单了解一下:

  • BP-607470660-10.200.50.133-1568802623014:BP表示blockpool,所以这个目录是一个块池目录,块池目录保存了一个块池在当前存储目录下存储的所有数据块, 在Federation部署方式中, Datanode的一个存储目录会包含多个以“BP”开头的块池目录。 BP后面会紧跟一个唯一的随机块池ID, 在这个示例中就是607470660。 接下来的IP地址10.200.50.133是当前块池对应的Namenode的IP地址。 最后一个部分是这个块池的创建时间。
  • VERSION文件:在current中存在一个VERSION文件,截图未显示,内容如下

块池目录的VERSION文件同样包含了文件系统布局版本(layoutVersion) 、 HDFS集群ID(clusterld) 以及创建时间(cTime) 等集群信息。 除此之外, 块池目录的VERSION文件还包含了以下信息。

    • storageType:存储类型,这里是DATA_NODE
  • current/BP-607470660-10.200.50.133-1568802623014/current目录:
    • finalized/rbw:finalized和rbw目录都是用于存储数据块的, 包括数据块文件以及对应的校验和文件。 rbw(replica being written, 正在写入副本) 目录保存了正在由HDFS客户端写入当前Datanode的数据块。 finalized目录包含了已经完成写入操作的数据块, 由于这样的数据块可能非常多, 所以finalized目录会以特定的目录结构存储这些数据块。每个数据块对应 2 个文件,blk 文件存放数据,另外一个以 meta 结尾的存放校验和等元数据
    • VERSION:这里会记录namespaceID,cTime,blockpoolId,layoutVersion
  • current/BP-607470660-10.200.50.133-1568802623014/scanner.cursor:DataNode 会定期的对每个 blk 文件做校验,这个文件是用来记录校验到哪个位置的
  • in_use.lock:被dn线程持有的锁文件,用于防止多个Datanode线程启动并且并发修改这个存储目录
  • lazyPersist: HDFS 2.X中引入了一个新的特性, 用于支持将临时数据写入内存, 然后通过懒持久化(lazyPersist) 方式写入磁盘。 如果用户开启了这个特性,lazyPersist目录就用于将内存中的临时数据懒持久化到磁盘。

1.2 功能划分

Datanode最重要的功能就是管理磁盘上存储的HDFS数据块(block)。

Datanode将这个管理功能切分为两个部分:

① 管理与组织磁盘存储目录(由dfs.data.dir指定) , 如current、previous、 detach、 tmp等, 这个功能由DataStorage类实现;

②管理与组织数据块及其元数据文件, 这个功能主要由FsDatasetImpl(对应每一个存储目录)相关类实现。

本文主要介绍第一部分:磁盘存储目录的管理。

2 磁盘存储目录管理

在dn中负责管理磁盘存储的主要继承结构如下:

因此我们分别了解一下这几个概念。

2.1 Storage

根据注释,此类用于存储storage file信息,本地的storage 信息存储在VERSION文件中,主要包括node的类型,存储布局版本,namespaceId,fs state create time。

本地存储可以驻留在多个目录中。每个目录都应包含与其他目录相同的VERSION 文件。在启动Hadoop服务器(名称节点和数据节点)期间读取它们的本地存储来自他们的信息。

服务器在运行时为每个存储目录持有一个锁,以便其他节点无法启动共享相同的存储。当服务器停止(正常或异常)时释放锁。

Storage是一个抽象类, 为Datanode、 Namenode提供抽象的存储服务。 Storage类管理着当前节点上( 可以是Datanode或者Namenode) 所有的存储目录, 每个存储目录都由一个StorageDirectory对象管理,StorageDirectory类定义了存储目录上的通用操作。 由于HDFS 2.X版本引入了Federation机制 , Datanode会为多个块池保存数据块, HDFS定义了BlockPoolSliceStorage类来管理Datanode上的一个块池, 这个块池分布在Datanode配置的所有存储目录中。Storage用一个线性表字段storageDirs存储它管理的所有StorageDirectory, 并通过Dirlterator迭代器进行遍历。

private final List<StorageDirectory> storageDirs = new CopyOnWriteArrayList<>();

2.1.1 Storage.StorageState

StorageState定义了存储空间可能出现的所有状态。 在升级、 回滚、 升级提交、 检查点等操作中, 节点(Datanode或者Namenode) 的存储空间可能出现各种异常, 例如误操作、 断电、 宕机等情况, 这个时候存储空间就可能处于某种中间状态, 引入中间状态, 有利于HDFS从错误中恢复过来。 存储状态的确定, 是在StorageDirectory.analyzeStorage()方法中进行的.

  public enum StorageState {
    NON_EXISTENT, // 存储不存在
    NOT_FORMATTED, // 存储未格式化
    COMPLETE_UPGRADE, // 完成升级
    RECOVER_UPGRADE,  // 恢复升级
    COMPLETE_FINALIZE, // 完成升级提交
    COMPLETE_ROLLBACK, // 完成回滚操作
    RECOVER_ROLLBACK,  // 恢复回滚
    COMPLETE_CHECKPOINT, // 完成检查点操作
    RECOVER_CHECKPOINT,  // 恢复检查点操作
    NORMAL; // 正常状态
  }

2.1.2 Storage.StorageDirectory

我们知道Datanode和Namenode都可以定义多个存储目录来存储数据,StorageDirectory是Storage的内部类, 定义了管理存储目录的通用方法。

重点字段:

// 存储目录的根, 就是java.io.File文件。
    final File root;              // root directory

    // 指示当前目录是否是共享的。
    // 例如在HA部署中, 不同的Namenode之间共享存储目录,
    // 或者在Federation部署中不同的块池之间共享存储目录。
    final boolean isShared;

    // 当前存储目录的类型。
    final StorageDirType dirType; // storage dir type

    // 独占锁, java.nio.FileLock类型,
    // 用来支持Datanode或者Namenode线程独占存储目录的锁操作。
    FileLock lock;                // storage lock

    // 权限信息
    private final FsPermission permission;

    // 存储目录的标识符。
    private String storageUuid = null;      // Storage directory identifier.

    // 位置信息
    private final StorageLocation location;

StorageDirectory的操作主要包含:

2.1.2.1 获取文件夹

主要是获取存储目录中的各个文件和目录的方法:

包括:

  • current和current Version文件
  • previous和previous Version文件
  • previous tmp目录
  • removed tmp目录
  • finlized tmp目录
  • lastCheckpoint tmp目录
  • previous.checkpoint文件
/**
     * Directory {@code current} contains latest files defining
     * the file system meta-data.
     * 
     * @return the directory path
     */
public File getCurrentDir() {
    if (root == null) {
        return null;
    }
    return new File(root, STORAGE_DIR_CURRENT);
}

/**
     * File {@code VERSION} contains the following fields:
     * <ol>
     * <li>node type</li>
     * <li>layout version</li>
     * <li>namespaceID</li>
     * <li>fs state creation time</li>
     * <li>other fields specific for this node type</li>
     * </ol>
     * The version file is always written last during storage directory updates.
     * The existence of the version file indicates that all other files have
     * been successfully written in the storage directory, the storage is valid
     * and does not need to be recovered.
     * 
     * @return the version file path
     */
public File getVersionFile() {
    if (root == null) {
        return null;
    }
    return new File(new File(root, STO
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值