共计 18387 个字符,预计需要花费 46 分钟才能阅读完成。
1、概述
Hadoop2.X中的 HDFS(Vsersion2.0) 相比于 Hadoop1.X 增加了两个重要功能,HA和 Federation。HA 解决了 Hadoop1.X Namenode 中一直存在的单点故障问题,HA策略通过热备的方式为主 NameNode 提供一个备用者,并且这个备用者的状态一直和主 Namenode 的元数据保持一致,一旦主 NameNode 挂了,备用 NameNode 可以立马转换变换为主 NameNode,从而提供不间断的服务。另外,Federation 特性,主要是允许一个 HDFS 集群中存在多个 NameNode 同时对外提供服务,这些 NameNode 分管一部分目录(水平切分),彼此之 间相互隔离,但共享底层的 DataNode 存储资源。本文档主要是总结我自己个人利用为 QJM(Quorum Journal Manager)为公司测试集群(hadoop2.2.0)部署HA 策略的过程以及自己在部署过程中遇到的一些问题。
2、HDFSHA 基本架构
先来看个手动挡切换的 HA 架构图:
在一个典型的 HDFS HA 场景中,通常由两个 NameNode 组成,一个处于 Active 状态,另一个处于 Standby 状态。Active NameNode 对外提供服务,比如处理来自客户端的 RPC 请求,而 Standby NameNode 则不对外提供服务,仅同步 Active NameNode 的状态,以便能够在它失败时快速进行切换。
为了能够实时同步 Active 和 Standby 两个 NameNode 的元数据信息(实际上 editlog),需提供一个共享存储系统,可以是 NFSQJ(Quorum Journal Manager)或者 Bookeeper,Active NameNode 将数据写入共享存储系统,我们可以在 Active NameNode 的50070端口上看到相应的 NameNode Journal Status 信息:
同时 Standby NameNode 监听该系统(QJM管理下的 Journalnode 进程对应的存储路径),一旦发现有新数据写入,则读取这些数据,并加载到自己内存中,以保证自己内存状态与 Active NameNode 保持基本一致,那么在紧急情况下 standby NameNode 便可快速切为 Active NameNode。另外,在Hadoop1.X 中的 Secondary NameNode 或者自己通过 nfs 热备的 NameNode 信息在 Hadoop2.X 中已经不再需要了,他们被 Standby NameNode 取代了。 在 Yarn 的官网中,我还看到一段关于 JournalNode 错误兼容性信息:
大概意思是主备 NameNode 之间通过一组 JournalNode 同步元数据信息(我的通俗理解就是 QJM 类似一个数据池,池里边装着多个 JournalNode 进程存储 editlog,Active NameNode 往池里边的 JournalNode 进程写 editlog,StandBy NameNode 向池里边的 JournalNode 取数据同步),一条数据只要成功写入多数 JournalNode 即认为写入成功。启动的 JournalNode 的个数必须为奇数个。如果你的 HA 策略中启动了 N 个JournalNode进程那么整个 QJM 最多允许 (N-1)/2 个进程死掉,这样才能保证 editLog 成功完整地被写入。比如 3 个 JournalNode 时,最多允许 1 个 JournalNode挂掉,5 个 JournalNode 时,最多允许 2 个 JournalNode 挂掉。
————————————– 分割线 ————————————–
Ubuntu 13.04 上搭建 Hadoop 环境 http://www.linuxidc.com/Linux/2013-06/86106.htm
Ubuntu 12.10 +Hadoop 1.2.1 版本集群配置 http://www.linuxidc.com/Linux/2013-09/90600.htm
Ubuntu 上搭建 Hadoop 环境(单机模式 + 伪分布模式)http://www.linuxidc.com/Linux/2013-01/77681.htm
Ubuntu 下 Hadoop 环境的配置 http://www.linuxidc.com/Linux/2012-11/74539.htm
单机版搭建 Hadoop 环境图文教程详解 http://www.linuxidc.com/Linux/2012-02/53927.htm
Hadoop 中 HDFS 和 MapReduce 节点基本简介 http://www.linuxidc.com/Linux/2013-09/89653.htm
《Hadoop 实战》中文版 + 英文文字版 + 源码【PDF】http://www.linuxidc.com/Linux/2012-10/71901.htm
Hadoop: The Definitive Guide【PDF 版】http://www.linuxidc.com/Linux/2012-01/51182.htm
————————————– 分割线 ————————————–
3、HDFS HA 部署
3.1、部署和测试环境
HDFS HA的部署和验证是在公司的测试集群中完成,其中测试集群中数据节点一共有 4 个主机名分别为 hadoop-slave1、hadoop-slave02、hadoop-slave03、hadoop-slave04,master 节点的主机名为 hadoop-master。因为JournalNode 和Zookeeper进程是非常轻量级的,可以其他服务共用节点。现在的部署情况是:
hadoop-master:作为Active NameNode
haoop-slave01: 作为StandBy NameNode
hadoop-slave02: 作为DataNode,并且启动一个JournalNode、启动一个Zookeeper
hadoop-slave03: 作为DataNode,并且启动一个JournalNode、启动一个Zookeeper
hadoop-slave04: 作为DataNode,并且启动一个JournalNode、启动一个Zookeeper
其他软件:
Apache Hadoop 2.2.0、JDK1.6
3.2、修改配置文件
主要配置 ${HADOOP_HOME}/etc/hadoop/ 下的hdfs-site.xml。下面是一些配置参数以及说明:
(1) dfs.nameservices
HDFS的命名服务逻辑名称,可以自己定义。在已经配置 HA 策略的 HDFS 会用到这个逻辑名称,同时该名称也会被基于 HDFS 的系统用,例如 HBASE 等。另外,如果需要启动 HDFS Federation 的话,可以通过该参数指定多个服务逻辑名称,用“,”作为分隔符。
我的配置如下:
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
<description>Logical name forthis new nameservice</description>
</property>
(2) dfs.ha.namenodes.[$nameserviceID]
命名服务下面包含的 NameNode 列表,可为每个 NameNode 指定一个自定义的 ID 名称,比如命名服务 testCluster 下有两个 NameNode,分别命名为 nn1 和 nn2(到目前为止一个命名服务下最多包含 2 个NameNode),我的配置如下:
<property>
<name>dfs.ha.namenodes.testCluster</name>
<value>nn1,nn2</value>
<description>Unique identifiers for each NameNode in the nameservice </description>
</property>
(3) dfs.namenode.rpc-address.[$nameserviceID].[$name node ID]
这个参数很容易理解,主要是为每个 NameNode 设置 RPC 地址,我的配置如下:
<property>
<name>dfs.namenode.rpc-address.testCluster.nn1</name>
<value>hadoop-master:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.testCluster.nn2</name>
<value>hadoop-slave01:8020</value>
</property>
(4) dfs.namenode.http-address.[$nameserviceID].[$name node ID]
这个参数主要是为 NameNode 设置对外的 HTTP 地址, 通过此配置的指定你可以执行在浏览器中管理 HDFS 界面等操作。我的配置如下:
<property>
<name>dfs.namenode.http-address.testCluster.nn1</name>
<value>hadoop-master:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.testCluster.nn2</name>
<value>hadoop-slave01:50070</value>
</property>
(5) dfs.namenode.shared.edits.dir
设置一组 JournalNode 的URL地址,ActiveNameNode会将 Edit Log 写入这些 JournalNode 所配置的本地目录(可以用 nfs 等共享文件系统,由参数 dfs.journalnode.edits.dir 控制)中,而 StandByNameNode 通过 DataNode 的心跳通知去读取这些Edit Log,并且作用在内存中的目录树中,其配置格式为:qjournal://host1:port1;host2:port2;host3:port3/journalId,我的配置如下:
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop-slave02:8485;hadoop-slave03:8485;hadoop-slave04:8485/testcluster</value>
<description>journalNodeList</description>
</property>
(6) dfs.journalnode.edits.dir
这个就是刚刚提到的 JournalNode 所在节点上的一个目录,用于存放 editlog 和其他状态信息,该参数只能设置一个目录,你可以对磁盘做 RIAD 提高数据可靠性。
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/home/hadoop/hadoop-2.2.0/journal/node/local/data</value>
</property>
(7) dfs.client.failover.proxy.provider.[$nameserviceID]
该参数设置 HDFS 客户端与 ActiveName 进行交互的 JAVA 实现类,HDFS客户端通过该参数来寻找到集群中的Active NameNode,此类默认实现ConfiguredFailoverProxyProvider,我的配置如下:
<property>
<name>dfs.client.failover.proxy.provider.testcluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
(8) dfs.ha.fencing.methods
这个参数比较重要,主要用于在主备节点切换时实现隔离机制的,在官方网站中做了相当详细的配置说明,其大概意思为:主备架构解决单点故障问题时,必须要认真解决的是脑裂问题,即出现两个 master 同时对外提供服务,导致系统处于不一致状态,可能导致数据丢失等潜在问题。在 HDFS HA 中,JournalNode 只允许一个 NameNode 写数据,不会出现两个 Active NameNode 的问题,但是,当主备切换时,之前的 Active NameNode 可能仍在处理客户端的 RPC 请求,为此,需要增加隔离机制(fencing)将之前的 Active NameNode 杀死。HDFS 允许用户配置多个隔离机制,当发生主备切换时,将顺次执行这些隔离机制,直到一个返回成功。Hadoop 2.0 内部打包了两种类型的隔离机制,分别是 shell 和 sshfence。
1)sshfence方式
sshfence 通过 ssh 登录到前一个 ActiveNameNode 并将其杀死。为了让该机制成功执行,需配置免密码 ssh 登陆(注意:这个为主备节点配置双向的 RSA 免密码登陆),这可通过参数 dfs.ha.fencing.ssh.private-key-files 指定一个私钥文件。我的配置如下:
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
另外,在设置一个超时时间,一旦 ssh 超过该时间,则认为执行失败。我的配置如下:
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
2) shell方式(我没有采用这种方式)
执行自定义的 Shell 脚本命令隔离旧的 ActiveNameNode。相比于sshfence 方式,个人认为这种方式有个好处就是,你在 shell 脚本里边可以将之前的 Active NameNode 直接 kill 掉,然后立马启动 NameNode,此时刚刚启动的NameNode 就是立马处于一个 StandBy 状态,立马就可以进入 HA 状态,如果采用 sshfence 方式还要手动自己重启刚刚被 kill 掉的 NameNode 从而才能进入 HA(这些的前提都是,采用手动HA 方式,之前的 Acitve NameNode 不是宕机而仅仅是 NameNode 进程挂掉)。配置可以为:
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh arg1 arg2 …)</value>
</property>
注意, Hadoop 中所有参数将以环境变量的形似提供给该 shell,但所有的“.”被替换成了“_”,比如“dfs.namenode.rpc-address.ns1.nn1”变为“dfs_namenode_rpc-address”。
3.3、启动各种服务
HDFS集群进程启动的大概顺序为:启动所有的 JournalNodeà 启动 nn1 和nn2à启动所有DataNode。具体详细步骤如下:
(1) 启动所有JournalNode
在所有的配置有 JournalNode 的服务节点上,以我的配置就是在 Hadoop-slave02、hadoop-slave03 和hadoop-slave04上分别执行:
$HADOOP_HOME/sbin/hdfs-daemon.sh startjournalnode
(2) 初始化JournalNode
此步骤要注意的是,如果你是将非 HA HDFS 的集群转化成为 HA HDFS 那么这一步骤就需要,如果都是 HA HDFS 就不需要执行此步骤。该步骤的主要作用是将非 HA HDFS 中NameNode的 edit log 去初始化 JourNalnodes。具体操作在nn1 上执行:
$HADOOP_HOME/bin/hdfs namenode -initializeSharedEdits [-force | -nonInteractive]。
此命令默认是交互式的,需要用户输入各种YOR N,如果嫌麻烦就直接执行:
$HADOOP_HOME/bin/hdfs namenode–initializeSharedEdits –force
(3) 启动 nn1 和nn2
子步骤1:
进入nn1,如果是新集群则format(注意,如果不是新集群千万不要format):
$HADOOP_HOME/bin/hadoop namenode -format
子步骤2:进入nn1,接着启动nn1:
hadoop-daemon.sh start namenode
子步骤 3:进入nn2,执行下面命令让nn2 从nn1上将最新的 FSimage 信息拉回来:
注意:如果是 nn2 的NameNode已经是被 format 掉了或者是将非 HA HDFS 的集群转化成为 HA HDFS 则不需要执行这一个步骤。
$HADOOP_HOME/bin/hdfs namenode -bootstrapStandby -force
子步骤 4: 进入nn2,然后启动nn2:
hadoop-daemon.sh start namenode
子步骤 5: 启动所有的DataNode
在各个 DataNode 节点执行:
hadoop-daemon.sh start datanode
或者直接在 nn1 节点直接执行:
hadoop-daemons.sh start namenode
各个服务到现在为止已经启动完毕,主备节点都还处于 StandBy 状态。我们可以看到主备节点的信息:
在这里说说一个遇到的“错误”问题,我在分别启动 nn1 和nn2之后,还没有将其中一个切换为 Acive NameNode 时,在 nn1 和nn2的日志上都报了以下这个“错误”:
其实这个错误信息完全可以不用管,出现这个问题原因上面信息已经很明显了,只要接下来将其中一个切换成 Acive NameNode 就ok了。
3.4、手动切换 Active NameNode
nn1和 nn2 启动后都处于 StandBy 状态,此时都不能够对外提供服务,现在需要将 nn1 切换为 Active NameNode,进入nn1 节点输入:
$HADOOP_HOME/bin/hdfs haadmin-transitionToActive nn1
切换后我们再看看 50070 页面,nn1已经被切换为 Active 了:
在来看看之前还没有切换 Acive NameNode 的“错误”信息已经消失了,下面分别是 nn1 和nn2的日志信息,非常正常:
另外,如果你现在想将 nn2 转化为 Acive NameNode,则在进入nn2 所在节点,输入命令:
$HADOOP_HOME/bin/hdfs haadmin-failover –forcefence –forceactive nn1 nn2
看看 nn2 上的日志:
1、概述
Hadoop2.X中的 HDFS(Vsersion2.0) 相比于 Hadoop1.X 增加了两个重要功能,HA和 Federation。HA 解决了 Hadoop1.X Namenode 中一直存在的单点故障问题,HA策略通过热备的方式为主 NameNode 提供一个备用者,并且这个备用者的状态一直和主 Namenode 的元数据保持一致,一旦主 NameNode 挂了,备用 NameNode 可以立马转换变换为主 NameNode,从而提供不间断的服务。另外,Federation 特性,主要是允许一个 HDFS 集群中存在多个 NameNode 同时对外提供服务,这些 NameNode 分管一部分目录(水平切分),彼此之 间相互隔离,但共享底层的 DataNode 存储资源。本文档主要是总结我自己个人利用为 QJM(Quorum Journal Manager)为公司测试集群(hadoop2.2.0)部署HA 策略的过程以及自己在部署过程中遇到的一些问题。
2、HDFSHA 基本架构
先来看个手动挡切换的 HA 架构图:
在一个典型的 HDFS HA 场景中,通常由两个 NameNode 组成,一个处于 Active 状态,另一个处于 Standby 状态。Active NameNode 对外提供服务,比如处理来自客户端的 RPC 请求,而 Standby NameNode 则不对外提供服务,仅同步 Active NameNode 的状态,以便能够在它失败时快速进行切换。
为了能够实时同步 Active 和 Standby 两个 NameNode 的元数据信息(实际上 editlog),需提供一个共享存储系统,可以是 NFSQJ(Quorum Journal Manager)或者 Bookeeper,Active NameNode 将数据写入共享存储系统,我们可以在 Active NameNode 的50070端口上看到相应的 NameNode Journal Status 信息:
同时 Standby NameNode 监听该系统(QJM管理下的 Journalnode 进程对应的存储路径),一旦发现有新数据写入,则读取这些数据,并加载到自己内存中,以保证自己内存状态与 Active NameNode 保持基本一致,那么在紧急情况下 standby NameNode 便可快速切为 Active NameNode。另外,在Hadoop1.X 中的 Secondary NameNode 或者自己通过 nfs 热备的 NameNode 信息在 Hadoop2.X 中已经不再需要了,他们被 Standby NameNode 取代了。 在 Yarn 的官网中,我还看到一段关于 JournalNode 错误兼容性信息:
大概意思是主备 NameNode 之间通过一组 JournalNode 同步元数据信息(我的通俗理解就是 QJM 类似一个数据池,池里边装着多个 JournalNode 进程存储 editlog,Active NameNode 往池里边的 JournalNode 进程写 editlog,StandBy NameNode 向池里边的 JournalNode 取数据同步),一条数据只要成功写入多数 JournalNode 即认为写入成功。启动的 JournalNode 的个数必须为奇数个。如果你的 HA 策略中启动了 N 个JournalNode进程那么整个 QJM 最多允许 (N-1)/2 个进程死掉,这样才能保证 editLog 成功完整地被写入。比如 3 个 JournalNode 时,最多允许 1 个 JournalNode挂掉,5 个 JournalNode 时,最多允许 2 个 JournalNode 挂掉。
————————————– 分割线 ————————————–
Ubuntu 13.04 上搭建 Hadoop 环境 http://www.linuxidc.com/Linux/2013-06/86106.htm
Ubuntu 12.10 +Hadoop 1.2.1 版本集群配置 http://www.linuxidc.com/Linux/2013-09/90600.htm
Ubuntu 上搭建 Hadoop 环境(单机模式 + 伪分布模式)http://www.linuxidc.com/Linux/2013-01/77681.htm
Ubuntu 下 Hadoop 环境的配置 http://www.linuxidc.com/Linux/2012-11/74539.htm
单机版搭建 Hadoop 环境图文教程详解 http://www.linuxidc.com/Linux/2012-02/53927.htm
Hadoop 中 HDFS 和 MapReduce 节点基本简介 http://www.linuxidc.com/Linux/2013-09/89653.htm
《Hadoop 实战》中文版 + 英文文字版 + 源码【PDF】http://www.linuxidc.com/Linux/2012-10/71901.htm
Hadoop: The Definitive Guide【PDF 版】http://www.linuxidc.com/Linux/2012-01/51182.htm
————————————– 分割线 ————————————–
3、HDFS HA 部署
3.1、部署和测试环境
HDFS HA的部署和验证是在公司的测试集群中完成,其中测试集群中数据节点一共有 4 个主机名分别为 hadoop-slave1、hadoop-slave02、hadoop-slave03、hadoop-slave04,master 节点的主机名为 hadoop-master。因为JournalNode 和Zookeeper进程是非常轻量级的,可以其他服务共用节点。现在的部署情况是:
hadoop-master:作为Active NameNode
haoop-slave01: 作为StandBy NameNode
hadoop-slave02: 作为DataNode,并且启动一个JournalNode、启动一个Zookeeper
hadoop-slave03: 作为DataNode,并且启动一个JournalNode、启动一个Zookeeper
hadoop-slave04: 作为DataNode,并且启动一个JournalNode、启动一个Zookeeper
其他软件:
Apache Hadoop 2.2.0、JDK1.6
3.2、修改配置文件
主要配置 ${HADOOP_HOME}/etc/hadoop/ 下的hdfs-site.xml。下面是一些配置参数以及说明:
(1) dfs.nameservices
HDFS的命名服务逻辑名称,可以自己定义。在已经配置 HA 策略的 HDFS 会用到这个逻辑名称,同时该名称也会被基于 HDFS 的系统用,例如 HBASE 等。另外,如果需要启动 HDFS Federation 的话,可以通过该参数指定多个服务逻辑名称,用“,”作为分隔符。
我的配置如下:
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
<description>Logical name forthis new nameservice</description>
</property>
(2) dfs.ha.namenodes.[$nameserviceID]
命名服务下面包含的 NameNode 列表,可为每个 NameNode 指定一个自定义的 ID 名称,比如命名服务 testCluster 下有两个 NameNode,分别命名为 nn1 和 nn2(到目前为止一个命名服务下最多包含 2 个NameNode),我的配置如下:
<property>
<name>dfs.ha.namenodes.testCluster</name>
<value>nn1,nn2</value>
<description>Unique identifiers for each NameNode in the nameservice </description>
</property>
(3) dfs.namenode.rpc-address.[$nameserviceID].[$name node ID]
这个参数很容易理解,主要是为每个 NameNode 设置 RPC 地址,我的配置如下:
<property>
<name>dfs.namenode.rpc-address.testCluster.nn1</name>
<value>hadoop-master:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.testCluster.nn2</name>
<value>hadoop-slave01:8020</value>
</property>
(4) dfs.namenode.http-address.[$nameserviceID].[$name node ID]
这个参数主要是为 NameNode 设置对外的 HTTP 地址, 通过此配置的指定你可以执行在浏览器中管理 HDFS 界面等操作。我的配置如下:
<property>
<name>dfs.namenode.http-address.testCluster.nn1</name>
<value>hadoop-master:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.testCluster.nn2</name>
<value>hadoop-slave01:50070</value>
</property>
(5) dfs.namenode.shared.edits.dir
设置一组 JournalNode 的URL地址,ActiveNameNode会将 Edit Log 写入这些 JournalNode 所配置的本地目录(可以用 nfs 等共享文件系统,由参数 dfs.journalnode.edits.dir 控制)中,而 StandByNameNode 通过 DataNode 的心跳通知去读取这些Edit Log,并且作用在内存中的目录树中,其配置格式为:qjournal://host1:port1;host2:port2;host3:port3/journalId,我的配置如下:
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop-slave02:8485;hadoop-slave03:8485;hadoop-slave04:8485/testcluster</value>
<description>journalNodeList</description>
</property>
(6) dfs.journalnode.edits.dir
这个就是刚刚提到的 JournalNode 所在节点上的一个目录,用于存放 editlog 和其他状态信息,该参数只能设置一个目录,你可以对磁盘做 RIAD 提高数据可靠性。
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/home/hadoop/hadoop-2.2.0/journal/node/local/data</value>
</property>
(7) dfs.client.failover.proxy.provider.[$nameserviceID]
该参数设置 HDFS 客户端与 ActiveName 进行交互的 JAVA 实现类,HDFS客户端通过该参数来寻找到集群中的Active NameNode,此类默认实现ConfiguredFailoverProxyProvider,我的配置如下:
<property>
<name>dfs.client.failover.proxy.provider.testcluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
(8) dfs.ha.fencing.methods
这个参数比较重要,主要用于在主备节点切换时实现隔离机制的,在官方网站中做了相当详细的配置说明,其大概意思为:主备架构解决单点故障问题时,必须要认真解决的是脑裂问题,即出现两个 master 同时对外提供服务,导致系统处于不一致状态,可能导致数据丢失等潜在问题。在 HDFS HA 中,JournalNode 只允许一个 NameNode 写数据,不会出现两个 Active NameNode 的问题,但是,当主备切换时,之前的 Active NameNode 可能仍在处理客户端的 RPC 请求,为此,需要增加隔离机制(fencing)将之前的 Active NameNode 杀死。HDFS 允许用户配置多个隔离机制,当发生主备切换时,将顺次执行这些隔离机制,直到一个返回成功。Hadoop 2.0 内部打包了两种类型的隔离机制,分别是 shell 和 sshfence。
1)sshfence方式
sshfence 通过 ssh 登录到前一个 ActiveNameNode 并将其杀死。为了让该机制成功执行,需配置免密码 ssh 登陆(注意:这个为主备节点配置双向的 RSA 免密码登陆),这可通过参数 dfs.ha.fencing.ssh.private-key-files 指定一个私钥文件。我的配置如下:
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
另外,在设置一个超时时间,一旦 ssh 超过该时间,则认为执行失败。我的配置如下:
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
2) shell方式(我没有采用这种方式)
执行自定义的 Shell 脚本命令隔离旧的 ActiveNameNode。相比于sshfence 方式,个人认为这种方式有个好处就是,你在 shell 脚本里边可以将之前的 Active NameNode 直接 kill 掉,然后立马启动 NameNode,此时刚刚启动的NameNode 就是立马处于一个 StandBy 状态,立马就可以进入 HA 状态,如果采用 sshfence 方式还要手动自己重启刚刚被 kill 掉的 NameNode 从而才能进入 HA(这些的前提都是,采用手动HA 方式,之前的 Acitve NameNode 不是宕机而仅仅是 NameNode 进程挂掉)。配置可以为:
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh arg1 arg2 …)</value>
</property>
注意, Hadoop 中所有参数将以环境变量的形似提供给该 shell,但所有的“.”被替换成了“_”,比如“dfs.namenode.rpc-address.ns1.nn1”变为“dfs_namenode_rpc-address”。
在这里说说我在切换时遇到过的几个小问题:
-
在住备节点上一定要配置双向的 RSA 免密码登陆,不然再切换时会出错,sshfence方式不能找到旧的 Active NameNode,直接被reject 掉。
-
第二,在切换的过程中我遇到了这个错误:
这个是权限问题,解决方法是直接在 core-site.xml 文件添加下面权限控制选项:
<property>
<name>Hadoop.http.filter.initializers</name>
<value>org.apache.hadoop.security.AuthenticationFilterInitializer</value>
</property>
<property>
<name>hadoop.http.authentication.type</name>
<value>simple</value>
</property>
<property>
<name>hadoop.http.authentication.token.validity</name>
<value>36000</value>
</property>
<property>
<name>hadoop.http.authentication.signature.secret.file</name>
<value>/home/hadoop/hadoop-http-auth-signature-secret</value>
</property>
<property>
<name>hadoop.http.authentication.cookie.domain</name>
<value></value>
</property>
<property>
<name>hadoop.http.authentication.simple.anonymous.allowed</name>
<value>true</value>
</property>
然后建立 /home/hadoop/hadoop-http-auth-signature-secret 文件,并且在文件写入访问用户,我写入的是 hadoop,然后将这个文件 scp 到各个节点, 问题解决。
-
如果你将 Active NameNode 从nn1转到 nn2 后,在各个 DataNode 日志出现一个“错误”信息:
其实这个是我意料之中的“错误”信息,其实是没有任何问题的。因为,当你的 Acive NameNode 从nn1切换至 nn2 时,nn1就会被 kill(即hadoop-msater 中的 NameNode 进程会被 kill 掉),在上面切换日志我标注红方框的地方已经很清楚了。此时,各个 DataNode 还是会同时向 Active NameNode 和StandBy NameNode同时发送心跳信息的,因为 nn1 已经被 kill 掉了,所有会报这个信息,对系统没有任何影响,切换后正常使用,如果你重启 nn1 则不会再报信息了,新启动的 nn1 是处于 StandBy 模式的。
我们知道,StandByNameNode是不处理 DataNode 的RPC请求的,那么各个 DataNode 为什么还会同时向 Active NameNode 和StandBy NameNode同时发送心跳呢?这是因为这 2 个心跳的用途是不同的,各个 DataNode 向Active NameNode发送心跳主要是汇报数据块的状态信息,而向 StandBy NameNode 发心跳的主要目的是通知 StandBy NameNode 告诉它 Active NameNode 元数据发生了改变,要求 StandBy NameNode 去QJM区下载更改过的 Edit Log 信息。
3.5、配置自动切换模式
自动切换模式的实现需要下面两个组建的额支持:
(1) Zookeeper实例
需要质数个 Zookeeper 实例,在本集群我一个启用了 3 个Zookeeper实例,分别部署在 Hadoop-slave02、hadoop-slave03、hadoop-slave04 中。
(2) ZKFailoverController(简称“ZKFC”)
ZKFC 是一个 Zookeeper 客户端,负责监控和管理 NameNode 的状态,每台运行 NameNode 的机器上也会运行一个 ZKFC 进程。
-
健康状况监控:
ZKFC 周期性地与本地的 NameNode 交互,执行一些健康状况监测命令。
-
Zookeeper session 管理:
如果本地 NameNode 是健康的,则会持有 Zookeeper 上一个 znode,如果它是 Active 的,会持有 zookeeper 的仅有的一个特殊 znode,该 znode 类型为 ephemeral,一旦 namenode 挂掉后,会自动消失。
-
基于 zookeeper 的选举:
如果本地 NameNode 是活的,而没有其他 Namenode 持有特殊的 znode,ZKFC 将尝试获取这个 znode,一旦获取成功后,则认为它“赢得了选举”,进而隔离之前的Active namenode,自己转换为新的 Active namenode。其大概结构如下图:
具体配置步骤:
步骤 1:关闭集群修改hdfs-site.xml 配置文件,增加自动切换选项:
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
步骤 2:编辑core-site.xml 文件,添加 Zookeeper 实例:
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop-slave02:2181,hadoop-slave03:2181,hadoop-slave04:2181</value>
</property>
步骤 3:启动节点上的zookeeper 实例:
分别进入 hadoop-slave02、hadoop-slave03、hadoop-slave04 节点执行:
$ZOOKEEPER_HOME/bin/zkServer.sh start
Zookeeper实例对应的进程名为:
步骤4:初始化zookeeper。
注意:这个步骤是针对第一次启动 zookeeper 实例用的,如果你的 zookeeper 实例不是第一次启动则不需要执行此命令。
$HADOOP_HOME/bin/hdfs zkfc -formatZK
步骤 5:启动 JournalNode、NameNode 和 DataNode。
步骤6:启动ZKFC。
分别进入 hadoop-master 和hadoop-slave1即在各个 NameNode 节点上执行:
$HADOOP_HOME/sbin/hadoop-daemon.sh startzkfc
ZKFC对应的进程名为:
要注意的一点是:我们最先启动的 NameNode 为Active NameNode。现在为止配置完毕,验证请看下面一小节。
4、HDFS HA 机制的可用性验证
4.1 手动切换模式验证
这里我使用的验证方法主要是模拟 ActiveNameNode 进程死掉的情况,另外 Active NameNode 所在节点发生宕机的情况也是一样的。现在集群中 nn1 为Active NameNode,nn2为StandBy NameNode,具体步骤:
步骤 1:进入nn1 所在节点即 Hadoop-master,运行kill -9 $NameNodePID 将nn1杀死(此时集群中只有一个StandByNameNode)。
步骤 2:往集群上传文件, 或者执行 hadoop fs 相关命令提示连接不到(此时,集群中没有 Active NameNode 来处理客户端的 RPC 请求)。看错误信息:
步骤 3:恢复集群,将StandBy NameNode 转换为 Active NameNode。进入nn2 所在节点即 hadoop-slave01 执行:
$HADOOP_HOME/bin/hdfshaadmin -transitionToActive nn2
此时,nn2已经变成为Active NameNode,看50070:
步骤 4:再次执行hadoop fs 相关命令或者上传文件,一切正常。
步骤 5:另外,不要忘记集群虽然是恢复了,但是此时已经没有了StandBy NameNode 了,这是直接进入 nn1 所在节点启动 NameNode 进程,此时 nn1 为Standby NameNode。
当目前为止,一起验证以及恢复已经完成。各个服务的日志也恢复了正常。
4.2、自动切换模式验证
自动切换模式的验证和手动切换基本一样,还是手动 kill 掉Active NameNode进程,观察集群是否会自动恢复,将备用节点转换为 Active NameNode。经过测试,当手动kill 掉Active NameNode后,Standby NameNode成功地自动转换为 Active NameNode 继续服务于个个DataNode。
更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13