HDFS QJM原理分析

前言最近在重新研读HDFS QJM的细节实现,所谓“温故而知新”,感觉还是收获不少。之前笔者曾简单地翻译过HDFS QJM的设计文档,感兴趣的同学可以点此链接:HDFS QJM的架构设计。本文笔者打算挑选其中的一些细节要点,进程阐述。背景在HDFS QJM出现之前,editlog的一种推荐存储方式是基于NAS网络存储设备。这种方式会带来一些局限性:对于特定硬件的要求。...
摘要由CSDN通过智能技术生成

前言


最近在重新研读HDFS QJM的细节实现,所谓“温故而知新”,感觉还是收获不少。之前笔者曾简单地翻译过HDFS QJM的设计文档,感兴趣的同学可以点此链接:HDFS QJM的架构设计。本文笔者打算挑选其中的一些细节要点,进程阐述。

背景


在HDFS QJM出现之前,editlog的一种推荐存储方式是基于NAS网络存储设备。这种方式会带来一些局限性:

  • 对于特定硬件的要求。
  • 部署操作的复杂性。

这么做的一个理由是它可以做到一定的高可用性。但是它的劣势是大于它所带来的好处的,于是社区提出了在软件层面来做这样的事,提出了以下3点基本要求:

  • 没有特定硬件的要求。
  • 软件层Fencing机理的实现。(Fencing的操作在这里是为了防止早些的writer对象进行写操作)。
  • 无单点问题,所有editlog都是完全高可用的。

基于Quorum的管理方法


QJM的全称是Quorum Journal Manager,管理的节点为JournalNode,NameNode往这些JournalNode上读/写editlog信息。在每次的写操作过程中,这些信息会发送到所有的JournalNode节点中,关键的一点是,它并不需要要求所有节点成功的回复信息,只需要多数以上(这里指半数以上)的成功信息即可。这就是Quorum原理的核心所在。

Quorum Journal管理的主执行流程


QuorumJournalManager内部控制editlog的写入步骤如下:

1.停止之前的writer对象。当前写editlog的writer对象在写的时候,必须保证之前的writer对象没有在写editlog信息。
2.恢复上一次未写入完全的editlog信息内容。因为存在一种可能性,早期的writer对象存在写失败的可能性,造成各个JournalNode上写入的editlog的内容长度不同,这里需要做一个数据同步恢复。这点会在下文中具体分析到。
3.开始写入一个新的editlog数据片段。
4.写入editlog信息片段。
5.Finalize(确认)editlog信息成功写入。只要步骤4中的执行结果在多数JournalNode中为成功即可。

下面我们来看其中的2个关键步骤的细节实现。

Fencing Writers


这个步骤的目的,笔者已经阐述过,是为了防止早期的writer对象继续写入editlog信息,造成脏数据的写入。那么问题来了,QJM内部是如何实现这点的呢?答案如下。

每个writer对象变为活跃的时候,QJM为每个writer对象分配一个唯一的epoch数字,这个数字是单调递增的,在QJM的写入过程中,不允许epoch数字小于当前epoch数字的writer对象写入数据。

所以,从上面的内容来看,这里提到了一个重要的变量:epoch数字。我们可以简单理解为“迭代轮次”的概念,比如说第一轮,第二轮,第三轮。。
但是在每次epoch数字的迭代增加中,是有一番讲究的,里面会涉及到协商选择的,细节步骤如下:

a.首先QJM会发送一条请求消息(getJournalState()请求),去获取每个JournalNode上当前的epoch数字值。这个值在JournalNode上被保存在名为lastPromisedEpoch的变量里。
b.QJM收到所有JournalNode返回来的epoch数字后,取出其中的最大值,然后在此值上加1,以此作为新的epoch值。
c.QJM以新的epoch值为内容,向各JournalNode发送newEpoch请求,每个JournalNode收到此请求时,比较自身保存的epoch值(即本地lastPromisedEpoch变量),如果比此值大,则更新本地值。

本地epoch值更新后,会在每次的写操作中被用作其中的一个检测条件,代码如下:

private synchronized void checkRequest(RequestInfo reqInfo) throws IOException {
    // 判断当前请求信息的epoch值是否小于当前的epoch值,如果是则抛出异常
    if (reqInfo.getEpoch() < lastPromisedEpoch.get()) {
      throw new IOException("IPC's epoch " + reqInfo.getEpoch() +
          " is less than the last promised epoch " +
          lastPromisedEpoch.get());
    } else if (reqInfo.getEpoch() > lastPromisedEpoch.get()) {
      // 否则用新的epoch值更新当前epoch值
      updateLastPromisedEpoch(reqInfo.getEpoch());
 
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值