HDFS的高可用HA

HDFS的高可用HA

 在Hadoop2.X之前,Namenode是HDFS集群中可能发生单点故障的节点,每个HDFS集群中只有一个Namenode,一旦这个节点不可用,则整个HDFS集群将处于不可用状态。
 HDFS的高可用HA方案就是为了解决上述问题而产生的,在HA HDFS集群中会同时运行两个Namenode,一个是活动的Active Namenode,另一个是备份的Standby Namenode。Standby Namenode与Active Namenode是实时同步的,当Active Namenode发生故障时而停止服务时,Standby Namenode可以立即切换为活动状态,而不影响HDFS集群的服务。

1.HA架构

 Active Namenode负责执行所有修改命名空间以及删除备份数据块的操作,Standby Namenod执行同步操作以保持与活动节点命名空间的一致性。
 两个Namenode都与一组独立运行的节点JournalNodes通信,当Active Namenode修改了命名空间,会定期将执行的操作记录在editlog中,并写入JNS的多数节点中。Standby Namenode则一直监听JNS上editlog的变化,如果发现editlog有改动,就会读取editlog并与当前的命名空间合并。当发生了错误切换时,Standby Namenode会先从JNS上读取了所有的editlog文件并与命名空间合并,然后才从Standby状态切为Active状态。
 Standby Namenode也保存了实时的数据块存储信息,当发生错误切换时,Standby Namenode不需要等待所有数据节点进行全量块汇报,可以直接切换为Active状态。而Datanode会同时向两个Namenode发送心跳及块汇报,这样当发生故障时,可以马上切换。
在这里插入图片描述
2.脑裂问题

 在HA架构中,没有保证同一时刻只有一个处于Active状态的Namenode,出现了两个Namenode同时修改命名空间的问题,这就是脑裂问题。
 脑裂的HDFS集群会造成数据块的丢失,以及向Datanode下发错误指令等异常情况。
 为预防脑裂情况,HDFS提供了三个级别的隔离机制:
 (1)共享存储隔离:同一时间只允许一个Namenode向JournalNodes写入editlog数据。
 (2)客户端隔离:同一时间只允许一个Namenode响应客户端请求。
 (3)Datanode隔离:同一时间只允许一个Namenode向Datanode下发Namenode指令。

3.HA的实现

 HDFS有两种HA状态切换方式:一种是管理员手动通过命令执行状态切换,另一种是自动状态切换机制触发状态切换。
 手动切换方式是管理员通过执行HA管理命令触发切换操作,底层是由客户端调用HAAdmin类提供的对应方法实现的。而自动状态切换机制,是由ZKFailoverController控制切换流程。这两种情况都会调用RPC接口HAServiceProtocol向Namenode发送HA请求。

(1)手动切换方式
 手动切换方式是管理员通过执行HA管理命令触发切换操作,底层是由客户端调用HAAdmin类提供的对应方法实现的。

HA管理命令
 HA管理命令如下:

hdfs haadmin -transitionToActive
把指定的Namenode转换成Active状态

hdfs haadmin -transitionToStandby
把指定的Namenode转换成Standby状态

hdfs haadmin -failover
在两个Namenode之间进行故障转移

hdfs haadmin -getServiceState
获取指定Namenode的状态

hdfs haadmin -checkHealth
检测指定Namenode的健康状态

HAAdmin
 HAAdmin的runCmd()方法会对管理命令进行判断,对于上面的每个命令会提供专门对应的私有方法。
 比较复杂的是"-failover"命令,也就是进行故障转移和切换Namenode状态的方法。如果第一个Namenode处于Standby状态,这个命令会直接将第二个Namenode转换成Active状态;如果第一个Namenode处于Active状态,这个命令会尝试将第一个Namenode转换成Standby状态,然后开始调方法去停止Active Namenode,直到Active Namenode成功停止了,才会把第二个Namenode转换成Active状态。
 它首先会解析命令行参数,从命令行中提取出执行切换操作的源节点与目标节点,并将这两个节点封装成两个HAServiceTarget对象,而HAServiceTarget实际上包装了发生主从切换的两个Namenode的HAServiceProtocol的代理。然后failover()方法会构造FailoverController对象用于控制主从切换,最后调用FailoverController.failover()执行切换操作。failover()方法会调用HAServiceProtocol的transitionToStandby()以及transitionToActive()方法将源节点切换为Standby状态,将目标节点切换为Active状态,同时在将目标节点切换至Active状态前执行fencing操作。如果目标节点切换Active状态失败,则执行回滚操作。

(2)自动切换方式
 自动状态切换机制,是由ZKFailoverController控制切换流程。它涉及到与ZooKeeper集群的耦合。

(3)OJM方案
 所有的HA实现方案都依赖一个保存editlog的共享存储,这个共享存储必须是高可用的,并且能够被集群中的所有Namenode同时访问。
 HA中Active Namenode和Standby Namenode之间是这样共享editlog文件的,Active Namenode将日志文件写到共享存储上,Standby Namenode实时地从共享存储读取editlog文件,然后合并到Standby Namenode的命名空间中。Hadoop提供了QJM(Quorum Journal Manager)方案来解决HA共享存储的问题。

 QJM方案是基于Paxos算法实现的,其结构如下:
在这里插入图片描述
QJM使用的算法
 HDFS集群中有2N+1个JN存储editlog文件,这些editlog文件是保存在JN的本地磁盘上的。每个JN对QJM暴露RPC接口QJournaleProtocol,允许Namenode读写editlog文件。当Namenode向共享存储写入editlog文件时,它会通过QJM向集群中的所有JN发送写editlog文件请求,当有一半以上的(≥N+1)JN返回写操作成功时即认为该次写成功。集群能容忍最多有N台机器挂掉,如果多于N台挂掉,这个算法就失效了。

使用QJM实现的HA方案的好处
 1.JN进程可以运行在普通的PC上,不用配置专业的共享存储硬件。
 2.不需要单独的fencing机制,其内置了fencing功能。
 3.不存在单点故障,集群中有2N+1个JournalNode,可以允许有N个JournalNode死亡。
 4.JN不会因为其中一台机器的延迟而影响整体的延迟,也不会因为JN数量的增多而影响性能。

4.QJM机制下的读写

(1)互斥机制
 当HA集群发生Namenode异常切换时,需要在共享存储上fencing上一个活动节点以保证该节点不能再向共享存储写入editlog。QJM方案的HA提供了epoch number解决互斥问题。
 epoch number有如下性质:
 1.当一个Namenode变为活动状态时,会分配给它一个epoch number。
 2.每个epoch number都是唯一的,没有任意两个Namenode有相同的epoch number。
 3.epoch number定义了Namenode写editlog文件的顺序。对任意两个Namenode,拥有更大epoch number的Namenode被认为是活动节点。

 当一个Namenode切换为活动状态时,它的QJM会向所有JN发送getJournalState()请求以获取该JN的lastPromisedEpoch变量值,lastPromisedEpoch变量保存了该JN认为的集群中活动的Namenode对应的epoch number值。当QJM接收到集群中多于一半的JN回复后,它会将接收到的最大值加1并保存到myEpoch变量中,之后QJM会调用newEpoch(myEpoch)方法向所有JN发起更新epoch number请求。每个JN比较QJM提交的myEpoch变量与JN保存的lsatPromisedEpoch变量,如果myEpoch较大,将lsatPromisedEpoch更新为myEpoch。如果QJM接收到超过一半的JN返回成功,则设置它的epoch number为myEpoch。

(2)写流程
 Active Namenode会将editlog写入集群中的JN上,QJM按下面的流程执行写操作:
 1.将editlog输出流中缓存的数据写入JN,对于集群中的每一个JN都存在一个独立的线程调用jouranl()向JN写入数据。
 2.当JN收到journal()请求后,JN会执行下面的操作:先验证epoch number是否正确,再确认写入数据对应的txid是否连续,然后将数据持久化到JN的本地磁盘,最后向QJM发送正确的响应。
 3.QJM等待JN的响应,如果多数JN返回成功,则写操作成功;否则写操作失败,QJM抛出异常。

(3)读流程
 Standby Namenode会从JN读取editlog,然后与Standby Namenode的命名空间合并以保持和Active Namenode命名空间的同步。读流程如下:
 1.首先发送请求到集群中的所有JN上
 2.JN接收到这个请求后,会将JN本地存储上保存的所有FINALLZED状态的editlog段落文件信息返回
 3.之后QJM会为所有JN返回的editlog段落文件构造输入流对象,并将这些输入流对象合并到一个对象中,这样Standby Namenode就可以使用这个对象从任意一个JN上读取每个editlog段落了。
 4.如果其中一个JN失败了,输入流对象会自动切换到另一个保存了这个editlog段落的JN上。

(4)恢复流程
 当Namenode发生主从切换时,原来的Standby Namenode会接管共享存储并执行写editlog的操作。Standby Namenode在切换为Active Namenode前,对于共享存储会执行下面的操作:
 1.fencing原来的Active Namenode
 2.恢复正在处理的editlog。由于Namenode发生了主从切换,集群上的正在执行写入操作的editlog数据可能不一致。在这种情况下,要对JN上所有状态不一致的editlog文件执行恢复操作,将他们的数据同步一致,并且将editlog文件转换为FINALIZED状态。
 3.此时不一致的editlog已经完成了恢复,所以原来的Standby Namenode就可以切换为Active Namenode并执行写editlog的操作了。
 4.写editlog,当打开了共享存储上的editlog文件并获得了输出流对象后,就可以向editlog中写入数据了。
 5.当Namenode完成了对一个editlog日志段落的写操作后,提交这个日志段落。

 日志恢复操作又可以分为下面几个阶段:
 1.确定需要执行恢复操作的editlog段落
 当集群中大多数JN都返回了最新的editlog段落的txid,QJM就可以确定出集群中最新的一个正在处理editlog段落的txid,然后QJM就会对这个txid对应的editlog段落执行恢复操作了。
 2.准备恢复
 QJM向集群中的所有JN发送请求,查询执行恢复操作的editlog段落文件在所有JN上的状态。
 3.接受恢复
 QJM接收到JN发回的响应后,会根据恢复算法选择执行恢复操作的源节点。然后QJM会发送RPC请求给每一个JN。接收到这个请求的JN会执行以下操作:首先同步editlog段落文件,如果当前JN磁盘上的editlog段落文件与请求中段落文件的状态不同,则JN会从请求中的url上下载段落文件并替换磁盘上的editlog文件。然后持久化恢复元数据,JN会将执行恢复操作的editlog段落文件的状态、触发恢复操作的QJM的epoch number等信息持久化到JN磁盘上。
 4.完成editlog段落文件
 此时,QJM已经确定集群中大多数JN保存的editlog文件的状态已经一致了,并且JN持久化了恢复信息。这是QJM就可以将这个editlog段落文件转换为FINALIZED状态。

 QJM选择源editlog段落文件的算法为:
 1.FINALIZED状态的editlog段落文件优于in-progress状态的editlog段落文件。
 2.如果存在多个FINALIZED状态的editlog段落文件,则这个文件的文件长度必须一致。
 3.如果都处于in-progress状态,则选择epoch number大的文件。
 4.如果都处于in-progress状态,且epoch number相同,则选择包含事务较多的editlog文件。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

loser与你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值