使用仲裁日志管理器实现 HDFS 高可用性

目的

本指南概述了 HDFS 高可用性 (HA) 功能,以及如何使用仲裁日志管理器 (QJM) 功能配置和管理 HA HDFS 集群。

本文档假定读者对 HDFS 集群中的通用组件和节点类型有大致了解。有关详细信息,请参阅 HDFS 架构指南。

注意:使用仲裁日志管理器或传统共享存储

本指南讨论如何使用仲裁日志管理器 (QJM) 配置和使用 HDFS HA,以便在活动和备用 NameNode 之间共享编辑日志。有关如何使用 NFS(而不是 QJM)配置 HDFS HA 以进行共享存储的信息,请参阅此备用指南。有关如何使用观察者 NameNode 配置 HDFS HA 的信息,请参阅本指南

背景

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

这以两种主要方式影响了 HDFS 集群的总可用性

  • 在机器崩溃等意外事件的情况下,集群将不可用,直到操作员重新启动 NameNode。

  • NameNode 机器上的计划维护事件(例如软件或硬件升级)将导致集群停机。

HDFS 高可用性功能通过在同一集群中以热备用方式在活动/被动配置中运行两个(3.0.0 及更高版本中为两个以上)冗余 NameNode 来解决上述问题。这样一来,如果一台机器崩溃,则可以快速故障转移到新的 NameNode,或者管理员可以出于计划维护的目的发起优雅的故障转移。

架构

在典型的 HA 集群中,两个或更多台独立机器被配置为 NameNode。在任何时间点,只有一个 NameNode 处于活动状态,而其他 NameNode 处于备用状态。活动 NameNode 负责集群中的所有客户端操作,而备用 NameNode 只是充当工作器,维护足够的状态以在必要时提供快速故障转移。

为了使备用节点保持其状态与活动节点同步,两个节点都与一组称为“日志节点”(JN)的单独守护进程通信。当活动节点执行任何名称空间修改时,它会将修改记录持久地记录到这些 JN 的大多数。备用节点能够从 JN 读取编辑,并且不断监视它们以查看编辑日志的更改。当备用节点看到编辑时,它会将其应用到自己的名称空间。在发生故障转移时,备用节点将确保在提升自身到活动状态之前已从日志节点读取所有编辑。这可确保在发生故障转移之前,名称空间状态完全同步。

为了提供快速故障转移,备用节点还必须拥有有关集群中块位置的最新信息。为了实现这一点,数据节点配置为所有名称节点的位置,并向所有节点发送块位置信息和心跳。

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

硬件资源

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

  • 名称节点计算机 - 您运行活动和备用名称节点的计算机应具有彼此相同的硬件,并且与非 HA 集群中使用的硬件相同。

  • 日志节点计算机 - 您运行日志节点的计算机。日志节点守护进程相对轻量级,因此这些守护进程可以合理地与其他 Hadoop 守护进程(例如名称节点、作业跟踪器或 YARN 资源管理器)一起并置在计算机上。注意:必须至少有 3 个日志节点守护进程,因为编辑日志修改必须写入到大多数 JN。这将允许系统容忍单个计算机的故障。您还可以运行 3 个以上的日志节点,但为了实际增加系统可以容忍的故障数量,您应该运行奇数个 JN(即 3、5、7 等)。请注意,在运行 N 个日志节点时,系统最多可以容忍 (N - 1) / 2 个故障并继续正常运行。

请注意,在 HA 集群中,备用 NameNode 也会对命名空间状态执行检查点,因此无需在 HA 集群中运行辅助 NameNode、检查点节点或备份节点。事实上,这样做会出错。这还允许将非 HA 启用的 HDFS 集群重新配置为 HA 启用的 HDFS 集群,以重复使用先前专门用于辅助 NameNode 的硬件。

部署

配置概述

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

与 HDFS 联合类似,HA 集群重复使用 nameservice ID 来标识一个可能实际上由多个 HA NameNode 组成的单个 HDFS 实例。此外,HA 中添加了一个名为 NameNode ID 的新抽象。集群中的每个不同的 NameNode 都具有不同的 NameNode ID 来对其进行区分。为了支持所有 NameNode 的单个配置文件,相关配置参数的后缀为 nameservice IDNameNode ID

配置详细信息

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

设置这些配置的顺序并不重要,但您为 dfs.nameservicesdfs.ha.namenodes.[nameservice ID] 选择的值将确定后续配置的值。因此,您应该在设置其余配置选项之前确定这些值。

  • dfs.nameservices - 此新名称服务的逻辑名称

    为此名称服务选择一个逻辑名称,例如“mycluster”,并将此逻辑名称用作此配置选项的值。您选择的名称是任意的。它将用于配置和作为集群中绝对 HDFS 路径的授权组件。

    注意:如果您也在使用 HDFS 联合,此配置设置还应包含其他名称服务的列表,无论是否为 HA,作为以逗号分隔的列表。

    <property>
      <name>dfs.nameservices</name>
      <value>mycluster</value>
    </property>
    
  • dfs.ha.namenodes.[名称服务 ID] - 名称服务中每个 NameNode 的唯一标识符

    使用以逗号分隔的 NameNode ID 列表进行配置。DataNode 将使用此列表来确定集群中的所有 NameNode。例如,如果您之前使用“mycluster”作为名称服务 ID,并且想要使用“nn1”、“nn2”和“nn3”作为 NameNode 的各个 ID,则可以按如下方式进行配置

    <property>
      <name>dfs.ha.namenodes.mycluster</name>
      <value>nn1,nn2, nn3</value>
    </property>
    

    注意:HA 的 NameNode 最小数量为两个,但您可以配置更多。建议不要超过 5 个(推荐 3 个 NameNode),因为通信开销较大。

  • dfs.namenode.rpc-address.[名称服务 ID].[名称节点 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>
    <property>
      <name>dfs.namenode.rpc-address.mycluster.nn3</name>
      <value>machine3.example.com:8020</value>
    </property>
    

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

  • dfs.namenode.http-address.[名称服务 ID].[名称节点 ID] - 每个 NameNode 侦听的完全限定 HTTP 地址

    与上面提到的 rpc-address 类似,设置两个 NameNode 的 HTTP 服务器侦听的地址。例如

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

    注意:如果您启用了 Hadoop 的安全功能,还应为每个 NameNode 类似地设置 https-address

  • dfs.namenode.shared.edits.dir - 标识 NameNode 将写入/读取编辑的 JN 组的 URI

    此处配置提供共享编辑存储的 JournalNode 的地址,由活动 NameNode 写入,备用 NameNode 读入,以随时了解活动 NameNode 所做的所有文件系统更改。虽然您必须指定多个 JournalNode 地址,但您应该只配置其中一个 URI。URI 应采用以下形式:qjournal://*host1:port1*;*host2:port2*;*host3:port3*/*journalId*。日志 ID 是此名称服务的唯一标识符,它允许一组 JournalNode 为多个联合名称系统提供存储。虽然不是必需的,但最好为日志标识符重复使用名称服务 ID。

    例如,如果此集群的 JournalNode 在机器“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.[名称服务 ID] - HDFS 客户端用于联系活动 NameNode 的 Java 类

    配置 Java 类的名称,DFS 客户端将使用该名称来确定哪个 NameNode 是当前活动 NameNode,因此哪个 NameNode 当前正在处理客户端请求。Hadoop 当前附带的两个实现是 ConfiguredFailoverProxyProviderRequestHedgingProxyProvider(对于第一个调用,它同时调用所有 namenode 来确定活动的 namenode,并且在后续请求中,调用活动的 namenode 直到发生故障转移),因此除非您正在使用自定义代理提供程序,否则请使用其中一个。例如

    <property>
      <name>dfs.client.failover.proxy.provider.mycluster</name>
      <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>
    
  • dfs.ha.fencing.methods - 在故障转移期间将用于隔离活动 NameNode 的脚本或 Java 类的列表

    为了系统的正确性,在任何给定时间只有一个 NameNode 处于活动状态是可取的。重要的是,当使用仲裁日志管理器时,将只允许一个 NameNode 向 JournalNodes 写入,因此不存在因脑裂场景而损坏文件系统元数据的可能性。但是,当发生故障转移时,以前的活动 NameNode 仍然有可能向客户端提供读取请求,在该 NameNode 尝试写入 JournalNodes 时关闭之前,这些请求可能已过时。因此,即使在使用仲裁日志管理器时,仍然需要配置一些隔离方法。但是,为了在隔离机制发生故障时提高系统的可用性,建议将一个保证返回成功的隔离方法配置为列表中的最后一个隔离方法。请注意,如果您选择不使用任何实际隔离方法,您仍然必须为该设置配置一些内容,例如“shell(/bin/true)”。

    在故障转移期间使用的隔离方法配置为一个以回车分隔的列表,该列表将按顺序尝试,直到一个指示隔离已成功。Hadoop 附带两种方法:shellsshfence。有关实现您自己的自定义隔离方法的信息,请参阅 org.apache.hadoop.ha.NodeFencer 类。


    sshfence - 通过 SSH 连接到活动 NameNode 并终止该进程

    sshfence 选项通过 SSH 连接到目标节点,并使用 fuser 终止侦听服务 TCP 端口的进程。为了使此隔离选项起作用,它必须能够在不提供密码的情况下通过 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 配置一个超时(以毫秒为单位),此后将认为此隔离方法已失败。可以像这样进行配置

        <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 隔离方法运行任意 shell 命令。可以像这样进行配置

        <property>
          <name>dfs.ha.fencing.methods</name>
          <value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
        </property>
    

    ‘(’ 和 ‘)’ 之间的字符串直接传递给 bash shell,并且可能不包含任何闭合括号。

    shell 命令将在一个环境中运行,该环境被设置为包含所有当前 Hadoop 配置变量,其中 ‘_’ 字符替换配置键中的任何 ‘.’ 字符。所使用的配置已经将任何特定于名称节点的配置提升为其通用形式 - 例如 dfs_namenode_rpc-address 将包含目标节点的 RPC 地址,即使配置可能将该变量指定为 dfs.namenode.rpc-address.ns1.nn1

    此外,还提供以下引用要隔离的目标节点的变量

    $target_host 要隔离的节点的主机名
    $target_port 要隔离的节点的 IPC 端口
    $target_address 以上两个,组合为 host:port
    $target_nameserviceid 要隔离的 NN 的名称服务 ID
    $target_namenodeid 要隔离的 NN 的名称节点 ID

    这些环境变量也可以用作 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,则确定隔离成功。如果它返回任何其他退出代码,则隔离不成功,并且将尝试列表中的下一个隔离方法。

    注意:此隔离方法不实现任何超时。如果需要超时,则应在 shell 脚本本身中实现它们(例如,通过派生子 shell 在几秒钟内杀死其父进程)。


  • 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 机器上的绝对路径,JN 使用的编辑和其他本地状态将存储在此处。您只能将一个路径用于此配置。通过运行多个单独的 JournalNode 或在此目录上配置本地连接的 RAID 阵列来提供此数据的冗余。例如

    <property>
      <name>dfs.journalnode.edits.dir</name>
      <value>/path/to/journal/node/local/data</value>
    </property>
    
  • dfs.ha.nn.not-become-active-in-safemode - 如果防止安全模式名称节点变为活动

    是否允许名称节点在安全模式下变为活动,当设置为 true 时,安全模式下的名称节点将在自动故障转移开启时向 ZKFC 报告 SERVICE_UNHEALTHY,或者在自动故障转移关闭时抛出异常以使转换失败。例如

    <property>
      <name>dfs.ha.nn.not-become-active-in-safemode</name>
      <value>true</value>
    </property>
    

部署详细信息

设置所有必需的配置选项后,您必须在将运行这些选项的机器集上启动 JournalNode 守护程序。这可以通过运行命令“hdfs --daemon start journalnode”并等待守护程序在每个相关机器上启动来完成。

JournalNode 启动后,必须先同步两个 HA 名称节点的磁盘元数据。

  • 如果您正在设置新的 HDFS 集群,您应该首先在其中一个名称节点上运行格式化命令 (hdfs namenode -format)。

  • 如果您已经格式化了名称节点,或者正在将非 HA 启用的集群转换为 HA 启用,您现在应该通过在未格式化的名称节点上运行命令“hdfs namenode -bootstrapStandby”将名称节点元数据目录的内容复制到另一个未格式化的名称节点。运行此命令还将确保 JournalNode(由 dfs.namenode.shared.edits.dir 配置)包含足够的编辑事务,以便能够启动两个名称节点。

  • 如果您正在将非 HA NameNode 转换为 HA,则应运行命令“hdfs namenode -initializeSharedEdits”,该命令将使用本地 NameNode 编辑目录中的编辑数据初始化 JournalNode。

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

您可以通过浏览其配置的 HTTP 地址分别访问每个 NameNode 的网页。您应注意,在配置的地址旁边将是 NameNode 的 HA 状态(“备用”或“活动”。)每当 HA NameNode 启动时,它最初处于备用状态。

管理命令

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

Usage: haadmin
    [-transitionToActive <serviceId>]
    [-transitionToStandby <serviceId>]
    [-failover [--forcefence] [--forceactive] <serviceId> <serviceId>]
    [-getServiceState <serviceId>]
    [-getAllServiceState]
    [-checkHealth <serviceId>]
    [-help <command>]

本指南描述了每个子命令的高级用法。有关每个子命令的具体用法信息,您应运行“hdfs haadmin -help <command>”。

  • transitionToActivetransitionToStandby - 将给定 NameNode 的状态转换为活动或备用

    这些子命令分别导致给定 NameNode 转换为活动或备用状态。这些命令不会尝试执行任何隔离,因此很少使用。相反,几乎总是应该优先使用“hdfs haadmin -failover”子命令。

  • failover - 在两个 NameNode 之间启动故障转移

    此子命令导致从第一个提供的 NameNode 故障转移到第二个。如果第一个 NameNode 处于备用状态,则此命令只会将第二个无错误地转换为活动状态。如果第一个 NameNode 处于活动状态,则将尝试将其平稳地转换为备用状态。如果失败,将按顺序尝试隔离方法(由 dfs.ha.fencing.methods 配置),直到成功为止。只有在此过程之后,第二个 NameNode 才会转换为活动状态。如果没有隔离方法成功,则第二个 NameNode 不会转换为活动状态,并且将返回错误。

  • getServiceState - 确定给定的 NameNode 是活动还是备用

    连接到提供的 NameNode 以确定其当前状态,适当地将“备用”或“活动”打印到 STDOUT。此子命令可由 cron 作业或监视脚本使用,这些脚本需要根据 NameNode 当前是活动还是备用而表现出不同的行为。

  • getAllServiceState - 返回所有 NameNode 的状态

    连接到配置的 NameNode 以确定当前状态,适当地将“备用”或“活动”打印到 STDOUT。

  • checkHealth - 检查给定 NameNode 的运行状况

    连接到提供的 NameNode 以检查其运行状况。NameNode 能够对自身执行一些诊断,包括检查内部服务是否按预期运行。如果 NameNode 运行状况良好,此命令将返回 0,否则返回非零值。可以将此命令用于监视目的。

    注意:此功能尚未实现,目前除非给定的 NameNode 完全关闭,否则将始终返回成功。

负载均衡器设置

如果您在负载均衡器(例如 AzureAWS )后面运行一组 NameNode,并且希望负载均衡器指向活动 NN,则可以使用 /isActive HTTP 端点作为运行状况探测。如果 NN 处于活动 HA 状态,http://NN_HOSTNAME/isActive 将返回 200 状态代码响应,否则返回 405。

正在进行的编辑日志尾随

在默认设置下,备用 NameNode 仅应用存在于已完成的编辑日志段中的编辑。如果需要具有最新命名空间信息的备用 NameNode,则可以启用正在进行的编辑段的尾随。此设置将尝试从 JournalNode 上的内存缓存中获取编辑,并且可以将事务在备用 NameNode 上应用之前的时间延迟减少到毫秒级。如果无法从缓存中提供编辑,备用仍然能够检索它,但延迟时间会长得多。相关配置为

  • dfs.ha.tail-edits.in-progress - 是否启用正在进行的编辑日志的尾随。这也将在 JournalNode 上启用内存编辑缓存。默认情况下禁用。

  • dfs.journalnode.edit-cache-size.bytes - JournalNode 上编辑的内存中缓存的大小。在典型环境中,每个编辑大约占用 200 字节,因此,例如,默认的 1048576 (1MB) 大小可以容纳大约 5000 个事务。建议监控 JournalNode 指标 RpcRequestCacheMissAmountNumMisses 和 RpcRequestCacheMissAmountAvgTxns,它们分别计算无法由缓存提供服务的请求数,以及请求成功所需的额外事务数。例如,如果一个请求尝试从事务 ID 10 开始获取编辑,但缓存中最旧的数据位于事务 ID 20,则会将值 10 添加到平均值中。

此功能主要与备用/观察者读取功能结合使用时很有用。使用此功能,可以从非活动 NameNode 提供读取请求;因此,跟踪正在进行的编辑为这些节点提供了使用更新鲜的数据提供请求的能力。有关此功能的更多信息,请参阅 Apache JIRA 工单 HDFS-12943。

自动故障转移

简介

以上部分介绍了如何配置手动故障转移。在此模式下,即使活动节点已发生故障,系统也不会自动触发从活动 NameNode 到备用 NameNode 的故障转移。本部分介绍如何配置和部署自动故障转移。

组件

自动故障转移向 HDFS 部署添加了两个新组件:ZooKeeper 仲裁和 ZKFailoverController 进程(缩写为 ZKFC)。

Apache ZooKeeper 是一项高可用性服务,用于维护少量协调数据,通知客户端有关该数据中的更改,以及监控客户端是否发生故障。自动 HDFS 故障转移的实现依赖 ZooKeeper 来完成以下任务

  • 故障检测 - 集群中的每台 NameNode 机器都在 ZooKeeper 中维护一个持久会话。如果机器崩溃,ZooKeeper 会话将过期,通知其他 NameNode(s) 应触发故障转移。

  • 活动 NameNode 选举 - ZooKeeper 提供了一种简单的机制来专门选举一个节点作为活动节点。如果当前活动 NameNode 崩溃,另一个节点可能会在 ZooKeeper 中获取一个特殊的独占锁,表示它应成为下一个活动节点。

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

  • 健康监控 - ZKFC 会定期使用健康检查命令 ping 其本地 NameNode。只要 NameNode 及时响应并处于健康状态,ZKFC 就会认为该节点是健康的。如果该节点已崩溃、冻结或进入其他不健康状态,健康监控器会将其标记为不健康。

  • ZooKeeper 会话管理 - 当本地 NameNode 健康时,ZKFC 会在 ZooKeeper 中保持会话处于打开状态。如果本地 NameNode 处于活动状态,它还将持有特殊的“锁定”znode。此锁定使用 ZooKeeper 对“临时”节点的支持;如果会话过期,锁定节点将自动删除。

  • 基于 ZooKeeper 的选举 - 如果本地 NameNode 健康,并且 ZKFC 看到当前没有其他节点持有锁定 znode,它本身将尝试获取锁定。如果成功,则它“赢得了选举”,并负责运行故障转移以使其本地 NameNode 处于活动状态。故障转移过程类似于上面描述的手动故障转移:首先,如果需要,将隔离之前的活动,然后本地 NameNode 转换为活动状态。

有关自动故障转移设计的更多详细信息,请参阅附加到 Apache HDFS JIRA 上的 HDFS-2185 的设计文档。

部署 ZooKeeper

在典型的部署中,ZooKeeper 守护进程配置为在三个或五个节点上运行。由于 ZooKeeper 本身对资源需求较低,因此可以将 ZooKeeper 节点与 HDFS NameNode 和备用节点放在同一硬件上。许多操作员选择将第三个 ZooKeeper 进程部署在与 YARN ResourceManager 相同的节点上。建议将 ZooKeeper 节点配置为将数据存储在与 HDFS 元数据分开的磁盘驱动器上,以获得最佳性能和隔离性。

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

开始之前

在开始配置自动故障转移之前,您应该关闭集群。在集群运行时,目前无法从手动故障转移设置过渡到自动故障转移设置。

配置自动故障转移

自动故障转移的配置需要在配置中添加两个新参数。在您的 hdfs-site.xml 文件中,添加

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

这指定集群应设置为自动故障转移。在您的 core-site.xml 文件中,添加

 <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.enabled.my-nameservice-id 来显式地仅为其中一个名称服务启用自动故障转移。

还有其他几个配置参数可以用来控制自动故障转移的行为;但是,大多数安装不需要这些参数。有关详细信息,请参阅特定配置键文档。

在 ZooKeeper 中初始化 HA 状态

添加配置键后,下一步是在 ZooKeeper 中初始化所需状态。您可以通过从其中一个 NameNode 主机运行以下命令来执行此操作。

[hdfs]$ $HADOOP_HOME/bin/hdfs zkfc -formatZK

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

使用 start-dfs.sh 启动集群

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

手动启动集群

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

[hdfs]$ $HADOOP_HOME/bin/hdfs --daemon start zkfc

保护对 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>

请注意这些值中的“@”字符 - 这指定配置不是内联的,而是指向磁盘上的文件。还可以通过 CredentialProvider 读取身份验证信息(请参阅 hadoop-common 项目中的 CredentialProviderAPI 指南)。

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

digest:hdfs-zkfcs:mypassword

…其中hdfs-zkfcs是 ZooKeeper 的唯一用户名,mypassword是作为密码使用的唯一字符串。

接下来,使用以下命令生成与此身份验证相对应的 ZooKeeper ACL

[hdfs]$ 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>来模拟 JVM 崩溃。或者,您可以对机器进行电源循环或拔下其网络接口以模拟不同类型的故障。在触发您希望测试的故障后,另一个 NameNode 应在几秒钟内自动变为活动状态。检测故障并触发故障转移所需的时间取决于ha.zookeeper.session-timeout.ms的配置,但默认为 5 秒。

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

自动故障转移常见问题解答

  • 我以任何特定顺序启动 ZKFC 和 NameNode 守护进程重要吗?

    不。在任何给定节点上,您都可以在其对应的 NameNode 之前或之后启动 ZKFC。

  • 我应该采取哪些其他监控措施?

    您应该在运行 NameNode 的每个主机上添加监控,以确保 ZKFC 保持运行。例如,在某些类型的 ZooKeeper 故障中,ZKFC 可能会意外退出,并且应该重新启动以确保系统已准备好进行自动故障转移。

    此外,您应该监控 ZooKeeper 仲裁组中的每个服务器。如果 ZooKeeper 崩溃,则自动故障转移将无法正常工作。

  • 如果 ZooKeeper 宕机,会发生什么?

    如果 ZooKeeper 集群崩溃,不会触发任何自动故障转移。但是,HDFS 将继续运行,不受任何影响。当 ZooKeeper 重新启动时,HDFS 将重新连接,不会出现任何问题。

  • 我可以将我的一个 NameNode 指定为主要/首选 NameNode 吗?

    不行。目前,不支持此功能。首先启动的 NameNode 将变为活动状态。你可以选择按特定顺序启动集群,以便你的首选节点首先启动。

  • 当配置了自动故障转移时,我如何启动手动故障转移?

    即使配置了自动故障转移,你也可以使用相同的 hdfs haadmin 命令启动手动故障转移。它将执行协调故障转移。

启用 HA 的 HDFS 升级/最终化/回滚

在 HDFS 版本之间移动时,有时只需安装较新的软件并重新启动集群即可。但是,有时升级正在运行的 HDFS 版本可能需要更改磁盘数据。在这种情况下,必须在安装新软件后使用 HDFS 升级/最终化/回滚工具。在 HA 环境中,此过程变得更加复杂,因为 NN 所依赖的磁盘元数据在定义上是分布式的,既在该对中的两个 HA NN 上,又(如果 QJM 用于共享编辑存储)在 JournalNode 上。本部分文档介绍了在 HA 设置中使用 HDFS 升级/最终化/回滚工具的过程。

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

  1. 正常关闭所有 NN,并安装较新的软件。

  2. 启动所有 JN。请注意,在执行升级、回滚或最终化操作时,所有 JN 必须正在运行。如果在运行任何这些操作时任何 JN 已关闭,则操作将失败。

  3. 使用 '-upgrade' 标志启动其中一个 NN。

  4. 启动后,此 NN 不会像在 HA 设置中通常那样进入备用状态。相反,此 NN 将立即进入活动状态,执行其本地存储目录的升级,并执行共享编辑日志的升级。

  5. 此时,HA 对中的其他 NN 将与已升级的 NN 不同步。为了使它重新同步并再次拥有高可用性设置,您应该通过使用 '-bootstrapStandby' 标志运行 NN 来重新引导此 NameNode。使用 '-upgrade' 标志启动此第二个 NN 是一个错误。

请注意,如果您在完成或回滚升级之前想要随时重新启动 NameNode,您应该像往常一样启动 NN,即不使用任何特殊启动标志。

要查询升级状态,操作员将使用 `hdfs dfsadmin -upgrade query' 命令,同时至少运行一个 NN。该命令将返回每个 NN 的 NN 升级过程是否已完成。

要完成 HA 升级,操作员将使用 `hdfs dfsadmin -finalizeUpgrade' 命令,同时 NN 正在运行并且其中一个处于活动状态。此时活动 NN 将执行共享日志的最终化,并且其本地存储目录包含先前 FS 状态的 NN 将删除其本地状态。

要执行升级回滚,应首先关闭两个 NN。操作员应在启动升级过程的 NN 上运行回滚命令,该命令将在本地目录以及共享日志(NFS 或 JN)上执行回滚。之后,应启动此 NN,并且操作员应在另一个 NN 上运行 `-bootstrapStandby' 以使这两个 NN 与此回滚的文件系统状态同步。