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

news/2024/11/9 0:58:40/

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"),	// 获取集群IDGENCLUSTERID ("-genclusterid"), // 生成集群IDREGULAR ("-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.ppmy.cn/news/60783.html

相关文章

保护移动设备免受恶意软件侵害优秀方法

几天前&#xff0c;移动恶意软件攻击增加了500%显然&#xff0c;我们大多数人都不知道不能很好地保护我们的手机下面小编揭秘有效保护移动设备免受恶意软件侵害的最佳方法。 1、使用移动反恶意软件 恶意软件很容易感染智能手机和平板电脑&#xff0c;因此在设备上安装可靠的…

Qt Installer Framework使用教程:

步骤一&#xff1a; 下载并安装Qt Installer Framework工具 http://download.qt.io/official_releases/qt-installer-framework/ 将安装目录添加到环境变量&#xff0c;如安装D盘时D:\Qt\QtIFW-4.5.0\bin 步骤二&#xff1a; 将测试例子(如D:\Qt\QtIFW-4.5.0\…

如何用ChatGPT做品牌联名方案策划?

该场景对应的关键词库&#xff08;15个&#xff09;&#xff1a; 品牌、个人IP、社交话题、联名策划方案、调研分析、市场影响力、资源互补性、产品体验、传播话题、视觉形象设计、合作职权分配、销售转化、曝光目标、宣发渠道、品牌形象 提问模板&#xff08;1个&#xff09;…

闭包函数

python从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129328397?spm1001.2014.3001.5502 回顾&#xff1a; 函数对象&#xff1a;可以将定义在函数内的函数返回到全局使用&#xff0c;从而打破函数的层级限制。名称空间与作用域&#xff…

有了MySQL,为什么还要有NoSQL

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;MySQL和NoSQL的区别 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入: 林在闪闪…

大数据开会记录【NiFi数据集成、AllData数据中台管理系统、RuoYi】

今天上午和下午开了个小会&#xff0c;上午说了一下Nifi&#xff0c;下午具体说了一下nifi和ruoyi。 目录 上午 下午 上午 三个人开会。 上次说的挖掘平台&#xff0c;您这边是否有技术人员对nifi比较熟悉&#xff0c;并且能够将相关功能集成到数据中台系统中。 现在结构化的…

基于Kali搭建SSH弱口令靶机并用Nmap实现排查

前言正文1、为宿主主机配置nmap环境变量2、为宿主主机和靶机配置同一局域网环境3、为靶机配置弱口令4、为靶机配置SSH服务[^2]5、主机用Nmap对靶机进行扫描5、主机用弱口令工具对靶机渗透6、验证弱口令 参考文献 前言 有时候&#xff0c;需要我们搭建SSH弱口令环境&#xff0c…

设计模式-创建型模式-(工厂、简单工厂、抽象工厂)

一、简单工厂模式 上代码 public class FoodFactory {public static Food makeFood(String name) {if (name.equals("noodle")) {Food noodle new LanZhouNoodle();noodle.addSpicy("more");return noodle;} else if (name.equals("chicken")…