hadoop系列十七——zookeeper概述

zookeeper概念介绍

ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

官方文档上这么解释zookeeper,它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

上面的解释有点抽象,简单来说zookeeper=文件系统+监听通知机制。

zookeeper的基本功能和应用场景

在这里插入图片描述

zookeeper的整体运行机制

Zookeeper 集群:

Zookeeper 是一个由多个 server 组成的集群,一个 leader,多个 follower。(这个不同于我们常见的Master/Slave模式)leader 为客户端服务器提供读写服务,除了leader外其他的机器只能提供读服务。
每个 server 保存一份数据副本全数据一致,分布式读 follower,写由 leader 实施更新请求转发,由 leader 实施更新请求顺序进行,来自同一个 client 的更新请求按其发送顺序依次执行数据更新原子性,一次数据更新要么成功,要么失败。全局唯一数据视图,client 无论连接到哪个 server,数据视图都是一致的实时性,在一定事件范围内,client 能读到最新数据。

集群角色

Leader:是整个 Zookeeper 集群工作机制中的核心 。** **。
主要工作:

事务请求的唯一调度和处理,保障集群处理事务的顺序性。
集群内各服务器的调度者。

Leader 选举是 Zookeeper 最重要的技术之一,也是保障分布式数据一致性的关键所在。我们以三台机器为例,在服务器集群初始化阶段,当有一台服务器Server1启动时候是无法完成选举的,当第二台机器 Server2 启动后两台机器能互相通信,每台机器都试图找到一个leader,于是便进入了 leader 选举流程.

每个 server 发出一个投票
投票的最基本元素是(SID-服务器id,ZXID-事物id)
接受来自各个服务器的投票
处理投票
优先检查 ZXID(数据越新ZXID越大),ZXID比较大的作为leader,ZXID一样的情况下比较SID
统计投票
这里有个过半的概念,大于集群机器数量的一半,即大于或等于(n/2+1),我们这里的由三台,大于等于2即为达到“过半”的要求。
这里也有引申到为什么 Zookeeper 集群推荐是单数。

集群数量 至少正常运行数量 允许挂掉的数量
2 2的半数为1,半数以上最少为2 0
3 3的半数为1.5,半数以上最少为2 1
4 4的半数为2,半数以上最少为3 1
5 5的半数为2.5,半数以上最少为3 2
6 6的半数为3,半数以上最少为4 2

通过以上可以发现,3台服务器和4台服务器都最多允许1台服务器挂掉,5台服务器和6台服务器都最多允许2台服务器挂掉,明显4台服务器成本高于3台服务器成本,6台服务器成本高于5服务器成本。这是由于半数以上投票通过决定的。

改变服务器状态
一旦确定了 leader,服务器就会更改自己的状态,且一半不会再发生变化,比如新机器加入集群、非 leader 挂掉一台。

Follower :是 Zookeeper 集群状态的跟随者。他的逻辑就比较简单。除了响应本服务器上的读请求外,follower 还要处理leader 的提议,并在 leader 提交该提议时在本地也进行提交。另外需要注意的是,leader 和 follower 构成ZooKeeper 集群的法定人数,也就是说,只有他们才参与新 leader的选举、响应 leader 的提议。

Observer :服务器充当一个观察者的角色。如果 ZooKeeper 集群的读取负载很高,或者客户端多到跨机房,可以设置一些 observer 服务器,以提高读取的吞吐量。Observer 和 Follower 比较相似,只有一些小区别:首先 observer 不属于法定人数,即不参加选举也不响应提议,也不参与写操作的“过半写成功”策略;其次是 observer 不需要将事务持久化到磁盘,一旦 observer 被重启,需要从 leader 重新同步整个名字空间。
在这里插入图片描述

1、 文件系统

Zookeeper维护一个类似文件系统的数据结构,zookeeper中对用户的数据采用kv形式存储
只是zk有点特别:

在ZooKeeper中,这些信息被保存在一个个数据节点上,这些节点被称为znode。它采用了类似文件系统的层级树状结构进行管理。

key:是以路径的形式表示的,那就以为着,各key之间有父子关系,比如
/ 是顶层key
用户建的key只能在/ 下作为子节点,比如建一个key: /aa 这个key可以带value数据
也可以建一个key: /bb
也可以建key: /aa/xx
zookeeper中,每一个key-value称为一个znode

综上所述,zk中的数据存储形式如下:
在这里插入图片描述

每个子目录项如 NameService 都被称作为 znode(目录节点),和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

有四种类型的znode:

  1. PERSISTENT-持久化目录节点

    客户端与zookeeper断开连接后,该节点依旧存在

  2. PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点

    客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

  3. EPHEMERAL-临时目录节点

    客户端与zookeeper断开连接后,该节点被删除

  4. EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点

    客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

2、 监听通知机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。

ZooKeeper的好处:

简单的分布式协调过程

同步 - 服务器进程之间的相互排斥和协作。此过程有助于Apache HBase进行配置管理。

有序的消息

序列化 - 根据特定规则对数据进行编码。确保应用程序运行一致。这种方法可以在MapReduce中用来协调队列以执行运行的线程。

可靠性

原子性 - 数据转移完全成功或完全失败,但没有事务是部分的。

. zookeeper的集群部署

1、上传安装包到集群服务器
2、解压
3、修改配置文件
进入zookeeper的安装目录的conf目录
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg
#The number of milliseconds of each tick
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/root/zkdata
clientPort=2181

#autopurge.purgeInterval=1
server.1=hdp20-01:2888:3888
server.2=hdp20-02:2888:3888
server.3=hdp20-03:2888:3888

对3台节点,都创建目录 mkdir /root/zkdata
对3台节点,在工作目录中生成myid文件,但内容要分别为各自的id: 1,2,3
hdp20-01上: echo 1 > /root/zkdata/myid
hdp20-02上: echo 2 > /root/zkdata/myid
hdp20-03上: echo 3 > /root/zkdata/myid

4、从hdp20-01上scp安装目录到其他两个节点
scp -r zookeeper-3.4.6/ hdp20-02 P W D s c p − r z o o k e e p e r − 3.4.6 / h d p 20 − 03 : PWD scp -r zookeeper-3.4.6/ hdp20-03: PWDscprzookeeper3.4.6/hdp2003:PWD

5、启动zookeeper集群
zookeeper没有提供自动批量启动脚本,需要手动一台一台地起zookeeper进程
在每一台节点上,运行命令:
bin/zkServer.sh start
启动后,用jps应该能看到一个进程:QuorumPeerMain

但是,光有进程不代表zk已经正常服务,需要用命令检查状态:
bin/zkServer.sh status
能看到角色模式:为leader或follower,即正常了。

zookeeper的命令行客户端操作

zookeeper的数据存储形式:

一、zookeeper中存储数据的基本形式为: key , value
二、zookeeper中的key是用路径表示的:
/aa : 88888
/aa/bb : “xxoo”
/aa/cc : “edu360”
/tt: 9898
每一个key-value称为一个znode(zookeeper数据节点)

数据管理功能:

创建节点: create /aaa ‘ppppp’
查看节点下的子节点: ls /aaa
获取节点的value: get /aaa
修改节点的value: set /aaa ‘mmmmm’
删除节点:rmr /aaa

数据监听功能:

ls /aaa watch
查看/aaa的子节点的同时,注册了一个监听“节点的子节点变化事件”的监听器

get /aaa watch
获取/aaa的value的同时,注册了一个监听“节点value变化事件”的监听器

注意:注册的监听器在正常收到一次所监听的事件后,就失效

zookeeper编程

zookeeper客户端api

public class ZookeeperClientDemo {
	ZooKeeper zk = null;
	@Before
	public void init()  throws Exception{
		// 构造一个连接zookeeper的客户端对象
		// 参数1:要创建的zookeeper的  参数2:要创建的zookeeper的端口 参数三是watcher的实现类,收到通知后的操作,可在该类实现  
		zk = new ZooKeeper("hdp-01:2181,hdp-02:2181,hdp-03:2181", 2000, null);
	}
	
	
	@Test
	public void testCreate() throws Exception{
        //创建节点:
		// 参数1:要创建的节点路径  参数2:数据  参数3:访问权限  参数4:节点类型
		String create = zk.create("/eclipse", "hello eclipse".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		
		System.out.println(create);
		
		zk.close();
		
	}
	
	
	@Test
	public void testUpdate() throws Exception {
		    //更新节点
		// 参数1:节点路径   参数2:数据    参数3:所要修改的版本,-1代表任何版本
		zk.setData("/eclipse", "我爱你".getBytes("UTF-8"), -1);
				zk.close();
		
	}
	
	
	@Test	
	public void testGet() throws Exception {
		//监听功能:获取该key的value,并且决定注册了一个监听“节点的子节点变化事件”的监听器
		// 参数1:节点路径    参数2:是否要监听    参数3:所要获取的数据的版本,null表示最新版本
		byte[] data = zk.getData("/eclipse", false, null);
		System.out.println(new String(data,"UTF-8"));
		
		zk.close();
	}
	
	
	
	@Test	
	public void testListChildren() throws Exception {
			//监听功能:获取该key的所有value,并且决定注册了一个监听“节点的子节点变化事件”的监听器
		// 参数1:节点路径    参数2:是否要监听   
		// 注意:返回的结果中只有子节点名字,不带全路径
		List<String> children = zk.getChildren("/cc", false);
		
		for (String child : children) {
			System.out.println(child);
		}
		
		zk.close();
	}
	
	
	@Test
	public void testRm() throws InterruptedException, KeeperException{
		  //更新节点删除节点
		  // 参数1:节点路径   参数2:所要修改的版本,-1表示所有版本,null表示最新版本
		zk.delete("/eclipse", -1);
		
		zk.close();
	}
	
	
	

}

zookeeper监听功能实现

public class ZookeeperWatchDemo {

	ZooKeeper zk = null;

	@Before
	public void init() throws Exception {
		// 构造一个连接zookeeper的客户端对象
		
		
		zk = new ZooKeeper("hdp-01:2181,hdp-02:2181,hdp-03:2181", 2000, new Watcher() {	// 在watcher类中重写precess方法,从而定义接到通知后的操作

			@Override
			public void process(WatchedEvent event) {

				if (event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeDataChanged) {
					System.out.println(event.getPath()); // 收到的事件所发生的节点路径
					System.out.println(event.getType()); // 收到的事件的类型
					System.out.println("赶紧换照片,换浴室里面的洗浴套装....."); // 收到事件后,我们的处理逻辑

					try {
						zk.getData("/mygirls", true, null);    //在操作完成后,再次查看value,建立监听,这样就可以不断循环监听

					} catch (KeeperException | InterruptedException e) {
						e.printStackTrace(); 
					}
				}else if(event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeChildrenChanged){
					
					System.out.println("子节点变化了......");
				}



//数据监听

@Test  //
	public void testGetWatch() throws Exception {

		byte[] data = zk.getData("/mygirls", true, null); // 监听节点数据变化
		
		List<String> children = zk.getChildren("/mygirls", true); //监听节点的子节点变化事件

		System.out.println(new String(data, "UTF-8"));

		Thread.sleep(Long.MAX_VALUE);   //是守护线程,如果不sleep,主线程会结束,关闭监听

	}

}

zookeeper监听案例功能实现

在这里插入代码片
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值