zookeeper使用

写在前面:
1.常量以_开通,所有字母大写
2.zookeeper的服务器通信端口和投票端口怎么设置/查看

1. 安装

下载 bin.tar.gz结尾的安装包,此后缀是编译后的安装包

tar -xvf xxxxx.tar.gz -C PATH_NAME  #解压到指定文件夹
cd conf/
touch zoo.cfg
cat zoo_sample.cfg >> zoo.cfg
vim zoo.cfg #修改相关配置,重要是dataDir  端口等

2. 终端命令

2.1 服务端

./zkServer.sh start #开启  stop终止 restart重启
./zkServer.sh status  #查看状态

zookeeper是一个分布式文件系统,可以理解成一个数据库,采用和Unix类似的树形目录;zookeeper存储的表现形式是ZNode,ZNode的名称即当前的path,ZNode可以存储小于1M的数据。

ZNode组成:
1)stat 状态
2)data 数据
3)children 子node列表

连接服务端的方式有两种:
1)zkCli.sh -server _IP:_PORT
2)java API: curator

节点分类(持久性&有序性):
1)PERSISTENT 持久化节点
2)EPHEMERAL 临时节点 -e 临时指仅在当前会话中有效,不能有子node
3)PERSISTENT_SEQUENTIAL 持久化顺序节点 -s
4) EPHEMERAL_SEQUENTIAL 临时顺序节点 -es

2.2 客户端

增删改查:create delete/deleteall set get/ls

./zkCli.sh -server _IP:_PORT
help #查看命令
quit #断开

########节点操作###########
create _NODE_PATH _NODE_VALUE #增 创建节点并赋值

delete _NODE_PATH # 删  删除单节点
deleteall _NODE_PATH #删 递归删除节点

set _NODE_PATH _NODE_VALUE #改  设置节点值

ls _DIR #查 查看目录下的节点
ls -R _DIR #查 递归查看
get _NODE_PATH #查 查看节点值



3. java API : curator

3.1 坐标

注意curator版本和zookeeper的版本兼容问题,zookeeper版本迭代较快,容易出兼容性问题

<!--坐标-->
<!--curator 注意zookeeper的版本不要过高,否则不兼容-->
	<!--zookeeper的底层API-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
        </dependency>

	<!--zookeeper的高级特性API如:Cache事件监听、选举、分布式锁、分布式计数器等-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency>

<!--最好导入日志的坐标,不然可能出现报错-->

3.2 节点操作

  • 连接
public class CuratorTest{

	CuratorFramework client;
	
	/*方式一
	*@param connecString zkserver的IP和端口,多个用逗号隔开
	*@param sessionTimeoutMs  会话超时时间 ms
	*@param connectionTimeoutMs 连接超时时间 ms
	*@param retryPolicy 重试连接策略
	
	RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);
	client = CuratorFrameworkFactory.newClient(
		"127.0.0.1:2181,192.168.0.1:2181",
		1000,
		2000,
		retryPolicy
	);
	*/
	
	//方式二 工厂模式
	client = CuratorFrameworkFactory.builder()
	.connectString("127.0.0.1:2181")
	.sessionTimeoutMs(1000)
	.connectionTimmeoutMs(1000)
	.retryPolicy(retryPolicy)
	.namespace("zookeeperCluster")
	.build();  //namespace相当于指定一个父ZNode,在一段时间内一直没有子节点的话会自动删除

	//开启连接
	client.start();

}
  • 创建节点
	//不指定节点数据则将client的IP作为数据
	String path1 = client.create().forPath("/app1");
	
	//创建带数据的节点
	String path2 = client.create().forPath("/app1","casey".getBytes());

	//创建带类型的节点,默认类型是persistent
	String path23 = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app1","casey".getBytes());

	//创建多级节点
	String path4 = client.create().creatingParentsIfNeeded().forPath("/app1/a","casey".getBytes());
  • 删除节点 delete deleteall
	//删除单个节点 delete
	client.delete().forPath("/app1");
	
	//递归删除节点 deleteall
	client.delete().deletingChildrenIfNeeded().forPath("/app1");

	//必须成功删除节点,防止网络抖动删除节点失败
	client.delete().guaranteed().forPath("/app1");
	
	//删除后回调,删除后回调方法,相当于删除触发事件
	client.delete().guaranteed().inBackground((CuratorFramework client, CuratorEvent event)->{System.out.println("ok");}).forPath("/app1");//inBackground方法的参数是 BackgroundCallback接口的实现类
  • 修改节点
	//直接修改数据
	client.setData().forPath("/app1","ccc".getBytes());
	
	//【推荐】根据版本(dataVersion)修改数据,解决数据的同步问题
	Stat status = new Stat();
	client.getData().storingStatIn(status)
	.forPath("/app1");
	int version = status.getVersion();	client.setData()
	.withVersion(version)
	.forPath("/app1","ccc".getBytes());
		
  • 查询节点
	//查数据 get
	byte[] data = client.getDate().forPath("/app1");
	String s = new String(data);
	System.out.println(s);
	
	//查询子节点 ls [-R]
	List<String> paths = client.getChildren().forPath("/app1");
	
	//查询节点状态 zk旧版直接shell用get就可以,新版要用ls -s
	Stat status = new Stat();
	client.getData().storingStatIn(status)
	.forPath("/app1");

  • 释放资源
	if(client != null ){
		client.close();
	}

3.2.5 watch机制

ZooKeeper 允许用户(节点)在服务端指定节点上注册一些Watcher,并且在一
些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制
是 ZooKeeper 实现分布式协调服务的重要特性,client收到通知后回去获取最新数据。

应用:
发布订阅系统
监听主机存活状态

watcher类型:
  • NodeCache 监听一个节点
  • PathChildrenCache: 节点的子节点(不包括该节点)
  • TreeCache: 前两个的并集
get _ZNode watch #给节点添加watch机制,一次性的,用完后有需求要再添加
	/*与上面的增删改查使用一个连接和资源释放*/
	
	//NodeCache
	//1.创建NodeCache对象
	NodeCahe nodeCache = new NodeCache(client , "/app1");
	
	//2.注册监听
	nodeCache.getListenable().addListener(new NodeCacheListener(){
		@override
		public void nodeChange() throws Exception{
			System.out.println("NODE CHANGED");
			//获取修改后的数据
			bytes newData = nodeCache.getCurrentData().getData();
			System.out.println(new String(newData));
		}
	})
	//3.开启监听
	nodeCache.start(true); //true表示开启监听时加载缓冲数据

//=================================================================
	
	//PathChildrenCache
	//1.创建PathChildrenCache对象
	PathChildrenCache pathChildrenCache = new PathChildrenCache(client , "/app1", true);
	
	//2.注册监听
	PathChildrenCache.getListenable().addListener(new PathChildrenCacheListener(){
		@override
		public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception{
			System.out.println("Children Node CHANGED");
			//使用event
			PathChildrenCacheEvent.Type type = event.getType(); // Type是一个枚举
			if(PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(type)){
				byte[] data = event.getData().getData();
				System.out.println(new String("变更后数据为:" + data));
			}	
		}
	})
	//3.开启监听
	pathChildrenCache.start(); //true表示开启监听时加载缓冲数据

//=================================================================

	//TreeCache
	//1.创建TreeCache对象
	TreeCache treeCache = new TreeCache(client,"/app1");
	//2.注册监听
	treeCache.getListenable().addListener(new TreeCacheListener(){
	@override
	public void childEvent(CuratorFramework client,TreeCacheEvent event) throws Exception{
		System.out.println("xxx Node CHANGED");
	}
})
	//开启监听
	treeCache.start();

触发watch后,watcher会发给client一个信息,封装了:keeper state、event type、触发条件,详细附录二

3.3 分布式锁

通过节点进行锁的控制,•核心思想:节点!

​ 当客户端要获取锁,则创建节点,使用完锁,则删除该节点。

1.客户端获取锁时,在lock节点(节点名字随便起)下创建临时(断开会话后自动删除,防止client挂掉无法主动删或忘了删)& 顺序(该每个请求的锁排优先级)节点。

2.然后客户端获取lock下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小(创建时机最靠前),那么就认为该客户端获取到了锁。使用完锁后,将该节点删除。

3.如果发现自己创建的节点并非lock所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器监听删除事件

4.如果发现比自己小的那个节点被删除,则客户端的

​ - Watcher会收到相应通知,此时再次判断自己创建的节点

​ - 是否是lock子节点中序号最小的,如果是则获取到了锁,

​ - 如果不是则重复以上步骤继续获取到比自己小的一个节点,并注册监听。

  • InterProcessSemaphoreMutex:分布式排它锁(非可重入

  • InterProcessMutex:分布式可重入排它锁,可重入即获得过一次锁,会再次获得,不用竞争

  • InterProcessReadWriteLock:分布式读写

  • InterProcessMultiLock:将多个锁作为单个实体管理的容器,多个锁组合成一个小组

  • InterProcessSemaphoreV2:共享信号量

public class Ticket12306 implements Runnable{

    private int tickets = 10;//数据库的票数

    private InterProcessMutex lock ; //可重入排他锁

    public Ticket12306(){//构造方法
        //重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        //2.第二种方式
        //CuratorFrameworkFactory.builder();
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("192.168.149.135:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy)
                .build();

        //开启连接
        client.start();
        lock = new InterProcessMutex(client,"/lock");
    }

    @Override
    public void run() {
        while(true){
            //获取锁
            try {
                lock.acquire(3, TimeUnit.SECONDS);
                if(tickets > 0){

                    System.out.println(Thread.currentThread()+":"+tickets);
                    Thread.sleep(100);
                    tickets--;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                //释放锁
                try {
                    lock.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4. zookeeper集群

4.1 相关概念

架构如下:
在这里插入图片描述

角色描述如下:
在这里插入图片描述
observer 可以不配置,一般只配置leader和follower。

4,2 相关机制

4.3 集群搭建

  • 在每个zookeeper的配置文件的dataDir对应目录下添加当前服务器id即myid ,用于投票和服务器编号,myid越大,选取权重越高
echo _MY_ID > _dataDIR_PATH/myid
  • 在集群的服务端配置文件注册
    每个zookeeper的zoo.cfg中配置集群服务器的IP、服务器通信端口(注意不是ClientPort,而是服务器之间使用的端口)、投票端口
dataDir=/export/servers/zookeeper-3.4.9/zkdatas
# 保留多少个快照
autopurge.snapRetainCount=3
# 日志多少小时清理一次
autopurge.purgeInterval=1
# 集群中服务器地址
server.1=192.168.174.101:2888:3888  # server.myid=IP:serverPort:votePort
server.2=192.168.174.102:2888:3888
server.3=192.168.174.103:2888:3888
  • 开启集群每个服务端
./zkServer.sh start
./zkServer.sh status #查看是否产生leader等

附录一 zkCli相关shell命令
在这里插入图片描述
附录二 watch机制触发的返回值
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值