文章大纲:
在 Hadoop 1.x 版本中,是没有 HA 实现方式的,它只有可以看做是冷备份的 SecondaryNameNode 来起到备份作用,因为 2NN 能够协助 NameNode 做一些检查点的工作,能同步磁盘镜像(FSImage)和日志(EditLog). 当 NN 挂掉,2NN 是没有办法立即启动起来继续为集群服务的,需要用手工的方式启动 2NN,这显然会产生服务中断,对业务连续性产生较大影响。
因此 Hadoop 2.x 版本中开始引入 HA 的热备份机制,包括 HDFS(NameNode) HA 和 YARN(ResourceManager) HA. 当主 NN 挂掉后,备 NN 会立即启动进行接管,从而为集群提供不间断的服务,保证集群对外没有任何宕机情况。而 DataNode 和 NodeManager 本身就是被设计为集群模式的,所以不用对他们引入特殊的 HA 机制处理。
1 Zookeeper
Zookeeper 是基于观察者模式设计的分布式管理协作开源框架,为分布式应用提供协调服务,负责接受观察者注册,并通知注册的观察者数据状态的变化。简单来说,就是文件系统及通知机制的组合。
图1-1-1:Zookeeper 工作机制
Zookeeper 集群可以用来保证 Hadoop 集群的高可用,其原理是(HDFS HA 中会作详细讲解):
Hadoop 集群中有两个 NameNode 服务,两个 NN 都会定时给 Zookeeper 发送心跳,告诉 Zookeeper 我还活着,可以提供服务,某一个时间只有一个 NN 是Active 状态,另外一个则是Standby 状态;一旦 Zookeeper 检测不到 Active NN 发送的心跳,就会切换到 Standby 状态的 NN 上,将其设置为 Active 状态。所以集群中总有一个可用的 NN,达到 NN 高可用目的。
1.1 Zookeeper 的特点
- Zookeeper 是由一个 Leader 和多个 Followers 组成的集群
- 只要有半数以上节点存活,Zookeeper 即可正常提供服务
- 集群中的每个 Server 保存一份相同的数据副本,以保证全局数据的一致性
- 来自同一个 Client 的更新请求按其发送顺序依次执行
- 数据更新具有原子性,一次数据更新要么成功,要么失败
- 数据具有实时性,在一定时间范围内,Client 能读到最新的数据
下面的选举机制会进一步阐述前两个特点。
1.2Zookeeper 的节点类型
Zookeeper 的目录结构跟 HDFS 类似,整体上可看作一棵树,每个节点称作zNode,每个 zNode 可存储1MB数据,并可通过其路径唯一标识。
图1-2-1:Zookeeper 目录结构
zNode 的类型分为四类:
- 持久化节点(Persistent):节点创建后一直存在,不会因为创建该节点的 Client 与 Zookeeper 的会话失效而消失。
- 持久化顺序编号节点(Persistent_sequential):这类节点的基本特性和持久化节点是一致的,不同的是,Zookeeper 的每个父节点会为他的第一级子节点维护一份时序,记录每个子节点创建的先后顺序,顺序号是一个单调递增的计数器。
- 临时节点(Ephemeral):节点创建后,其生命周期和 Client 会话绑定,若创建该节点的 Client 与 Zookeeper 的会话失效,这个节点就会自动被清除掉。此类节点下不能创建子节点。
- 临时顺序编号节点(Ephemeral_sequential):这类节点的基本特性和临时节点是一致的,不同的是,此类节点会被父节点维护一份时序,创建的节点带顺序编号。
图1-2-2:Zookeeper 节点类型
1.3 Zookeeper 的选举机制
Zookeeper 集群除了能让 Hadoop 高可用外,其自身也有一套 HA 机制。
Zookeeper 集群机器中会有一个 Leader 和多个 Followers 的角色。因为集群中的 Leader 角色只有一个,因此就会存在单点故障的隐患,而 Zookeeper 的选举机制就是用来解决单点故障隐患,以实现高可用的。
Leader 角色由哪台机器担任不是固定的,而是由内部的选举机制临时产生的。选举的流程是:集群中处于启动的任意一台机器发现集群中没有 Leader 时,就会推荐自己为 Leader,其他机器来同意,当超过半数的机器同意它为 Leader 时,选举结束。
图1-3-1:Zookeeper 选举机制
由此可见,Zookeeper 集群中只要有半数以上的机器存活,集群即可用。因此,Zookeeper 集群适合安装奇数台机器,这样就算当 Leader 机器宕机后,也能很快选举出新的 Leader,保证了 Zookeeper 集群本身的高可用,同时也能避免资源浪费。
1.4 Zookeeper 的数据读写流程
Zookeeper 的数据写入 HA 流程:
- Client 向 Zookeeper 请求写入数据时,要先写入 Leader,若收到请求的机器不是 Leader,则写入数据的请求会转发给 Leader
- Leader 同意写入后,会将请求广播给各个机器,通知 Followers 写入,各机器写入成功后会通知 Leader
- 当 Leader 收到大多数(半数以上)机器写入数据成功,则认为数据写入成功,进而通知接收到请求的机器,因此就算有部分机器宕机,也不会影响数据写入
- 接收请求的机器会进一步通知发出请求的 Client 数据写入成功
图1-4-1:Zookeeper 数据写入流程
Zookeeper 的读取数据 HA 流程:
Client 向 Zookeeper 请求读取数据时,因为 Zookeeper 的全局数据一致性特点,无需通知 Leader,可以直接从任意一台机器上读取数据,因此就算有部分机器宕机,也不会影响数据读取。
2 HDFS HA
HDFS 是单 NameNode 的 Hadoop 非 HA 部署的缺陷在于会存在单点故障问题,若 NameNode 不可用,则会导致整个 HDFS 文件系统不可用。所以需要设计高可用的 HDFS(Hadoop HA)来解决 NameNode 单点故障的问题。
2.1 HDFS HA 架构
在 Hadoop 2.x 版本中,HDFS 架构解决了单点故障问题,其方式是在 HDFS 集群中引入多 NameNode 节点架构,同时借助共享存储系统来进行元数据的同步,并使用 Zookeeper 集群进行 NameNode 之间的协作。因此HDFS 的 HA 机制主要是依靠依赖于 QJM 共享存储组件的元数据同步和依赖于 Zookeeper 和 ZKFC 的主备选举机制。
图2-1-1:HDFS HA 架构图
2.2 Quorum Journal Manager(QJM)
元数据的同步主要是要保证主备 NameNode 的元数据是保持一致的,即保证磁盘镜像(FSImage)和日志(EditLog)在备 NN 上也是完整的,而元数据的同步很大程度取决于 EditLog 的同步,而这步的关键就是共享存储系统。
共享存储系统的一般类型有:Shared NAS NFS、BookKeeper、BackupNode 和 Quorum Journal Manager(QJM),目前用得较多的是 QJM 共享存储组件,通过搭建奇数台 JournalNode 实现主备 NameNode 之间的元数据信息同步。
QJM 全称是 Quorum Journal Manager, 由 JournalNode(JN)组成,一般会搭建奇数台机器,以实现 JN 的高可用。每个 JN 对外有一个简易的 RPC 接口,以供 NN 读写 EditLog 到 JN 本地磁盘。当写 EditLog 时,Active NN 会同时向所有 JN 并行写文件,只要有半数以上机器写成功则认为此次写操作成功(与 Zookeeper 的数据写入类似)。
Standby NN 不对外提供元数据的访问,它从 Active NN 上拷贝 FSImage 文件,从 JN 上拷贝 EditLog 文件,然后合并 FSImage 和 EditLog 文件,相当于 2NN 的作用。最终目的是保证 Standby NN 的元数据信息和 Active NN 的元数据信息一致,以实现热备份。
图2-2-1:QJM 内部实现框架
2.3 主备故障自动切换机制
要完成 HA,除了元数据同步外,还得有一个完备的主备故障自动切换机制,这个机制就是依赖于 Zookeeper 集群的主备选举机制,而整个切换的过程由 ZKFC 来进行控制。
ZKFC 是自动故障转移中的一个组件,是 Zookeeper 的客户端,每个运行 NameNode 的主机上都会启动一个 ZKFC 进程。ZKFC 可以监视和管理 NameNode 的状态,并把 NN 的状态信息汇报给 Zookeeper 集群。
ZKFC 可分为 HealthMonitor、ZKFailoverController 和 ActiveStandbyElector 三个组件:
- ZKFailoverController: HealthMontior 和 ActiveStandbyElector 的母体,执行具体的切换操作
- HealthMonitor: 监控 NameNode 健康状态,若状态异常会触发回调 ZKFailoverController 进行自动主备切换
- ActiveStandbyElector: 通知 Zookeeper 执行主备选举,若 Zookeeper 完成变更,会回调 ZKFailoverController 相应方法进行主备状态切换
主备切换的具体工作方式:
- ZKFC 的 HealthMonitor 组件会负责监控 NameNode 节点的状态,并将监控状态返回 FailoverController 组件,通过 Heartbeat 将监控状态保存在 Zookeeper 中的一个 zNode(其节点类型为临时节点)中,并保持一个特殊的 zNode 锁。
- 当 Active NN 出现故障后,Zookeeper 会通过 Active ZKFC 的 FailoverController 感知,而由于 zNode 是临时节点,会话失效,节点就会被删除。
- 此时 ActiveStandbyElector 组件会通知 Zookeeper 进行主备选举,选举方式:若 Standby NN 是健康的,且 Standby ZKFC 发现没有其它的节点当前持有 zNode 锁,它将为自己获取该锁;如果成功,则它赢得选举。选举结果返回 FailoverController 组件。
- Standby ZKFC 的 FailoverController 通知 Zookeeper 将自己的 NN 切换为 Active 状态,并修改 zNode 上的数据。
图2-3-1:HDFS HA 主备切换工作方式
防脑裂机制:
当 HDFS 中同一时刻出现两个及以上的 Active NameNode 即出现脑裂(Brain Split)。
防止脑裂出现的方法是,在故障切换期间,Zookeeper 会让出现故障的 Active NN 通过 FailoverController 通知 Standby ZKFC,强行杀掉 Active NN 的进程以防止脑裂。若此举失效,Standby ZKFC 会调用用户自定义的程序脚本结束进程。
图2-3-2:HDFS HA 防脑裂机制
3 YARN HA
Hadoop 2.4 版本之后,YARN 也引入了 HA 的机制,以解决 ResourceManager 的单点故障问题,实现 YARN 的高可用性。
3.1 YARN HA 架构
YARN 的 ResouceManager 记录着当前集群的资源分配情况和 JOB 的运行调度状态,YRAN HA 利用 Zookeeper 来存储这些信息,并实现 RM 的主备故障自动切换。
YARN 主备切换的工作方式与 HDFS 类似:
- ResourceManager 启动后会向 Zookeeper 的目录写一个锁文件,若写成功则成为 Active RM,否则成为 Standby RM.
- Active RM 会向 Zookeeper 的 RMStateStore(位于/rmstore 下)写入资源分配及 JOB 运行调度状态等信息。
- ZKFC 会负责监控 ResourceManager 节点的状态,并将监控状态汇报 Zookeeper.
- 当 Active RM 出现故障后,ZKFC 会通知 Zookeeper 进行选举,并让 MasterHADaemon 停止 RM 的服务。若 Standby RM 是健康的,并发现锁文件缺失,它会尝试去创建锁文件,成功则赢得选举成为 Active RM.
- Standby ZKFC 通知 Zookeeper 将自己的 RM 切换为 Active 状态,并让 MasterHADaemon 启动 RM 的服务。
- 切换为 Active 状态的 RM 会从 Zookeeper 的/rmstore 目录读取相应的作业信息,并重构作业的内存信息,然后启动内部服务,开始接收 NodeManager 的心跳,构建集群资源的信息,并接收客户端的提交作业的请求等。
图3-1-1:YARN HA 架构图
3.2 YARN HA 与 HDFS HA 的区别
YARN HA 尽管实现方式上与 HDFS HA 类似,但也存在以下的区别:
- HDFS HA 中,ZKFC 是一个独立守护的进程;YARN HA 中,ZKFC 是 RM 进程中的一个线程。
- HDFS HA 由独立中间件的数据集群来维护;YARN HA 的资源分配及 JOB 运行调度信息维护在 Zookeeper 中。
- HDFS 中的 DataNode 会向两个 NameNode 同时发送心跳;YARN 中 NodeManager 只会向 Active ResourceManager 上报资源。