博客原文:hackershellnode
以前在准备中级课程PPT,整理了下HA的基本内容,而且感谢松哥为咱们提供了HA不会切的问题,以致于以后恰好出现的NameNode宕机,可以快速解决。算法
NameNode的HA能够我的认为简单分为共享editLog机制和ZKFC对NameNode状态的控制shell
在此以前,我先提几个问题:网络
通常致使NameNode切换的缘由数据结构
ZKFC的做用是什么?如何判断一个NN是否健康ssh
NameNode HA是如何实现的?ide
NameNode由于断电致使不能切换的原理,怎样进行恢复函数
通常致使NameNode切换的缘由ui
随着集群规模的变大和任务量变多,NameNode的压力会愈来愈大,一些默认参数已经不能知足集群的平常需求,除此以外,异常的Job在短期内建立和删除大量文件,引发NN节点频繁更新内存的数据结构从而致使RPC的处理时间变长,CallQueue里面的RpcCall堆积,甚至严重的状况下打满CallQueue,致使NameNode响应变慢,甚至无响应,ZKFC的HealthMonitor监控本身的NN异常时,则会断开与ZooKeeper的连接,从而释放锁,另一个NN上的ZKFC进行抢锁进行Standby到Active状态的切换。这是通常引发的切换的流程。this
固然,若是你是手动去切换这也是能够的,当Active主机出现异常时,有时候则须要在必要的时间内进行切换。
ZKFC的做用是什么?如何判断一个NN是否健康
在正常的状况下,ZKFC的HealthMonitor主要是监控NameNode主机上的磁盘仍是否可用(空间),咱们都知道,NameNode负责维护集群上的元数据信息,当磁盘不可用的时候,NN就该进行切换了。
/** * Return true if disk space is available on at least one of the configured * redundant volumes, and all of the configured required volumes. * * @return True if the configured amount of disk space is available on at * least one redundant volume and all of the required volumes, false * otherwise. */ public boolean hasAvailableDiskSpace() { return NameNodeResourcePolicy.areResourcesAvailable(volumes.values(), minimumRedundantVolumes); }
除了可用状态(SERVICE_HEALTHY)以外,还有SERVICE_UNHEALTHY(磁盘空间不可用),SERVICE_NOT_RESPONDING(其余的一些状况)状态,在这两个状态中,它都认为NN是不健康的。
NameNode HA是如何实现的?
咱们前面说到,ZKFC是如何判断NN是否健康,接下来当NN处于非健康状态时,NameNode是如何进行切换的呢?
在ZKFailoverController这个类中,实行了两个重要的Callbacks函数,一个叫ElectorCallbacks,另外一个叫HealthCallbacks,顾名思义就是选举和健康检查用的回调函数,其中还有两个重要的组成部分elector(ActiveStandbyElector),healthMonitor(HealthMonitor),整体的就如上图所示。
ElectorCallbacks:
/** * Callbacks from elector */ class ElectorCallbacks implements ActiveStandbyElectorCallback { @Override public void becomeActive() throws ServiceFailedException { ZKFailoverController.this.becomeActive(); } @Override public void becomeStandby() { ZKFailoverController.this.becomeStandby(); } ... }
HealthCallbacks:
/** * Callbacks from HealthMonitor */ class HealthCallbacks implements HealthMonitor.Callback { @Override public void enteredState(HealthMonitor.State newState) { setLastHealthState(newState); recheckElectability(); } }
对于HealthMonitor来讲,在ZKFC进程启动的时候,就已经将HealthCallbacks注册进去了,HealthMonitor都会按期的检查NameNode是否健康,咱们能够经过监控ha.health-monitor.check-interval.ms去设置监控的间隔时间和经过参数ha.health-monitor.rpc-timeout.ms设置timeout时间,当集群变大的时候,须要适当的设置改值,让ZKFC的HealthMonitor没那么“敏感”。
ZKFC经过RPC调用监控NN进程,当出现异常时,则进入不一样的处理逻辑,如下是简化的代码:
private void doHealthChecks() throws InterruptedException { while (shouldRun) { try { status = proxy.getServiceStatus(); proxy.monitorHealth(); healthy = true; } catch (HealthCheckFailedException e) { ... enterState(State.SERVICE_UNHEALTHY); } catch (Throwable t) { ... enterState(State.SERVICE_NOT_RESPONDING); Thread.sleep(sleepAfterDisconnectMillis); return; } ... }
回调函数就是这么起做用啦,那么回调函数作了什么呢?总的来讲,若是NN健康(SERVICE_HEALTHY)就加入选举,若是不健康就退出选举(SERVICE_UNHEALTHY,SERVICE_NOT_RESPONDING)
case SERVICE_UNHEALTHY: case SERVICE_NOT_RESPONDING: LOG.info("Quitting master election for " + localTarget + " and marking that fencing is necessary"); elector.quitElection(true); break;
说到退出选举就关系到elector(ActiveStandbyElector)了,true表明若是NN从Actice变为Standby出现异常是要去fence的,这就是为啥NN会挂掉的缘由之一
如何退出选举?就是close zkClient的连接,让ZooKeeper上面的维持的选举锁消失
void terminateConnection() { if (zkClient == null) { return; } LOG.debug("Terminating ZK connection for " + this); ZooKeeper tempZk = zkClient; ... try { tempZk.close(); } catch(InterruptedException e) { LOG.warn(e); } ... }
对于ActiveStandbyElector来讲,他有个WatcherWithClientRef类专门用来监听ZooKeeper上的的znode的事件变化,当事件变化时,就会调用ActiveStandbyElector的processWatchEvent的方法
watcher = new WatcherWithClientRef(); ZooKeeper zk = new ZooKeeper(zkHostPort, zkSessionTimeout, watcher);
和
/** * Watcher implementation which keeps a reference around to the * original ZK connection, and passes it back along with any * events. */ private final class WatcherWithClientRef implements Watcher { ... @Override public void process(WatchedEvent event) { hasReceivedEvent.countDown(); try { hasSetZooKeeper.await(zkSessionTimeout, TimeUnit.MILLISECONDS); ActiveStandbyElector.this.processWatchEvent( zk, event); } catch (Throwable t) { fatalError( "Failed to process watcher event " + event + ": " + StringUtils.stringifyException(t)); } } ... }
在ActiveStandbyElector的processWatchEvent方法中,处理来自不一样事件的逻辑,从新加入选举或者继续监控znode的变化,当另一个ZKFC监控到事件变化得时候,就去抢锁,抢锁实质上就是建立znode的过程,并且建立的是CreateMode.EPHEMERAL类型的,因此,当HealthMonitor监控到NN不健康时,就会断开链接,节点就会消失,watcher就会监控到NodeDeleted事件,进行建立节点。
switch (eventType) { case NodeDeleted: if (state == State.ACTIVE) { enterNeutralMode(); } joinElectionInternal(); break; case NodeDataChanged: monitorActiveStatus(); break;
又由于ActiveStandbyElector实现了StatCallback接口,当节点建立成功时,就会回调processResult方法看是否建立成功,若是建立成功则去检查zkBreadCrumbPath是否存在以前的Active节点,若是存在,则调用RPC让其变为Standby,看可否转变成功,不然则SSH过去fence掉NN进程。,保持Active节点只有一个,而且恢复正常服务
NameNode由于断电致使不能切换的原理,怎样进行恢复
ActiveNN断电,网络异常,负载太高或者机器出现异常没法链接,Standby NN没法转化为Active,使得HA集群没法对外服务,缘由是Active NN节点在断电和不能服务的状况下,zknode上保存着ActiveBreadCrumb, ActiveStandbyElectorLock两个Active NN的信息,ActiveStandbyElectorLock因为Active NN出现异常断开,Standby NN去抢锁的时候就会去检查ActiveBreadCrumb是否有上一次的Active NN节点,若是有,就会就会尝试让Active NN变为Standby NN,本身转化为Active NN,可是因为调用出现异常,因此会采用ssh的方式去Fence以前的Active NN,由于机器始终链接不上,因此没法确保old active NN变为Standby NN,本身也没法变为Active NN,因此仍是保持Standby状态,避免出现脑裂问题。
解决方案是肯定Active关机的状况下从新hdfs zkfc -formatZK就能够了。
总 结
NN GC或者在压力大的状况下能够调整GC算法和增长NameNode节点的线程数,加快NN对请求的处理速度,也能够分离节点的端口dfs.namenode.rpc-address.ns1.nn2和dfs.namenode.servicerpc-address.ns1.nn2分离client和datanode节点等服务类型的请求,进行分担压力,也能够适当的调整ZKFC的监控timeout的时间等等
可是遇到异常的job,只能经过别的方式去处理问题了,祷告吧!哈哈