zookeeper总结

HADOOPHA场景下,即使Active节点发生故障,系统也不会自动触发从Active到Standby的故障转移。
需要进行手动的故障转移。 手动故障转移显然不是我们所需要的解决方案。 为了实现自动故障转移,
需要引入两个新组件:ZooKeeper和ZKFailoverController(ZKFC)进程。

Apache ZooKeeper是一种高可用性服务,用于维护少量协调数据,通知客户端该数据的更改以及监视客户端
是否存在故障。自动故障转移的实现依赖于ZooKeeper来实现以下功能:

  1. 故障检测:集群中的每个NameNode在ZooKeeper中维护了一个持久会话,如果机器崩溃,
    ZooKeeper中的会话将终止,ZooKeeper通知另一个NameNode需要触发故障转移。

  2. Active NameNode选举ZooKeeper提供了一个简单的机制用于唯一的选择一个节点为active状态。
    如果当前Active节点崩溃,则另一个节点可能从ZooKeeper获得特殊的排他锁以表明它成为下一个Active节点。

ZKFC是自动故障转移中的另一个新组件,是ZooKeeper的客户端,也监视和管理NameNode的状态。
每个运行NameNode的主机也运行了一个ZKFC进程,ZKFC负责:

1)健康监测:ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode,只要该NameNode及时地回复
健康状态,ZKFC认为该节点是健康的。如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非
健康的。

2)ZooKeeper会话管理:当本地NameNode是健康的,ZKFC保持一个在ZooKeeper中打开的会话。
如果本地NameNode处于active状态,ZKFC也保持一个特殊的znode锁,该锁使用了ZooKeeper对短暂节点的支持,
如果会话终止,锁节点将自动删除。

3)基于ZooKeeper的选举(word文档):如果本地NameNode是健康的,且ZKFC发现没有其它的节点当前持有znode锁,
它将为自己获取该锁。如果成功,则它已经赢得了选举,并通过RPC将它的本地NameNode的状态置为active。
必要时对先前的Active进行隔离(Fence),然后本地NameNode转换为活动状态。

注意:
1)DN同时向active和standby发送心跳和块报告

2)ACTIVE NN将操作记录写到自己的edit log ,同时将edit log写入JN集群。每个JN都会写。

3)STANDBY NN:?同时接收JN集群的日志(随机选个写入成功的JN节点读),重演edits log操作,使得自己的元数据和active nn节点保持一致。

4)在激活新的Active NN之前,会对旧的Active NN进行隔离操作防止脑裂。(kill掉)

安装zookeeper:单机模式

a.下载zookeeper3.4.6.tar.gz 通过挂载盘上传
b.解压至【/home/crx/soft】
进入soft文件夹下解压
[crx@master soft]$ tar -zxvf zookeeper-3.4.6.tar.gz
c.创建软连接: > l n − s z o o k e e p e r 3.4.6 / z o o k e e p e r d . 配 置 环 境 变 量 : 在   / . b a s h p r o f i l e 中 追 加 e x p o r t Z O O K E E P E R H O M E = / h o m e / c r x / s o f t / z o o k e e p e r e x p o r t P A T H = >ln -s zookeeper3.4.6/ zookeeper d.配置环境变量:在~/.bash_profile中追加 export ZOOKEEPER_HOME=/home/crx/soft/zookeeper export PATH= >lnszookeeper3.4.6/zookeeperd. /.bashprofileexportZOOKEEPERHOME=/home/crx/soft/zookeeperexportPATH=ZOOKEEPER_HOME/bin:$PATH

[crx@master ~]$ source ~/.bash_profile
e.进入安装目录:/home/crx/soft/zookeeper-3.4.6/conf
复制一份 zoo_sample.cfg 为zoo.cfg
[crx@master conf]$ cp zoo_sample.cfg zoo.cfg
修改【{ZOOKEEPER_HOME}/conf/zoo.cfg】zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/crx/tmp/zookeeper
clientPort=2181
f.开启zookeeper Server
$>zkServer.sh start
$>jps
5914 QuorumPeerMain //QuorumPeerMain:zookeeper Server的守护进程
5931 Jps
g.客户端连接:
$>zkCli.sh -server 127.0.0.1:2181
5988 ZooKeeperMain //ZooKeeperMain:zookeeper client的守护进程

$>quit 退出客户端
h.关机Zookeeper Server
$>zkServer.sh stop

i.查看:zookeeper.out /home/crx/tmp/zookeeper


1.zookeeper集群模式:
a.[修改zoo.cfg文件]:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/crx/tmp/zookeeper
clientPort=2181
server.1=master:2888:3888
server.2=slave1:2888:3888
server.3=slave2:2888:3888
b.在/home/crx/tmp/zookeeper目录下,创建myid文件
> e c h o " 1 " > > m y i d / / 在 m a s t e r 节 点 c . 将 z o o k e e p e r 复 制 到 其 它 两 个 节 点 [ c r x @ m a s t e r s o f t ] >echo "1" >> myid //在master节点 c.将zookeeper复制到其它两个节点 [crx@master soft] >echo"1">>myid//masterc.zookeeper[crx@mastersoft] scp -r zookeeper-3.4.6 crx@slave1:~/soft/
[crx@master soft]$ scp -r zookeeper-3.4.6 crx@slave2:~/soft/
分别创建zookeeper软链接 ln -s zookeeper-3.4.6 zookeeper

d.复制dataDir=/home/crx/tmp/zookeeper
$> scp -r ~/tmp/zookeeper/ crx@slave1:~/tmp/
$> scp -r ~/tmp/zookeeper/ crx@slave2:~/tmp/

e.复制环境变量
$> scp ~/.bash_profile crx@slave1:~/
$> scp ~/.bash_profile crx@slave2:~/

f.修改myid文件
slave1进入到zookeeper目录下创建myid 内容为2
slave2进入到zookeeper目录下创建myid 内容为3

分别三个节点启动【master slave1 slave2】zkServer.sh start
分别查看状态:
[crx@master conf]$ zkServer.sh status
[crx@slave1 conf]$ zkServer.sh status
[crx@slave2 conf]$ zkServer.sh status

设置自动容灾(官)

启动集群查50070 , 测试kill -9 active所在的节点
【修改hdfs-site.xml】

dfs.ha.automatic-failover.enabled
true

【修改core-site.xml】

ha.zookeeper.quorum
master:2181,slave1:2181

将配置文件同步至所有节点:
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/hdfs-site.xml crx@slave1:~/soft/hadoop/etc/hadoop/
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/hdfs-site.xml crx@slave2:~/soft/hadoop/etc/hadoop/
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/core-site.xml crx@slave1:~/soft/hadoop/etc/hadoop/
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/core-site.xml crx@slave2:~/soft/hadoop/etc/hadoop/

3.格式化zk
分别将所有节点的zkServer开启
[crx@master ~]$ zkServer.sh start
[crx@slave1 ~]$ zkServer.sh start
[crx@slave2 ~]$ zkServer.sh start

如果手动管理群集上的服务,则需要在运行NameNode的每台计算机上手动启动zkfc守护程序。
您可以通过运行以下命令来启动守护程序:
[hdfs] $ $ HADOOP_PREFIX / sbin / hadoop-daemon.sh --script $ HADOOP_PREFIX / bin / hdfs start zkfc

实例化hadoop和zookeeper的状态(让它们两个认识,一定要先开启zkServer)

[master]$>hdfs zkfc -formatZK
说明:将在Zookeeper的树状节点上注册一个Znode

4.确保zookeeper集群是开启状态:
$>jps
5458 QuorumPeerMain

5.start-dfs.sh
注意:nn1和nn2均要配置相同的无密登录;!!!!!!

6.测试:
将active的节点kill掉,查看另一个节点状态;
[crx@master hadoop]$ jps
16352 NameNode
16711 DFSZKFailoverController
16776 Jps
16203 JournalNode
16476 DataNode
12543 QuorumPeerMain
[crx@master hadoop]$ kill -9 16711


HA启动过程的顺序

step1:开启zookeeper服务:
     $>zkServer.sh start
(略)step2:开启hdfs:
     【$>start-dfs.sh    //说明:namenode-->datanode-->journalnode-->zkfc】
step3:开启journalnode守护进程(在qjournal协议指定的节点上执行):
    $>hadoop-daemon.sh start journalnode 
step4:开启namenode守护进程(在nn1和nn2上执行)
    $>hadoop-daemon.sh start namenode
step5:开启datanode守护进程(在namenode节点上执行hadoop-daemons.sh开启所有datanode节点)
    $>hadoop-daemons.sh start datanode
step6:开启zkfc守护进程
    $>hadoop-daemon.sh --script $HADOOP_PREFIX/bin/hdfs start zkfc

守护进程的说明:
5458 QuorumPeerMain 【zookeeper Server端】
7715 Jps 【java进程】
7626 DFSZKFailoverController 【ZKFC:设置自动故障转移】
7324 JournalNode 【QJM:日志节点进程】
7405 NameNode 【名称节点】
6015 DataNode 【数据节点】

以一个简单的例子来说明整个选举的过程.
假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,
在存放数据量这一点上,都是一样的.假设这些服务器依序启动,来看看会发生什么.

  1. 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态

  2. 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,
    所以id值较大的服务器2胜出(Leader id:就是我们配置的myid中的值,每个机器一个),
    但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态.

  3. 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,
    所以它成为了这次选举的leader.

  4. 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,
    所以它只能接收当小弟的命了.

  5. 服务器5启动,同4一样,当小弟.

集群服务器宕掉的情况, 半数以上服务器宕机代表zookeeper服务器宕机
例如我们集群服务器有3台, 其中有一台zkServer宕机,那么整个ZK还是可以服务的
如果2台服务器,1台宕机是就是不可用的

案例演示 分别启动zkServer.sh start(master slave1 slave2)
1.查看选举状态zkServer.sh status(分别三台节点查看)
2.jps查看leader的状态 kill掉leader所在的节点
3.再次查看 slave2应该是leader
4.再次启动slave1的zkServer.sh start 它只能当小弟了

搭建zookeeper伪分布模式,采用了多线程的方式来模拟分布式环境
a.创建zoo*.cfg配置文件【创建三个文件:分别为5,6,7】
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/crx/tmp/zookeeper/data*
clientPort=218*
server.5=master:2888:3888
server.6=master:2889:3889
server.7=master:2890:3890
注:在【/home/crx/tmp/zookeeper/data*】目录下创建对应的myid文件
b.开启server端:
$>zkServer.sh start zoo*.cfg
c.开启客户端连接zookeeper集群:
$>zkCli.sh -server master:2181,master:2182,master:2183

***集群模式下,首先开启Zookeeper集群

   http://zookeeper.apache.org/doc/current/zookeeperProgrammers.html
2.zookeeper维护了一份分布式文件系统,每个节点称为“Znode”,Znode维护数据和与之关联的子节点;
  Znodes维护一个状态结构:
  【znode:/根节点stat说明  
    cZxid = 0x0                             //create事务ID
	ctime = Wed Dec 31 16:00:00 PST 1969    //当前节点的create时间
	mZxid = 0x0                             //当前节点的修改事务ID
	mtime = Wed Dec 31 16:00:00 PST 1969    //当前节点的时间
	pZxid = 0x900000018                     //最后修改此znode的子项的更改的zxid
	cversion = 4                            //此znode的子项的更改数
	dataVersion = 0                         //此znode数据的更改次数(版本)
	aclVersion = 0                          //ACL(访问控制列表)的版本
	ephemeralOwner = 0x0                    //表示当前节点是否为临时节点,如有数据为临时节点;如为0X0,代表当前节点的永久节点;
	dataLength = 0                          //表示当前节点的数据长度,默认情况下,每个Znode节点可存放1M的数据
	numChildren = 2                         //表示当前节点拥有的子节点数
  】
3. 测试kill -9 leader所在的节点

zookeeper数据模型

1.会话 
    $ bin/zkCli.sh -server 127.0.0.1:2181
       创建znode  临时,永久等
$ bin/zkCli.sh -server slave1:2181

    $ bin/zkCli.sh -server master:2181,slave1:2181

  	close 关闭当前Zk连接会话
   $>close
connect host:port 连接其他的Zookeeper服务端:
   $>connect slave1:2181

1.创建永久节点,不加s和加s的区别,序号
[zk: master:2181(CONNECTED) 1] create /aaa1 helloword
Created /aaa1
[zk: master:2181(CONNECTED) 2] ls /
[zookeeper, aaa1, hadoop-ha]
[zk: master:2181(CONNECTED) 3] create -s /aaa2 helloword2
Created /aaa20000000023

2.zookeeper当中不能往znode中去追加内容,只能覆盖
set /aaa20000000023 newwords

3.创建临时znode (临时节点不能有子节点)
create -e /path data

4.删除znode(删除znode时,不能有子znode,需要先删除子znode再删除父znode)
delete /path

5.rmr 删除所有znode,可以包含子路径

ZooKeeper中的节点有两种,分别为临时节点和永久节点。节点的类型在创建时即被确定,并且不能改变。
① 临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除,
当然可以也可以手动删除。虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。
另外,ZooKeeper的临时节点不允许拥有子节点。

② 永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。

顺序节点
当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。
这个计数对于此节点的父节点来说是唯一的,它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。
当计数值大于232-1时,计数器将溢出。

观察
客户端可以在节点上设置watch,我们称之为监视器。
当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。
当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,
因为watch只能被触发一次,这样可以减少网络流量。

监听/path下的变化
stat /path true

****运行项目报错 ****
1.将log4j.properties拷贝到项目下,路径不能放错
2.将hadoop jar包引入项目下

Zookeeper API

1.API 测试:


//创建zookeeper对象 
	//192.168.179.103:2181    192.168.179.103    master
	ZooKeeper zk = new ZooKeeper("192.168.179.103:2181",5000,null);
	
	//创建永久znode   create /ccc1  hellowordccc

// zk.create("/ccc2", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

	//创建永久znode   create -s /ccc1  hellowordccc

// zk.create("/ccc2", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);

	//创建临时znode   create -e /ccc3  hellowordccc

// zk.create("/ccc3", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

	//创建临时znode zonde有序列   create -e /ccc3  hellowordccc

// zk.create("/ccc4", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

// Thread.sleep(10000L);

	//设置要给版本 set /ccc1 "new ccc1"

// zk.setData("/ccc1", "new ccc2 ".getBytes(), 1);

	// ls /

// List paths = zk.getChildren("/ccc1", null);
// for(String path : paths) {
// System.out.println(path);
// }

	//没有子路径的znode删除

// zk.delete("/ccc1", -1);

	//有子路径的znode删除

// List paths = zk.getChildren("/ccc1", null);
// for(String path : paths) {
// zk.delete("/ccc1/"+path, -1);
// }
// zk.delete("/ccc1", -1);

	zk.close();



   public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
	String host = "192.168.179.136:2181";
	ZooKeeper zKeeper = new ZooKeeper(host, 2000,null);  
	zKeeper.create("/bbb", "bbbword".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
	zKeeper.close();
}

   public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
	String host = "192.168.179.135:2181";
	ZooKeeper zKeeper = new ZooKeeper(host, 2000,null);  

	//删除目录不能有子节点
	zKeeper.delete("/aaaccc", 1);
	
	Thread.sleep(10000L);
	zKeeper.close();
}    

// 版本 -1 ,可以不指定版本
zKeeper.setData("/test2", "ok1231212".getBytes(), 1);  
[zk: master:2181(CONNECTED) 8] get /test2
ok1231212


byte[] byts = zk.getData("/a2", null, null);
System.out.println(new String(byts));

    
List<String> list = zKeeper.getChildren("/", null); 
for(String znode : list) {
	System.out.println(znode);
}



List<String> childres  = zk.getChildren("/a2", null);
for(String path : childres) { 
	zk.delete("/a2/"+path, -1); 
}
zk.delete("/a2", -1);
System.out.println("OK");



[zk: master:2181,slave1:2181(CONNECTED) 36] ls /a4
[aaa]
[zk: master:2181,slave1:2181(CONNECTED) 37] rmr /a4

   Stat stat = zkClient.exists("/eclipse", false);
   System.out.println(stat==null?"not exist":"exist");

实现观察者要么事先接口, 要么内部类
watcher(观察者 案例) zk客户端连接服务端触发一次事件(构造函数连接zk的服务端), 所以执行一次process

   命令行: stat    /test2    true

   测试:stat命令可以得以一个znode节点的属性,并允许我们在已经存在的znode节点上设置监视点.
   通过在路径后面设置参数true来添加监视点,当活动的主节点崩溃时, 我们会观察到.
   

   $>stat /master true

   $>set /master 2222222helloword


 创建观察者两种方式,1创建 内部类  2实现Watcher接口
2.watcher(观察者)
 public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
	Watcher wc = new Watcher(){
	   @Override
		public void process(WatchedEvent event) { 
			System.out.println("观察者正在执行"+event.getType()+"   " +event.toString());
		} 
	 };
	
	String host = "192.168.179.135:2181";
	ZooKeeper zKeeper = new ZooKeeper(host, 2000,wc);  
    //Thread.sleep(10000L);

	zKeeper.setData("/test2", "ok3666".getBytes(), 2);  
	System.out.println("设置test2"); 

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值