ZooKeeper FailoverController(ZK故障转移控制器)原理
阅读原文时间:2021年04月20日阅读:1
@Author  : Spinach | GHB
@Link    : http://blog.csdn.net/bocai8058

文章目录

概述

本文基于官方ZK Failover Controller Design文档的。

    ZooKeeper(自此“ZK”)本身高度可用,并提供以下功能,可以在此基础上构建:
        1. 对于少量的任意信息,一个非常一致的存储库(znode)。
        2. 创建一个znode的能力,它在创建者的客户端失败时自动删除(一个临时节点)。
        3. 当znode的状态发生变化时,监控和异步通知的能力(watchers)。利用以上功能,本设计以几个关键的方式使用ZooKeeper。
        4. 故障检测器-主动NameNode在ZK中创建一个临时节点。如果活动应该失败,临时节点将在一个可配置超时后自动被删除。
        5. 主动节点定位器——通过将少量信息写入ZK中,客户端或其他服务可以对当前活动节点进行权威性定位。
        6. 由于ZK是一致且高度可用的,所以我们可以使用它来确保在任何时候至多一个节点处于活动状态。

其他用于自动故障转移的设计可以替换上述部分或全部的不同组件。例如,linux - ha项目可以提供一些相同的构建块。然而,ZK特别具有吸引力,因为它满足单个系统中的所有方面,没有外部配置。许多Hadoop部署也已经为Apache HBase等其他应用程序部署了ZooKeeper。

设计

2.1 组件

现阶段,下述三个组件都运行在一个JVM中,即JVM与NN的JVM在同一个机器上。但是为两个独立的进程。一个典型的HA集群,有两个NN组成,每个NN都有自己的ZKFC进程。

ZK-based的automatic Failover主要由三个组件组成:

    HealthMonitor --- 用于监控NN是否unavailable或者处于unhealth状态。
    ActiveStandbyElector --- 用于监控NN在zk中的状态。
    ZKFailoverController --- 从HealthMonitor和ActiveStandbyElector中订阅事件并管理NN的状态,另外ZKFC还需要负责fencing。

2.2 HealthMonitor设计

HealthMonitor由HADOOP-7788完成提交,它由一个loop循环的调用一个monitorHealth rpc来检视本地的NN的健康性。如果NN返回的状态信息发生变化,那么它将经由callback的方式向ZKFC发送message。HealthMonitor具有一下状态:

    INITIALIZING -- 表示HealthMonitor正在启动,但是仍未与NN进行联通。
    SERVICE NOT RESPONDING -- 表示Health检测RPCs调用超时(timeout),否则不会返回最终的成功或失败。
    SERVICE HEALTHY -- 表示Health检测RPCs调用返回成功。
    SERVICE UNHEALTHY -- 表示Health检测RPCs调用返回确认的失败类型(eg:NN本身检测出一些健康问题,比如离开本地磁盘空间)。
    HEALTH MONITOR FAILED -- 表示HealthMonitor线程由于未捕获的异常导致失败,等等。这通常是导致终止的致命错误。

2.3 ActiveStandbyElector设计

ActiveStandbyElector(在hadoop - 7992中提交并在hadoop - 8163,hadoop - 8212中改进)负责协调ZooKeeper。ZKFC主要以两种主要的方式进行互动:

    joinElection(…) -- 通知ASE,本地的NN可以被选为活动NN。
    quitElection(…) -- 通知ASE,本地的NN不能被选为活动NN(eg: because its health has gone bad)。
  • 一旦ZKFC调用了joinElection,那么ASE将试图获取ZK中的lock。该锁由一个临时的znode组成,如果ZKFC进程崩溃或节点失去网络连接,它将自动删除。如果ASE成功的创建了该锁,那么它向ZKFC调用becomeActive(),否则调用becameStandby()并且开始监控其他节点的锁。
  • 在当前lock-holder失效的情况下,另一个监控在这个lock上的ZKFC将被触发,然后试图获取这个lock。如果成功,ASE将同样的调用becomeActive方法来通知ZKFC
  • 如果ZK的session过期,那么ASE将在本地NN上调用enterNeutralMode而不是调用becomeStandby。因为它无法知道另一个NN是否已经准备好接管。这种情况下,将本地NN转移到Standby状态是由fencing机制来完成(详见下文)

2.4 ZKFC设计

ZKFC本身非常简单,它运行以下进程:

  1. 启动时,通知HealthMonitor去监控本地NN,然后使用配置好的ZK去初始化ASE,但是绝不能立即参加Election。

  2. 当HealthMonitor的状态改变时,ZKFC相应的做出如下反应:

    SERVICE_HEALTHY -- 通知elector去join Election,如果还没有的话。
    HEALTH MONITOR FAILED -- 中断所有的ZKFC进程,因为ZKFC也没法工作了。
    INITIALIZING -- 这个情况一般是NN刚刚重启还没准备好进行服务。ZKFC会退出Election,并且通知fencing是没必要进行的,因为NN总是以Standby来开始。
    Other states -- 退出Election,如果当前是在Election状态。
  3. 当ActiveStandbyElector发布一个改变的时候,ZKFC做出如下反应:

    becomeActive() -- ZKFC将在本地NN上调用transitionToActive()。
                      如果失败了,将退出Election然后sleep一段时间,重新进入Election。Sleep是为了让其他准备好了的NN也有机会成为ActiveNN。
                      这种情况下退出Election并不会删除breadcrumb node (这是为了确保了无论谁成为了ActiveNN之后可以fencing这个NN,尽管
                      这个情况的失败可能导致这个NN可能会进入partially-active状态)。
    becomeStandby() -- 在本地NN上调用transitionToStandby()。如果失败,另一个NN将毫不犹疑的将这个NN进行fencing(详见fencing)。
    enterNeutralMode() -- 当前没有反应,因为目前的设计中,不会进入此状态。
    fenceOldActive(...) -- 详见fencing。
    notifyFatalError(...) -- 中断ZKFC,因为已经没法正常工作了。
  4. 所有的调用都是在ZKFC上进行同步,这样确保了串行化所有事件的顺序确保其逻辑的正确性。

ZKFC状态机图:

2.5 Fencing设计

HADOOP-8163对ASE进行了增强,主要是通过增加了fencing的回调机制,详细如下:

  1. 在获取了ActiveLock之后,通知本地NN成为了Active之前,检查breadcrumb znode的存在性

    - 若breadcrumb znode存在的话,调用fenceOldActive(data)从那个NN上传入data数据,如果成功了,删除breadcrumb znode。
    - 如果fencing失败,log一个error,扔掉lock,sleep一会儿,重新进行Election。这样也给其他NN有机会成为ActiveNN。
    - 使用本地NN的标识数据,创建一个新的breadcrumb node。
  2. 当退出Election的时候,quiting的NN能够自己判定是否需要fencing。如果需要,将删除breadcrumb node,然后关闭ZK session。

2.6 支持手动故障转移与自动切换

尽管一个集群可以配置为自动故障转移,但是允许管理员以优雅的手动故障转移仍然是很有用的,特别是在有计划的升级硬件资源或在发生故障转以后将StandlyNN转为ActiceNN的时候。

  1. 在最初的实现中,是不能触发故障转移的。所以要达到想要的结果只能手工模拟fail的情况,比如kill掉一个NN以便让另一个NN成为ActiveNN。这有如下缺点:

    - 没有对standby机器的预先检查机制,如果standby不是ready的话,这将导致service不可用。
    - 如果standby在成为Active的时候发生错误,则无法快速返回,因为先前的NN已经killed。
    - 考虑到之前的ActiveNN被un-gracefully失效,这将导致fencing的执行,有可能导致STONITH等其它fencing,
                                                                这是相当不理想的,特别是如果管理员只是想在重新启动之前进行简单的配置更改。
  2. 为了在HA设置中支持手动故障转移,我们建议以下更改:

在每个namespace中添加一个新的配置,名为dfs.ha.auto-failover.enabled。如果该标志被设置为true,则通过以下行为改变:

    - haadmin -failover命令行工具不再直接对NameNodes进行RPC调用,而是采用一下描述的方式来代替。
    - NameNodes进入一种只接受ZKFCs中mutative HAServiceProtocol RPCs的模式。
    - 在运行NN的每个节点上,可以利用start-dfs.sh脚本自动启动ZKFC守护进程。

    上面的内容确保了错误配置的客户端不能意外地更改自动故障转移设置下的HA状态。

当管理员执行Failover时候,首先执行haadmin -failover -to ,我们会自动将其转化为no-automatic的设置语法 haadmin -failover -from -to 。以下操作将被执行:

HAAdmin为目标ZKFC创建了一个RPC failoverToYou()。ZKFC进行以下操作:
    (a) 检查它是否处于健康状态(即在选举中)。如果不健康,就抛出异常。
    (b) 检查它是否已经激活。如果是,返回成功。
    (c) 发送一个concedeLock() RPC给当前的活动ZKFC,这个ZKFC将会执行:
        i. 向本地NN发送一个transitionToStandby() RPC。
        ii. 如果在短时间内成功,则删除它的breadcrumb节点。否则,将breadcrumb节点保留在tact中。
        iii. 退出Election,并设置一个定时器,在下一个5-10秒内将不会再次参加Election。
    (d) 当这个RPC返回时,希望lock已被其他NN删除,等待5-10秒再验证这个NN是否已成功获取了该lock。不管本地NN是否成功成为ActiveNN,均对client作出响应。

    注意:目前仅仅假定只有两个NN在参加Election,将来我们将支持多个standbyNN,这需要添加新的znode来标识需要成为Active的NN,
         然后更改Election的过程,在这个NN想获取lock之前先检查这个NN。

2.7 示例场景

  1. ActiveNN产生JVM crash
    • 一旦这种情况发生,HealthMonitor在调用monitorHealth()将失效。然后HM将向ZKFC调用enterState(SERVICE_NOT_RESPONDING),本地ZKFC将退出Election,另外一个ZKFC获取active lock,执行fencing,变成active。
  2. ActiveNN JVM freeze(e.g sigstop)
    • 如果JVM freeze了但是没有crash掉,这与上面情况一直,monitorHealth会由于timeout而引发上述过程。FUTURE-WORK:使用JVMTI来判断NN是否在进行gc,如此可以使用另一个timeout来为gc进行failover。
  3. ActiveNN machine crash
    • 当整个机器crash了,ASE在zk的session将会过期,另一个ZKFC将会获取这个事件,引发failover。
  4. Active ZKFC crash
    • 尽管ZKFC设计简单,但是仍然有可能会crash掉,在这个情况下,failover将会被错误的触发。另一个NN的ZKFC将会对ActiveNN调用transitionToStandby让它放弃active lock,然后进行aggressive fencing。尽管会成功,但是会导致进行了一次没有必要的failover。
  5. Zookeeper crash
    • 当zk集群crash了,那么所有的ZKFC将收到DISCONNECTED事件。然后ZKFC在本地NN调用enterNeutralMode,除此之外不做任何改变。系统除了不能执行failover之外,与其他情况无异。
    • 当zk恢复了,clients立马能够重连。而zk能够将之前的session信息重新被各个client进行获取(在启动的一个timeou时间内)。所以所有的nodes将会重新获取session,不需要进行无必要的failover。
    • FutureWork:breadcrumb znode在这个情况下可以优先的给予到ActiveNN,在ZK挂掉之前。

2.8 待发掘的细节

  1. 和手动failover的集成
    • 如前所述,尽管有了强大的automatic failover,但是手动的failover在某些场合下仍是不二选择。
    • 加入一个简单的quiesceActiveState() RPC接口到ZKFC,这个rpc通知NN退出Election,并等待StandbyNN发起failover,如果等待超时仍未有failover发起,那么这个NN重新获取Active lock。并向client汇报错误。

2.9 Future work

  1. 优先节点
    • 某些情况,可能希望为将指定的NN成为ActiveNN。现阶段是通过公平竞争来获取Active lock从而变成ActiveNN。可以通过两个方式来达成这个目的:一个是延迟非优选节点加入Election。另一个是提供failback将非优选节点从ActiveNN变成StandbyNN。
  2. 自我fencing
    • 当HM通知本地NN变成unhealthy时候,在退出Election之前,ZKFC能够执行自我fencing。例如,它能进行fuse -k -9 来强制击杀本地NN。这个方法能够避免很多复杂的fencing机制
  3. 管理Process
    • 当前的设计认为ZKFC process和本地NN独立的运行。NN挂掉了,ZKFC也不会视图去重启它,只是继续监控IPC端口直到NN被另外方式重启了。
    • 当然如果ZKFC来负责NN的进程管理,这样使得部署要简单些,但是同时也增加了ZKFC本身的复杂度。因为java中的进程管理就是一坨屎。尽管如此当前的模块化设计足以使得以后如要进行这个工作很直接

参与的引用:https://issues.apache.org/jira/secure/attachment/12521279/zkfc-design.pdf | http://blog.csdn.net/chenpingbupt/article/details/7922089 |


手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章