【大数据Hadoop】HDFS3.3.1-Datanode-DataStorage的实现原理

news2024/12/22 20:51:14

DataStorage的实现原理

  • 前言
  • Storage类继承关系
  • StorageInfo
  • Storage.StorageState
  • Storage.StorageDirectory
    • 文件夹操作
    • 加锁/解锁操作
    • 存储状态恢复操作
  • Storage
  • DataStorage

前言

Datanode 最重要的功能就是管理磁盘上存储的 HDFS 数据块。Datanode 将这个管理功能切分为两个部分:①管理与组织磁盘存储目录(由 dfs.data.dir 指定),如 current、 previous、 detach、 tmp 等,这个功能由 DataStorage 类实现;② 管理与组织数据块及其元数据文件,这个功能主要由 FsDatasetlmpl 相关类实现。本节介绍 DataStorage 类的实现。

Storage类继承关系

Data Storage 的父类为 Storage,如下图 给出了 Storage 类的继承关系。Storagelnfo 为根接口,描述存储的基本信息。子类 Storage 是抽象类,它为 Datanode、 Namenode 提供抽象的存储服务。

在这里插入图片描述

一个 Storage 可以定义多个存储目录,存储目录由 Storage 的内部类 StorageDirectory 描述, StorageDirectory 类定义了存储目录上的通用操作。这里我们以 Datanode 的配置为例,Datanode 可以定义多个存储目录保存数据块,如下配置所示,Datanode 定义了两个数据存储目录,即 /data/hdfs/dfs/data ” 和 “ /data/hdfs/afs/data2”。HDFS 会使用一个 Data Storage 对象管理整个 Datanode 的存储,而这两个存储目录则由两个 StorageDirectory 对象管理。

<property>
  <name>dfs.data.dir</name>
  <value>[DISK]/data/hdfs/data_1,[SSD]/data/hdfs/data_2</value>
</property>

由于Federation联邦机制,Datanode会管理多个块池。HDFS 定义了 BlockPoolSliceStorage 类来管理 Datanode 上的一个块池,这个块池分布在 Datanode 配置的所有存储目录中。DataStorage 类会持有所有 BlockPoolSliceStorage 对象的引用,并通过这些引用管理 Datanode 上的所有块池。

StorageInfo

Storagelnfo 用于描述存储的基本信息,这个类有以下5个字段。

  • layout Version:存储系统布局版本号,当节点存储的目录结构发生改变或者 fsimage 和 editlog 的格式发生改变时,存储系统布局版本号会更新。这个版本号一般是负数。
  • namespacelD:存储系统命名空间标识。
  • cTime:存储系统创建时间。
  • clusterID:存储系统的集群 ID。
  • storageType:节点类型,有 DATA NODE、 NAME NODE、 JOURNAL NODE 等类型。

这里要注意,Storagelnfo中定义的信息都存储在存储目录的 VERSION 文件中,一个 VERSION 文件就是一个典型的 Java Properties(属性)文件,除了上述5个属性外,不同类型节点的 VERSION 文件还存储了其他特有的属性。

Storagelnfo 的方法大多是 get/set 方法,以及从 Properties 文件中读取属性然后赋值字段的方泆,比较简单,这里就不再赘述了

Storage.StorageState

Storage 类定义了一个非常重要的内部枚举类—StorageState,这个枚举类完整地定义了存储空间可能出现的所有状态。在升级、回滚、升级提交、检查点等操作中,节点 (Datanode 或者 Namenode)的存储空间可能出现各种异常,例如误操作、断电、宕机等情况,这个时候存储空间就可能处于某种中间状态,引入中间状态,有利于 HDFS 从错误中恢复过来。对于存储状态的确定,是在 StorageDireetory.analyseStorage0) 方法中进行的,我们在下一节 StorageDirectory 中介绍这个方法。

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

这里要特别注意,Storage 状态还与启动选项有关,这些选项的存储在 HdfsServerConstants 类中,代码如下:

  enum StartupOption{
    FORMAT  ("-format"), // 格式化操作
    CLUSTERID ("-clusterid"),	// 获取集群ID
    GENCLUSTERID ("-genclusterid"), // 生成集群ID
    REGULAR ("-regular"),	// 正常启动
    BACKUP  ("-backup"),	// 备份
    CHECKPOINT("-checkpoint"),	// 
    UPGRADE ("-upgrade"),	//	升级
    ROLLBACK("-rollback"),	//	回滚
    ROLLINGUPGRADE("-rollingUpgrade"),	//	滚动升级
    IMPORT  ("-importCheckpoint"),	//
    BOOTSTRAPSTANDBY("-bootstrapStandby"),
    INITIALIZESHAREDEDITS("-initializeSharedEdits"),
    RECOVER  ("-recover"),
    FORCE("-force"),
    NONINTERACTIVE("-nonInteractive"),
    SKIPSHAREDEDITSCHECK("-skipSharedEditsCheck"),
    RENAMERESERVED("-renameReserved"),
    METADATAVERSION("-metadataVersion"),
    UPGRADEONLY("-upgradeOnly"),
    // The -hotswap constant should not be used as a startup option, it is
    // only used for StorageDirectory.analyzeStorage() in hot swap drive scenario.
    // TODO refactor StorageDirectory.analyzeStorage() so that we can do away with
    // this in StartupOption.
    HOTSWAP("-hotswap"),
    // Startup the namenode in observer mode.
    OBSERVER("-observer");
    // ...
  }

Storage.StorageDirectory

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

  • root:存储目录的根,就是 java.io.File 文件。
  • dirType:当前存储目录的类型。
  • isShared:指示当前目录是否是共享的。例如在 HA 部署中,不同的 Namenode 之间共享存储目录,或者在 Federation 部署中不同的块池之间共享存储目录。
  • lock:独占锁,java.nio.FileLock 类型,用来支持 Datanode 或者 Namenode 线程独占存储目录的锁操作。
  • storageUuid:存储目录的标识符。

StorageDirectory 的方法主要分为三类:获取文件夹相关操作、加锁/解锁操作、存储状态恢复操作。下面我们依次看一下这三种类型方法的实现。

文件夹操作

获取当前存储目录结构中的各个文件/文件夹的方法,在 HDFS 升级过程中涉及的所有目录都可以通过 StorageDirectory 提供的方法获得:

在这里插入图片描述

  • getCurrentDir() —— 获取 current目录。
  • getVersionFile() —— 获取 current 目录下的 VERSION 文件。
  • getPreviousDir() —— 获取 previous 目录。
  • getPrevious VersionFile() —— 获取 previous 目录下的 VERSION 文件。
  • getPreviousTmp() —— 获取 previous.tmp 目录。
  • getRemovedTmp() —— 获取 removed.tmp 目录。
  • getFinalizedTmp() —— 获取 finalized.tmp 文件。
  • getLastCheckpointTmp() —— 获取 lastcheckpoint.tmp 文件。
  • getPreviousCheckpoint() —— 获取 previous.checkpoint 文件。

加锁/解锁操作

在 Datanode 磁盘存储结构小节中,我们介绍了存储目录下会有一个 in_use.lock 文件,j 个文件用于对当前存储目录加锁,以保证 Datanode 进程对存储目录的独占使用。当 Datanode进程退出执行时,in_use.lock 文件会被删除。StorageDirectory 提供了 tryLock0与 unlock0两个锁方法,分别实现了对存储目录加锁以及解锁的功能。

StorageDirectory 中真正进行加锁操作的是 tryLockO方法。tryLockO方法会首先构造锁文件,然后调用 file.getChannel.lockO方法尝试获得存储目录的独占锁,如果已经有进程占有锁文件,那么 file.getChannel.lock(就会返回一个 null 的引用,表明有另一个节点运行在当前的存储目录上,tryLockO方法会抛出异常并退出执行。如果加锁成功,tryLockO方法会在锁文件中写入虚拟机信息。

存储状态恢复操作

Datanode 在执行升级、回滚、提交操作的过程中会出现各种异常,例如误操作、断电、 宕机等情况。那么 Datanode 在重启时该如何恢复上一次中断的操作呢?StorageDirectory 提供了 doRecover()和 analyzeStorage(两个方法,Datanode 会首先调用 analyzeStorage(方法分析当前节点的存储状态,然后根据分析所得的存储状态调用 doRecover(方法执行恢复操作。

Storage

Storage 是一个抽象类,为 Datanode、 Namenode 提供抽象的存储服务。Storage 类管理着当前节点上(可以是 Datanode 或者 Namenode)所有的存储目录,每个存储目录都由一个 StorageDirectory 对象管理,Storage 用一个线性表字段 storageDirs 存储它管理的所有 StorageDirectorv,并通过 Dirlterator 迭代器进行遍历。

DataStorage

DataStorage 继承自 Storage 抽象类,提供了管理 Datanode 存储空间的功能。本节介绍 DataStorage 类的实现。

在 HDFSFederation 架构中,一个 Datanode 可以保存多个命名空间的数据块,每个命名空间在 Datanode 磁盘上都拥有一个独立的块池(BlockPool),这个块池会分布在 Datanode 的所有存储目录下,它们共同保存了这个块池在当前 Datanode 上的所有数据块。HDFS 定义了 BlockPoolSliceStorage 类管理 Datanode 上单个块池的存储空间 (BlockPoolSliceStorage 的实现我们在下一节中介绍),DataStorage 类则定义了 bpStorageMap 字段保存 Datanode 上所有块池 BlockPoolSliceStorage 对象的引用。如下代码所示,bpStorageMap 字段是 Map 类型的,维护了 bpld->BlockPoolSliceStorage 的映射关系。

private final Map<String, BlockPoolSlicestorage> bpstorageMap = Collections.synchronizedMap (new HashMap<String, BlockPoolSlicestorage>());

Datanode 在启动时会调用 DataStorage 提供的方法初始化 Datanode 的存储空间,在 HDFS Federation 架构中,Datanode 会保存多个命名空间的数据块。对于每一个命名空间,Datanode 都会构造一个 BPOfferService 类维护与这个命名空间 Namenode 的通信(请参考文件系统数据集的 BlockManager 节的 BPOfferService 小节)。如图 4-15 所示,当 BPOfferService 中的 BPServiceActor 类与该命名空间的 Namenode 握手成功后,就会调用 DataNode.initBlockPool( 初始化该命名空间的块池。DataNode.initBlockPool0 方法最终会调用 DataStorage.recoverTransitionRead() 来执行块池存储的初始化操作。

希望对正在查看文章的您有所帮助,记得关注、评论、收藏,谢谢您

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/484252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

确定不进来看看吗?详细讲解C语言文件操作(示例分析每个函数)

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言初阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:讲解c语言中的文件操作,文件的读取,输入输出,流的概念…

【分布式搜索引擎03】

分布式搜索引擎03 11.9.数据聚合11.9.1.聚合的种类11.9.2.DSL实现聚合11.9.2.1.Bucket聚合语法11.9.2.2.聚合结果排序11.9.2.3.限定聚合范围11.9.2.4.Metric聚合语法11.9.2.5.小结 11.9.3.RestAPI实现聚合11.9.3.1.API语法11.9.3.2.业务需求11.9.3.3.业务实现 11.10.自动补全&a…

AMBA协议-AXI协议详解(读写时序、Outstanding、乱序传输、原子操作)

目录 1. AXI 写通道信号 1.1. 写地址通道信号 1.2. 写数据通道信号 1.3. 写response通道信号 1.5. 握手规则 1.4. AXI 写通道之间关系 2. AXI 读通道信号 2.1. 读地址通道信号 2.2. 读数据通道信号 2.3. AXI 读通道之间关系 3. AXI传输 3.1. AXI突发读传输 3.2. …

EventBus(事件总线)的使用和源码的简单解析

Google Guava EventBus(事件总线)的使用和源码的简单解析 什么是EventBus&#xff1f; 事件总线&#xff08;EventBus&#xff09;是一种广泛用于软件架构中的设计模式&#xff0c;用于实现解耦和松散耦合的通信机制。它可以帮助组织和管理应用程序中不同组件之间的通信&…

【SQL篇】面试之高级查询和连接

603 连续空余座位 select distinct c1.seat_id from Cinema c1 join Cinema c2 on abs(c2.seat_id-c1.seat_id) 1 where c1.free1 and c2.free1 order by c1.seat_id;总结 思路&#xff1a;为什么我们这里需要abs和distinct&#xff0c;如果是如下代码&#xff0c;为什么不可…

[架构之路-178]-《软考-系统分析师》-17-嵌入式系统分析与设计- 3- 分区操作系统(Partition Operating System)概述

目录&#xff1a; 本文概述&#xff1a; 1.1 什么是分区操作系统 1.2 分区操作系统出现背景 1. 前后台系统(Foreground/Background System) 2. 实时操作系统(RTOS) 本文概述&#xff1a; 随着嵌入式系统日趋复杂化以及对安全性要求的不断提高&#xff0c;采用空间隔离、时…

[计算机图形学]光场,颜色与感知(前瞻预习/复习回顾)

一、Light Field / Lumigraph—光场 1.我们看到的是什么 我们的眼睛能够把3D世界转换为2D的成像信号被我们感知&#xff0c;如上面第一幅图&#xff0c;这就是我们看到整个世界的过程&#xff0c;那么如果我们把之前记录的光的信息都完美的放在一个幕布上&#xff0c;那么我们…

第15章 信息(文档)和配置管理

文章目录 软件文档的分类&#xff08;1&#xff09;开发文档&#xff1a;描述开发过程 本身&#xff08;2&#xff09;产品文档&#xff1a;描述开发过程的 产物&#xff08;3&#xff09;管理文档&#xff1a;记录项目管理的信息 文档的质量可以分为四级&#xff08;1&#xf…

第二十五章 刚体Rigidbody

在物理学中&#xff0c;静止和匀速直线运动是物体的平衡状态&#xff0c;如果给该物体施加某一个力的话&#xff0c;物体的平衡状态就会改变&#xff0c;当然这个真理的前提是理想状态。我们知道在现实世界中&#xff0c;由于重力和摩擦力的存在&#xff0c;任何一个物体都不可…

【SQL篇】窗口函数和公共表达式

1077 项目员工 III # Write your MySQL query statement below select project_id, employee_id from (select project_id, e.employee_id, rank() over(partition by project_id order by experience_years desc) as rkfrom Employee ejoin Project pon e.employee_id p.empl…

【Fluent】接着上一次计算的结果继续计算,利用计算过程中得到的物理场(温度、速度、压力等)插值Interpolate文件初始化模型的方法

一、问题背景 因为fluent中支持的初始化无非三种类型。 1、Standard initialization 标准初始化 2、Hybridinitialization 混合初始化 3、FMG initialization FMG初始化 另外&#xff0c;还可以用UDF通过坐标判断的方式予以初始化。 但是这些初始化方法都没办法利用以前计算过…

通关MyBatis(上)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;spring框架 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 什么是MyBatis 如何使用Mybatis 添加依赖 创建数据库 配置数据库连接字符串 MyBatis的操作流程 数据持久层 配置mybatis的xml文件 mapp…

Windows自动虚拟机WSL和VMware虚拟机兼容问题(此平台不支持虚拟化的 Intel VT-x/EPT)

问题背景与原因分析 在安装了WSL2之后&#xff0c;忽然发现VMware Workstation无法正常启动了。就是在开启虚拟机时遇到了这种情况&#xff1a; “ 此平台不支持虚拟化的 Intel VT-x/EPT” 问题描述&#xff1a;出现以上问题&#xff0c;发现WSL2和 VMware Workstation 是不兼…

idea使用git遇到的小问题

idea使用git遇到的小问题 前置说明颜色含义中文插件修改提交的用户名 前置说明 idea版本为2022专业版 github需要自己会科学上网 颜色含义 在idea中使用github后&#xff0c;会发现项目中会有各种各样的颜色&#xff0c;如图所示文件全为绿色 这颜色含义分别为&#xff1a;…

函数-函数递归及练习

目录 1、什么是递归&#xff1f; 2、递归的两个必要条件 3、递归的练习 3.1 接受一个整型值&#xff08;无符号&#xff09;&#xff0c;按照顺序打印它的每一位 3.2 编写函数不允许创建临时变量&#xff0c;求字符串的长度 3.3 求第n个斐波那契数 3.4 字符串逆序&…

UG NX二次开发(C++)-建模-修改NXObject或者Feature的颜色(二)

文章目录 1、前言2、在UG NX中修改Body的颜色操作3、采用NXOpen(C)实现3.1 创建修改对象颜色的方法3.2 在do_it()中添加调用的代码3.3 测试效果 1、前言 在UG NX中&#xff0c;改变NXObject和Feature的操作是不相同的&#xff0c;所以其二次开发的代码也不一样&#xff0c;我们…

企业级信息系统开发讲课笔记4.1 Spring Boot入门程序

文章目录 零、学习目标一、Spring Boot框架概述&#xff08;一&#xff09;由Spring到Spring Boot&#xff08;二&#xff09;Spring Boot框架的核心功能&#xff08;三&#xff09;Spring Boot框架的应用 二、使用Maven方式构建Spring Boot项目&#xff08;一&#xff09;创建…

二维字符数组的三种输入方式浅析(scanf()、gets()和fgets())

二维字符数组的输入 目录 二维字符数组的输入1.scanf函数知识点scanf()关于回车的问题&#xff1a; 2.gets函数3.fgets函数参考链接 1.scanf函数 知识点 按照常规输入数组的办法&#xff0c;通过 for 循环实现 将整个字符串输入时&#xff0c;在数组名前不加&&#xff0…

Java 基础进阶篇(二)—— static 静态关键字与单例模式

文章目录 一、static 静态关键字1.1 静态成员变量与实例成员变量1.2 静态成员方法与实例成员方法1.3 static 访问注意事项1.4 内存使用情况 二、工具类三、代码块四、单例模式4.1 饿汉单例4.2 懒汉单例 一、static 静态关键字 static&#xff1a;代表静态的意思&#xff0c;可…

Java 基础进阶篇(六)—— 接口详解

文章目录 一、接口概述二、接口的基本使用三、接口从 JDK 8 开始新增的方法四、接口的注意事项&#xff08;了解&#xff09;补充&#xff1a;接口与接口的关系 一、接口概述 规范的基本特征是约束和公开。 接口就是一种规范&#xff0c;其约束别人必须干什么事情。 所以&…