Zookeeper快速入门

8 篇文章 0 订阅
3 篇文章 1 订阅


大家有兴趣可以看看3y大佬的文章,讲解什么是Zookeeper,强烈推荐 https://zhuanlan.zhihu.com/p/62526102

一、Zoookeeper简介

为什么需要Zoookeeper

集群、可靠
当信息还没同步完成时,不对外提供服务
同步的时间压缩的更短

Zookeeper诞生历史

无单点问题的分布式协调框架,精力集中在处理业务逻辑
内部很多项目都是使用动物的名字来命名
大型的动物园

Zookeeper是什么?

ZooKeeper: A Distributed Coordination Service forDistributed Applications
Zookeeper是开源的高性能的分布式应用协调系统,一个高性能的分布式数据一致性解决方案

5大特点

顺序一致性
原子性
单一视图
可靠性
及时性

Zookeeper和CAP的关系

CP:一致性+分区容错性
能得到一致的数据结果,同时系统对网络具备容错性
但是它不能保证每次服务请求的可用性

作用

分布式服务注册与订阅
统一配置文件
生成分布式唯一ID
Master节点选举
分布式锁

二、Zookeeper的安装和配置

1、Linux 下安装

1)、安装 wget https://downloads.apache.org/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz
如果下载速度慢、或者下载失败建议本地下载好后,在上传到Linux:
下载地址:http://archive.apache.org/dist/zookeeper/

tar zxvf apache-zookeeper-3.6.0-bin.tar.gz
cd apache-zookeeper-3.6.0-bin
cp conf/zoo_sample.cfg conf/zoo.cfg

在这里插入图片描述

2)、配置 zoo.cfg

vi conf/zoo.cfg 

把内容修改为:

tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181

3)、启动

./bin/zkServer.sh start 

在这里插入图片描述

4)、停止

./bin/zkServer.sh stop

2、windows 下安装

下载 zookeeper
网址 https://zookeeper.apache.org/releases.html
下载 3.6.0

解压 zookeeper
解压运行 zkServer.cmd ,初次运行会报错,没有 zoo.cfg 配置文件

修改 zoo.cfg 配置文件
将 conf 下的 zoo_sample.cfg 复制一份改名为 zoo.cfg 即可。

注意几个重要位置:
dataDir=./ 临时数据存储的目录(可写相对路径)
clientPort=2181 zookeeper 的端口号
修改完成后再次启动 zookeeper,运行 zkServer.cmd

三、基本使用

1、znode节点

在这里插入图片描述
节点的性质:

  • 树形结构,也可以理解为linux的文件目录
  • 每一个节点都是znode,里面可以包含数据,也可以有子节点
  • 点分为永久节点和临时节点( session失效,也就是客户端断开后,临时节点消失)
  • 每个znode都有版本号,每当数据变化,版本号会累加(乐观锁)
  • 删除或修改节点,版本号不匹配的话(版本号已过时),会报错
  • 每个节点存储的数据不宜过大,几K即可
  • 节点可以设置权限,来限制用户的访问
  • Zookeeper保证读和写都是原子操作,且每次读写操作都是对数据的完整读取或完整写入

节点的类型:

  • 持久节点
  • 临时节点
  • 顺序节点

节点的属性:

  • dataVersion
  • cversion
  • aclVersion

2、常用命令

基础命令

启动:

./bin/zkServer.sh start

可能出现的问题:
在这里插入图片描述
关闭防火墙即可

systemctl stop firewalld

连接到zk server

./bin/zkCli.sh -server 127.0.0.1:2181

./bin/zkCli.sh

在这里插入图片描述
Ctrl+c可退出

查看节点的状态 stat /
在这里插入图片描述

查看节点ls /
在这里插入图片描述

查看节点的数据和状态 get
在这里插入图片描述

创建、修改、删除节点
在这里插入图片描述
在这里插入图片描述

高级命令

create -s的使用:
在这里插入图片描述
判断是否为持久节点(stat /):
在这里插入图片描述
创建临时节点(create -e):
在这里插入图片描述
临时节点呢,当我们结束这次会话的时候,zookeeper且以完成刷新,可以发现这个tmp的节点就已经不存在了。

条件更新(乐观锁):(set -v)
在这里插入图片描述
当一个线程把cx节点的值
当已经有一个线程通过版本1更改了cx节点的值为6,而另外的节点在同一时间也拿着版本1更改cx节点为7,会出现version No is not valid。

删除delete /:
在这里插入图片描述

3、watcher机制

  • 触发器、监督者
  • 使用场景:统一资源配置
    在这里插入图片描述

Watcher事件类型
在这里插入图片描述
ACL

  • access control list 权限控制
  • 它使用权限位来允许/禁止对节点及其所作用域的各种操作
  • ACL仅与特定的znode有关,与子节点无关

Scheme

  • ACL : [scheme采用的权限机制:id用户:permissions权限组合字符串]
  • world
  • auth
  • digest
  • ip
  • super

权限字符串crdwa

  • Create
  • Read
  • Delete
  • Write
  • Admin

权限使用场景

  • 区分开发/测试/运维环境,防止误操作
  • 可以针对不同IP而产生具体的配置,更安全

四、代码实操

  • 利用ZK原生的Java的API
  • 利用Apache Curator作为客户端来操作ZK

1、Java原生客户端连接到ZK

IDEA创建Maven项目
在这里插入图片描述

引入依赖pom.xml:

<dependencies>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.6.0</version>
    </dependency>
</dependencies>

log4j.properties:

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %p %c{2}: %m%n

ZKConnect .java:

public class ZKConnect implements Watcher {

	public static final String SERVER_PATH = "192.168.17.132:2181";

	public static final Integer TIMEOUT = 5000;

	public static void main(String[] args) throws IOException, InterruptedException {
		/**
		 * 客户端和服务端他们是异步连接,连接成功之后,客户端会收到watcher通知。
		 * connectString:服务器的IP+端口号,比如127.0.0.1:2181
		 * sessionTimeout:超时时间
		 * watcher:通知事件
		 */
		ZooKeeper zk = new ZooKeeper(SERVER_PATH, TIMEOUT, new ZKConnect());
		System.out.println("客户端开始连接ZK服务器了");
		System.out.println(zk.getState());
		Thread.sleep(2000);
		System.out.println(zk.getState());
	}

	@Override
	public void process(WatchedEvent event) {
		System.out.println("收到了通知" + event);
	}
}

在这里插入图片描述

2、用代码对节点进行操作

ZKOperator.java:

public class ZKOperator implements Watcher {

	public static final String SERVER_PATH = "192.168.17.132:2181";

	public static final Integer TIMEOUT = 20000;

	public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
		/**
		 * 客户端和服务端他们是异步连接,连接成功之后,客户端会收到watcher通知。
		 * connectString:服务器的IP+端口号,比如127.0.0.1:2181
		 * sessionTimeout:超时时间
		 * watcher:通知事件
		 */
		ZooKeeper zk = new ZooKeeper(SERVER_PATH, TIMEOUT, new ZKConnect());
		System.out.println("客户端开始连接ZK服务器了");
		System.out.println(zk.getState());
		Thread.sleep(2000);
		/**
		 * path:创建的路径
		 * data:存储的数据
		 * acl:权限、开放
		 * createMode:永久、临时、顺序
		 */
		zk.create("/cx-create-node", "lk".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
	}

	@Override
	public void process(WatchedEvent event) {
	}
}

在这里插入图片描述
获取刚才创建节点的内容:

byte[] data = zk.getData("/cx-create-node", null, null);
System.out.println(new String(data));

在这里插入图片描述
修改该节点的值:

zk.setData("/cx-create-node", "lkaicx".getBytes(), 0);

在这里插入图片描述
当我们再次进行更改但我们不对版本号进行更改时:
在这里插入图片描述
删除节点(删除也需要版本号对应):
为了便于我们观察删除节点是否成功,我们需要在多写一个类:
DeleteCallBack.java:

import org.apache.zookeeper.AsyncCallback.VoidCallback;

public class DeleteCallBack implements VoidCallback {

	@Override
	public void processResult(int rc, String path, Object ctx) {
		System.out.println("删除节点" + path);
		System.out.println((String) ctx);
	}
}

ZKOperator.java:

String ctx = "删除成功";
zk.delete("/cx-create-node", 1, new DeleteCallBack(), ctx);
// 由于callback往往是异步的,所以为了达到我们想要的效果(打印删除节点和打印我们传过去的删除成功),需要睡上几秒
Thread.sleep(20000);

在这里插入图片描述

3、处理Watcher事件

和节点相关:是否存在,获取数据,加上watch
ZKGetNode.java:

public class ZKGetNode implements Watcher {

	public static final String SERVER_PATH = "192.168.17.132:2181";

	public static final Integer TIMEOUT = 50000;

	public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
		/**
		 * 客户端和服务端他们是异步连接,连接成功之后,客户端会收到watcher通知。
		 * connectString:服务器的IP+端口号,比如127.0.0.1:2181
		 * sessionTimeout:超时时间
		 * watcher:通知事件
		 */
		ZooKeeper zk = new ZooKeeper(SERVER_PATH, TIMEOUT, new ZKConnect());
		System.out.println("客户端开始连接ZK服务器了");
		System.out.println(zk.getState());
		Thread.sleep(20000);
		System.out.println(zk.getState());

		Stat exists = zk.exists("/cx-create-node", false);
		if (exists != null) {
			System.out.println("节点的版本为:" + exists.getVersion());
		} else {
			System.out.println("改节点不存在");
		}
	}

	@Override
	public void process(WatchedEvent event) {
		System.out.println("收到了通知" + event);
	}
}

在这里插入图片描述
ZKGetNode.java:

public class ZKGetNode implements Watcher {

	public static final String SERVER_PATH = "192.168.17.132:2181";

	public static final Integer TIMEOUT = 50000;

	private static CountDownLatch countDownLatch = new CountDownLatch(1);
	public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
		/**
		 * 客户端和服务端他们是异步连接,连接成功之后,客户端会收到watcher通知。
		 * connectString:服务器的IP+端口号,比如127.0.0.1:2181
		 * sessionTimeout:超时时间
		 * watcher:通知事件
		 */
		ZooKeeper zk = new ZooKeeper(SERVER_PATH, TIMEOUT, new ZKConnect());
		System.out.println("客户端开始连接ZK服务器了");
		System.out.println(zk.getState());
		Thread.sleep(20000);
		System.out.println(zk.getState());

//		Stat exists = zk.exists("/cx-create-node", false);
//		if (exists != null) {
//			System.out.println("节点的版本为:" + exists.getVersion());
//		} else {
//			System.out.println("改节点不存在");
//		}

		zk.getData("/cx-create-node", true, null);
		countDownLatch.await();
	}

	@Override
	public void process(WatchedEvent event) {
		if (event.getType() == EventType.NodeDataChanged) {
			System.out.println("数据被改变");
			countDownLatch.countDown();
		}
		System.out.println("收到了通知" + event);
	}
}

程序运行,然后在linux进行人工更改节点cx-create-node的值:
在这里插入图片描述

4、用Curator操作ZK

原生的Java的API的缺点

  • 不支持连接超时后的自动重连
  • Watcher注册一次后会失效
  • 不支持递归创建节点

利用Apache Curator

  • 解决了Watcher注册一次后会失效的问题
  • API更加简单易用,提供了工具类

用Curator来操作ZK实操:
引入pom.xml依赖:

<dependency>
   <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.12.0</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.12.0</version>
</dependency>

常规操作:

CuratorTests.java:

public class CuratorTests {

	public static void main(String[] args) throws Exception {
		// ZK服务器连接
		String connectString = "192.168.17.132:2181";
		ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000, 3);
		CuratorFramework client = CuratorFrameworkFactory.newClient(connectString, retry);
		client.start();

		// 创建节点
		String path = "/curator";
		String data = "test";
		client.create().withMode(CreateMode.PERSISTENT).forPath(path, data.getBytes());

		// 获取节点值
		byte[] bytes = client.getData().forPath(path);
		System.out.println(new String(bytes));

		// 删除节点
		client.delete().forPath(path);
	}
}

添加监听器的形式:
CuratorTests.java:

public class CuratorTests {

	public static void main(String[] args) throws Exception {
		// ZK服务器连接
		String connectString = "192.168.17.132:2181";
		String path = "/curator";


		ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000, 3);
		CuratorFramework client = CuratorFrameworkFactory.newClient(connectString, retry);
		client.start();

		// 监听器
		client.getCuratorListenable().addListener((CuratorFramework c, CuratorEvent event) -> {
			switch (event.getType()) {
				case WATCHED:
					WatchedEvent watchedEvent = event.getWatchedEvent();
					if (watchedEvent.getType() == EventType.NodeDataChanged) {
						System.out.println(new String(c.getData().forPath(path)));
					}
			}
		});

		// 创建节点
		String data = "test";
		String data2 = "test2";
		client.create().withMode(CreateMode.PERSISTENT).forPath(path, data.getBytes());

		// 获取节点值
		byte[] bytes = client.getData().watched().forPath(path);
		System.out.println(new String(bytes));

		// 修改节点的值
		client.setData().forPath(path, data2.getBytes());

		// 删除节点
		client.delete().forPath(path);
		Thread.sleep(20000);
	}
}

在这里插入图片描述
Zookeeper的学习就到这里ヾ(✿゚▽゚)ノ

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值