Hadoop HDFS高可用性(HA) 原理篇

Hadoop HA(High Available)经过同时配置两个处于Active/Passive模式的Namenode来解决上述问题,分别叫Active Namenode和Standby Namenode. Standby Namenode做为热备份,从而容许在机器发生故障时可以快速进行故障转移,同时在平常维护的时候使用优雅的方式进行Namenode切换。Namenode只能配置一主一备,不能多于两个Namenode。node

主Namenode处理全部的操做请求(读写),而Standby只是做为slave,维护尽量同步的状态,使得故障时可以快速切换到Standby。为了使Standby Namenode与Active Namenode数据保持同步,两个Namenode都与一组Journal Node进行通讯。当主Namenode进行任务的namespace操做时,都会确保持久会修改日志到Journal Node节点中的大部分。Standby Namenode持续监控这些edit,当监测到变化时,将这些修改应用到本身的namespace。web

当进行故障转移时,Standby在成为Active Namenode以前,会确保本身已经读取了Journal Node中的全部edit日志,从而保持数据状态与故障发生前一致。promise

为了确保故障转移可以快速完成,Standby Namenode须要维护最新的Block位置信息,即每一个Block副本存放在集群中的哪些节点上。为了达到这一点,Datanode同时配置主备两个Namenode,并同时发送Block报告和心跳到两台Namenode。安全

确保任什么时候刻只有一个Namenode处于Active状态很是重要,不然可能出现数据丢失或者数据损坏。当两台Namenode都认为本身的Active Namenode时,会同时尝试写入数据(不会再去检测和同步数据)。为了防止这种脑裂现象,Journal Nodes只容许一个Namenode写入数据,内部经过维护epoch数来控制,从而安全地进行故障转移。session

有两种方式能够进行edit log共享:架构

  1. 使用NFS共享edit log(存储在NAS/SAN)
  2. 使用QJM共享edit log

使用NFS共享存储

这里写图片描述

如图所示,NFS做为主备Namenode的共享存储。这种方案可能会出现脑裂(split-brain),即两个节点都认为本身是主Namenode并尝试向edit log写入数据,这可能会致使数据损坏。经过配置fencin脚原本解决这个问题,fencing脚本用于:svg

  • 将以前的Namenode关机
  • 禁止以前的Namenode继续访问共享的edit log文件

使用这种方案,管理员就能够手工触发Namenode切换,而后进行升级维护。但这种方式存在如下问题:
- 只能手动进行故障转移,每次故障都要求管理员采起措施切换。
- NAS/SAN设置部署复杂,容易出错,且NAS自己是单点故障。
- Fencing 很复杂,常常会配置错误。
- 没法解决意外(unplanned)事故,如硬件或者软件故障。oop

所以须要另外一种方式来处理这些问题:spa

  • 自动故障转移(引入ZooKeeper达到自动化)
  • 移除对外界软件硬件的依赖(NAS/SAN)
  • 同时解决意外事故及平常维护致使的不可用

Quorum-based 存储 + ZooKeeper

QJM(Quorum Journal Manager)是Hadoop专门为Namenode共享存储开发的组件。其集群运行一组Journal Node,每一个Journal 节点暴露一个简单的RPC接口,容许Namenode读取和写入数据,数据存放在Journal节点的本地磁盘。当Namenode写入edit log时,它向集群的全部Journal Node发送写入请求,当多数节点回复确认成功写入以后,edit log就认为是成功写入。例若有3个Journal Node,Namenode若是收到来自2个节点的确认消息,则认为写入成功。3d

而在故障自动转移的处理上,引入了监控Namenode状态的ZookeeperFailController(ZKFC)。ZKFC通常运行在Namenode的宿主机器上,与Zookeeper集群协做完成故障的自动转移。整个集群架构图以下:

这里写图片描述

Namenode使用QJM 客户端提供的RPC接口与Namenode进行交互。写入edit log时采用基于仲裁的方式,即数据必须写入JournalNode集群的大部分节点。

在Journal Node节点上(服务端)

服务端Journal运行轻量级的守护进程,暴露RPC接口供客户端调用。实际的edit log数据保存在Journal Node本地磁盘,该路径在配置中使用dfs.journalnode.edits.dir属性指定。

Journal Node经过epoch数来解决脑裂的问题,称为JournalNode fencing。具体工做原理以下:
1)当Namenode变成Active状态时,被分配一个整型的epoch数,这个epoch数是独一无二的,而且比以前全部Namenode持有的epoch number都高。

2)当Namenode向Journal Node发送消息的时候,同时也带上了epoch。当Journal Node收到消息时,将收到的epoch数与存储在本地的promised epoch比较,若是收到的epoch比本身的大,则使用收到的epoch更新本身本地的epoch数。若是收到的比本地的epoch小,则拒绝请求。

3)edit log必须写入大部分节点才算成功,也就是其epoch要比大多数节点的epoch高。

这里写图片描述

这种方式解决了NFS方式的3个问题:

  • 不须要额外的硬件,使用原有的物理机
  • Fencing经过epoch数来控制,避免出错。
  • 自动故障转移:Zookeeper处理该问题。

使用Zookeeper进行自动故障转移

前面提到,为了支持故障转移,Hadoop引入两个新的组件:Zookeeper Quorum和ZKFailoverController process(简称ZKFC)。

Zookeeper的任务包括:

  • 失败检测:每一个Namnode都在ZK中维护一个持久性session,若是Namnode故障,session过时,使用zk的事件机制通知其余Namenode须要故障转移。
  • Namenode选举:若是当前Activenamenode挂了,另外一个namenode会尝试获取ZK中的一个排它锁,获取这个锁就表名它将成为下一个Active NN。

在每一个Namenode守护进程的机器上,同时也会运行一个ZKFC,用于完成如下任务:

  • Namenode健康健康
  • ZK Session管理
  • 基于ZK的Namenode选举

若是ZKFC所在机器的Namenode健康状态良好,而且用于选举的znode锁未被其余节点持有,则ZKFC会尝试获取锁,成功获取这个排它锁就表明得到选举,得到选举以后负责故障转移,若是有必要,会fencing掉以前的namenode使其不可用,而后将本身的namenode切换为Active状态。