原文的参考文章:《HDFS High Availability Using the Quorum Journal Manager》
http://hadoop.apache.org/docs/r2.5.2/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html#Deployment%E3%80%81
一. 目的
本指南提供一个 HDFS HA 特性的综述,描述了如何使用 Quorum Journal Manager (QJM) 配置和管理一个 HA HDFS 集群。本文档假设读者对于 HDFS 中的通用组件和节点类型有一个大体的认识。请参考 HDFS 架构指南获取更多信息。
二. 使用 QJM 或者传统的共享存储
本文档讨论了如何用 QJM 配置和使用 HDFS HA 在 Active NameNode 和 Standby NameNode 共享 edit 日志文件。关于如何使用 NFS 代替 QJM 作为共享存储配置 HDFS HA的信息,请看High Availability With NFS。
三. 背景
在 Hadoop2.0.0 之前,NameNode 在 HDFS 集群中是单点故障的。每一个集群都有一个 NameNode,如果 NameNode 所在的机器或者进程变得不可用,在 NameNode 重新启动或者在另外一台机器上启动之前,整个集群将变得不可用。
这从两个方面影响了HDFS集群的可用性:
- 在一些意外的情况下,像机器宕机,知道 NameNode 重新启动之前,集群将不可用
- 有计划的升级事件,像 NameNode 上软件或者硬件的升级将导致集群停机
HDFS 的 HA 特性解决了上述问题,通过提供一个选择,在一个集群中,配置 Active/Passive 两个冗余的NameNode,进行热备份。这允许在机器宕机或者优雅的进行管理员发起有计划的维护目的的故障转移的情况下可以快速的故障转移到一个新的 NameNode。
四. 架构
在一个典型的 HA 集群中,两个独立的机器被配置为 NameNode。在任何时间点,仅有一个 NameNode 在 Active 状态,另一个是 Standby 状态。Active NameNode 负责处理集群中所有客户端的操作,同时,Standby NameNode 简单的作为 slave,保持足够的状态信息在必要的时候提供快速的故障转移。
为了使 Standby NameNode 保持它的状态与 Active NameNode 同步,两个 NameNode 节点用一组单独的守护进程通信,这组守护进程名叫 JournalNodes。当任何的 namespace 的修改发生在 Active NameNode 上,它记录一条修改记录到这些 JNs 中的大多数。Standby NameNode 能够从 JNs 中读取这些 edit,不断的观察这组 JNs 中 edit 的变化。当 Standby NameNode 看到这些 edit 的时候,它应用这些 edit 到它自己的 namespace。在发生故障转移的时候,StandbyNameNode 在提升它自己为 Active NameNode 之前,将确保它读取了所有来自 JNs 的 edit。这将保证故障转移发生前,namespace 的状态被完全同步。
为了提供一个快速的故障转移,Standby NameNode 有最新的关于集群中 Block 的位置信息是必要的。为了实现这个目的,DataNode 用两个 NameNode 的位置去配置,然后发送 Block 位置信息和心跳给两个 NameNode。
一个集群在同一时间只有一个 NameNode 是 Active 状态对于正确的操作是至关重要的。否则,namespace 的状态将会快速的在两个 NameNode 之间产生分歧,可能会丢失数据或者产生其他不正确的结果。为了保证这个属性和防止所谓的 split-brain 场景,JNs 将永远只允许一个NameNode 往其写入。在故障转移期间,将要成为 Active 的 NameNode 将只是简单的接管JNs的写角色,这将有效的防止其他的 NameNode 继续在 Active 状态,使新的 Active NameNode 安全的处理故障转移。
五. 硬件资源
为了部署一个HA 集群,你应该准备下面这些:
Nameode Machines
运行 Active 和 Standby NameNode 的进程的机器,这两台机器应该具有相同的硬件资源,也应该与 non-HA 集群中的 NameNode 硬件资源一样。JournalNode Machines
运行 JournalNode 的机器。JournalNode 守护进程相对轻量级,所有这些守护进程可以合理地安排在运行其他Hadoop进程的机器,例如 NameNode,JobTracker 或者 Yarn ResourceManger。注意:至少应该有 3 个 JournalNode 守护进程,因为 edit 日志修改必须被写入 JNs 的大多数。这将允许系统容忍单台机器故障。你也可以运行超过 3 个 JournalNode,但是为了真正的增加系统可以容忍的故障的数量,亦应该运行奇数个 JNs。注意,当运行 N 个 JournalNode 的时候,系统可以容忍 (N - 1) / 2 个节点失效时,继续正常的工作。
注意,在一个HA集群中,Standby NameNode 也可以执行 namespace 状态的 Checkpoint,因此,在一个HA的集群中,没有必要再运行一个Secondary NameNode,CheckpointNode或者BackupNode。事实上,如果这么做,这将是个错误。这也允许你重用在 non-HA 的 HDFS 集群中用来做为 Secondary NameNode 的机器将集群配置成 HA 的。
六. 部署
6.1 部署概述
与 Federation 配置相似,HA 配置是向后兼容的,允许一个存在的单 NameNode 的集群配置不用改变就可以工作。新的配置被设计成假设集群中所有的节点可能具有相同的配置,没有根据节点的类型部署不同的配置文件到不同的机器。
就像 HDFS Federation ,HA 集群重用 nameservice 的 ID 来标识一个 HDFS 实例,但事实上这个实例可能包含多个 HA 的 NameNode 节点。另外,一个新的概念 NameNode ID 被 HA 增加。每一个 NameNode 都有一个不同的 NameNode ID 来区分彼此。为了支持所有NameNode 一个配置文件,相关的配置用需要增加 nameservice ID 和 NameNode ID 前缀。
6.2 详细配置
为了配置一个 HA NameNode,你必须增加几个配置选项到你的 hdfs-site.xml 配置文件中。
这些配置的顺序是不重要的,但是 dfs.nameservices 和 dfs.ha.namenodes.[nameservice ID] 选择将决定下面的配置的 key 的名称。因此,你应该在配置剩下的配置先决定这两个配置的值。
1. dfs.nameservices:nameservice 的逻辑名称
为 nameservice 选择一个逻辑名称,例如, “mycluster”,使用这个逻辑名称作为该配置选项的值。你选择的 name 是任意的。它将在集群中其他的属性配置和作为 HDFS 绝对路径的 authority 部分被使用。
- 注意:如果你同时使用 HDFS Federation,这个配置的设置应该包括其他的 nameservice,不管是不是 HA 的集群,逗号分隔开。
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
<description>the logical name for this new nameservice</description>
</property>
2. dfs.ha.namenodes.[nameservice ID] :nameservice中每一个NameNode的唯一的标识符
用逗号分隔的 NameNode 的 ID 列表来配置。这将被 DataNode 用来确定集群中所有的 NameNode。例如,如果用 “mycluster” 作为 nameservice 的 ID,然后你想用 “nn1” 和 “nn2” 作为两个 NameNode 各自的 ID,你将像下面这样配置:
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
<description>unique identifiers for each NameNode in the nameservice</description>
</property>
- 注意:目前,一个nameservice中只可以被配置两个NameNode
3. dfs.namenode.rpc-address.[nameservice ID].[name node ID]:RPC地址的完全限定名,配置每一个 NameNode 的监听地址
对于两个先前配置的 NameNode 的 ID,设置 NameNode 进程的全限定名的地址和 RPC 端口号。注意这将导致两个独立的配置选项。例如:
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>machine1.example.com:8020</value>
<description>the fully-qualified RPC address for NameNode nn1 to listen on</description>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>machine2.example.com:8020</value>
<description>the fully-qualified RPC address for NameNode nn2 to listen on</description>
</property>
- 注意:如果你愿意,也可以配置 RPC “servicerpc-address” 设置。
4. dfs.namenode.http-address.[nameservice ID].[name node ID]:每个NamNode的监听地址,全限定名的HTTP地址
与上边的 rpc-address 类似,设置两个 NameNode 的 Http Server 的监听地址。例如:
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>machine1.example.com:50070</value>
<description>the fully-qualified HTTP address for NameNode nn1 to listen on</description>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>machine2.example.com:50070</value>
<description>the fully-qualified HTTP address for NameNode nn2 to listen on</description>
</property>
- 注意:如果你启动了 Hadoop 的安全特性,你也应该同样地为每个 NameNode 设置 https-address 的地址。
5. dfs.namenode.shared.edits.dir:标识两个 NameNode 将分别写入/读取 edit 的一组 JNs 的 URL
这是提供共享 edit 存储的一组 JNs 的地址,这些地址,被 Active NameNode 写入,被 Standby NameNode 读取,来保持 Active NameNode 产生的文件系统的所有的修改信息的最新版本。虽然你必须指定多个 JournalNode地址,你应该只配置这些URL地址中的一个。URL应该是这种格式
qjournal://host1:port1;host2:port2;host3:port3/journalId
这个 Journal ID 是这个 nameservice 唯一的标识符,这将允许一组 JNs 为多个 federation 的命名空间系统提供存储。虽然不是必须的,重用 nameservice ID 作为 Journal 的标示符是一个好的想法。
例如,如果这个集群的一组 JournalNode 正运行在 “node1.example.com”, “node2.example.com” 和 “node3.example.com” 这3台机器上,nameservice ID 是 “mycluster”,你将用下面这个配置作为值(JournalNode 默认的端口号是 8485):
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/mycluster</value>
<description>the URI which identifies the group of JNs where the NameNodes will write/read edits </description>
</property>
6. dfs.client.failover.proxy.provider.[nameservice ID]:HDFS 客户端用来连接 Active NameNode 的Java 类
配置被 HDFS 客户端用来决定哪一个 NameNode 当前是 Active 的 Java 类,从而决定哪一个 NameNode 目前服务于客户端请求。目前只有一个实现,ConfiguredFailoverProxyProvider,所以除非你用了自定义的类否则就用这个。例如:
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
<description>the Java class that HDFS clients use to contact the Active NameNode</description>
</property>
7. dfs.ha.fencing.methods :脚本或 Java 类的列表,它们将在一次故障转移期用来保护 Active NameNode
在任意给定的时刻只有一个 NameNode 处在 Active 状态对于系统的正确性是积极的。重要的是,当使用 QJM时,永远将只有一个 NameNode 被允许写入到 JNs 中,所以没有可能对于从一个 split-brain 场景破坏文件系统元数据。然而,当发生一次故障转移时,先前 Active 的 NameNode 可以处理客户端的读请求是可能的,当试图写入 JNs 时,这个 NameNode 可能直到关机才失效。因为这个原因,即使在使用 QJM 的时候,配置 fencing methods 也是值得的。然而,为了提高系统在 fencing 机制失效时的可用性,建议在列表的最后配置一个总是返回 success 的 fencing method 。注意,如果你选择使用不真实的方法,你仍然需要为此配置些东西,例如,”shell(/bin/true)”。
故障转移期间使用的 fencing methods 被配置为回车分隔的列表,它们将顺序的被尝试知道一个显示 fencing 已经成功。有两个与 Hadoop 运行的方式:shell 和 sshfence。关于更多实现你自定义的 fencing method,查看org.apache.hadoop.ha.NodeFencer 类。
- shfence:SSH 到 Active NameNode 然后杀掉这个进程
sshfence 选择 SSH 到目标节点,然后用 fuser 命令杀掉仍坚挺继续在服务的 TCP 端口上的进程。为了使 fencing option 工作,它必须能够免密码 SSH 到目标节点。因此,你必须配置 dfs.ha.fencing.ssh.private-key-files 选项,这是一个逗号分隔的SSH私钥文件的列表。例如:
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
<description>SSH to the Active NameNode and kill the process</description>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/exampleuser/.ssh/id_rsa</value>
<description>use sshfence isolation mechanism need ssh login</description>
</property>
可选择地,你可以配置一个非标准的用户名或者端口号来执行 SSH。你也可能为此 SSH 配置一个超时限制,单位毫秒,超过此超时限制 fencing method 将被认为失败。它可能被配置成这样:
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence([[username][:port]])</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
<description>sshfence time</description>
</property>
- shell:运行任意的 shell 命令来fence Active NameNode
shell fence 的方式会运行一个任意的 shell 命令,它可能配置成这样:
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
</property>
括号之间字符串被直接传给 bash shell 命令,可能不包含任何关闭括号。
Shell 命令将运行在一个包含当前所有 Hadoop 配置变量的环境中,在配置的 key 中用 '_'
代替 '.'
。所用的配置已经将任何一个 namenode 特定的配置改变成通用的形式。例如 dfs_namenode_rpc-address
将包含目标节点的 RPC 地址,即使配置可能指定的变量是 dfs.namenode.rpc-address.ns1.nn1。
此外,下面的这些涉及到被 fence 的目标节点的变量,也是可用的
变量 | 解释 |
---|---|
$target_host | hostname of the node to be fenced |
$target_port | IPC port of the node to be fenced |
$target_address | the above two, combined as host:port |
$target_nameserviceid | the nameservice ID of the NN to be fenced |
$target_namenodeid | the namenode ID of the NN to be fenced| |
这些环境变量可能被用来替换 shell 命令中的变量,例如:
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh --nameservice=$target_nameserviceid $target_host:$target_port)</value>
</property>
如果 shell 命令结束返回 0,fence 被认为是成功了。如果返回任何其他的结束码,fence 不是成功的,列表中的下个 fence 方法将被尝试。
注意:fence 方法不实现任何的 timeout。如果 timeout 是必要的,它们应该在 shell脚本中实现(例如通过 fork 一个字 shell 在多少秒后杀死它的父 shell)
8. fs.defaultFS :Hadoop文件系统客户端使用的默认的路径前缀
可选地,你现在可能为 Hadoop 客户端配置了默认使用的路径来用新的启用 HA 的逻辑 URI。如果你用 “mycluster” 作为 nameservice ID,这个 id 将是所有你的 HDFS 路径的的 authority 部分。这可能被配置成这样,在你的 core-site.xml 文件里:
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
<description>the default path prefix used by the Hadoop FS client when none is given </description>
</property>
9. dfs.journalnode.edits.dir:JournalNode 守护进程将存储它的本地状态的位置
这是一个在 JournalNode 机器上的绝对路径,此路径中存储了 edit 和 JNs 使用的其他的本地状态。你可能只用配置一个单独的路径。这些数据的冗余通过运行多个独立的 JournalNode 来实现,或者通过配置这个路径到一个 RAID 组。例如:
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/path/to/journal/node/local/data</value>
<description> the path where the JournalNode daemon will store its local state </description>
</property>
6.3 部署详细
在所有必要的配置被设置之后,你必须启动所有的 JournalNode 守护进程。这可以通过运行
hdfs-daemon.sh journalnode
命令完成,然后等待守护进程在每一台相关的机器上启动。
一旦 JournalNode 被启动,你必须先同步两个 HA NameNode 磁盘上的元数据。
- 如果你建立了一个全新的 HDFS 集群,你应该首先在一台 NameNode 上运行 format 命令
hdfs namenode -format
- 如果你已经格式化了 NameNode,或者是从一个非 HA 的集群转变成一个 HA 集群,你现在应该复制你的NameNode 上的元数据目录到另一个 NameNode,没有格式化的 NameNode 通过在此机器上运行
hdfs namenode -bootstrapStandby
命令格式化。运行此命令也将确保 JournalNode(就像通过 dfs.namenode.shared.edits.dir 配置的那样)包含足够的 edit 事务来启动两个 NameNode
- 如果你将一个非 HA 的集群转变为一个HA的集群,你应该运行
hdfs -initializeSharedEdits
这个命令将会用本地 NameNode 的 edit 目录中的数据初始化 JNs
这个时候,你可能启动两个HA NameNode,就像你启动一个NameNode一样。
你可以访问分别每一个 NameNode 的 web 主页通过浏览他们配置的 HTTP 地址。你应该注意到配置的地址的下面将会是 NameNode 的 HA 状态(Standby 或 Active)。不管一个 HA NameNode 何时启动,它首先会处在Standby 状态。
6.4 管理员命令
既然你的 HA NameNode 被配置和启动了,你将可以使用一些命令来管理你的 HA HDFS 集群。特别的,你应该熟悉“hdfs haadmin” 命令的所有子命令。不加任何参数运行此命令将显示下面的帮助信息:
Usage: DFSHAAdmin [-ns <nameserviceId>]
[-transitionToActive <serviceId>]
[-transitionToStandby <serviceId>]
[-failover [--forcefence] [--forceactive] <serviceId> <serviceId>]
[-getServiceState <serviceId>]
[-checkHealth <serviceId>]
[-help <command>]
本指南描述这些子命令的高级用法。对于每一个子命令特殊的用法的信息,你应该运行以下命令来获得
hdfs haadmin -help <command>
1. transitionToActive 和 transitionToStandby:将给定的 NameNode 转变为 Active 或者 Standby
这两个子命令使给定的 NameNode 各自转到 Active 或者 Standby 状态。这两个命令不会尝试运行任何的fence,因此不应该经常使用。你应该更倾向于用 “hdfs haadmin -failover” 命令。
2. failover :在两个 NameNode 之间发起一次故障转移
这个子命令从第一个提供的 NameNode 到第二个提供的 NameNode 发起一次故障转移。如果第一个 NameNode 是 Standby 状态,这个命令将简单的将第二个 NameNode 转成 Active 状态,不会报错。如果第一个 NameNode 在 Active 状态,将会尝试优雅的将其转变为 Standby 状态。如果这个过程失败,fence method(就像 dfs.ha.fencing.methods 配置的)将会被顺序尝试直到有一个返回 success。在这个过程之后,第二个 NameNode 将会被转换为 Active 状态。如果没有 fence method 成功,第二个 NameNode 将不会被转变成 Active 状态,将会返回一个错误。
3. getServiceState :判断给定的 NameNode 是 Active 还是 Standby
连接到给定的 NameNode 来判断它目前的状态,打印 Standby 或者 Active 到合适的标准输出。这个子命令可以被需要根据 NameNode 目前的状态做出不同 Action 的定时任务或者监控脚本使用。
4. checkHealth :检查给定 NameNode 的健康状况
连接到给定的 NameNode 检查它的健康状况。NameNode 可以在对自己进行一些检测,包括检查是否有内部服务正在运行。如果 NameNode 是健康的,这个命令将返回 0,不是则返回 非0 值。你可以用这个命令用于检测目的。
注意:这还没有实现,现在将总是返回success,除非给定的NameNode完全关闭。
七. 自动故障转移
7.1 简介
上边的部分描述了如果配置一个手工故障转移。在那种模式下,系统将不会自动触发一个故障转移,将一个NameNode 从 Active 装成 Standby,即使 Active 节点已经失效。这个部分描述了如何配置和部署一个自动故障转移。
7.2 组件
自动故障转移增加了两个新的组件到 HDFS 的部署中:一个Zookeeper 仲裁,ZKFailoverController 进程(简称ZKFC)。
Apache Zookeeper 是一个维护少量数据一致性的高可用的服务,通知客户端那些数据的变化,同时监控客户端的失效状况。HDFS的自动故障转移的实现下面的部分依赖Zookeeper:
Failure detection
集群中的每一台 NameNode 机器在 Zookeeper 中保持一个永久的 session。如果这台机器宕机,通知其他的NameNode,故障转移应该被触发了。Active NameNode选举
Zookeeper 提供了一个简单的机制专门用来选择一个节点为 Active。如果目前 Active NameNode 宕机,另一个namonode 节点可以获取 Zookeeper 中的一个特殊的排它锁,声明它应该变成下一个 Active NameNode。
ZKFailoverController (ZKFC) 是一个新的组件,它是一个 Zookeeper 客户端,同时也用来监视和管理 NameNode 的状态。每一台运行 NameNode 的机器都要同时运行一个 ZKFC 进程,此进程主要负责:
健康监控
ZKFC 周期性地用健康监测命令 ping 它的本地 NameNode 只要 NameNode 及时地用健康状态响应,ZKFC就认为此节点是健康的。如果此节点宕机,睡眠或者其他的原因进入了一个不健康的状态,健康监控器将会标记其为不健康。Zookeeper Session管理
当本地的 NameNode 是健康的,ZKFC 在 Zookeeper 中保持一个打开的 session。如果本地 NameNode 是 Active 状态,它同时在 znode 中保持一个特殊的 “lock” 。这个锁是利用 Zookeeper 对 ephemeral node 的支持;如果 session 过期,这个 lock node 将会自动删除。基于Zookeeper的选举
如果本地 NameNode 是健康的,ZKFC 看到当前没有其他的节点保持 lock znode,它将自己尝试获取这个锁。如果获取成功,它就赢得了选举,然后负责运行一个故障转移来使它本地的 NameNode 变为 Active。故障转移进程与上边描述的的手工转移的类似:首先,如果有必要,原来 Active NameNode 被 fence,然后,本地NameNode 转变为 Active 状态。
一个参考自动故障转移的设计文档来获取更多的信息,参考 Apache HDFS JIRA 上的 HDFS-2185 设计文档。
7.3 ZooKeeper 部署
在一个典型的部署中,Zookeeper 守护进程配置为在 3 到 5 个节点上运行。因为 Zookeeper 本身有轻量级的资源需求,将 Zookeeper 守护进程跟 HDFS 的 Active NameNode 和 Standby NameNode 是可以接受的。许多管理员也选择将第三个 Zookeeper 进程部署到 YARN ResourceManager 一个节点上。建议将 Zookeeper 节点存储它们的数据到一个单独的磁盘驱动,以为了更好的性能和解耦,与存放 HDFS 元数据的驱动程序分开。
Zookeeper的建立超出了本文档的范围。我们将假设你已经建立起了一个3个或者更多节点的ZooKeeper集群,已经通过用ZK CLI连接到ZKServer验证了其正确性。
7.4 在你开始之前
在你开始配置自动故障转移之前,你应该关闭你的集群。目前,在集群运行过程中,从手工故障转移到自动故障转移的转变是不可能的。
7.5 配置自动故障转移
- 自动故障转移的配置需要增减两个新的参数到你的配置文件中。 在 hdfs-site.xml 中增加:
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
<description>on/off NameNode failed switch</description>
</property>
- 这指出集群应该被建立为自动故障转移模式。在 core-site.xml 中,增加:
<property>
<name>ha.zookeeper.quorum</name>
<value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
<description>this lists the host-port pairs running the ZooKeeper service</description>
</property>
这列出了多个正在运行 Zookeeper 服务的主机名-端口号信息。
就像本文档中先前描述的参数一样,这些设置可能用每一个 nameservice 的 id 做前缀来作为配置时的 key。例如,在开启 federation 的集群中,你可能需要明确的指定所要开启自动故障转移的 nameservice,用 dfs.ha.automatic-failover.enabled.my-nameservice-id
指定。
也有其他的配置参数,可能被用来管理自动故障转移的表现;然而,对于大多数的安装来说是不必要的。请参考特定文档获取更多信息。
也有其他的配置参数,可能被用来管理自动故障转移的表现;然而,对于大多数的安装来说是不必要的。请参考特定文档获取更多信息。
7.6 初始化 Zookeeper 中的 HA 状态
在增加了配置之后,下一步就是初始化 Zookeeper 中的必要的状态。你可以通过在任意 NameNode 所在的主机上运行下面的命令来完成这个操作:
hdfs zkfc -formatZK
这将在 Zookeeper 中创建一个 znode,自动故障转移系统存储它的数据在这个 znode 上。
7.7 用 start-dfs.sh 启动集群
因为自动故障转移在配置中已经被开启了,start-dfs.sh 脚本将会在任意运行 NameNode 的机器上自动启动一个 ZKFC 守护进程。当 ZKFC 启动,它们将自动选择一个 NameNode 变成 Active。
7.8 手动启动集群
如果手工管理集群上的服务,你将需要手动在将要运行 NameNode 的机器上启动 zkfc。你可以用下面的命令启动守护进程:
hadoop-daemon.sh start zkfc
7.9 安全访问 Zookeeper
如果你正在运行一个安全的集群,你将很可能希望确保存储在 Zookeeper 中的信息也是安全的。这将防止恶意的客户端修改 Zookeeper 中的元数据或者潜在地触发一个错误的故障转移。
为了确保Zookeeper中信息的安全,首先增加下面的配置到core-site.xml文件:
<property>
<name>ha.zookeeper.auth</name>
<value>@/path/to/zk-auth.txt</value>
</property>
<property>
<name>ha.zookeeper.acl</name>
<value>@/path/to/zk-acl.txt</value>
</property>
请注意这两个值中的 “@”字符,这指出配置不是内联的,而是指向磁盘中的一个文件。
- 第一次配置的文件以跟 ZK CLI 使用的相同的格式指出了一个 Zookeeper 认证的列表。例如,你可能像下面这样指定一些东西:
digest:hdfs-zkfcs:mypassword
….. hdfs-zkfcs 是 Zookeeper 中全局唯一的用户名,mypassword 是一个唯一的字符串,作为密码。
- 下一步,根据这个认证,生成相应的 Zookeeper ACL,使用类似于下面的命令:
java -cp $ZK_HOME/lib/*:$ZK_HOME/zookeeper-3.4.2.jar org.apache.zookeeper.server.auth.DigestAuthenticationProvider hdfs-zkfcs:mypasswordoutput: hdfs-zkfcs:mypassword->hdfs-zkfcs:P/OQvnYyU/nF/mGYvB/xurX8dYs=
- 复制和粘贴 output “->” 后的部分,写到 zk-acls.txt 文件中,要加上 ” digest: ” 前缀,例如:
digest:hdfs-zkfcs:vlUvLnd8MlacsE80rDuu6ONESbM=:rwcda
为了使 ACL 生效,你应该重新运行
zkfc -formatZK
命令做了这些之后,你可能需要验证来自 ZK CLI 的 ACL,像下面这样:
[zk: localhost:2181(CONNECTED) 1] getAcl /hadoop-ha'digest,'hdfs-zkfcs:vlUvLnd8MlacsE80
7.10 验证自动故障转移
一旦自动故障转移被建立,你应该验证它的可用性。为了验证,首先定位 Active NameNode。以可以通过浏览NameNode 的 web 接口分辨哪个 NameNode 是 Active 的。
一旦定位了 Active NameNode,你可以在那个节点上造成一个故障。例如,你可以用 kill -9 <pid of NN>
模拟一次 JVM 崩溃。或者,你可以关闭这台机器或者拔下它的网卡来模仿一次不同类型的中断。在触发了你想测试的中断之后,另一个 NameNode 应该可以在几秒后自动转变为 Active 状态。故障检测和触发一次故障转移所需的时间依靠配置 ha.zookeeper.session-timeout.ms
来实现,默认是5秒。
如果检测不成功,你可能丢掉了配置,检查 zkfc 和 NameNode 进程的日志文件以进行进一步的问题检测。
八. 自动故障转移常见问题
- 我启动 ZKFC 和 NameNode 守护进程的顺序重要么?
不重要,在任何给定的节点上,你可以任意顺序启动 ZKFC 和 NameNode 进程
- 我应该在此增加什么样的监控?
你应该在每一台运行 NameNode 的机器上增加监控以确保 ZKFC 保持运行。在某些类型的 Zookeeper 失效时,例如,ZKFC 意料之外的结束,应该被重新启动以确保,系统准备自动故障转移。
除此之外,你应该监控 Zookeeper 集群中的每一个 Server。如 Zookeeper 宕机,自动故障转移将不起作用。
- 如果Zookeeper宕机会怎样?
如果 Zookeeper 集群宕机,没有自动故障转移将会被触发。但是,HDFS 将继续没有任何影响的运行。当Zookeeper
被重新启动,HDFS 将重新连接,不会出现问题。
- 我可以指定两个 NameNode 中的一个作为主要的 NameNode 么?
当然不可以。目前,这是不支持的。先启动的 NameNode 将会先变成 Active 状态。你可以指定的顺序,先启动你希望成为 Active 的节点,来完成这个目的。
- 自动故障转移被配置时,如何发起一次手工故障转移?
即使自动故障转移被卑职,你也可以用 hdfs haadmin 发起一次手工故障转移。这个命令将执行一次协调的故障转移。
九. HA 开启时 HDFS 升级 /finalization/ 回滚
当在 HDFS 的版本进行转换时,有时,新版本的软件可以被简单的安装,集群被重新启动。然而,有时,HDFS 版本的升级需要改动磁盘上的数据。在这种情况下,在安装了新版本的软件之后,你必须用 HDFS Upgrade/Finalize/Rollback 工具。这个过程在 HA 的环境中更复杂,因为 NameNode 依赖的磁盘上的元数据是根据定义分布在两个 HA 的 NameNode 中的,在用 QJM 来共享 edit 存储时,数据在 JNs 中。文档的本部分描述了在一个 HA 的集群中用 HDFS Upgrade/Finalize/Rollback 工具实现这个过程。
1. 升级一个集群,管理员必须做下面这些:
正常关闭所有的 NameNode,安装新版本的软件
启动所有的 JNs,注意,在执行升级,回滚和 finalization 操作时,所有的 JNs 处于运行状态是至关重要的。如果 JNs 中的任何一个进程在执行升级,回滚和 finalization 操作时当掉,操作将失败。
用
-upgrade
启动 NameNode启动时,正在操作的 NameNode 将不会像在 HA 启动时那样进入 Standby 状态。这个 NameNode 将会立即进入 Active 状态,执行本地存储目录的升级,同时执行共享 edit 日志的升级。
在这时,另一个 NameNode 将不会与已经升级的 NameNode 保持同步。为了将其保持到同步,有一个高可用的集群,你应该用
"-bootstrapStandby"
命令重新引导这个 NameNode。运行第二个 NameNode 时还用"-upgrade"
是错误的。
注意:如果任何时候你想在 finalization 和回滚之前重新启动 NameNode,你应该正常的启动 NameNode,不要加任何特殊的启动标识。
- 结束升级一个HA集群,管理员需要在两个 NameNode 都运行或者其中一个是 Active 状态是运行
hdfs dfsadmin -finalizeUpgrade
命令。这个时候,Active NameNode将会结束共享日志,NameNode 所有包含先前文件系统状态的本地目录将会删除它们的本地状态。
- 回滚一次升级,首先,两个 NameNode 应该关闭。管理员应该在发起升级过程的 NameNode 运行回滚命令,这将在本地目录和共享日志(NFS 或者 JNs)执行回滚。之后,NameNode 应该被启动,管理员在另一个NameNode 运行
"-bootstrapStandby"
,将两个 NameNode 用回滚之后的文件系统状态同步。