1、概述 

    Hadoop2.X中的HDFS(Vsersion2.0)相比于Hadoop1.X增加了两个重要功能,HAFederationHA解决了Hadoop1.X  Namenode中一直存在的单点故障问题,HA策略通过热备的方式为主NameNode提供一个备用者,并且这个备用者的状态一直和主Namenode的元数据保持一致,一旦主NameNode挂了,备用NameNode可以立马转换变换为主NameNode,从而提供不间断的服务。另外,Federation特性,主要是允许一个 HDFS 集群中存在多个 NameNode 同时对外提供服务,这些 NameNode 分管一部分目录(水平切分),彼此之间相互隔离,但共享底层的 DataNode 存储资源。本文档主要是总结我自己个人利用为QJMQuorum Journal Manager)为公司测试集群(hadoop2.2.0)部署HA策略的过程以及自己在部署过程中遇到的一些问题。

2、HDFSHA基本架构

    先来看个手动挡切换的HA架构图:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第1张图片

    在一个典型的 HDFS  HA 场景中,通常由两个NameNode 组成,一个处于Active状态,另一个处于Standby状态。Active NameNode 对外提供服务,比如处理来自客户端的 RPC 请求,而 Standby NameNode 则不对外提供服务,仅同步 Active NameNode的状态,以便能够在它失败时快速进行切换。

为了能够实时同步 Active Standby 两个 NameNode 的元数据信息(实际上editlog,需提供一个共享存储系统,可以是 NFSQJQuorum Journal Manager)或者 BookeeperActive  NameNode 将数据写入共享存储系统,我们可以在Active  NameNode50070端口上看到相应的NameNode Journal  Status信息:利用QJM实现HDFS的HA策略部署与验证工作记录分享_第2张图片

同时Standby NameNode监听该系统(QJM管理下的Journalnode进程对应的存储路径),一旦发现有新数据写入,则读取这些数据,并加载到自己内存中,以保证自己内存状态与 Active NameNode 保持基本一致,那么在紧急情况下 standby NameNode便可快速切为Active NameNode。另外,在Hadoop1.X中的Secondary NameNode或者自己通过nfs热备的NameNode信息在Hadoop2.X中已经不再需要了,他们被Standby NameNode取代了。 在Yarn的官网中,我还看到一段关于JournalNode错误兼容性信息:利用QJM实现HDFS的HA策略部署与验证工作记录分享_第3张图片

大概意思是主备NameNode 之间通过一组JournalNode 同步元数据信息(我的通俗理解就是QJM类似一个数据池,池里边装着多个JournalNode进程存储editlogActive NameNode往池里边的JournalNode进程写editlogStandBy NameNode向池里边的JournalNode取数据同步),一条数据只要成功写入多数 JournalNode 即认为写入成功。启动的JournalNode的个数必须为奇数个。如果你的HA策略中启动了NJournalNode进程那么整个QJM最多允许(N-1)/2个进程死掉,这样才能保证editLog成功完整地被写入。比如 3 JournalNode 时,最多允许 1 JournalNode挂掉,5 JournalNode 时,最多允许 2 JournalNode 挂掉。

3、  HDFS HA部署

 3.1、部署和测试环境

HDFS HA的部署和验证是在公司的测试集群中完成,其中测试集群中数据节点一共有4个主机名分别为hadoop-slave1hadoop-slave02hadoop-slave03hadoop-slave04master节点的主机名为hadoop-master。因为JournalNodeZookeeper进程是非常轻量级的,可以其他服务共用节点。现在的部署情况是:

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.0JDK1.6


3.2、修改配置文件

主要配置${HADOOP_HOME}/etc/hadoop/下的hdfs-site.xml。下面是一些配置参数以及说明:

(1)      dfs.nameservices

HDFS的命名服务逻辑名称,可以自己定义。在已经配置HA策略的HDFS会用到这个逻辑名称,同时该名称也会被基于HDFS的系统用,例如HBASE等。另外,如果需要启动HDFS Federation的话,可以通过该参数指定多个服务逻辑名称,用“,”作为分隔符。

 我的配置如下:


   dfs.nameservices
    mycluster
    Logical name forthis new nameservice

(2)     dfs.ha.namenodes.[$nameserviceID]

命名服务下面包含的NameNode列表,可为每个NameNode 指定一个自定义的 ID 名称,比如命名服务 testCluster 下有两个 NameNode,分别命名为 nn1 nn2(到目前为止一个命名服务下最多包含2NameNode),我的配置如下:


    dfs.ha.namenodes.testCluster
    nn1,nn2
    Unique identifiers for each NameNode in the nameservice

(3)      dfs.namenode.rpc-address.[$nameserviceID].[$name node ID]

   这个参数很容易理解,主要是为每个NameNode设置RPC地址,我的配置如下:


   dfs.namenode.rpc-address.testCluster.nn1
    hadoop-master:8020


   dfs.namenode.rpc-address.testCluster.nn2
   hadoop-slave01:8020

(4)      dfs.namenode.http-address.[$nameserviceID].[$name node ID]

这个参数主要是为NameNode设置对外的HTTP地址, 通过此配置的指定你可以执行在浏览器中管理HDFS界面等操作。我的配置如下:


    dfs.namenode.http-address.testCluster.nn1
    hadoop-master:50070


    dfs.namenode.http-address.testCluster.nn2
    hadoop-slave01:50070 

(5)      dfs.namenode.shared.edits.dir

设置一组JournalNodeURL地址,ActiveNameNode会将Edit Log写入这些JournalNode所配置的本地目录(可以用nfs等共享文件系统,由参数dfs.journalnode.edits.dir控制)中,而StandByNameNode通过DataNode的心跳通知去读取这些Edit Log,并且作用在内存中的目录树中,其配置格式为:qjournal://host1:port1;host2:port2;host3:port3/journalId,我的配置如下:


       dfs.namenode.shared.edits.dir
       qjournal://hadoop-slave02:8485;hadoop-slave03:8485;hadoop-slave04:8485/testcluster
        journalNodeList

(6)      dfs.journalnode.edits.dir

这个就是刚刚提到的JournalNode所在节点上的一个目录,用于存放 editlog 和其他状态信息,该参数只能设置一个目录,你可以对磁盘做 RIAD 提高数据可靠性。


       dfs.journalnode.edits.dir
        /home/hadoop/hadoop-2.2.0/journal/node/local/data

(7)      dfs.client.failover.proxy.provider.[$nameserviceID]

该参数设置HDFS客户端与ActiveName进行交互的JAVA实现类,HDFS客户端通过该参数来寻找到集群中的Active NameNode,此类默认实现ConfiguredFailoverProxyProvider,我的配置如下:


        dfs.client.failover.proxy.provider.testcluster
       org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider

(8)      dfs.ha.fencing.methods

这个参数比较重要,主要用于在主备节点切换时实现隔离机制的,在官方网站中做了相当详细的配置说明,其大概意思为:主备架构解决单点故障问题时,必须要认真解决的是脑裂问题,即出现两个 master 同时对外提供服务,导致系统处于不一致状态,可能导致数据丢失等潜在问题。在 HDFS HA中,JournalNode 只允许一个 NameNode 写数据,不会出现两个 Active NameNode 的问题,但是,当主备切换时,之前的 Active NameNode 可能仍在处理客户端的 RPC 请求,为此,需要增加隔离机制(fencing)将之前的 Active NameNode 杀死。HDFS 允许用户配置多个隔离机制,当发生主备切换时,将顺次执行这些隔离机制,直到一个返回成功。Hadoop 2.0 内部打包了两种类型的隔离机制,分别是 shell  sshfence

  1sshfence方式

sshfence 通过 ssh 登录到前一个 ActiveNameNode 并将其杀死。为了让该机制成功执行,需配置免密码 ssh 登陆(注意:这个为主备节点配置双向的RSA免密码登陆),这可通过参数 dfs.ha.fencing.ssh.private-key-files 指定一个私钥文件。我的配置如下:


        dfs.ha.fencing.methods
       sshfence


       dfs.ha.fencing.ssh.private-key-files
       /home/hadoop/.ssh/id_rsa

另外,在设置一个超时时间,一旦 ssh 超过该时间,则认为执行失败。我的配置如下:


   dfs.ha.fencing.ssh.connect-timeout
    30000

  2  shell方式(我没有采用这种方式)

         执行自定义的Shell脚本命令隔离旧的ActiveNameNode。相比于sshfence方式,个人认为这种方式有个好处就是,你在shell脚本里边可以将之前的 Active NameNode 直接kill掉,然后立马启动NameNode,此时刚刚启动的NameNode就是立马处于一个StandBy状态,立马就可以进入HA状态,如果采用sshfence方式还要手动自己重启刚刚被kill掉的NameNode从而才能进入HA(这些的前提都是,采用手动HA方式,之前的Acitve NameNode不是宕机而仅仅是NameNode进程挂掉)。配置可以为:


   dfs.ha.fencing.methods
   shell(/path/to/my/script.sh arg1 arg2 ...)

注意, Hadoop 中所有参数将以环境变量的形似提供给该 shell,但所有的“.”被替换成了“_”,比如“dfs.namenode.rpc-address.ns1.nn1”变为“dfs_namenode_rpc-address”。


3.3、启动各种服务

HDFS集群进程启动的大概顺序为:启动所有的JournalNodeà启动nn1nn2à启动所有DataNode。具体详细步骤如下:

(1)          启动所有JournalNode

在所有的配置有JournalNode的服务节点上,以我的配置就是在hadoop-slave02hadoop-slave03hadoop-slave04上分别执行:

$HADOOP_HOME/sbin/hdfs-daemon.sh startjournalnode

(2)          初始化JournalNode

此步骤要注意的是,如果你是将非HA HDFS的集群转化成为HA HDFS那么这一步骤就需要,如果都是HA HDFS就不需要执行此步骤。该步骤的主要作用是将非HA HDFSNameNodeedit log去初始化JourNalnodes。具体操作在nn1上执行:

 $HADOOP_HOME/bin/hdfs namenode -initializeSharedEdits [-force | -nonInteractive]

此命令默认是交互式的,需要用户输入各种YOR N,如果嫌麻烦就直接执行:

$HADOOP_HOME/bin/hdfs namenode–initializeSharedEdits –force

(3)          启动nn1nn2

子步骤1

进入nn1,如果是新集群则format(注意,如果不是新集群千万不要format):

$HADOOP_HOME/bin/hadoop namenode -format

子步骤2:进入nn1,接着启动nn1:

hadoop-daemon.sh start namenode

子步骤3:进入nn2,执行下面命令让nn2nn1上将最新的FSp_w_picpath信息拉回来:

注意:如果是nn2NameNode已经是被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状态。我们可以看到主备节点的信息:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第4张图片

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第5张图片

    在这里说说一个遇到的“错误”问题,我在分别启动nn1nn2之后,还没有将其中一个切换为Acive NameNode时,在nn1nn2的日志上都报了以下这个“错误”:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第6张图片

其实这个错误信息完全可以不用管,出现这个问题原因上面信息已经很明显了,只要接下来将其中一个切换成Acive NameNodeok了。


3.4、手动切换Active NameNode

    nn1nn2启动后都处于StandBy状态,此时都不能够对外提供服务,现在需要将nn1切换为Active NameNode,进入nn1节点输入:

$HADOOP_HOME/bin/hdfs haadmin-transitionToActive nn1

切换后我们再看看50070页面,nn1已经被切换为Active了:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第7张图片

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第8张图片

在来看看之前还没有切换Acive NameNode的“错误”信息已经消失了,下面分别是nn1nn2的日志信息,非常正常:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第9张图片

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第10张图片

另外,如果你现在想将nn2转化为Acive NameNode,则在进入nn2所在节点,输入命令:

$HADOOP_HOME/bin/hdfs haadmin-failover --forcefence --forceactive nn1 nn2

看看nn2上的日志:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第11张图片

在这里说说我在切换时遇到过的几个小问题:

  • 在住备节点上一定要配置双向的RSA免密码登陆,不然再切换时会出错,sshfence方式不能找到旧的Active NameNode,直接被reject掉。

  • 第二,在切换的过程中我遇到了这个错误:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第12张图片

这个是权限问题,解决方法是直接在core-site.xml文件添加下面权限控制选项:


   hadoop.http.filter.initializers
    org.apache.hadoop.security.AuthenticationFilterInitializer


   hadoop.http.authentication.type
    simple


   hadoop.http.authentication.token.validity
    36000


   hadoop.http.authentication.signature.secret.file
    /home/hadoop/hadoop-http-auth-signature-secret


   hadoop.http.authentication.cookie.domain
    


   hadoop.http.authentication.simple.anonymous.allowed
    true

然后建立/home/hadoop/hadoop-http-auth-signature-secret文件,并且在文件写入访问用户,我写入的是hadoop,然后将这个文件scp到各个节点,问题解决。

  • 如果你将Active NameNodenn1转到nn2后,在各个DataNode日志出现一个“错误”信息:

wKioL1PLy9KB-KjfAAUasSkPxVg154.jpg

其实这个是我意料之中的“错误”信息,其实是没有任何问题的。因为,当你的Acive NameNodenn1切换至nn2时,nn1就会被kill(即hadoop-msater中的NameNode进程会被kill掉),在上面切换日志我标注红方框的地方已经很清楚了。此时,各个DataNode还是会同时向Active NameNodeStandBy NameNode同时发送心跳信息的,因为nn1已经被kill掉了,所有会报这个信息,对系统没有任何影响,切换后正常使用,如果你重启nn1则不会再报信息了,新启动的nn1是处于StandBy模式的。

    我们知道,StandByNameNode是不处理DataNodeRPC请求的,那么各个DataNode为什么还会同时向Active NameNodeStandBy NameNode同时发送心跳呢?这是因为这2个心跳的用途是不同的,各个DataNodeActive NameNode发送心跳主要是汇报数据块的状态信息,而向StandBy NameNode发心跳的主要目的是通知StandBy NameNode告诉它Active NameNode元数据发生了改变,要求StandBy NameNodeQJM区下载更改过的Edit Log信息。


3.5、配置自动切换模式

自动切换模式的实现需要下面两个组建的额支持:

(1)      Zookeeper实例

需要质数个Zookeeper实例,在本集群我一个启用了3Zookeeper实例,分别部署在hadoop-slave02hadoop-slave03hadoop-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持有特殊的 znodeZKFC 将尝试获取这个 znode,一旦获取成功后,则认为它“赢得了选举”,进而隔离之前的Active namenode,自己转换为新的 Active namenode。其大概结构如下图:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第13张图片

具体配置步骤:

步骤1:关闭集群修改hdfs-site.xml配置文件,增加自动切换选项:

    dfs.ha.automatic-failover.enabled

    true

步骤2:编辑core-site.xml文件,添加Zookeeper实例:

    ha.zookeeper.quorum

    hadoop-slave02:2181,hadoop-slave03:2181,hadoop-slave04:2181

步骤3:启动节点上的zookeeper实例:

分别进入hadoop-slave02hadoop-slave03hadoop-slave04节点执行:

$ZOOKEEPER_HOME/bin/zkServer.sh start

Zookeeper实例对应的进程名为:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第14张图片

步骤4:初始化zookeeper

注意:这个步骤是针对第一次启动zookeeper实例用的,如果你的zookeeper实例不是第一次启动则不需要执行此命令。

$HADOOP_HOME/bin/hdfs zkfc -formatZK

步骤5:启动 JournalNodeNameNode DataNode

步骤6:启动ZKFC

分别进入hadoop-masterhadoop-slave1即在各个 NameNode 节点上执行:

$HADOOP_HOME/sbin/hadoop-daemon.sh startzkfc

ZKFC对应的进程名为:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第15张图片

要注意的一点是:我们最先启动的NameNodeActive NameNode。现在为止配置完毕,验证请看下面一小节。

4、 HDFS HA机制的可用性验证

4.1手动切换模式验证

这里我使用的验证方法主要是模拟ActiveNameNode进程死掉的情况,另外Active NameNode所在节点发生宕机的情况也是一样的。现在集群中nn1Active NameNodenn2StandBy NameNode,具体步骤:

步骤1:进入nn1所在节点即hadoop-master,运行kill -9  $NameNodePIDnn1杀死(此时集群中只有一个StandByNameNode)。

步骤2:往集群上传文件,或者执行hadoop fs相关命令提示连接不到(此时,集群中没有Active NameNode来处理客户端的RPC请求)。看错误信息:

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第16张图片


步骤3:恢复集群,将StandBy NameNode转换为Active NameNode。进入nn2所在节点即hadoop-slave01执行:

$HADOOP_HOME/bin/hdfshaadmin -transitionToActive nn2

此时,nn2已经变成为Active NameNode,看50070

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第17张图片

步骤4:再次执行hadoop fs相关命令或者上传文件,一切正常。

步骤5:另外,不要忘记集群虽然是恢复了,但是此时已经没有了StandBy NameNode了,这是直接进入nn1所在节点启动NameNode进程,此时nn1Standby NameNode

利用QJM实现HDFS的HA策略部署与验证工作记录分享_第18张图片

当目前为止,一起验证以及恢复已经完成。各个服务的日志也恢复了正常。


4.2、自动切换模式验证

自动切换模式的验证和手动切换基本一样,还是手动killActive NameNode进程,观察集群是否会自动恢复,将备用节点转换为Active NameNode。经过测试,当手动killActive NameNode后,Standby NameNode成功地自动转换为Active NameNode继续服务于个个DataNode


参考文献:

[1] http://hadoop.apache.org/docs/r2.2.0/hadoop-yarn/hadoop-yarn-site/HDFSHighAvailabilityWithQJM.html

[2] http://www.sizeofvoid.net/hadoop-2-0-namenode-ha-federation-practice-zh/

[3] http://yanbohappy.sinaapp.com/?p=205