本指南讨论如何使用 Quorum Journal Manager (QJM)配置和使用 HDFS HA 在 Active 和 Standby NameNodes 之间共享edit logs。

背景

在 Hadoop 2.0.0之前,NameNode 是 HDFS 集群中的单点故障(SPOF)。每个集群都有一个 NameNode,如果该机器或进程不可用,则集群作为一个整体将不可用,直到 NameNode 重新启动。

这从两个方面影响了 HDFS 集群的总可用性:

  • 在计划外事件(如机器崩溃)的情况下,集群将不可用,直到操作员重新启动 NameNode
  • 计划的维护事件(如 NameNode 计算机上的软件或硬件升级)将导致集群停机窗口

HDFS 高可用性特性解决了上述问题,它提供了在主动/被动配置和热备份中在同一集群中运行两个冗余 namenode 的选项。这允许在机器崩溃的情况下快速故障转移到新的 NameNode,或者为了计划的维护目的由管理员启动的故障转移。

Architecture

在典型的 HA 集群中,将两台独立的机器配置为 NameNodes。在任何时候,确切地说,NameNodes 中的一个处于活动状态Active,另一个处于备用状态Standby。Active NameNode 负责集群中的所有客户机操作,而 Standby 只是充当从机,维护足够的状态,以便在必要时提供快速故障转移。

为了使Standby节点的状态与Active节点保持同步,两个节点都与一组称为“ JournalNodes”(JNs)的独立守护进程进行通信。当主动节点执行任何名称空间修改时,它会持久地将修改记录记录到大多数JNs上。Standby 节点能够从 JNs 中读取edits,并不断观察它们对edits的更改。当 Standby Node 看到edits时,它将它们应用到自己的名称空间。在发生故障转移时,Standby 将确保在将自己升级到 Active 状态之前,已经从 JounalNodes 读取了所有edits。这可以确保在故障转移发生之前,命名空间状态是完全同步的。

为了提供快速故障转移,备用节点还必须具有有关群集中块的位置的最新信息。为了实现这一点,DataNodes 配置了两个 NameNodes 的位置,并向两者发送块位置信息和心跳。

每次只有一个 namenode 处于活动状态对于 HA 集群的正确操作至关重要。否则,名称空间的状态将很快在两者之间发生分歧,可能导致数据丢失或其他不正确的结果。为了确保此属性并防止所谓的“裂脑场景”,JournalNodes 一次只允许单个 NameNode 作为写入器。在故障转移期间,即将变为活动的 NameNode 将简单地接管写入 JournalNodes 的角色,这将有效地防止其他 NameNode 继续处于活动状态,从而允许新的 Active 安全地继续进行故障转移。

硬件资源

为了部署 HA 集群,您应该准备以下内容:

  • NameNode machines- 在其上运行 Active 和 Standby NameNodes 的机器应该具有彼此相等的硬件,以及与非 ha 集群中使用的硬件相等的硬件
  • JournalNode machines- 运行 JournalNodes 的机器。JournalNode 守护进程是相对轻量级的,因此这些守护进程可以合理地与其他 Hadoop 守护进程并存在同一机器上,例如 NameNodes 或者 yaresourcemanager ,必须至少有3个 JournalNode 守护进程,因为edits修改必须写入大多数的 JournalNodes。这将允许系统容忍单台机器的故障。您也可以运行多于3个日志节点,但是为了实际增加系统可以容忍的故障数量,您应该运行奇数个 JournalNode (即3、5、7等)。请注意,当使用 n 个 journalnode 运行时,系统最多只能容忍(n-1)/2的故障,并继续正常运行

部署

配置概述

与 Federation 配置类似,HA 配置是向后兼容的,并允许现有的单个 NameNode 配置在不更改的情况下工作。新配置的设计使得集群中的所有节点可以拥有相同的配置,而不需要根据节点的类型将不同的配置文件部署到不同的机器上。

与 HDFS 联邦一样,HA 集群重用 nameservice ID 来识别单个 HDFS 实例,该实例实际上可能由多个 HA NameNodes 组成。此外,还在 HA 中添加了一个名为 NameNode ID 的新抽象。集群中每个不同的 NameNode 都有一个不同的 NameNode ID 来区分它。为了支持所有 NameNode 的单个配置文件,相关的配置参数以名称服务 ID 和 NameNode ID 作为后缀。

配置细节

要配置 HA NameNodes,必须向 hdfs-site.xml 配置文件添加几个配置选项。

设置这些配置的顺序并不重要,重要的是为 dfs.nameservices 和 dfs.ha.namenodes 选择的值。[ nameservicid ]将确定后面的密钥。因此,您应该在设置其余配置选项之前确定这些值。

  • dfs.nameservices - 这个新命名服务的逻辑名称
    为此命名服务选择一个逻辑名称,例如“ mycluster”,并将此逻辑名称用作此配置选项的值。你选择的名字是随意的。它既用于配置,也用作集群中绝对 HDFS 路径的授权组件。
    注意: 如果您也在使用 HDFS Federation,这个配置设置还应该包括其他名称服务(HA 或其他)的列表,作为一个逗号分隔的列表。
<property>
  <name>dfs.nameservices</name>
  <value>mycluster</value>
</property>
  • dfs.ha.namenodes.[nameservice ID] - 名称服务中每个 NameNode 的唯一标识符
    使用逗号分隔的 NameNode id 列表进行配置。DataNodes 将使用它来确定集群中的所有 namenode。例如,如果您以前使用“ mycluster”作为名称/服务 ID,并且希望使用“ nn1”和“ nn2”作为 NameNodes 的单个 ID,那么可以这样配置:
<property>
  <name>dfs.ha.namenodes.mycluster</name>
  <value>nn1,nn2</value>
</property>

注意: 目前,每个名称服务最多只能配置两个 NameNodes。

  • dfs.namenode.rpc-address.[nameservice ID].[name node ID] - 监听每个 NameNode 的完全限定 RPC 地址
    对于以前配置的两个 NameNode id,请设置 NameNode 处理器的完整地址和 IPC 端口。请注意,这将导致两个独立的配置选项。例如:
<property>
  <name>dfs.namenode.rpc-address.mycluster.nn1</name>
  <value>machine1.example.com:8020</value>
</property>
<property>
  <name>dfs.namenode.rpc-address.mycluster.nn2</name>
  <value>machine2.example.com:8020</value>
</property>

注意: 如果您愿意,也可以同样地配置“ servicerpc-address”设置。

  • dfs.namenode.http-address.[nameservice ID].[name node ID] - 监听每个 NameNode 的完全限定的 HTTP 地址

与上面的 rpc-address 类似,为 NameNodes 的 HTTP 服务器设置监听的地址:

<property>
  <name>dfs.namenode.http-address.mycluster.nn1</name>
  <value>machine1.example.com:50070</value>
</property>
<property>
  <name>dfs.namenode.http-address.mycluster.nn2</name>
  <value>machine2.example.com:50070</value>
</property>

注意: 如果启用了 Hadoop 的安全特性,还应该为每个 NameNode 类似地设置 https-address。

  • dfs.namenode.shared.edits.dir - URI,标识 NameNodes 将在其中写入/读取编辑的 JNs 组
    在这里,配置 JournalNodes 的地址,这些 JournalNodes 提供共享的编辑存储,由 Active nameNode 写入并由 Standby nameNode 读取,以便随时更新 Active nameNode 所做的所有文件系统更改。虽然必须指定多个 JournalNode 地址,但是应该只配置其中一个 uri。URI 的格式应该是: “ qjournal://host1: port1; host2: port2; host3: port3/journalId”。Journal ID 是这个名称服务的唯一标识符,它允许一组单独的 JournalNodes 为多个联邦名称系统提供存储空间。
    例如,如果这个集群的 JournalNodes 运行在机器“ node1.example.com”、“ node2.example.com”和“ node3.example.com”上,并且名称服务 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>
</property>
  • dfs.client.failover.proxy.provider.[nameservice ID] - HDFS 客户端用来联系 Active NameNode 的 Java 类
    配置将由 DFS 客户机使用的 Java 类的名称,以确定哪个 NameNode 是当前的 Active,从而确定哪个 NameNode 当前正在服务客户机请求。当前与 Hadoop 一起提供的唯一实现是 ConfiguredFailoverProxyProvider,因此除非使用自定义实现,否则请使用它。例如:
<property>
  <name>dfs.client.failover.proxy.provider.mycluster</name>
  <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
  • **dfs.ha.fencing.methods **- 在故障转移期间用于保护 Active NameNode 的脚本或 Java 类的列表
    为了保证系统的正确性,在任何给定的时间内只有一个NameNode处于活动状态。重要的是,当使用Quorum Journal Manager时,将只允许一个NameNode向journalnode写入数据,因此不存在破坏裂脑场景中的文件系统元数据的可能性。但是,当故障转移发生时,前一个活动的NameNode仍然可能向客户端提供读请求,这些请求可能会过期,直到NameNode在试图写入journalnode时关闭。由于这个原因,即使在使用Quorum Journal Manager时,仍然需要配置一些fencing方法。但是,为了在防御机制失败时提高系统的可用性,建议配置一个防御方法,它可以保证返回成功,作为列表中的最后一个防御方法。请注意,如果您选择不使用实际的fencing方法,您仍然必须为该设置配置一些东西,例如“shell(/bin/true)”。
    故障转移过程中使用的隔离方法被配置为一个回车分隔列表,将依次尝试,直到其中一个表明隔离已经成功。Hadoop附带了两种方法:shell和sshfence。有关实现您自己的自定义防护方法的信息,请参阅org.apache.hadoop.ha。NodeFencer类。
  • sshfence - SSH 到 Active NameNode 并终止进程
    sshfence 选项 SSHes 指向目标节点,并使用 fuser 杀死侦听服务的 TCP 端口的进程。为了使这个fencing选项起作用,它必须能够通过 SSH 连接到目标节点,而不提供密码短语。因此,还必须配置 dfs.ha.fencing.SSH.private-key-files 选项,这是一个用逗号分隔的 SSH 私钥文件列表。例如:
<property>
  <name>dfs.ha.fencing.methods</name>
  <value>sshfence</value>
</property>
<property>
  <name>dfs.ha.fencing.ssh.private-key-files</name>
  <value>/home/exampleuser/.ssh/id_rsa</value>
</property>

也可以配置一个非标准的用户名或端口来执行 SSH。还可以为 SSH 配置一个超时(以毫秒为单位) ,超过这个超时后,这个fencing方法将被视为失败。它可以这样配置:

<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>
</property>
  • shell - 运行任意的 shell 命令来保护活动 NameNode
    Shell fencing 方法运行一个任意的 shell 命令:
<property>
  <name>dfs.ha.fencing.methods</name>
  <value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
</property>
  • fs.defaultFS - 在没有给定任何路径时,Hadoop FS 客户机使用的默认路径前缀
    或者,您现在可以为 Hadoop 客户端配置默认路径,以使用新的支持 ha 的逻辑 URI。如果您使用“ mycluster”作为前面的命名服务 ID,那么这将是所有 HDFS 路径的权限部分的值。在 core-site.xml 文件中,可以这样配置:
<property>
  <name>fs.defaultFS</name>
  <value>hdfs://mycluster</value>
</property>
  • dfs.journalnode.edits.dir - JournalNode 守护进程将存储其本地状态的路径
    这是 JournalNode 计算机上的绝对路径,存储 JNIs 使用的编辑和其他本地状态。此配置只能使用单一路径。通过运行多个独立的 JournalNodes 或在本地附加的 RAID 阵列上配置此目录,可以为此数据提供冗余。例如:
<property>
  <name>dfs.journalnode.edits.dir</name>
  <value>/path/to/journal/node/local/data</value>
</property>

部署细节

在设置了所有必要的配置选项之后,必须在将要运行 JournalNode 守护进程的机器集上启动它们。这可以通过运行命令“ hadoop-daemon”来实现。sh start journalnode”并等待守护进程在每台相关机器上启动。

启动 JournalNodes 之后,必须首先同步两个 HA NameNodes 的磁盘上元数据。

  • 如果您正在设置一个新的 HDFS 集群,应该首先运行 format 命令( hdfs namenode -format)在一个 NameNodes 上
  • 如果您已经格式化了 NameNode,或者正在将不支持 ha 的集群转换为支持 ha 的,那么现在应该通过运行命令将 NameNode 元数据目录的内容复制到另一个未格式化的 NameNode 上,并在未格式化的节点上运行hdfs namenode -bootstrapStandby命令,以便能够启动两个 NameNodes
  • 如果要将非 HA NameNode 转换为 HA,则应运行命令”hdfs -initializeSharedEdits”,它将使用来自本地 NameNode 编辑目录的编辑数据初始化 journalnode

此时,您可以像通常启动 NameNode 那样启动两个 HA NameNode。

您可以通过浏览配置的 HTTP 地址来访问 NameNodes 的每个网页。您应该注意到,配置地址旁边将是 NameNode 的 HA 状态(“ standby”或“ active”.)无论何时启动 HA NameNode,它最初都处于备用状态。

管理命令

现在您的 HA NameNodes 已经配置和启动,您将可以访问一些其他命令来管理您的 HA HDFS 集群。具体来说,您应该熟悉“ hdfs hadmin”命令的所有子命令。在没有任何附加参数的情况下运行该命令将显示以下使用信息:

Usage: DFSHAAdmin [-ns <nameserviceId>]
    [-transitionToActive <serviceId>]
    [-transitionToStandby <serviceId>]
    [-failover [--forcefence] [--forceactive] <serviceId> <serviceId>]
    [-getServiceState <serviceId>]
    [-checkHealth <serviceId>]
    [-help <command>]

本指南描述了每个子命令的高级使用。对于每个子命令的特定用法信息,您应该运行“ hdfs hadmin-help < command >”。

  • transitionToActivetransitionToStandby - 将给定 NameNode 的状态转换为 Active 或 Standby
  • failover - 启动两个 NameNodes 之间的故障转移
  • getServiceState 确定给定的 NameNode 是活动还是待机
  • **checkHealth **检查给定 NameNode 的健康状况

自动故障转移

引言

以上部分描述了如何配置手动故障转移。在这种模式下,即使主动节点失败,系统也不会自动触发从主动到备用 NameNode 的故障转移。本节描述如何配置和部署自动故障转移。

组件

自动故障转移为 HDFS 部署添加了两个新组件: ZooKeeper quorum 和 ZKFailoverController 进程(简称为 ZKFC)。

Apache ZooKeeper 是一个高可用性的服务,用于维护少量的协调数据,通知客户数据的变化,并监视客户的故障。自动 HDFS 故障转移的实现依赖于 ZooKeeper 做以下事情:

  • Failure detection- 集群中的每个 NameNode 机器在 ZooKeeper 中维护一个持久会话。如果机器崩溃,ZooKeeper 会话将过期,通知其他 NameNode 应该触发故障转移
  • Active NameNode election- ZooKeeper 提供了一个简单的机制来将一个节点独占地选为活动节点。如果当前活动的 NameNode 崩溃,另一个节点可能会在 ZooKeeper 中获得一个特殊的独占锁,表明它应该成为下一个活动的

ZKFailoverController (ZKFC)是一个新组件,它是一个 ZooKeeper 客户机,它还监视和管理 NameNode 的状态。每台运行 NameNode 的机器也运行 ZKFC,ZKFC 负责:

  • Health monitoring- ZKFC 通过一个健康检查命令,定期发送当地的 NameNode。只要 NameNode 及时以健康状态作出反应,ZKFC 就认为节点是健康的。如果节点已崩溃、冻结或以其他方式进入不健康状态,健康状态监视器将标记为不健康
  • ZooKeeper session management -当当地的 NameNode 是健康的,ZKFC持有Zookeeper的一个会话。如果本地 NameNode 处于活动状态,它还保存一个特殊的“ lock” znode。这个锁使用 ZooKeeper 对“ ephemeral”节点的支持; 如果会话过期,锁节点将被自动删除。
  • ZooKeeper-based election - 如果本地 NameNode 是健康的,ZKFC 看到目前没有其他节点持有锁 znode,它将自己尝试获得锁。如果成功,那么它已经“赢得了选举”,并负责运行故障转移,使其本地 NameNode 处于活动状态。故障转移过程类似于上面描述的手动故障转移。

部署 ZooKeeper

在典型的部署中,ZooKeeper 守护进程被配置为在三个或五个节点上运行。由于 ZooKeeper 本身有轻量级的资源需求,因此将 ZooKeeper 节点配置在 HDFS NameNode 和 Standby Node 所在的硬件上是可以接受的。许多操作员选择在同一个节点上部署第三个 ZooKeeper 进程。建议配置 ZooKeeper 节点,将其数据存储在与 HDFS 元数据不同的磁盘驱动器上,以获得最佳性能和最佳隔离。

ZooKeeper 的设置超出了本文档的范围。我们假设您已经建立了一个在三个或更多节点上运行的 ZooKeeper 集群,并且通过使用 ZK CLI 连接验证了它的正确操作。

在你开始之前

在开始配置自动故障转移之前,应该关闭群集。当前不可能在集群运行时从手动故障转移设置转移到自动故障转移设置。

配置自动故障转移

自动故障转移的配置需要在配置中添加两个新的参数:

<property>
   <name>dfs.ha.automatic-failover.enabled</name>
   <value>true</value>
 </property>

这指定应该为自动故障转移设置集群:

<property>
   <name>ha.zookeeper.quorum</name>
   <value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
 </property>

它列出了运行 ZooKeeper 服务的主机端口对。

与文档中前面描述的参数一样,可以在每个名称服务的基础上配置这些设置,方法是在配置密钥后面加上名称服务 ID。例如,在启用联合的集群中,可以通过设置 dfs.ha.automatic-failover,显式地只为其中一个名称服务启用自动故障转移。可以,我的同名者 id。

还可以设置其他几个配置参数来控制自动故障转移的行为; 但是,对于大多数安装来说,它们并不是必需的。有关详细信息,请参阅配置关键字特定文档。

在 ZooKeeper 中初始化 HA 状态

在添加了配置键之后,下一步是在 ZooKeeper 中初始化所需的状态。可以通过从 NameNode 主机之一运行以下命令来实现。

$ hdfs zkfc -formatZK

这将在 ZooKeeper 中创建一个 znode,自动故障转移系统在其中存储数据。

使用以下命令启动集群start-dfs.sh

由于在配置中启用了自动故障转移,因此 start-dfs.sh 脚本现在将在任何运行 NameNode 的机器上自动启动 ZKFC 守护进程。当 zkfc 启动时,它们将自动选择一个 namenode 以变为活动。

手动启动集群

如果您手动管理集群上的服务,则需要在每台运行 NameNode 的机器上手动启动 zkfc 守护进程。可以通过运行以下命令来启动守护进程:

$ hadoop-daemon.sh start zkfc

保护对 ZooKeeper 的访问

如果您正在运行一个安全的集群,您可能希望确保 ZooKeeper 中存储的信息也是安全的。这可以防止恶意客户端修改 ZooKeeper 中的元数据,或者可能触发错误的故障转移。

为了保护 ZooKeeper 中的信息,首先在您的核心 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>

请注意这些值中的“@”字符——这表明配置指向磁盘上的一个文件。

第一个配置的文件指定了一个 ZooKeeper 身份验证列表,其格式与 ZK CLI 使用的格式相同。例如,您可以指定如下内容:

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:mypassword
output: hdfs-zkfcs:mypassword->hdfs-zkfcs:P/OQvnYyU/nF/mGYvB/xurX8dYs=

复制并粘贴输出中’->’字符串之后的部分到 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:vlUvLnd8MlacsE80rDuu6ONESbM=
: cdrwa

验证自动故障转移

设置了自动故障转移之后,应该测试其操作。为此,首先定位活动的 NameNode。您可以通过访问 NameNode web 接口来判断哪个节点是活动的——每个节点在页面顶部报告其 HA 状态。

找到活动 NameNode 后,可能会导致该节点出现故障。例如,您可以使用 kill -9 <pid of NN> 。或者,您可以循环启动机器,或者拔掉网络接口,以模拟不同类型的中断。在触发您希望测试的停机之后,其他 NameNode 应该会在几秒钟内自动变为活动状态。检测故障并触发故障转移所需的时间取决于 ha.zookeeper.session-timeout 的配置。多发性硬化症,但默认为5秒。

如果测试没有成功,你可能有一个错误的配置。检查 zkfc 守护进程和 NameNode 守护进程的日志,以便进一步诊断问题。

启用 HA 的 HDFS 升级/终止/回滚

在不同版本的 HDFS 之间移动时,有时可以简单地安装较新的软件并重新启动集群。然而,有时升级您正在运行的 HDFS 版本可能需要更改磁盘上的数据。在这种情况下,必须在安装新软件后使用 HDFS 升级/敲定/回滚工具。在 HA 环境中,这个过程变得更加复杂,因为 NN 依赖的磁盘元数据是分布式的,既分布在两个 HA NNs 上,也分布在使用 QJM 进行共享编辑存储的 JournalNodes 上。本文档小节描述在 HA 设置中使用 HDFS 升级/敲定/回滚工具的过程。

要执行 HA 升级,操作员必须执行以下操作:

  1. 正常关闭所有的 NNs,并安装新的软件
  2. 启动所有的 JNs 。当执行升级、回滚或终止操作时,所有的 JNs 都必须在运行。如果在运行这些操作中的任何一个时,任何一个 JNs 处于停机状态,则操作将失败
  3. 启动其中一个 NNs -upgrade
  4. 在开始时,这个 NN 不会像通常在 HA 设置中那样进入备用状态。相反,这个 NN 将立即进入活动状态,执行本地存储文件的升级,并且还将执行共享编辑日志的升级
  5. 此时,其他 NN 将与升级后的 NN 不同步。为了使其恢复同步并再次拥有高可用性的设置,您应该通过使用 '-bootstrapStandby’ 启动第二个NN