【大数据Hadoop】HDFS3.3.1-Namenode-租约管理

news2024/11/24 20:14:11

租约管理

  • 前言
    • LeaseManager.Lease
    • LeaseManager
      • 添加租约 - addLease
      • 租约检查 - FsNamesystem.checkLease
      • 租约更新 - renewLease
      • 删除租约 - removeLease
      • 租约检查 - Monitor 线程
      • 租约恢复 - Monitor 线程发起
      • 租约恢复 - 其他方式发起

前言

我们知道 HDFS 文件是 write-once-read-many,并且不支持客户端的并行写操作,那么这里就需要一种机制保证对 HDFS 文件的互斥操作。HDFS 提供了租约(Lease)机制来实现这个功能,租约是 HDFS 中一个很重要的概念,是 Namenode 给予租约持有者(LeaseHolder,一般是客户端)在规定时间内拥有文件权限(写文件)的合同。

在 HDFS 中,客户端写文件时需要先从租约管理器(LeaseManager)申请一个租约,成功申请租约之后客户端就成为了租约持有者,也就拥有了对该 HDFS 文件的独占权限,其他客户端在该租约有效时无法打开这个 HDFS 文件进行操作。

Namenode 的租约管理器保存了 HDFS 文件与租约、租约与租约持有者的对应关系,租约管理器还会定期检查它维护的所有租约是否过期。租约管理器会强制收回过期的租约,所以租约持有者需要定期更新租约 (renew),维护对该文件的独占锁定。当客户端完成了对文件的写操作,关闭文件时,必须在租约管理器中释放租约。

LeaseManager.Lease

我们知道一个 HDFS 客户端是可以同时打开多个 HDFS 文件进行读写操作的,为了便于管理,在租约管理器中将一个客户端打开的所有文件组织在一起构成一条记录,也就是 LeaseManager. Lease 类。

给出了 Lease 类定义的所有字段,其中 holder 字段保存了客户端也就是租约持有者的信息,paths 字段保存了该客户端打开的所有 HDFS 文件的路径,lastUpdate 字段则保存了租约最后的更新时间。

在这里插入图片描述

Lease 类中还有三个比较重要的方法需要重点讲解,这些方法都是供 LeaseManager 管理 Lease 时调用的

  • renewrenew方法用于更新客户端的 lastUpdate 最近更新时间。

  • expiredSoftLimit: 用于判附当前柤约是否超出了软限制(sofLimit),软限制是写文件规定的租约超时时间,默认是60 秒,不可以配置。

  • expiredHardLimit:用于判断当前租约是否超出了硬限制 (hardLimit),硬限制是用于考虑文件关闭异常时,强制回收租约的时间,默认是 60 分钟,不可以配置。在 LeaseManager 中有一个内部类用于定期检查租约的更新情况,当超过硬限制时间时,会触发租约恢复机制。

LeaseManager

LeaseManager 是 Namenode 中维护所有租约操作的类,它不仅仅保存了 HDFS 中所有租约的信息,提供租约的增、删、改、查方法,同时还维护了一个 Monitor 线程定期检查租约是否超时,对于长时间没有更新租约的文件(超过硬限制时间),LeaseManager 会触发租约恢复机制,然后关闭文件。

LeaseManager 中使用数据结构 leasessortedLeases 以及 sortedLeasesByPath 三个字段保存 Namenode 中的所有租约;使用 Imthread 字段保存租约检查线程;使用 sofLimit 字段保存软限制时间(默认是60 秒,不可以配置);使用 hadrLimit 字段保存硬限制时间(默认是60分钟,不可以配置)。

在这里插入图片描述

下面我们看一下 LeaseManager 保存租约的三个字段:leasessortedLeasessortedLeasesByPath

  • leases:保存了租约持有者与租约的对应关系。

  • sortedLeases:以租约更新时间为顺序保存 LeaseManager 中的所有租约,如果更新时间相同,则按照租约持有者的字典序保存。

  • sortedLeasesByPath:保存了文件路径与租约的对应关系,以路径的字典序为顺序保存。

了解了 LeaseManager 定义的字段,下面我们学习 LeaseManager 提供的增加、删除、更新以及恢复租约的方法。

添加租约 - addLease

当客户端创建文件和追加写文件时,FSNamesystem.startFilelnternal() 以及 appendFilelnternal() 方法都会调用 LeaseManager.addLease() 为该客户端在 HDFS 文件上添加一个租约。addLease() 方法有两个参数,其中 holder 参数保存租约的持有者信息,src 参数则保存创建或者追加写文件的路径,这两个参数分别对应于 ClientProtocol.ercate() 或者 append() 方法中的 clientNamesrc 参数。addLease() 方法的实现也非常简单,先是通过 getLease() 方法构造租约,然后在 LeaseManager 定义的保存租约的数据结构中添加这个租约的信息。

synchronized Lease addLease(String holder, long inodeId) {
    Lease lease = getLease(holder);
    if (lease == null) {
      // 构造 Lease 对象
      lease = new Lease(holder);
      // 在leaseManager.leases字段添加Lease对象
      leases.put(holder, lease);
    } else {
      renewLease(lease);
    }
    leasesById.put(inodeId, lease);
    lease.files.add(inodeId);
    return lease;
  }

addLease() 在另外两种情况下也会被调用,就是 Namenode 读取 fsimage 文件时,fsimage 文件记录了当前 HDFS 文件处于构建状态中,这时需要重建这个构建中的文件并将文件对应的 INode 对象加入文件系统目录树中,然后还需要在 LeaseManager 中添加租约信息;以及在 Namenode 读取 editlog 时,editlog 记录了一个 OP_ADD 操作,也就是创建文件的操作, Namenode 创建完 INode 对象并添加到文件系统目录树之后,还需要在 LeaseManager 中添加租约信息。

租约检查 - FsNamesystem.checkLease

如图 3-51 所示,当客户端已经成功打开了一个 HDFS 文件并添加租约后,客户端调用 abandonBlock()放弃新申请的数据块(客户端数据流管道建立失败时),调用 getAddtionalBlock() 申请新的数据块(客户端完成了上一个数据块的写入,申请新的数据块时),调用 completeFilelnternal()提交文件(客户端完成 HDFS 文件的写操作,提交文件时)等情况时, 都需要检查租约是否正常。

这里的检查操作是由 FSNamesystem.checkLease() 方法执行的,checkLease() 方法会检查当前 HDFS 文件是否存在、INode 是否是一个目录、文件是否处于构建中状态、文件是否已被删除、输入的文件的租约持有者与实际的租约持有者是否相同。如果这些检查不正常,则抛出 LeaseExpiredException

租约更新 - renewLease

当客户端打开了一个文件用于写或者追加写操作时,LeaseManager 会保存这个客户端在该文件上的租约。客户端会启动一个 LeaseRenewer 定期更新租约,以防止租约过期。

租约更新操作是由 FSNamesystem.renewLease() 响应的,这个方法最终会调用 LeaseManager.renewLease() 方法。renewLease() 方法会首先从 sortedLeases 字段中移除这个租约,然后更新这个租约的最后更新时间,再重新加入 sortedLeases 中。这么做的原因是, sortedLeases 是一个以最后更新时间排序的集合,所以每次更新租约后,sortedLeases 中的顺序也需要重新改变。

删除租约 - removeLease

LeaseManager 中的租约会在两种情况下被删除。

  • Namenode 关闭构建中的 HDFS 文件时,会调用 FSNamesystem.finalizeINodeFileUnderConstruction() 方法将 INode 从构建状态转换成非构建状态,同时由于客户端已经完成了文件的写操作,所以需要从 LeaseManager 中删除该文件的租约,这里调用了 removeLease() 方法删除租约。

  • 在进行目录树的删除操作时,对于已经打开的文件,如果客户端从文件系统目录树中移出该 HDFS 文件,则会调用 removeLeaseWithPrefixPath()方法从 LeaseManager 中删除租约。

removeLease()removeLeaseWithPrefixPath() 的实现都比较简单,从 LeaseManager 保存租约的数据结构中删除租约信息即可,读者可以直接参考以下代码:

租约检查 - Monitor 线程

我们知道租约管理器除了对租约提供增、删、改、查等操作外,还会定期检查所有租约, 对于长时间没有进行租约更新的文件,LeaseManager 会对这个文件进行租约恢复操作,然后关闭这个文件。在什么情况下会出现租约过期呢?我们知道 HDFS是一个分布式系统,客户端很有可能在打开一个文件之后出现故障,这也就造成了客户端不能完成租约更新以及写文件之后的租约删除操作,这时就会造成租约过期。

租约的定期检查操作是由 LeaseManager 的内部类 Monitor 执行的,Monitor 是一个线程类, 它的 run() 方法会每隔2 秒调用一次 LeaserManager.checkLeases() 方法检查租约。

在前面的小节中我们己经介绍过,LeaseManager 中有两个限制时间,其中软限制时间用于记录写文件规定的租约超时时间;硬限制时间则用于判断文件是否由于异常而未能正确关闭。在 checkLeases() 方法中就是使用硬限制时间(60 分钟)判断是否需要进行租约恢复操作的。

checkLeases() 方法会遍历 leaseManager 中管理的所有租约,找出所有超过硬限制时间而未更新的租约。由于租约保存了这个客户端打开的所有 HDFS 文件,所以 checkLeases() 方法会遍历这个租约上的所有文件,并调用 FSNamesystem.internalReleaseLease() 方法进行租约恢复操作。checkLeases() 方法的代码如下:


租约恢复 - Monitor 线程发起

对于 HDFS文件的租约恢复操作是通过调用 FSNamesystem.internalReleaseLease() 实现的, 这个方法用于将一个已经打开的文件进行租约恢复并关闭。如果成功关闭了文件, internalReleaseLease() 方法会返回 true:如果仅触发了租约恢复操作,则返回 false。我们知道租约恢复是针对已经打开的构建中的文件的,所以 internalReleaseLease() 会判断文件中所有数据块的状态,对于异常的状态则直接抛出异常。在 checkLeases() 方法中,对于调用 FSNamesystem.internalReleaseLease() 方法时抛出异常的租约,则直接调用 removeLease() 方法删除。

当文件处于构建状态时,有三种情况可以直接关闭文件,并返回 true。

  • 这个文件所拥有的所有数据块都处于 COMPLETED 状态,也就是客户端还没有来得及关闭文件和释放租约就出现了故障,这时 interalReleaseLease() 可以直接调用 finalizeINodeFileUnderConstruction() 方法关闭文件并删除租约。

  • 文件的最后一个数据块处于提交状态(COMMITTED),并且该数据块至少有一个有效的副本,这时可以直接调用 finalizeINodeFileUnderConstruction() 方法关闭文件并删除租约。

  • 文件的最后一个数据块处于构建中状态,但这个数据块的长度为 0,且当前没有 Datanode 汇报接收了这个数据块,这种情况很可能是客户端向数据流管道中写数据前发生了故障,这时可以将最后一个未写入数据的数据块删除,之后调用 finalizeINodeFileUnderConstruction() 方法关闭文件并删除租约。

当最后一个数据块处于 UNDER RECOVERY 或者 UNDER CONSTRUCTION 状态,且这个数据块己经写入了数据时,则构造一个新的时间戳作为 recoveryld,调用 initializeBlockRecovery() 触发租约恢复,更新当前文件的租约持有者为 “HDFS NameNode”。 internalReleaseLease() 的代码如下:


下面我们看一下租约恢复的过程,这里是在需要进行租约恢复的数据块上调用 initializeBlockRecovery() 方法,该方法会遍历所有保存副本的数据节点,选取一个最近一次进行汇报的数据节点作为主恢复节点,然后向这个数据节点发送租约恢复指令,Namenode 会通过心跳将租约恢复的名字节点指令下发给该恢复节点。

租约恢复指令是通过心跳响应携带给主恢复数据节点的,主恢复数据节点的租约恢复流程如图 3-52 所示。主恢复数据节点接收到指令后,会调用 Datanode.recoverBlock() 方法开始租约恢复,这个方法首先会通过 Inter DatanodeProtocolinitReplicaRecovery() 方法向数据流管道中参与租约恢复的数据节点收集副本信息,副本信息会以 ReplicaRecoveryinfo 对象返回给主恢复节点。initReplicaRecovery() 方法会从该数据块的所有副本中选取一个最好的状态,作为所有副本恢复的目标状态。然后主恢复节点会调用 InterDatanodeProtocol.updateReplicaUnderRecovery() 方法同步所有 Datanode 上该数据块副本至目标状态。同步结束后,这些数据节点上的副本长度和时间戳将一致。最后,主恢复节点会调用 DatanodeProtocol.commitBlock Synchronization() 向名字节点报告这次租约恢复的结果。
在这里插入图片描述

现在我们看一下数据块同步的提交方法 commitBlockSynchronization()commitBlockSynchronization() 方法用于将进行了租约恢复的数据节点上的副本信息与名字节点上的数据块信息同步。这个方法的参数也比较多,其中 lastblock 是被恢复的数据块,newgenerationstamp 是租约恢复以后新的时间戳,newlength 是租约恢复以后副本的长度,closeFile 用于指示是否关闭数据块对应的 HDFS文件,deleteblock 用于指示是否直接删除这个数据块,newtargets 存储了租约恢复后保存这个数据块副本的数据节点列表,newtargetstorages 保存了数据节点的存储信,息。

在数据块恢复过程中,如果发现数据流管道中并不存在这个副本或者所有副本的长度都为0,则可以不用进行租约恢复操作,直接删除这个数据块即可,这时主恢复节点会将 deleteblock 字段设置为 ture, commitBlockSynchronization() 方法会从 Namenode 中删除这个数据块,然后关闭文件;否则,commitBlockSynchronization() 方法进行数据块更新操作,更新 Namenode 上数据块的时间戳和长度,使 Namenode 上的数据块信息与 Datanode 上进行租约恢复后的副本一致。由于可能只有部分数据节点参与租约恢复,所以还需要更新 DatanodeStoragelnfo 上的数据块信息,以及 INodeFile 中的数据块信息。
完成了 commitBlockSynchronization() 方法,Namenode 上数据块的信息与 Datanode 上的副本信息也就一致了,这时整个租约恢复流程也就结束了。

租约恢复 - 其他方式发起

租约恢复除了可以由 LeaseManager.Monitor 线程发起外,如图3-53 所示,还有以下三种情况会调用 FSNamesystem.recoverLeaselnternal() 方法触发租约恢复操作,这三种情况调用 recoverLeaselnternal() 的不同之处在于 force 字段的赋值不同。
客户端通过 ClientProtocol.recoverLease() 远程方法发起租约恢复,最终会由 FSNamesystem.recoverLeaselnternal() 响应,这里会将 force 字段置为 true,也就是强制执行 internalReleaseLease() 方法关闭文件并释放租约,而不用判断租约是否超过了软限制时间。

客户端通过 startFilelnternal() 打开一个文件以进行写操作,这时候会调用 recoverLeaselinternal() 方法检查是否有别的客户端打开了这个文件,以防止多个客户端同时写这个文件。如果有别的客户端打开了这个文件,recoverLeaseInternal() 方法会抛出 AlreadyBeingCreatedException 异常。这里的 force 字段设置为 false,方法会判断原租约持有者是否已经软超时(softLimit),如果超时则进行租约恢复操作释放租约并关闭文件,为文件写操作做准备。

客户端通过 appendFilelnternal() 打开文件进行追加写操作与 startFilelnternal()是同一个道理,调用 recoverLeaselnternal() 方法检查是否有别的客户端同时打开了这个文件。

本文内容结合自 《Hadoop 2.X HDFS 源码剖析》以及自己的理解

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

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

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

相关文章

CloudCompare插件开发之点云如何创建、保存并显示?

文章目录0.引言1.创建插件工程2.代码编写3.显示点云4.保存点云0.引言 CloudCompaer是一款优秀的开源软件,在点云处理时可以根据实际要求开发合适的插件,在实际使用中,创建点云、保存点云、显示点云的操作较为基础,为了使这些操作得…

施工组织设计合集

34-6 施工组织设计02017-年亲曼旗大镇市政道路及广场公园园林绿化工程(第一.A1-1五中教学楼施工组织设计A2施工组织设计(方案) 报审表hasuploaded-中建施|组织设计 (22P)安徽大包庄125万吨疏铁矿斜坡道施工组织设计 (修改)宝山万科四季花城施T组织设计 (126P)对税信息培训中心装…

软件测试,月薪还没过万的进来看

目录 前言 一、技能提升 二、多语言掌握 三、团队协作 四、持续学习 五、提高测试效率 六、质量保障 七、职业发展 八、总结 前言 在当今IT行业中,软件测试是一个不可或缺的环节。随着互联网和移动应用的发展,对软件质量的要求也越来越高。因此…

前后端分离架构

前后端分离架构介绍 前后端分离已成为互联网项目开发的业界标准使用方式,将前端和后端的开发进行解耦。并且前后端分离会为以后的大型分布式架构、微服务架构、多端化服务(各种客户端,比如浏览器、车载终端、安卓、IOS等)打下坚实…

[Netty] FastThreadLocal (十四)

文章目录1.FastThreadLocal介绍2.FastThreadLocal分析3.FastThreadLocal结构分析4.FastThreadLocal方法分析4.1 FastThreadLocal.get()4.2 FastThreadLocal.set()1.FastThreadLocal介绍 FastThreadLocal是Netty中常用的一个工具类, FastThreadLocal所使用的InternalThreadLoca…

[架构之路-159]-《软考-系统分析师》-10-系统分析-6-现有业务流程分析, 系统分析最核心的任务

目录 第 10章 现有系统 分 析 1 0 . 6 现有业务流程分析 10.6.1 业务流程分析槪述 1 . 业务流程分析的步骤 2 . 业务流程分析的方法 10.6.2 业务-流程图TFD 1. T F D 的基本符号 2. TFD的绘制 10.6.3 业务 - 活动图 10.6.4 业务流程建模BPM 1. B P M 概述 2 . 标杆…

Pytest自动化测试框架一些常见的插件

Pytest拥有丰富的插件架构,超过800个以上的外部插件和活跃的社区,在PyPI项目中以“ pytest- *”为标识。 本篇将列举github标星超过两百的一些插件进行实战演示。 插件库地址:http://plugincompat.herokuapp.com/ 1、pytest-html&#xff1…

python机器学习决策树和SVM向量机算法实现红酒分类

1、红酒数据介绍 经典的红酒分类数据集是指UCI机器学习库中的Wine数据集。该数据集包含178个样本,每个样本有13个特征,可以用于分类任务。 具体每个字段的含义如下: alcohol:酒精含量百分比 malic_acid:苹果酸含量&a…

中科大ChatGPT学术镜像小白部署教程,全民都可以拥抱AI

docker…不会用…python不会用…服务器默认python版本3.6不会升级…代理也不会配置…各种命令不会用… 那么下面就是最简单办法,点点点即可【希望有帮助?】 文章目录一、体验镜像地址二、 基本配置2.1 config.py文件2.2 main.py文件三、下载项目四、项目…

FRP内网穿透配置

FRP内网穿透(WIN) 官方文档:点击进入 1.下载地址:点击进入 2.linux 压缩命令:tar -zxvf 包名,即可! 3.linux配置服务端(frps) [common] bind_addr0.0.0.0 # frp监听的…

【NLP实战】基于Bert和双向LSTM的情感分类【下篇】

文章目录前言简介第一部分关于pytorch lightning保存模型的机制关于如何读取保存好的模型完善测试代码第二部分第一次训练出的模型的过拟合问题如何解决过拟合后记前言 本文涉及的代码全由博主自己完成,可以随意拿去做参考。如对代码有不懂的地方请联系博主。 博主…

TCP协议与UDP协议

1.TCP协议特点 1.1连接的建立与断开 TCP协议提供的是:面向连接、可靠的、字节流服务。使用TCP协议通信的双发必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。TCP连接是全…

从C语言到C++(第一章_C++入门_下篇)内联函数+auto关键字(C++11)+范围for +nullptr

目录 1. 内联函数 1.1 内联函数的概念 1.2 内联函数的特性 1.3 宏的优缺点和替代方法 2. auto关键字(C11) 2.1 改版前的auto 2.2 改版后的auto 2.3 auto 的使用场景 2.3.1处理很长的数据类型 2.3.2 auto 与指针结合起来使用: 2.4…

第2章 数据的类型

第2章 数据的类型 文章目录第2章 数据的类型2.2 为什么要进行区分2.3 结构化数据和非结构化数据案例:数据预处理字数/短语数特殊符号文本相对长度文本主题2.4 定量数据和定性数据2.4.1 案例:咖啡店数据2.4.2 案例:世界酒精消费量2.4.3 更深入…

4.18、TCP滑动窗口

4.18、TCP滑动窗口1.滑动窗口的介绍2.滑动窗口通信的例子1.滑动窗口的介绍 滑动窗口(Sliding window)是一种流量控制技术。早期的网络通信中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道网络拥塞状况,同时发送数…

客户案例 | 迎接智能化浪潮,传统水厂数字化势在必行

关键发现 客户痛点:传统水厂业务离散,无法实现数据实时同步,为收集和分析处理数据并辅助决策带来障碍。需要智能化管理系统帮助水厂提升管理效率,优化管理流程,实现数字化、智能化的目标。 解决方案:天津腾…

你说你还不会Redis?别怕,今天带你搞定它!

Redis 前言 本文章是我学习过程中,不断总结而成,篇幅较长,可以根据选段阅读。 全篇17000字,图片 十三 张,预计用时1小时。 认识Redis 什么是Redis? 要使用一门技术,首先要知道这门技术是什…

pytorch进阶学习(三):在数据集数量不够时如何进行数据增强

对图片数据增强,可以对图片实现: 1. 尺寸放大缩小 2. 旋转(任意角度,如45,90,180,270) 3. 翻转(水平翻转,垂直翻转) 4. 明亮度改变(变…

一零五五、mysql8.0高版本数据导入5.6低版本通解

背景 今日想将本机的mysql(8.0)中的数据库文件导出到远程服务器中的mysql(5.6)中,刚开始用source 一直报一大串ERROR,由于数据量比较大,那就直接用图形化工具导吧,连接上远程数据库&…

【常见CSS扫盲之渐变效果】好看的24种CSS渐变效果汇总(附源码)

【写在前面】web开发过程中,页面背景色想要一个渐变的效果很多时候网上一找全是官网那种很丑的色系,尤其是一些按钮和一些大背景色时候,不能搞得很yellow,今天我就做个工具人给大家罗列一些我在工作过程中总结的一些好看的渐变效果…