1. 介绍

之前写过一篇关于hadoop2.7安装的文章,但是里面没有说如何配置HA避免单点故障。今天准备总结下。

较早版本的hadoop虽然也支持通过secondarynamenode来恢复namenode,但是其原理是基于检查点的,仍然会丢数据。新的基于主备的HA通过JNs实时同步edit log可以避免数据丢失的情况。

主要参考资料:HDFS High Availability Using the Quorum Journal Manager

我的机器配置如下:

hostname role
a1 namenode active,datanode,yarn manager
a2 namenode standby,datanode
a3 datanode

2. 准备工作

  1. JDK
  2. ssh无密码登入
  3. 环境变量设置
  4. ZK集群安装并且成功启动

本篇文章重点在配置上,以上常规工作假设都已经完成。

这些还不会的可以参考我的另一篇非HA的hadoop安装:hadoop2.7.2+spark1.6.2环境搭建教程

3. 相关定义

3.1 standby和active

HDFS配置HA的时候,有standby节点和active节点,只有active节点才能提供服务;standby节点会同步active节点的信息。

namespace state的检查点信息由standby维护,不需要再开secondary namenode

3.2 JournalNodes(JNs)

JournalNode集群可以单独部署,上面运行着多个守护进程,用于接受actrive namenode的修改信息。active namenode上的任何修改会以edit log的形式写给JNs。standby namenode会从JNs当中读取edit log信息,来保证和主节点进行同步。备节点备激活成active状态前,会把JNs的信息全部读取并且生效后再把自己激活,从而保证和主节点完全同步。

同时为了保证较快的进行故障转移,datanode会把块信息同时发送给namenode和datanode

JNs只允许一个namenode对他进行写,然后使得这个namenode为active状态,从而避免多个active状态的namenode造成异常。

Journal Node必须开启奇数个,方便该集群容错。道理类似ZK。

3.2 Quorum Journal Manager (QJM)

这个是用来干嘛的呢?实际上就是个管理器,利用JournalNodes的信息来完成HA的功能。官方描述如下:

HDFS HA using the Quorum Journal Manager (QJM) to share edit logs between the Active and Standby NameNodes

根据官方描述,JN守护进程也应该属于QJM。QJM是个管理器,利用JN的信息来完成HA。

4. 配置文件

4.1 core-stie.xml

<configuration>
    <property>
        <name>hadoop.tmp.dir</name> 
        <value>/home/appadmin/hadoop-2.7.2/tmp</value>
    </property>
    <!--高可用配置,这里使用hsfs-site.xml中配置的nameservice-->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://ns</value>
    </property>
    <!--使用zk用于主备namenode切换-->
    <property>
            <name>ha.zookeeper.quorum</name>
            <value>10.8.12.16:2181,10.8.12.17:2181,10.8.12.18:2181</value>
    </property>
</configuration>

4.2hdfs-site.xml

<configuration>
 <!--复制的份数,默认为3份,仅仅在datanode上配置-->
        <property>
            <name>dfs.replication</name>
                <value>3</value>
        </property>

 <!--namenode元数据存储目录,多个目录的数据是重复的-->
        <property>
            <name>dfs.namenode.name.dir</name>
                <value>/home/appadmin/hadoop-2.7.2/hdfs/namenode</value>
        </property>

<!--datanode 数据存放目录,多个目录逗号分隔-->
        <property>
                <name>dfs.datanode.data.dir</name>
                <value>/home/appadmin/hadoop-2.7.2/hdfs/datanode</value>
        </property>

  <!--指定hdfs的nameservice为ns,需要和core-site.xml中的保持一致 -->    
    <property>    
            <name>dfs.nameservices</name>    
            <value>ns</value>    
    </property>  
    
<!-- ns下面有两个NameNode,分别是nn1,nn2,名字可以自取,最多配置2个 -->
    <property>
           <name>dfs.ha.namenodes.ns</name>
           <value>nn1,nn2</value>
    </property>
                 

<!-- nn1的RPC通信地址 -->
    <property>
           <name>dfs.namenode.rpc-address.ns.nn1</name>
           <value>10.8.12.16:9000</value>
    </property>
     
<!-- nn1的http通信地址 -->
    <property>
            <name>dfs.namenode.http-address.ns.nn1</name>
            <value>10.8.12.16:50070</value>
    </property>
                            
<!-- nn2的RPC通信地址 -->
    <property>
            <name>dfs.namenode.rpc-address.ns.nn2</name>
            <value>10.8.12.17:9000</value>
    </property>
                            
<!-- nn2的http通信地址 -->
    <property>
            <name>dfs.namenode.http-address.ns.nn2</name>
            <value>10.8.12.17:50070</value>
    </property>
                            
<!-- 指定NameNode的元数据(edit log)存放在哪些JournalNode上,以及存放位置,最后的是journalid,一般用集群的nameservice名字来代替 -->
    <property>
             <name>dfs.namenode.shared.edits.dir</name>
             <value>qjournal://10.8.12.16:8485;10.8.12.17:8485;10.8.12.18:8485/ns</value>
    </property>
     
                  
<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
    <property>
              <name>dfs.journalnode.edits.dir</name>
              <value>/home/appadmin/hadoop-2.7.2/journal</value>
    </property>
                                
<!-- 开启NameNode故障时自动切换 -->
    <property>
              <name>dfs.ha.automatic-failover.enabled</name>
              <value>true</value>
    </property>
                                
<!-- 配置失败自动切换实现方式 -->
    <property>
                <name>dfs.client.failover.proxy.provider.ns</name>
                <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>
                                    
<!-- 配置隔离机制 -->
<!--
这个参数比较重要,主要用于在主备节点切换时实现隔离机制的,在官方网站中做了相当详细的配置说明,其大概意思为:主备架构解决单点故障问题时,必须要认真解决的是脑裂问题,即出现两个 master 同时对外提供服务,导致系统处于不一致状态,可能导致数据丢失等潜在问题。在 HDFS HA 中, JournalNode 只允许一个 NameNode 写数据,不会出现两个 Active NameNode 的问题,但是,当主备切换时,之前的 Active NameNode 可能仍在处理客户端的 RPC 请求,为此,需要增加隔离机制( fencing )将之前的 Active NameNode 杀死。 HDFS 允许用户配置多个隔离机制,当发生主备切换时,将顺次执行这些隔离机制,直到一个返回成功。 Hadoop 2.0 内部打包了两种类型的隔离机制,分别是 shell  和 sshfence 。

-->
    <property>
                 <name>dfs.ha.fencing.methods</name>
                 <value>sshfence</value>
    </property>
                                      

<!-- 使用隔离机制时需要ssh免登陆 -->
    <property>
                <name>dfs.ha.fencing.ssh.private-key-files</name>
                <value>/home/appadmin/.ssh/id_rsa</value>
    </property>
                                                              
                            
                          
<!-- 在NN和DN上开启WebHDFS (REST API)功能,不是必须 -->                                                                    
    <property>    
           <name>dfs.webhdfs.enabled</name>    
           <value>true</value>    
    </property>    


</configuration>

4.3 mapred-site.xml

<configuration>
 <property>
  <name>mapreduce.framework.name</name>
   <value>yarn</value>
 </property>
</configuration>

4.4 yarn-site.xml

<configuration>
<!--yarn相关的IP设置-->
    <property>
        <name>yarn.resourcemanager.address</name>
        <value>10.45.10.33:8032</value>
    </property>
    <property>
        <name>yarn.resourcemanager.scheduler.address</name>
        <value>10.45.10.33:8030</value>
    </property>
    <property>
        <name>yarn.resourcemanager.resource-tracker.address</name>
        <value>10.45.10.33:8031</value>
    </property>
    <property>
        <name>yarn.resourcemanager.admin.address</name>
        <value>10.45.10.33:8033</value>
    </property>
    <property>
        <name>yarn.resourcemanager.webapp.address</name>
        <value>10.45.10.33:8088</value>
    </property>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
    <!--支持mr任务提交到yarn-->
    <property>
      <name>yarn.nodemanager.aux-services</name>
      <value>mapreduce_shuffle</value>
  </property>
</configuration>

4.5 slaves文件

不要忘记配置

5. 常用HA命令

Usage: haadmin
[-transitionToActive ]
[-transitionToStandby ]
[-failover [--forcefence] [--forceactive] ]
[-getServiceState ]
[-checkHealth ]
[-help ]

This guide describes high-level uses of each of these subcommands. For specific usage information of each subcommand, you should run “hdfs haadmin -help ”.

  1. transitionToActive and transitionToStandby :transition the state of the given NameNode to Active or Standby

These subcommands cause a given NameNode to transition to the Active or Standby state, respectively. These commands do not attempt to perform any fencing, and thus should rarely be used. Instead, one should almost always prefer to use the “hdfs haadmin -failover” subcommand.

  1. failover - initiate a failover between two NameNodes

This subcommand causes a failover from the first provided NameNode to the second. If the first NameNode is in the Standby state, this command simply transitions the second to the Active state without error. If the first NameNode is in the Active state, an attempt will be made to gracefully transition it to the Standby state. If this fails, the fencing methods (as configured by dfs.ha.fencing.methods) will be attempted in order until one succeeds. Only after this process will the second NameNode be transitioned to the Active state. If no fencing method succeeds, the second NameNode will not be transitioned to the Active state, and an error will be returned.

  1. getServiceState - determine whether the given NameNode is Active or Standby

Connect to the provided NameNode to determine its current state, printing either “standby” or “active” to STDOUT appropriately. This subcommand might be used by cron jobs or monitoring scripts which need to behave differently based on whether the NameNode is currently Active or Standby.

  1. checkHealth - check the health of the given NameNode

Connect to the provided NameNode to check its health. The NameNode is capable of performing some diagnostics on itself, including checking if internal services are running as expected. This command will return 0 if the NameNode is healthy, non-zero otherwise. One might use this command for monitoring purposes.

PS: 用的时候是hdfs haadmin 选项

6. 启动集群

6.1 JNs

首先在JNs集群上开启JN进程(所有节点上均要执行一遍以下命令):
hadoop-daemon.sh start journalnode

使用jps查看确保进程都开启了(我下面其他进程是ZK的):

PS:如果journal node和hdfs cluster在一个集群上,可以直接用start-dfs来启动JN,跳过该步。

6.2 hdfs cluster

操作步骤如下:

  1. 启动dfs: start-dfs.sh(此时namenode 是启动不起来,提示要格式化)
  2. hdfs namenode -format(如果是全新集群,先进行该操作)
  3. 在要做为active的namenode上执行:hdfs namenode -initializeSharedEdits
  4. 初始化ZK节点上信息:hdfs zkfc -formatZK
  5. 使用“hadoop-daemon.sh start namenode”命令把两个namenode启动起来

启动集群后用命令:hdfs haadmin -getServiceState nn1/nn2可以验证哪个是standby

如果和预计的不符,可以用hdfs haadmin -failover nn2 nn1来设置两个namenode的状态(第一个参数是做为standby的,第二个参数nn1 是要被激活的)

7. HA测试

我们直接jps 查看active namenode的进程 然后杀死,查看nn2是否被激活。

7.1 初始状态

nn1上的进程:


nn2上的进程:

7.2 开始删除进程

kill -9 来杀死nn1上的namenode
然后查看nn2是否为active

然后我们重启nn1 namenode

hadoop-daemon.sh start namenode

再次查看发现变成了standby:

我有时候有点强迫症。。。让我们再把nn1换成active的吧

完美~~~