Zookeeper 是一个分布式协调服务的开源框架。 主要用来解决分布式集群中应用系统的一致性问题,例如怎样避免同时操作同一数据造成脏读的问题。分布式系统中数据存在一致性的问题!!
Follower
Observer
Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。
下载
首先我们下载稳定版本的zookeeper http://zookeeper.apache.org/releases.html
解压 压缩包
修改配置文件创建data与log目录
#创建zk存储数据目录
mkdir -p /opt/lagou/servers/zookeeper-3.4.14/data
#创建zk日志文件目录
mkdir -p /opt/lagou/servers/zookeeper-3.4.14/data/logs
#修改zk配置文件
cd /opt/lagou/servers/zookeeper-3.4.14/conf
#文件改名
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg
#更新datadir
dataDir=/opt/lagou/servers/zookeeper-3.4.14/data
#增加logdir
dataLogDir=/opt/lagou/servers/zookeeper-3.4.14/data/logs
#增加集群配置
##server.服务器ID=服务器IP地址:服务器之间通信端口:服务器之间投票选举端口
server.1=centos7-1:2888:3888
server.2=centos7-2:2888:3888
server.3=centos7-3:2888:3888
#打开注释
#ZK提供了自动清理事务日志和快照文件的功能,这个参数指定了清理频率,单位是小时
autopurge.purgeInterval=1
添加myid配置
cd /opt/lagou/servers/zookeeper-3.4.14/data
echo 1 > myid
安装包分发并修改myid的值
修改myid值 centos7-2/centos7-3
cd /opt/lagou/servers/zookeeper-3.4.14/data
echo 2 > myid
cd /opt/lagou/servers/zookeeper-3.4.14/data
echo 3 > myid
依次启动三个zk实例
启动命令(三个节点都要执行)
/opt/lagou/servers/zookeeper-3.4.14/bin/zkServer.sh start
#查看zk启动情况
/opt/lagou/servers/zookeeper-3.4.14/bin/zkServer.sh status
#集群启动停止脚本
vim zk.sh
#!/bin/sh
echo "start zookeeper server..."
if(($#==0));then
echo "no params";
exit;
fi
hosts="centos7-1 centos7-2 centos7-3"
for host in $hosts
do
ssh $host "source /etc/profile; /opt/lagou/servers/zookeeper-
3.4.14/bin/zkServer.sh $1"
done
ZooKeeper数据模型Znode
在ZooKeeper中,数据信息被保存在一个个数据节点上,这些节点被称为znode。ZNode 是Zookeeper 中最小数据单位,在 ZNode 下面又可以再挂 ZNode,这样一层层下去就形成了一个层次化命名空间 ZNode 树,我们称为 ZNode Tree,它采用了类似文件系统的层级树状结构进行管理。见下图
示例:
在 Zookeeper 中,每一个数据节点都是一个 ZNode,上图根目录下有两个节点,分别是:app1 和app2,其中 app1 下面又有三个子节点,所有ZNode按层次化进行组织,形成这么一颗树,ZNode的节点路径标识方式和Unix文件系统路径非常相似,都是由一系列使用斜杠(/)进行分割的路径表示,开发人员可以向这个节点写入数据,也可以在这个节点下面创建子节点。
Zookeeper 节点类型可以分为三大类:
持久性节点(Persistent)
临时性节点(Ephemeral)
顺序性节点(Sequential)
在开发中在创建节点的时候通过组合可以生成以下四种节点类型:持久节点、持久顺序节点、临时节点、临时顺序节点。不同类型的节点则会有不同的生命周期
事务ID
首先,先了解,事务是对物理和抽象的应用状态上的操作集合。往往在现在的概念中,狭义上的事务通常指的是数据库事务,一般包含了一系列对数据库有序的读写操作,这些数据库事务具有所谓的ACID特性,即原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
而在ZooKeeper中,事务是指能够改变ZooKeeper服务器状态的操作,我们也称之为事务操作或更新操作,一般包括数据节点创建与删除、数据节点内容更新等操作。对于每一个事务请求,ZooKeeper都会为其分配一个全局唯一的事务ID,用 ZXID 来表示,通常是一个 64 位的数字。每一个 ZXID 对应一次更新操作,从这些ZXID中可以间接地识别出ZooKeeper处理这些更新操作请求的全局顺序。
zk中的事务指的是对zk服务器状态改变的操作(create,update data,更新字节点);zk对这些事务操作都会编号,这个编号是自增长的被称为ZXID。
#使用bin/zkCli.sh 连接到zk集群
[zk: localhost:2181(CONNECTED) 2] get /zookeeper
cZxid = 0x0
ctime = Wed Dec 31 19:00:00 EST 1969
mZxid = 0x0
mtime = Wed Dec 31 19:00:00 EST 1969
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
整个 ZNode 节点内容包括两部分:节点数据内容和节点状态信息。数据内容是空,其他的属于状态信息。那么这些状态信息都有什么含义呢?
cZxid 就是 Create ZXID,表示节点被创建时的事务ID。
ctime 就是 Create Time,表示节点创建时间。
mZxid 就是 Modified ZXID,表示节点最后一次被修改时的事务ID。
mtime 就是 Modified Time,表示节点最后一次被修改的时间。
pZxid 表示该节点的子节点列表最后一次被修改时的事务 ID。只有子节点列表变更才会更新 pZxid,子
节点内容变更不会更新。
cversion 表示子节点的版本号。
dataVersion 表示内容版本号。
aclVersion 标识acl版本
ephemeralOwner 表示创建该临时节点时的会话 sessionID,如果是持久性节点那么值为 0
dataLength 表示数据长度。
numChildren 表示直系子节点数。
Zookeeper使用Watcher机制实现分布式数据的发布/订阅功能
一个典型的发布/订阅模型系统定义了一种 一对多的订阅关系,能够让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使它们能够做出相应的处理。
在 ZooKeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。ZooKeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,那么Zk就会向指定客户端发送一个事件通知来实现分布式的通知功能。
整个Watcher注册与通知过程如图所示。
Zookeeper的Watcher机制主要包括客户端线程、客户端WatcherManager、Zookeeper服务器三部分。
具体工作流程为:
现在已经搭建起了一个能够正常运行的zookeeper服务了,所以接下来,就是来借助客户端来对zookeeper的数据节点进行操作
首先,进入到zookeeper的bin目录之后
通过zkClient进入zookeeper客户端命令行
./zkcli.sh 连接本地的zookeeper服务器
./zkCli.sh -server ip:port(2181) 连接指定的服务器
# 创建节点
# 使用create命令,可以创建一个Zookeeper节点, 如
create [-s][-e] path data
# 其中,-s或-e分别指定节点特性,顺序或临时节点,若不指定,则创建持久节点
# 1.创建顺序节点(路径+内容)
create -s /zk-test 123
# 2.创建临时节点
create -e /zk-temp 123
# 临时节点在客户端会话结束后,就会自动删除,下面使用quit命令退出客户端
quit
# 再次使用客户端连接服务端,并使用ls / 命令查看根目录下的节点
ls /
# 3.创建永久节点
# 使用 create /zk-permanent 123 命令创建zk-permanent永久节点 ,可以看到永久节点不同于顺序节点,不会自动在后面添加一串数字
create /zk-permanent 123
读取节点
与读取相关的命令有ls 命令和get 命令
ls命令可以列出Zookeeper指定节点下的所有子节点,但只能查看指定节点下的第一级的所有子节点;
ls path
其中,path表示的是指定数据节点的节点路径
# get命令可以获取Zookeeper指定节点的数据内容和属性信息。
get path
# 若获取根节点下面的所有子节点,使用ls / 命令即可
ls /
# 若想获取/zk-permanent的数据内容和属性,可使用如下命令:get /zk-permanent
get /zk-permanent
从上面的输出信息中,我们可以看到,第一行是节点/zk-permanent 的数据内容,其他几行则是创建该节点的事务ID(cZxid)、最后一次更新该节点的事务ID(mZxid)和最后一次更新该节点的时间(mtime)等属性信息
更新节点
使用set命令,可以更新指定节点的数据内容,用法如下
set path data
其中,data就是要更新的新内容,version表示数据版本,在zookeeper中,节点的数据是有版本概念的,这个参数用于指定本次更新操作是基于Znode的哪一个数据版本进行的,如将/zk-permanent节点的数据更新为456,可以使用如下命令:set /zk-permanent 456
删除节点
使用delete命令可以删除Zookeeper上的指定节点,用法如下
delete path
其中version也是表示数据版本,使用delete /zk-permanent 命令即可删除/zk-permanent节点
可以看到,已经成功删除/zk-permanent节点。值得注意的是,若删除节点存在子节点,那么无法删除该节点,必须先删除子节点,再删除父节点
ZkClient
ZkClient是Github上一个开源的zookeeper客户端,在Zookeeper原生API接口之上进行了包装,是一个更易用的Zookeeper客户端,同时,zkClient在内部还实现了诸如Session超时重连、Watcher反复注册等功能
接下来,还是从创建会话、创建节点、读取数据、更新数据、删除节点等方面来介绍如何使用zkClient这个zookeeper客户端。
添加依赖:
在pom.xml文件中添加如下内容
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.4.14version>
dependency>
<dependency>
<groupId>com.101tecgroupId>
<artifactId>zkclientartifactId>
<version>0.2version>
dependency>
1.创建会话
使用ZkClient可以轻松的创建会话,连接到服务端。
package com.hust.grid.leesf.zkclient.examples;
import java.io.IOException;
import org.I0Itec.zkclient.ZkClient;
public class CreateSession {
/*
创建一个zkClient实例来进行连接
*/
public static void main(String[] args) {
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
System.out.println("ZooKeeper session created.");
}
}
运行结果:ZooKeeper session created.
结果表明已经成功创建会话。
2. 创建节点
ZkClient提供了递归创建节点的接口,即其帮助开发者先完成父节点的创建,再创建子节点
package com.hust.grid.leesf.zkclient.examples;
import org.I0Itec.zkclient.ZkClient;
public class Create_Node_Sample {
public static void main(String[] args) {
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
System.out.println("ZooKeeper session established.");
//createParents的值设置为true,可以递归创建节点
zkClient.createPersistent("/lg-zkClient/lg-c1",true);
System.out.println("success create znode.");
}
}
运行结果:success create znode.
结果表明已经成功创建了节点,值得注意的是,ZkClient通过设置createParents参数为true可以递归的先创建父节点,再创建子节点
3.删除节点
ZkClient提供了递归删除节点的接口,即其帮助开发者先删除所有子节点(存在),再删除父节点。
package com.hust.grid.leesf.zkclient.examples;
import org.I0Itec.zkclient.ZkClient;
public class Del_Data_Sample {
public static void main(String[] args) throws Exception {
String path = "/lg-zkClient/lg-c1";
ZkClient zkClient = new ZkClient("127.0.0.1:2181", 5000);
zkClient.deleteRecursive(path);
System.out.println("success delete znode.");
}
}
运行结果: success delete znode.
结果表明ZkClient可直接删除带子节点的父节点,因为其底层先删除其所有子节点,然后再删除父节点
4. 监听节点变化
package com.lagou.zk.demo;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.client.ZooKeeperSaslClient;
import java.util.List;
/*
演示zkClient如何使用监听器
*/
public class Get_Child_Change {
public static void main(String[] args) throws InterruptedException {
//获取到zkClient
final ZkClient zkClient = new ZkClient("linux121:2181");
//zkClient对指定目录进行监听(不存在目录:/lg-client),指定收到通知之后的逻辑
//对/lag-client注册了监听器,监听器是一直监听
zkClient.subscribeChildChanges("/lg-client", new IZkChildListener() {
//该方法是接收到通知之后的执行逻辑定义
public void handleChildChange(String path, List<String> childs)
throws Exception {
//打印节点信息
System.out.println(path + " childs changes ,current childs " + childs);
}
});
//使用zkClient创建节点,删除节点,验证监听器是否运行
zkClient.createPersistent("/lg-client");
Thread.sleep(1000); //只是为了方便观察结果数据
zkClient.createPersistent("/lg-client/c1");
Thread.sleep(1000);
zkClient.delete("/lg-client/c1");
Thread.sleep(1000);
zkClient.delete("/lg-client");
Thread.sleep(Integer.MAX_VALUE);
/*
1 监听器可以对不存在的目录进行监听
2 监听目录下子节点发生改变,可以接收到通知,携带数据有子节点列表
3 监听目录创建和删除本身也会被监听到
*/
}
}
运行结果:
/lg-zkClient 's child changed, currentChilds:[]
/lg-zkClient 's child changed, currentChilds:[c1]
/lg-zkClient 's child changed, currentChilds:[]
/lg-zkClient 's child changed, currentChilds:null
结果表明:
客户端可以对一个不存在的节点进行子节点变更的监听。
一旦客户端对一个节点注册了子节点列表变更监听之后,那么当该节点的子节点列表发生变更时,服务端都会通知客户端,并将最新的子节点列表发送给客户端
该节点本身的创建或删除也会通知到客户端。
5. 获取数据(节点是否存在、更新、删除)
package com.lagou.zk.demo;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
//使用监听器监听节点数据的变化
public class Get_Data_Change {
public static void main(String[] args) throws InterruptedException {
// 获取zkClient对象
final ZkClient zkClient = new ZkClient("linux121:2181");
//设置自定义的序列化类型,否则会报错!!
zkClient.setZkSerializer(new ZkStrSerializer());
//判断节点是否存在,不存在创建节点并赋值
final boolean exists = zkClient.exists("/lg-client1");
if (!exists) {
zkClient.createEphemeral("/lg-client1", "123");
}
//注册监听器,节点数据改变的类型,接收通知后的处理逻辑定义
zkClient.subscribeDataChanges("/lg-client1", new IZkDataListener() {
public void handleDataChange(String path, Object data) throws
Exception {
//定义接收通知之后的处理逻辑
System.out.println(path + " data is changed ,new data " + data);
}
//数据删除--》节点删除
public void handleDataDeleted(String path) throws Exception {
System.out.println(path + " is deleted!!");
}
});
//更新节点的数据,删除节点,验证监听器是否正常运行
final Object o = zkClient.readData("/lg-client1");
System.out.println(o);
zkClient.writeData("/lg-client1", "new data");
Thread.sleep(1000);
//删除节点
zkClient.delete("/lg-client1");
Thread.sleep(Integer.MAX_VALUE);
}
}
结果表明可以成功监听节点数据变化或删除事件。
选举机制
集群首次启动
假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动:
Zookeeper的选举机制
(1)服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。
(2)服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。
(3)服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。
(4)服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。
(5)服务器5启动,同4一样称为follower。
集群非首次启动
每个节点在选举时都会参考自身节点的zxid值(事务ID);优先选择zxid值大的节点称Leader!!
1. 分布式数据一致性问题
为什么会出现分布式数据一致性问题?
在分布式系统中引入数据复制机制后,多台数据节点之间由于网络等原因很容易产生数据不一致的情况。
举例
当客户端Client1将系统中的一个值K1由V1更新为V2,但是客户端Client2读取的是一个还没有同步更新的副本,K1的值依然是V1,这就导致了数据的不一致性。其中,常见的就是主从数据库之间的复制延时问题。
2. ZAB协议
follower如何座到与leader数据同步呢?
ZK就是分布式一致性问题的工业解决方案,paxos是其底层理论算法(晦涩难懂著名),其中zab,raft和众多开源算法是对paxos的工业级实现。ZK没有完全采用paxos算法,而是使用了一种称为Zookeeper Atomic Broadcast(ZAB,Zookeeper原子消息广播协议)的协议作为其数据一致性的核心算法。
ZAB协议
ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持崩溃恢复和原子广播协议。
主备模式保证一致性
ZK怎么处理集群中的数据?所有客户端写入数据都是写入Leader中,然后,由 Leader 复制到
Follower中。ZAB会将服务器数据的状态变更以事务Proposal的形式广播到所有的副本进程上,ZAB协议能够保证了事务操作的一个全局的变更序号(ZXID)。
广播消息
ZAB 协议的消息广播过程类似于 二阶段提交过程。对于客户端发送的写请求,全部由 Leader 接收,Leader 将请求封装成一个事务 Proposal(提议),将其发送给所有 Follwer ,如果收到超过半数反馈ACK,则执行 Commit 操作(先提交自己,再发送 Commit 给所有 Follwer)。
不能正常反馈Follower恢复正常后会进入数据同步阶段最终与Leader保持一致。
细节
zk提供的应该是最终一致性的标准。zk所有节点接收写请求之后可以在一定时间内保证所有节点都能看到该条数据。
Leader 崩溃问题
Leader宕机后,ZK集群无法正常工作,ZAB协议提供了一个高效且可靠的leader选举算法。
Leader宕机后,被选举的新Leader需要解决的问题:
基于上面的目的,ZAB协议设计了一个选举算法:能够确保已经被Leader提交的事务被集群接受,丢弃还没有提交的事务。
这个选举算法的关键点:保证选举出的新Leader拥有集群中所有节点最大编号(ZXID)的事务。
ZooKeeper是一个典型的发布/订阅模式的分布式数据管理与协调框架,我们可以使用它来进行分布式数据的发布与订阅。另一方面,通过对ZooKeeper中丰富的数据节点类型进行交叉使用,配合Watcher事件通知机制,可以非常方便地构建一系列分布式应用中都会涉及的核心功能,如数据发布/订阅、命名服务、集群管理、Master选举、分布式锁和分布式队列等。那接下来就针对这些典型的分布式应用场景来做下介绍。
Zookeeper的两大特性:
1.客户端如果对Zookeeper的数据节点注册Watcher监听,那么当该数据节点的内容或是其子节点列表发生变更时,Zookeeper服务器就会向订阅的客户端发送变更通知。
2.对在Zookeeper上创建的临时节点,一旦客户端与服务器之间的会话失效,那么临时节点也会被自动删除
利用其两大特性,可以实现集群机器存活监控系统,若监控系统在/clusterServers节点上注册一个Watcher监听,那么但凡进行动态添加机器的操作,就会在/clusterServers节点下创建一个临时节点:/clusterServers/[Hostname],这样,监控系统就能够实时监测机器的变动情况。
分布式系统中,主节点会有多台,主节点可能因为任何原因出现宕机或者下线,而任意一台客户端都要能实时感知到主节点服务器的上下线。
思路分析
具体实现
NameNode机器发生意外,如宕机,集群将无法使用,直到管理员重启
NameNode机器需要升级,包括软件、硬件升级,此时集群也将无法使用
HDFS HA功能通过配置Active/Standby两个NameNodes实现在集群中对NameNode的热备来解决上述问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种方式将NameNode很快的切换到另外一台机器。
通过双NameNode消除单点故障(Active/Standby)
HDFS-HA工作要点
HDFS-HA工作机制
配置部署HDFS-HA进行自动故障转移。自动故障转移为HDFS部署增加了两个新组件:ZooKeeper和ZKFailoverController(ZKFC)进程,ZooKeeper是维护少量协调数据,通知客户端这些数据的改变和监视客户端故障的高可用服务。HA的自动故障转移依赖于ZooKeeper的以下功能:
ZKFC是自动故障转移中的另一个新组件,是ZooKeeper的客户端,也监视和管理NameNode的状态。每个运行NameNode的主机也运行了一个ZKFC进程,ZKFC负责:
https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoophdfs/HDFSHighAvailabilityWithQJM.html
环境准备
集群规划
启动Zookeeper集群
配置HDFS-HA集群
rm -rf /opt/lagou/servers/ha/hadoop-2.9.2/data
<property>
<name>dfs.nameservicesname>
<value>lagouclustervalue>
property>
<property>
<name>dfs.ha.namenodes.lagouclustername>
<value>nn1,nn2value>
property>
<property>
<name>dfs.namenode.rpc-address.lagoucluster.nn1name>
<value>centos7-1:9000value>
property>
<property>
<name>dfs.namenode.rpc-address.lagoucluster.nn2name>
<value>centos7-2:9000value>
property>
<property>
<name>dfs.namenode.http-address.lagoucluster.nn1name>
<value>centos7-1:50070value>
property>
<property>
<name>dfs.namenode.http-address.lagoucluster.nn2name>
<value>centos7-2:50070value>
property>
<property>
<name>dfs.namenode.shared.edits.dirname>
<value>qjournal://centos7-1:8485;centos7-2:8485;centos7-3:8485/lagouvalue>
property>
<property>
<name>dfs.client.failover.proxy.provider.lagouclustername>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvidervalue>
property>
<property>
<name>dfs.ha.fencing.methodsname>
<value>sshfencevalue>
property>
<property>
<name>dfs.ha.fencing.ssh.private-key-filesname>
<value>/root/.ssh/id_rsavalue>
property>
<property>
<name>dfs.journalnode.edits.dirname>
<value>/opt/journalnodevalue>
property>
<property>
<name>dfs.ha.automatic-failover.enabledname>
<value>truevalue>
property>
<property>
<name>fs.defaultFSname>
<value>hdfs://lagouclustervalue>
property>
<property>
<name>hadoop.tmp.dirname>
<value>/opt/lagou/servers/ha/hadoop-2.9.2/data/tmpvalue>
property>
<property>
<name>ha.zookeeper.quorumname>
<value>centos7-1:2181,centos7-2:2181,centos7-3:2181value>
property>
启动HDFS-HA集群
/opt/lagou/servers/ha/hadoop-2.9.2/sbin/hadoop-daemon.sh start journalnode
/opt/lagou/servers/ha/hadoop-2.9.2/bin/hdfs namenode -format
/opt/lagou/servers/ha/hadoop-2.9.2/sbin/hadoop-daemon.sh start namenode
/opt/lagou/servers/ha/hadoop-2.9.2/bin/hdfs namenode -bootstrapStandby
/opt/lagou/servers/ha/hadoop-2.9.2/bin/hdfs zkfc -formatZK
/opt/lagou/servers/ha/hadoop-2.9.2/sbin/start-dfs.sh
YARN-HA工作机制
https://hadoop.apache.org/docs/stable/hadoop-yarn/hadoop-yarnsite/ResourceManagerHA.html
** 规划集群**
具体配置
<property>
<name>yarn.nodemanager.aux-servicesname>
<value>mapreduce_shufflevalue>
property>
<property>
<name>yarn.resourcemanager.ha.enabledname>
<value>truevalue>
property>
<property>
<name>yarn.resourcemanager.cluster-idname>
<value>cluster-yarnvalue>
property>
<property>
<name>yarn.resourcemanager.ha.rm-idsname>
<value>rm1,rm2value>
property>
<property>
<name>yarn.resourcemanager.hostname.rm1name>
<value>centos7-2value>
property>
<property>
<name>yarn.resourcemanager.hostname.rm2name>
<value>centos7-3value>
property>
<property>
<name>yarn.resourcemanager.zk-addressname>
<value>centos7-1:2181,centos7-2:2181,centos7-3:2181value>
property>
<property>
<name>yarn.resourcemanager.recovery.enabledname>
<value>truevalue>
property>
<property>
<name>yarn.resourcemanager.store.classname>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStorevalue>
property>
## centos-3:
sbin/start-yarn.sh
## centos-2(杀死3上的yarn2来顶替):
sbin/yarn-daemon.sh start resourcemanager