HDFS的standby节点启动过慢原因分析以及应对策略

news2024/9/30 17:31:58

HDFS的standby节点启动过慢原因分析以及应对策略

  • 1. NN启动大致流程
  • 2. Editlog日志清理策略
    • 2.1 为什么需要合并editlog?
    • 2.2 什么时候删除editlog?
  • 3. NN启动的日志加载策略
  • 4. Standby启动慢应对策略
  • 5. 疑问和思考
    • 5.1 如何人工阅读editlog文件的内容?
    • 5.2 checkpoint的触发策略是什么?
    • 5.3 如果删除editlog失效导致保存过多的editlog,如果nn重启,启动过程是否会很长?
  • 6. 参考文档

在hdfs的nn重启过程时,以standby的方式进行启动,其中当前节点的fsimage和active节点的editlog数量对启动时间起到关键性的影响。本问题探讨hdfs的active节点正常,当standby节点重启时重启过慢的原因分析以及应对的策略。


为了分析出standby节点启动慢的原因,有必要分析和了解nn启动过程中在做什么事情,才能进一步分析慢在哪里,以及怎么优化。

1. NN启动大致流程

这里不探讨nn启动过程中复杂的代码逻辑实现,梳理整体上nn启动时,nn在能处理client的请求之前必须完成以下几步:

  1. 从fsimage文件中读取系统metadata
  2. 读取edit logs并把记录在其中的操作合并到系统metadata中去
  3. 生成一个新的checkpoint(新的fsimage必须和旧fsimage加上edit log上操作保持一致)
  4. 保持safe mode直到Datanodes上报足够数量的block信息
  5. 节点状态升级为standby,集群状态恢复,可以给客户端提供服务

图形如下

启动服务
加载fsimage
拉取editlog进行数据合并
进行checkpoint
通知active拉取fsimage
safe mode 上报block
启动完成

说明

  • 启动时会调用jn的rpc接口拉取editlog进行合并,值得注意的是,editlog信息并不会写入到本地的editlog文件中而是加载到当前节点的内存中进行数据合并,因此standby节点的editlog会被active节点少
  • standby完成checkpoint后生成fsimage文件后通知acrive节点,active节点通过jn的GET接口拉取fsimage,完成checkpoint同步
  • editlog合并、checkpoint生成fsimage依赖机器的内存、磁盘io性能,并且如果需要合并的editlog文件很多,就会导致启动过程很慢

根据生产经验,在大多数情况下,造成nn启动慢的原因,是在拉取editlog进行数据合并环节耗时过多,针对该问题进行重点分析。

2. Editlog日志清理策略

在HA架构下,fsimage + checkpoint后的editlog组成了完整的数据,但是不代表hdfs的nn节点只保存checkpoint后的editlog。事实上,nn拥有自己的保存策略。在讨论这个问题前,我觉得有必要回顾一下为什么需要合并editlog以及合并editlog的策略是什么。

2.1 为什么需要合并editlog?

在client写数据是,在一致性流程中我们在HDFS高可用架构涉及常用功能整理进行了梳理,editlog会通过append的方式记录数据写入的相关操作,在获得极致的写入性能同时,却牺牲了数据的组织性,因此难以通过查询editlog的方式组织数据结构。这就会导致一个问题,editlog持续写入,如果不进行数据合并,就会导致editlog越来越多,最后难以管理,特别是重启后,需要重新回放所有的editlog,这是难以接受的。所以通过合并editlog的方式(过程叫checkpoint),生产fsimage。为了减少active的压力,合并editlog的工作是交给standby负责的。

大体上的checkpoint流程如下
在这里插入图片描述

2.2 什么时候删除editlog?

之前我一直以为,nn是在standby完成checkpoint,active将fsimage同步完成后会自行删除editlog,减少active的过期的editlog。直到我重新做了认真整理了checkpoint环节并阅读了部分代码后,发现checkpoint和删除editlog策略是两件不相干的事儿

editlog日志的删除,内部维护了特定的日志删除策略。主要的代码如下

/**
   void purgeOldStorage(NameNodeFile nnf) throws IOException {
    FSImageTransactionalStorageInspector inspector =
        new FSImageTransactionalStorageInspector(EnumSet.of(nnf));
    storage.inspectStorageDirs(inspector);

    long minImageTxId = getImageTxIdToRetain(inspector);
    purgeCheckpointsOlderThan(inspector, minImageTxId);
    
    if (nnf == NameNodeFile.IMAGE_ROLLBACK) {
      // do not purge edits for IMAGE_ROLLBACK.
      return;
    }

    // If fsimage_N is the image we want to keep, then we need to keep
    // all txns > N. We can remove anything < N+1, since fsimage_N
    // reflects the state up to and including N. However, we also
    // provide a "cushion" of older txns that we keep, which is
    // handy for HA, where a remote node may not have as many
    // new images.
    //
    // First, determine the target number of extra transactions to retain based
    // on the configured amount.
    long minimumRequiredTxId = minImageTxId + 1;
    //最小的日志事务id为: 最小需要保留的事务txid减去需要额外保留的事务id,其中minimumRequiredTxId为检查点镜像文件的最后一条事务id,本质上就是保留numExtraEditsToRetain条事务。
    long purgeLogsFrom = Math.max(0, minimumRequiredTxId - numExtraEditsToRetain);
    
    //edit log的文件输入流
    ArrayList<EditLogInputStream> editLogs = new ArrayList<EditLogInputStream>();
    //填充
    purgeableLogs.selectInputStreams(editLogs, purgeLogsFrom, false, false);
    //排序,优先比较第一条事务txid,然后比较最后一条事务txid
    Collections.sort(editLogs, new Comparator<EditLogInputStream>() {
      @Override
      public int compare(EditLogInputStream a, EditLogInputStream b) {
        return ComparisonChain.start()
            .compare(a.getFirstTxId(), b.getFirstTxId())
            .compare(a.getLastTxId(), b.getLastTxId())
            .result();
      }
    });

    // Remove from consideration any edit logs that are in fact required.
    //如果edit log文件的第一个事务txid比最小需要保留的事务txid大,那么该edit log需要保留,从待editLogs list中移除。
    while (editLogs.size() > 0 &&
        editLogs.get(editLogs.size() - 1).getFirstTxId() >= minimumRequiredTxId) {
      editLogs.remove(editLogs.size() - 1);
    }
    
    // Next, adjust the number of transactions to retain if doing so would mean
    // keeping too many segments around.
    //如果editLogs list的条数比需要保留的最大edits文件数多,那么能保留的最小事务id  purgeLogsFrom 需要扩大,将purgeLogsFrom 置为该日志的文件事务txid
    //如果了解前因后果的话,需要清除的日志由两个参数控制,需要保留的事务数量及需要保留的日志文件数,两个是且的关系,只有两个条件都满足的日志才会保留,有一个不满足就会删除,这里其实就是当日志文件数大于需要保留的日志文件数时,多余的日志文件数需要清除。
    while (editLogs.size() > maxExtraEditsSegmentsToRetain) {
      purgeLogsFrom = editLogs.get(0).getLastTxId() + 1;
      editLogs.remove(0);
    }
    
    // Finally, ensure that we're not trying to purge any transactions that we
    // actually need.
    //最后确认下,本次清除的事务id必须比最低要求低,不然抛出异常。
    if (purgeLogsFrom > minimumRequiredTxId) {
      throw new AssertionError("Should not purge more edits than required to "
          + "restore: " + purgeLogsFrom + " should be <= "
          + minimumRequiredTxId);
    }
    //调用方法清除,这个前文已经将了
    purgeableLogs.purgeLogsOlderThan(purgeLogsFrom);
  }

更多细节不在展开,总结下来,nn删除editlog主要由2个策略决定

  • 保留 numExtraEditsToRetain 条事务
  • 保留 maxExtraEditsSegmentsToRetain 个edit log日志文件

两个策略独立运行,只要有一个条件不满足,日志就会被删除。

查看源码得知,

  • numExtraEditsToRetain对应的参数为 dfs.namenode.num.extra.edits.retained(默认值1000000)
  • maxExtraEditsSegmentsToRetain对应的参数为 dfs.namenode.max.extra.edits.segments.retained(默认值10000)

所以整体总结过来的策略是,editlog的删除策略是

  • 最多保留dfs.namenode.max.extra.edits.segments.retained(默认值10000)+ n (n跟fsimage的文件个数有关)个editlog,如果nn的事务增长较快,由于只保留dfs.namenode.num.extra.edits.retained(默认值1000000)条事务,因此editlog数量可能会少于dfs.namenode.max.extra.edits.segments.retained(默认值10000)个。

另外,可以从fsimage的名称可以获取最小的事务id,比如fsimage_000000000096796869,对应的最小事务id是000000000096796869,往前保留1000000个事务,即从95796870开始,事务ID比这个小的editlog文件都会被删除(包含95796870的editlog会被保留,即便该editlog文件的事务ID可能会比95796870小
在这里插入图片描述
在查看hadoop的官方hdfs-default.xml文档获得相关配置的解释。

名称默认值description翻译
dfs.namenode.num.extra.edits.retained1000000The number of extra transactions which should be retained beyond what is minimally necessary for a NN restart. It does not translate directly to file’s age, or the number of files kept, but to the number of transactions (here “edits” means transactions). One edit file may contain several transactions (edits). During checkpoint, NameNode will identify the total number of edits to retain as extra by checking the latest checkpoint transaction value, subtracted by the value of this property. Then, it scans edits files to identify the older ones that don’t include the computed range of retained transactions that are to be kept around, and purges them subsequently. The retainment can be useful for audit purposes or for an HA setup where a remote Standby Node may have been offline for some time and need to have a longer backlog of retained edits in order to start again. Typically each edit is on the order of a few hundred bytes, so the default of 1 million edits should be on the order of hundreds of MBs or low GBs. NOTE: Fewer extra edits may be retained than value specified for this setting if doing so would mean that more segments would be retained than the number configured by dfs.namenode.max.extra.edits.segments.retained.应该保留的额外事务的数量超出了 NN 重新启动所需的最低限度。它不会直接转换为文件的年龄或保存的文件数量,而是转换为事务的数量(这里“编辑”是指事务)。一个编辑文件可能包含多个事务(编辑)。在检查点期间,NameNode 将通过检查最新的检查点事务值减去此属性的值来确定要保留的编辑总数。然后,它扫描编辑文件以识别不包括计算范围的保留交易的旧文件,并随后清除它们。保留对于审计目的或 HA 设置很有用,其中远程备用节点可能已离线一段时间并且需要保留更长的保留编辑积压才能重新开始。通常,每次编辑大约为几百字节,因此默认的 100 万次编辑应该是数百 MB 或低 GB 的数量级。注意:如果这样做意味着保留的段数多于 dfs.namenode.max.extra.edits.segments.retained 配置的数量,则保留的额外编辑可能少于为此设置指定的值。
dfs.namenode.num.checkpoints.retained2最多保存2个fsimage文件

3. NN启动的日志加载策略

nn启动时会加载本地的fsimage,然后通过jn下载editlog进行数据回放,但是如果nn的editlog清理策略不生效,保留了很长时间以前的editlog,standby重启后,到底是把active节点的所有editlog都下载下来回放还是会根据本地的fsimage下载相应的editlog(fsimage最小事务之后的editlog)进行回放?也就是说,active如果保留了过多的editlog,是否会对standby的启动流程是否有影响?

为了解答这个疑问,我自己搭建了一个hdfs集群,并进行模拟和验证,观察相关的日志情况如下

nn2节点(standby)重启,相关日志如下,nn2加载了fsimage_0000000000000002066,并记录当前的txid=0000000000000002066,并开始从txid=2067进行下载,因此直接忽略txid=2066的editlog文件。
在这里插入图片描述
可以得出结论

  • standby重启后,会根据fsimage计算最小的txid,并从最小txid开始下载editlog,因此active节点如果保存了过多的editlog并不会干扰standby的启动过程。
  • 如果standby本地的fsimage版本过老,就会需要从nn1下载大量的editlog进行数据合并,需要消耗很长时间
  • 正常情况下,active最多保存dfs.namenode.max.extra.edits.segments.retained(默认值10000)+ n (n跟fsimage的文件个数有关)个editlog,如果standby宕机时间过久,本地的fsimage + active保留的editlog,有可能无法完成数据回放,会出现数据丢失。

4. Standby启动慢应对策略

如果standby启动过慢,原因是由于fsimage版本过老,应对的策略应该是从active节点同步最新的fsimage,从而减少下载editlog日志。

如下2种方式均可

  1. 将active节点的fsimage拷贝给standby节点,在启动standby节点
  2. 执行命令同步元数据后,在启动standby节点
hdfs namenode -bootstrapStandby

如果standby节点宕机时间过长,active节点由于没有standby节点进行checkpoint,可能fsimage的版本很低,可以在启动standby节点前手动执行savepoint,在同步fsimage。但是需要注意,手动执行checkpoint需要先进入安全模式,此时客户端是不能读写的,对业务有影响,需要业务低峰期执行。

# 进入安全模式
hdfs dfsadmin -safemode enter

# 执行checkpoint
hdfs dfsadmin -saveNamespace
hdfs dfsadmin -saveNamespace

# 离开安全模式
hdfs dfsadmin -safemode leave

# standby同步元数据
hdfs namenode -bootstrapStandby

5. 疑问和思考

5.1 如何人工阅读editlog文件的内容?

可以通过hdfs提供的工具进行读取

hdfs oev -i edits_0000000000000157832-0000000000000158267 -o test_edits.xml
# -i 为输入edits文件地址
# -o 为输出的xml地址

cat  test_edits.xml

在这里插入图片描述

5.2 checkpoint的触发策略是什么?

触发进行checkpoint的时机由这么几个配置项决定

dfs.namenode.checkpoing.check.period

检测是否满足上面两个条件的时间间隔,默认值为60秒。即1分钟检查一次。

dfs.namenode.checkpoint.period

执行checkpoint的最小时间间隔,默认为3600秒,即1小时。

dfs.namenode.checkpoint.txns

触发checkpoint的事务数,默认值为1000000。

上述两个条件只要符合其一,则执行checkpoint。
也就是说,3600s内一定会触发一次checkpoint,如果集群的写频繁,满足1000000条事务(还没到3600s)就会触发checkpoint

5.3 如果删除editlog失效导致保存过多的editlog,如果nn重启,启动过程是否会很长?

不一定。启动过程时,依赖本地的fsimage,通过fsimage计算最小txid,并基于最小txid加载回放editlog,通常回放editlog的多少对启动过程的时长有很大的影响。

因此,如果standby进行checkpoint的流程正常,fsimage的版本比较高,nn启动过程也是比较快的。
如果standby进行checkpoint的流程不正常,fsimage的版本比较低,nn启动过程就会比较慢。

6. 参考文档

  • hadoop edits日志不删除现象排查
  • HDFS——fsimage

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

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

相关文章

IDEA jdk版本切换问题

打开 IntelliJ IDEA 的 Project Structure&#xff08;快捷键通常是 Ctrl Alt Shift S&#xff09;。 转到 Project Settings > Modules。 选择相应的模块&#xff0c;然后在 Sources 标签页下&#xff0c;查看 Language level 是否设置为 自己需要的jdk版本语言。 接…

YOLOv8训练自己的数据集,通过LabelImg

记录下labelImg标注数据到YOLOv8训练的过程,其中容易遇到labelImg的坑 数据集处理 首先在mydata下创建4个文件夹 images文件夹下存放着所有的图片&#xff0c;包括训练集和测试集等。后续会根据代码进行划分。 json文件夹里存放的是labelImg标注的所有数据。需要注意的是&…

qtcreator使用qwt库

先配置好.pro文件&#xff0c;再去ui界面拖拽控件 ui界面会更改配置&#xff0c;故顺序错一个&#xff0c;就凉了&#xff0c;重来吧 准备&#xff1a;库&#xff0c;库头文件 库文件&#xff1a;路径如下 头文件&#xff1a;路径如下 鼠标->右键 &#xff08;有些不用勾…

读元宇宙改变一切笔记13_治理与管理

1. 元宇宙的经济价值 1.1. 元宇宙的价值最终将“超过”物理世界 1.2. 人们之所以对低延迟网络进行投资&#xff0c;是因为有一些体验需要元宇宙&#xff1a;同步实时渲染的虚拟世界、AR和云游戏流 1.3. 在大多数情况下&#xff0c;数字经济并不是什么新鲜事 1.3.1. 数字经济…

【算法】北极通讯网络(Kruskal)

题目 北极的某区域共有 n 座村庄&#xff0c;每座村庄的坐标用一对整数 (x,y) 表示。 为了加强联系&#xff0c;决定在村庄之间建立通讯网络&#xff0c;使每两座村庄之间都可以直接或间接通讯。 通讯工具可以是无线电收发机&#xff0c;也可以是卫星设备。 无线电收发机有…

【shell-10】shell实现的各种kafka脚本

kafka-shell工具 背景日志 log一.启动kafka->(start-kafka)二.停止kafka->(stop-kafka)三.创建topic->(create-topic)四.删除topic->(delete-topic)五.获取topic列表->(list-topic)六. 将文件数据 录入到kafka->(file-to-kafka)七.将kafka数据 下载到文件-&g…

Oracle RAC集群日志

文章目录 一、DB日志1、日志所在位置介绍2、知识介绍 二、ASM日志1、日志所在位置介绍2、知识介绍 三、CRS日志1、日志所在位置介绍2、知识介绍 四、RAC相关日志详细总结 一、DB日志 DB日志也就是数据库日志&#xff0c;全称Oracle Database Logs 1、日志所在位置介绍 日志位…

【计算机图形学】实验五 一个简单的交互式绘图系统(实验报告分析+截图+源码)

可以先看一看这篇呀~【计算机图形学】专栏前言-CSDN博客https://blog.csdn.net/m0_55931547/article/details/135863062 目录 一、实验目的 二、实验内容

Transformer and Pretrain Language Models3-6

Pretrain Language Models预训练语言模型 content&#xff1a; language modeling&#xff08;语言模型知识&#xff09; pre-trained langue models(PLMs&#xff09;&#xff08;预训练的模型整体的一个分类&#xff09; fine-tuning approaches GPT and BERT&#xff08;…

银行数据仓库体系实践(3)--数据架构

狭义的数据仓库数据架构用来特指数据分布&#xff0c;广义的数据仓库数据架构还包括数据模型、数据标准和数据治理。即包含相对静态部分如元数据、业务对象数据模型、主数据、共享数据&#xff0c;也包含相对动态部分如数据流转、ETL、整合、访问应用和数据全生命周期管控治理。…

Angular组件(一) 分割面板ShrinkSplitter

Angular组件(一) 分割面板ShrinkSplitter 前言 分割面板在日常开发中经常使用&#xff0c;可将一片区域&#xff0c;分割为可以拖拽整宽度或高度的两部分区域。模仿iview的分割面板组件&#xff0c;用angular实现该功能&#xff0c;支持拖拽和[(ngModel)]双向绑定的方式控制区…

为什么 FPGA 比 CPU 和 GPU 快?

FPGA、GPU 与 CPU——AI 应用的硬件选择 现场可编程门阵列 (FPGA) 为人工智能 (AI) 应用带来许多优势。图形处理单元 (GPU) 和传统中央处理单元 (CPU) 相比如何&#xff1f; 人工智能&#xff08;AI&#xff09;一词是指能够以类似于人类的方式做出决策的非人类机器智能。这包…

Excel 2019 for Mac/Win:商务数据分析与处理的终极工具

在当今快节奏的商业环境中&#xff0c;数据分析已经成为一项至关重要的技能。从市场趋势预测到财务报告&#xff0c;再到项目管理&#xff0c;数据无处不在。而作为数据分析的基石&#xff0c;Microsoft Excel 2019 for Mac/Win正是一个强大的工具&#xff0c;帮助用户高效地处…

77 C++对象模型探索。虚函数- 从静态联编,动态联编出发,分析 虚函数调用问题探究

什么叫做单纯的类&#xff1a; 比较简单的类&#xff0c;尤其不包括 虚函数 和虚基类。 什么叫不单纯的类&#xff1a; 从上一章的学习我们知道&#xff0c;在某些情况下&#xff0c;编译器会往类内部增加一些我们看不见但是真实存在的成员变量&#xff0c;例如vptr&#xff…

matlab appdesigner系列-图窗工具2-工具栏

工具栏&#xff0c;就是一般在任意软件界面上方的工具菜单栏 示例&#xff1a;工具菜单绘制正弦函数 操作步骤如下&#xff1a; 1&#xff09;将坐标区和工具栏拖拽到画布上 2)点击工具栏的号&#xff0c;可以看到可以添加2种工具&#xff0c;按钮工具和切换工具&#xff0c…

【JavaScript权威指南第七版】读书笔记速度

JavaScript权威指南第七版 序正文前言&#xff1a;图中笔记重点知识第1章 JavaScript简介第一章总结 第2章 词法结构注释字面量标识符和保留字Unicode可选的分号第二章总结 第3章 类型、值和变量【重要】原始类型特殊类型第三章总结 第4章 表达式与操作符表达式操作符条件式调用…

【量化交易】股市舞者:小明的撮合交易之旅

马西森AES撮合交易系统 在繁华的都市中&#xff0c;小明&#xff0c;一个普通的青年&#xff0c;刚刚赚到了人生的第一桶金——20万。这笔意外的财富&#xff0c;点燃了他对股市的强烈兴趣。他开始如饥似渴地学习金融知识&#xff0c;钻研各种交易策略。 一天&#xff0c;小…

基于 java+springboot+mybatis电影售票网站管理系统前台+后台设计和实现

基于 javaspringbootmybatis电影售票网站管理系统前台后台设计和实现 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承…

微软 Power Apps Canvas App 画布应用将上传的附件转化为base64编码操作

微软 Power Apps Canvas App 画布应用将上传的附件结合Power Automate转化为base64编码操作 在使用canvas app的过程中&#xff0c;我们有时需要将上传的文件转换为base64存入数据库或者&#xff0c;调用外部接口传参&#xff0c;那么看下如何将文件转化为base64编码格式。 首先…

金智易表通构建学生缴费数据查询+帆软构建缴费大数据报表并整合到微服务

使用金智易表通挂接外部数据,快速建设查询类服务,本次构建学生欠费数据查询,共有3块设计,规划如下: 1、欠费明细查询:学校领导和财务处等部门可查询全校欠费学生明细数据;各二级学院教职工可查询本二级学院欠费学生明细数据。 2、大数据统计报表:从应收总额、欠费总额…