三、zookeeper--实现NN和RM的HA

一、hdfs namenode HA

1、概述

​ 在hadoop1.0的时候,hdfs集群中namenode存在单点故障的问题,当namenode不可用的时候,就会导致整个hdfs集群服务不可用。另外如果需要临时对namenode进行设计或者其他操作时,停掉namenode之后,hdfs集群也无法使用了。
​ 通过HA的方式,可以一定程度上解决单点故障问题。

2、namenode HA工作要点

1)元数据管理方式需要改变:
内存中各自保存一份元数据;
Edits日志只有Active状态的namenode节点可以做写操作;
两个namenode都可以读取edits;
共享的edits放在一个共享存储中管理(qjournal和NFS两个主流实现);

2)需要一个状态管理功能模块
hadoop实现了一个zkfailover,常驻在每一个namenode所在的节点,每一个zkfailover负责监控自己所在namenode节点,利用zk进行状态标识,当需要进行状态切换时,由zkfailover来负责切换,切换时需要防止brain split现象的发生。

3)必须保证两个NameNode之间能够ssh无密码登录。用于后面的隔离。通过ssh方式到另外的namenode节点上,将namenode进程彻底杀死。防止脑裂。

4)隔离(Fence),即同一时刻仅仅有一个NameNode对外提供服务

3、namenode HA自动故障转移工作机制

namenode HA自动故障转移除了要两个namenode之外,还需要增加两个组件:zookeeper集群服务,ZKFailoverController(ZKFC)。

(1)ZKFC

它是zookeeper的一个客户端,同时负责监控namenode的状态。每个namenode上都运行一个ZKFC进程。
1)健康监测:
ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode,只要该NameNode及时地回复健康状态,ZKFC认为该节点是健康的。如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非健康的。
2)ZooKeeper会话管理:
当本地NameNode是健康的,ZKFC保持一个在ZooKeeper中打开的会话。如果本地NameNode处于active状态,ZKFC也保持一个特殊的znode锁,该锁使用了ZooKeeper对短暂节点(也就是临时节点)的支持,如果会话终止,锁节点将自动删除。

ZKFC会在zookeeper上创建一个  /hadoop-ha/namenodeHA集群名称/ 这样一个节点,
该节点上有两个子节点:
ActiveBreadCrumb:
持久节点,节点的值中记录了  HA集群名称 active节点别名 active节点地址
主要用于其他想访问namenode服务的client用于获取active状态的namenode地址,所以必须得是持久节点。

ActiveStandbyElectorLock:
临时节点,节点的值中记录了  HA集群名称 active节点别名 active节点地址。
起到互斥锁的作用,只有获取到该节点的使用权,才能修改上面ActiveBreadCrumb节点的值。
因为是临时节点,所以当active namenode和zk保持连接,该节点就会一直存在,而standby的namenode也是和zk保持连接,但是发现该临时节点已存在,就明白已经有人占用了,所以它不会做任何事。当上面的active namenode发生问题,不正常了,ZKFC就会断开和zk的连接,那么临时节点就会消失。此时standby namenode就会重新创建该临时节点,相当于获得了锁,可以修改ActiveBreadCrumb的值。此时它自己也就顺理成章变成新的active namenode。

3)基于ZooKeeper的选择:
如果本地NameNode是健康的,且ZKFC发现没有其它的节点当前持有znode锁,它将为自己获取该锁。如果成功,则它已经赢得了选择,并负责运行故障转移进程以使它的本地NameNode为active。

4、HA配置

(1)环境规划

主机 角色
bigdata121/192.168.50.121 namenode,journalnode,datanode,zk
bigdata122/192.168.50.122 namenode,journalnode,zk
bigdata123/192.168.50.123 zk
软件版本 hadoop2.8.4,zookeeper3.4.10,centos7.2

jdk,zookeeper部署不重复讲了,看之前的文章吧

基础环境配置:
每个机器添加主机名解析/etc/hosts
每台主机对自己,以及对另外两台主机都要配置ssh免秘钥登录
关闭防火墙以及selinux

(2)部署

hadoop的完整部署可以看之前的文章,这里着重讲namenode HA的配置。
修改配置文件:
core-site.xml

<configuration>
        <!--指定namenode的HA集群的名字 -->
        <property>
                <name>fs.defaultFS</name>
                <value>hdfs://mycluster</value>
        </property>

        <!--指定hadoop中hdfs保存数据块和元数据块的目录-->
        <property>
                <name>hadoop.tmp.dir</name>
                <value>/opt/modules/HA/hadoop-2.8.4/data/ha_data</value>
        </property>

        <!--指定使用的zk集群的所有节点ip:port-->
        <property>
                <name>ha.zookeeper.quorum</name>
            <value>bigdata121:2181,bigdata122:2181,bigdata123:2181</value>
        </property>
</configuration>

hdfs-site.xml

<configuration>
        <!-- namenode完全分布式集群名称,名字需和core-site中定义的集群名字一样 -->
        <property>
                <name>dfs.nameservices</name>
                <value>mycluster</value>
        </property>

        <!-- 集群中NameNode节点都有哪些,这里是节点的别名 -->
        <property>
                <name>dfs.ha.namenodes.mycluster</name>
                <value>nn1,nn2</value>
        </property>

        <!-- nn1的RPC通信地址 -->
        <property>
                <name>dfs.namenode.rpc-address.mycluster.nn1</name>
                <value>bigdata121:9000</value>
        </property>

        <!-- nn2的RPC通信地址 -->
        <property>
                <name>dfs.namenode.rpc-address.mycluster.nn2</name>
                <value>bigdata122:9000</value>
        </property>

        <!-- nn1的http通信地址 -->
        <property>
                <name>dfs.namenode.http-address.mycluster.nn1</name>
                <value>bigdata121:50070</value>
        </property>

        <!-- nn2的http通信地址 -->
        <property>
                <name>dfs.namenode.http-address.mycluster.nn2</name>
                <value>bigdata122:50070</value>
        </property>

        <!-- 指定NameNode元数据在JournalNode上的存放位置,用于存放edits日志 ,多个节点用逗号隔开-->
        <property>
                <name>dfs.namenode.shared.edits.dir</name>
        <value>qjournal://bigdata121:8485;bigdata122:8485/mycluster</value>
        </property>

        <!-- 配置隔离机制,即同一时刻只能有一台服务器对外响应,有shell和sshfence两种方式,主要用于到down掉的namenode所在主机将进程kill掉
             防止脑裂的情况 -->
        <property>
                <name>dfs.ha.fencing.methods</name>
                <value>sshfence</value>
        </property>

        <!-- 使用隔离机制时需要ssh无秘钥登录到另外的主机上将namenode进程kill掉,这里指定私钥的路径-->
        <property>
                <name>dfs.ha.fencing.ssh.private-key-files</name>
                <value>/root/.ssh/id_rsa</value>
        </property>

        <!-- 声明journalnode服务器存储目录-->
        <property>
                <name>dfs.journalnode.edits.dir</name>
                <value>/opt/modules/HA/hadoop-2.8.4/data/jn</value>
        </property>

        <!-- 关闭权限检查-->
        <property>
                <name>dfs.permissions.enable</name>
                <value>false</value>
        </property>

        <!-- 访问代理类:client,mycluster,active配置失败自动切换实现方式。用于访问已配置HA的namenode-->
        <property>
                <name>dfs.client.failover.proxy.provider.mycluster</name>
                <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
        </property>

        <!-- 启动ha的自动故障转移,无需手动切换故障的namenode-->
        <property>
                <name>dfs.ha.automatic-failover.enabled</name>
                <value>true</value>
        </property>
</configuration>

配置文件同步到各个节点中。使用scp或者rsync随意吧。

(3)启动集群

第一次启动时:

cd /opt/modules/HA/hadoop-2.8.4

1)各个journalnode节点上启动journalnode服务
sbin/hadoop-daemon.sh start journalnode

2)nn1上格式化namenode,并启动
bin/hdfs namenode -format
sbin/hadoop-daemon.sh start namenode

3)nn2上通过启动的journalnode从nn1上同步namenode的数据到本地namenode
bin/hdfs namenode -bootstrapStandby

4)启动nn2
sbin/hadoop-daemon.sh start namenode

5)nn1上启动所有datanode
sbin/hadoop-daemons.sh start datanode

6)两台namenode上查看namenode状态
bin/hdfs haadmin -getServiceState nn1
bin/hdfs haadmin -getServiceState nn2
正常情况一个是active,一个是standby

7)手动转换成active和standby
bin/hdfs haadmin -transitionToActive namenode名称
bin/hdfs haadmin -transitionToStandby namenode名称
注意,如果需要手动切换,那么需要将hdfs-site.xml中的自动切换关掉。否则报错。
或者使用 --forceactive 进行强制转换。

启动完成后,可以手动将active的namenode关掉,可以看到刚刚standby的namenode会自动转为 active。而刚才关掉的namenode重新上线的话,就会变为standby。

第二次启动:
直接start-dfs.sh即可

(4)为什么没有SNN?

当我们启动完整个namenode的HA集群之后,我们发现并没有SNN的身影,天真的我以为以为还需要手动启动,就手动启动一发了,结果报错了。
查看SNN的启动日志,可以发现有这么一个报异常信息

org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode: Failed to start secondary namenode
java.io.IOException: Cannot use SecondaryNameNode in an HA cluster. The Standby Namenode will perform checkpointing.
        at org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode.<init>(SecondaryNameNode.java:189)
        at org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode.main(SecondaryNameNode.java:690)

意思很明显了,就是说SNN的职责由standby的namenode来完成了,HA状态下不需要SNN的存在了。这样其实也很合理,可以说是充分利用了standby的namenode,免得它闲在那里。

二、yarn resourceManager HA

1、工作机制

其实和上面的namenode的ha类似,也是借助ZKFC进行监控RM。
会在 zk上创建一个 /yarn-leader-election/yarn集群名称 的节点,
下面有两个子节点:ActiveBreadCrumb, ActiveStandbyElectorLock
作用类似,不重复讲。工作机制基本类似的

2、HA配置

(1)规划

主机 角色
bigdata121 zk, rm
bigdata122 zk, rm
bigdata123 zk

(2)配置文件

yarn-site.xml

<configuration>

<!-- Site specific YARN configuration properties -->
        <!--指定reducer获取数据方式为shuffle机制-->
        <property>
                <name>yarn.nodemanager.aux-services</name>
                <value>mapreduce_shuffle</value>
        </property>

        <!--启动日志聚集功能-->
        <property>
                <name>yarn.log-aggregation-enable</name>
                <value>true</value>
        </property>

        <!--指定日志保留时间为7天,单位是秒-->
        <property>
                <name>yarn.log-aggregation.retain-seconds</name>
                <value>604800</value>
        </property>

    <!--启用resourcemanager ha-->
    <property>
        <name>yarn.resourcemanager.ha.enabled</name>
        <value>true</value>
    </property>

    <!--声明两台resourcemanager的集群名称-->
    <property>
        <name>yarn.resourcemanager.cluster-id</name>
        <value>cluster-yarn1</value>
    </property>

    <!--声明两台resourcemanager的节点的别名-->
    <property>
        <name>yarn.resourcemanager.ha.rm-ids</name>
        <value>rm1,rm2</value>
    </property>

    <!--声明两台rm的地址-->
    <property>
        <name>yarn.resourcemanager.hostname.rm1</name>
        <value>bigdata121</value>
    </property>

    <property>
        <name>yarn.resourcemanager.hostname.rm2</name>
        <value>bigdata122</value>
    </property>

    <!--指定zookeeper集群的地址-->
    <property>
        <name>yarn.resourcemanager.zk-address</name>
        <value>bigdata121:2181,bigdata122:2181,bigdata123:2181</value>
    </property>

    <!--启用自动恢复,故障自动切换-->
    <property>
         <name>yarn.resourcemanager.recovery.enabled</name>
        <value>true</value>
    </property>

    <!--指定resourcemanager的状态信息存储在zookeeper集群-->
    <property>
        <name>yarn.resourcemanager.store.class</name>
        <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
    </property>
</configuration>

配置文件同步到其他节点。

(3)启动集群

bigdata121:启动yarn
sbin/start-yarn.sh

bigdata122:启动rm
sbin/yarn-daemon.sh start resourcemanager

查看服务状态:
bin/yarn rmadmin -getServiceState rm1
bin/yarn rmadmin -getServiceState rm2

测试方式和namenode类似,这里不重复

上一篇:基于cephfs搭建高可用分布式存储并mount到本地


下一篇:zookeeper 都有哪些使用场景?