Hadoop高可用(HA机制)详解

目录

一、ZooKeeper监听器

二、HDFS HA原理

1、元数据同步

2、主备切换


在前面的文章 Zookeeper(2)基础架构与内部原理解析(数据存储、watch机制、监听器、选举机制)中有详细介绍分布式协调框架Zookeeper的相关组件和原理,本文结合Zookeeper当中的监听器再来进一步介绍HDFS的HA方案。

一、ZooKeeper监听器

关于ZooKeeper监听器有三个重要的逻辑:

  • 注册:客户端向ZooKeeper集群注册监听器

  • 监听事件:监听器负责监听特定的事件

  • 回调函数:当监听器监听到事件的发生后,调用注册监听器时定义的回调函数

类比举例:

为了便于理解,举例:旅客住店无房可住的情况

  • 一哥们去酒店办理入住,但是被告知目前无空房

  • 这哥们告诉客服:你给我记住了,帮我留意一下有没有空出的房间,如果有,及时通知我(类似注册监听器,监听特定事件

  • 将近12点,有房客退房,有空闲的房间(事件

  • 客服发现有空房(监听到事件

  • 及时通知这哥们

  • 这哥们收到通知后,做一些事,比如马上从附近酒吧赶回酒店(调用回调函数

 

二、HDFS HA原理

关键逻辑:

①监听器:注册、监听事件、回调函数

②共享存储:JournalNode

在Hadoop 1.x版本,HDFS集群的NameNode一直存在单点故障问题:

  • 集群只存在一个NameNode节点,它维护了HDFS所有的元数据信息

  • 当该节点所在服务器宕机或者服务不可用,整个HDFS集群处于不可用状态

Hadoop 2.x版本提出了高可用 (High Availability, HA) 解决方案,HDFS HA方案主要分两部分:

①元数据同步

②主备切换

1、元数据同步

在同一个HDFS集群,运行两个互为主备的NameNode节点。

一台为主Namenode节点,处于Active状态,一台为备NameNode节点,处于Standby状态。

其中只有Active NameNode对外提供读写服务,Standby NameNode会根据Active NameNode的状态变化,在必要时切换成Active状态。

JournalNode集群

  • 在主备切换过程中,新的Active NameNode必须确保与原Active NamNode元数据同步完成,才能对外提供服务

  • 所以用JournalNode集群作为共享存储系统;

  • 当客户端对HDFS做操作,会在Active NameNode中edits.log文件中作日志记录,同时日志记录也会写入JournalNode集群;负责存储HDFS新产生的元数据

  • 当有新数据写入JournalNode集群时,Standby NameNode能监听到此情况,将新数据同步过来

  • Active NameNode(写入)和Standby NameNode(读取)实现元数据同步

  • 另外,所有datanode会向两个主备namenode做block report

2、主备切换

ZKFC涉及角色:

每个NameNode节点上各有一个ZKFC进程

ZKFC即ZKFailoverController,作为独立进程存在,负责控制NameNode的主备切换

ZKFC会监控NameNode的健康状况,当发现Active NameNode异常时,通过Zookeeper集群进行namenode主备选举,完成Active和Standby状态的切换

  • ZKFC在启动时,同时会初始化HealthMonitor和ActiveStandbyElector服务

  • ZKFC同时会向HealthMonitor和ActiveStandbyElector注册相应的回调方法(如上图的①回调、②回调)

  • HealthMonitor定时调用NameNode的HAServiceProtocol RPC接口(monitorHealth和getServiceStatus),监控NameNode的健康状态,并向ZKFC反馈

  • ActiveStandbyElector接收ZKFC的选举请求,通过Zookeeper自动完成namenode主备选举

    选举完成后回调ZKFC的主备切换方法对NameNode进行Active和Standby状态的切换

主备选举过程:

  • 启动两个NameNode、ZKFC

  • 两个ZKFC通过各自ActiveStandbyElector发起NameNode的主备选举,这个过程利用Zookeeper的写一致性和临时节点机制实现

  • 当发起一次主备选举时,ActiveStandbyElector会尝试在Zookeeper创建临时节点/hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock,Zookeeper的写一致性保证最终只会有一个ActiveStandbyElector创建成功

  • ActiveStandbyElector从ZooKeeper获得选举结果

  • 创建成功的 ActiveStandbyElector回调ZKFC的回调方法②,将对应的NameNode切换为Active NameNode状态

    而创建失败的ActiveStandbyElector回调ZKFC的回调方法②,将对应的NameNode切换为Standby NameNode状态

  • 不管是否选举成功,所有ActiveStandbyElector都会在临时节点ActiveStandbyElectorLock上注册一个Watcher监听器,来监听这个节点的状态变化事件

  • 如果Active NameNode对应的HealthMonitor检测到NameNode状态异常时,通知对应ZKFC

  • ZKFC会调用 ActiveStandbyElector 方法,删除在Zookeeper上创建的临时节点ActiveStandbyElectorLock(或者ActvieStandbyElector与ZooKeeper的session断开,临时节点也会被删除,但有可能此时原Active NameNode仍然是active状态)

  • 此时,Standby NameNode的ActiveStandbyElector注册的Watcher就会监听到此节点的 NodeDeleted事件。

  • 收到这个事件后,此ActiveStandbyElector发起主备选举,成功创建临时节点ActiveStandbyElectorLock,如果创建成功,则Standby NameNode被选举为Active NameNode(过程同上)

如何防止脑裂?

脑裂

在分布式系统中双主现象又称为脑裂,由于Zookeeper的“假死”、长时间的垃圾回收或其它原因都可能导致双Active NameNode现象,此时两个NameNode都可以对外提供服务,无法保证数据一致性

隔离

对于生产环境,这种情况的出现是毁灭性的,必须通过自带的隔离(Fencing)机制预防此类情况

原理

ActiveStandbyElector成功创建ActiveStandbyElectorLock临时节点后,会创建另一个ActiveBreadCrumb持久节点

ActiveBreadCrumb持久节点保存了Active NameNode的地址信息

当Active NameNode在正常的状态下断开Zookeeper Session,会一并删除临时节点ActiveStandbyElectorLock、持久节点ActiveBreadCrumb

但是如果ActiveStandbyElector在异常的状态下关闭Zookeeper Session,那么持久节点ActiveBreadCrumb会保留下来(此时有可能由于active NameNode与ZooKeeper通信不畅导致,所以此NameNode还处于active状态

当另一个NameNode要由standy变成active状态时,会发现上一个Active NameNode遗留下来的ActiveBreadCrumb节点,那么会回调ZKFailoverController的方法对旧的Active NameNode进行fencing

①首先ZKFC会尝试调用旧Active NameNode的HAServiceProtocol RPC接口的transitionToStandby方法,看能否将其状态切换为Standby

②如果transitionToStandby方法切换状态失败,那么就需要执行Hadoop自带的隔离措施,Hadoop目前主要提供两种隔离措施:

  • sshfence:SSH to the Active NameNode and kill the process;
  • shellfence:run an arbitrary shell command to fence the Active NameNode

③只有成功地fencing之后,选主成功的ActiveStandbyElector才会回调ZKFC的becomeActive方法transitionToActive将对应的NameNode切换为Active,开始对外提供服务