[root@node01 hadoop]# jps
19425 NameNode
12642 SparkSubmit
23571 NodeManager
13942 JournalNode
14231 DFSZKFailoverController
20042 Jps
25675 YarnSessionClusterEntrypoint
13660 DataNode
13214 QuorumPeerMain
[root@node02 hadoop]# jps
928 NodeManager
8594 DFSZKFailoverController
8355 DataNode
7046 Jps
8454 JournalNode
6283 NameNode
1340 ResourceManager
8189 QuorumPeerMain
复制代码
在 Hadoop 1.0 时代,NameNode 存在单点问题(SPOF,single point of failure ),一旦挂掉,整个 HDFS 都不能访问,而依赖它的 MapReduce、Hive、HBase 等都将没法正常服务。node
一个 NameNode 有单点问题,若是再提供一个 NameNode 做为备份,不是能解决问题?这即是主备模式的思想。继续这个思路,光有备份的 NameNode 够吗?咱们知道 NameNode 上存储的是 HDFS 上全部的元数据信息,所以最关键的问题在于 NameNode 挂了一个,备份的要及时顶上,这就意味着咱们要把全部的元数据都同步到备份节点。好,接下来咱们考虑如何同步呢?每次 HDFS 写入一个文件,都要同步写 NameNode 和其备份节点吗?若是备份节点挂了就会写失败?显然不能这样,只能是异步来同步元数据。若是 NameNode 恰好宕机却没有将元数据异步写入到备份节点呢?那这部分信息岂不是丢失了?这个问题就天然要引入第三方的存储了,在 HA 方案中叫作“共享存储”。每次写文件时,须要将日志同步写入共享存储,这个步骤成功才能认定写文件成功。而后备份节点按期从共享存储同步日志,以便进行主备切换。算法
能够看出,这里的核心是共享存储的实现,这些年有不少的 NameNode 共享存储方案,好比 Linux HA, VMware FT, shared NAS+NFS, BookKeeper, QJM/Quorum Journal Manager, BackupNode 等等。在关于共享存储设备的选择上,由于NFS也会有单点故障问题,目前社区已经把由 Clouderea 公司实现的基于 QJM(Quorum Journal Manager)的方案合并到 HDFS 的 trunk 之中而且做为默认的共享存储实现。shell
基于 QJM 的共享存储系统主要用于保存 EditLog,并不保存 FSImage 文件。FSImage 文件仍是在 NameNode 的本地磁盘上。QJM 共享存储的基本思想来自于 Paxos 算法,采用多个称为 JournalNode 的节点组成的 JournalNode 集群来存储 EditLog。每一个 JournalNode 保存一样的 EditLog 副本。每次 NameNode 写 EditLog 的时候,除了向本地磁盘写入 EditLog 以外,也会并行地向 JournalNode 集群之中的每个 JournalNode 发送写请求,只要大多数 (majority) 的 JournalNode 节点返回成功就认为向 JournalNode 集群写入 EditLog 成功。若是有 2N+1 台 JournalNode,那么根据大多数的原则,最多能够容忍有 N 台 JournalNode 节点挂掉。bash
虽然 Active NameNode 向 JournalNode 集群提交 EditLog 是同步的,但 Standby NameNode 采用的是定时从 JournalNode 集群上同步 EditLog 的方式,那么 Standby NameNode 内存中文件系统镜像有很大的多是落后于 Active NameNode 的,因此 Standby NameNode 在转换为 Active NameNode 的时候须要把落后的 EditLog 补上来。网络
假设 NameNode1 当前为 Active 状态,NameNode2 当前为 Standby 状态。若是某一时刻 NameNode1 对应的 ZKFailoverController 进程发生了“假死”现象,那么 Zookeeper 服务端会认为 NameNode1 挂掉了,根据前面的主备切换逻辑,NameNode2 会替代 NameNode1 进入 Active 状态。可是此时 NameNode1 可能仍然处于 Active 状态正常运行,即便随后 NameNode1 对应的 ZKFailoverController 由于负载降低或者 Full GC 结束而恢复了正常,感知到本身和 Zookeeper 的 Session 已经关闭,可是因为网络的延迟以及 CPU 线程调度的不肯定性,仍然有可能会在接下来的一段时间窗口内 NameNode1 认为本身仍是处于 Active 状态。这样 NameNode1 和 NameNode2 都处于 Active 状态,均可以对外提供服务。架构
这种状况对于 NameNode 这类对数据一致性要求很是高的系统来讲是灾难性的,数据会发生错乱且没法恢复。Zookeeper 社区对这种问题的解决方法叫作 fencing,中文翻译为隔离,也就是想办法把旧的 Active NameNode 隔离起来,使它不能正常对外提供服务。ssh
在进行 fencing 的时候,会执行如下的操做:异步
首先尝试调用这个旧 Active NameNode 的 HAServiceProtocol RPC 接口的 transitionToStandby 方法,看能不能把它转换为 Standby 状态。 若是 transitionToStandby 方法调用失败,那么就执行 Hadoop 配置文件之中预约义的隔离措施,Hadoop 目前主要提供两种隔离措施,一般会选择 sshfence: sshfence:经过 SSH 登陆到目标机器上,执行命令 fuser 将对应的进程杀死; shellfence:执行一个用户自定义的 shell 脚原本将对应的进程隔离;oop
参考文章 zhuanlan.zhihu.com/p/66245906spa