Zookeeper入门级知识笔记

初识Zookeeper

Zookeeper是Apache Hadoop项目下的一个子项目,是一个树形目录服务。翻译过来就是动物园管理员,用来管理Hadoop、Hive、Pig等动物的。Zookeeper是一个分布式的、开源的、分布式应用程序的协调服务。

最常用的功能:配置管理、分布式锁、集群管理。
(个人感觉和Nacos差不多)

安装Zookeeper

Zookeeper安装配置 - ZooKeeper教程™ (yiibai.com)
Zookeeper集群搭建-Windows - 掘金 (juejin.cn)
zookeeper 集群搭建 - YSOcean - 博客园 (cnblogs.com)

操作Zookeeper

数据模型

zookeeper拥有一个层次化树形结构

image.png
其中每一个节点都被称为ZNode,每一个节点上都会保存自己的数据和节点信息。
节点可以拥有子节点,同时也允许有少量(1MB)数据存储。
节点可以分为四类:

  • 持久节点(PERSISTENT):session断联、服务端重启还在;可以创建子节点,子节点可以临时也可以持久;不能同名。
  • 临时节点(EPHEMERAL)-e :session链接断开就没了;不能创建子节点;不能同名。
  • 持久顺序节点(PERSISTENT_SEQUENTIAL)-s:session断联、服务端重启还在;可以创建子节点,子节点可以临时也可以持久;同名节点会在后面添加上序号。
  • 临时顺序节点(EPHEMERAL_SEQUENTIAL)-es :session链接断开就没了;不能创建子节点;同名节点会在后面添加上序号(分布式锁使用的好处)

命令

服务端命令

./zkServer.sh start/status/stop/restart
客户端命令
./zkCli.sh -server localhost:2181
create -e/-s/-es【节点】【子节点】【数据】
get 【节点】 = 【数据】
set 【节点】【数据】
delete 【节点】【子节点】
deleteall 【节点】
ls -s 【节点】

image.png

JavaAPI操作

Curator简化开发
常用命令:
链接、增删改查、Watch事件监听、分布式锁
搬运这个大佬的:
https://gitee.com/gaozhihong/Zookpper_HM


需要的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.cl</groupId>
    <artifactId>CuratorApi</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.6.0</version>
            <type>jar</type>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.6.0</version>
            <type>jar</type>
        </dependency>
    </dependencies>
</project>

链接

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;

/**
 * 标题:获取Zookeeper连接对象
 * 作者:何处是归程
 * 时间:2020/4/16 - 15:41
 */
public class CuratorConnection {
	public static void main(String[] args) {
		// 创建连接对象
		CuratorFramework client = CuratorFrameworkFactory
                .builder()
		// IP地址端口号
                .connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 命名空间
		.namespace("create")
		// 构建连接对象
		.build();	
		// 打开连接
		client.start();
		System.out.println(client.isStarted());
		// 关闭连接
		client.close();
	}
}

新增节点

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 标题:新增节点
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorCreate {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
        	.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 命名空间
		.namespace("create")
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 新增节点
	 * @作者: 高志红
	 */
	@Test
	public void create1() throws Exception {
		String path = client.create()
		// 节点的类型
		.withMode(CreateMode.PERSISTENT)
		// 节点的权限列表 world:anyone:cdrwa
		.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
		// 第一个参数:节点的名字
		// 第二个参数:节点的数据
		.forPath("/node1", "node1".getBytes());
		System.out.println(path);
	}

	/**
	 * @功能: 创建节点并自定义权限列表
	 * @作者: 高志红
	 */
	@Test
	public void create2() throws Exception {
		// 权限列表
		List<ACL> acls = new ArrayList<>();
		// 授权模式和授权对象
		Id id = new Id("ip", "39.98.67.88");
		acls.add(new ACL(ZooDefs.Perms.ALL, id));
		String path = client.create()
		.withMode(CreateMode.PERSISTENT)
		.withACL(acls)
		.forPath("/node2", "node2".getBytes());
		System.out.println(path);
	}

	/**
	 * @功能: 递归创建节点树
	 * @作者: 高志红
	 */
	@Test
	public void create3() throws Exception {
		String path = client.create()
		// 支持递归节点的创建
		.creatingParentsIfNeeded()
		.withMode(CreateMode.PERSISTENT)
		.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
		.forPath("/node3/node31", "node31".getBytes());
		System.out.println(path);
	}

	/**
	 * @功能: 异步创建节点
	 * @作者: 高志红
	 */
	@Test
	public void create4() throws Exception {
		client.create()
		.creatingParentsIfNeeded()
		.withMode(CreateMode.PERSISTENT)
		.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
		.inBackground(new BackgroundCallback() {
		@Override
			public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
				// 节点的路径
				System.out.println(curatorEvent.getPath());
				// 事件类型
				System.out.println(curatorEvent.getType());
			}
		})
		.forPath("/node4", "node4".getBytes());
		TimeUnit.SECONDS.sleep(1);
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}

删除节点

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * 标题:删除节点
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorDelete {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
				.builder()
				// IP地址端口号
				.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
				// 会话超时时间
				.sessionTimeoutMs(5000)
				// 重连机制
				// new RetryOneTime(3000):每三秒重连一次,只重连一次
				// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
				// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
				// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
				.retryPolicy(new ExponentialBackoffRetry(1000, 3))
				// 命名空间
				.namespace("delete")
				// 构建连接对象
				.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 删除节点
	 * @作者: 高志红
	 */
	@Test
	public void delete1() throws Exception {
		client.delete()
		// 第一个参数:节点路径
		.forPath("/node1");
		System.out.println("已删除!");
	}

	/**
	 * @功能: 删除节点,并进行版本检测
	 * @作者: 高志红
	 */
	@Test
	public void delete2() throws Exception {
		client.setData()
		// 版本号 -1 标识忽略版本号
		.withVersion(0)
		.forPath("/node1");
		System.out.println("已删除");
	}

	/**
	 * @功能: 删除包含子节点的节点
	 * @作者: 高志红
	 */
	@Test
	public void delete3() throws Exception {
		client.delete()
		// 如有子节点 则一并删除
		.deletingChildrenIfNeeded()
		.withVersion(-1)
		.forPath("/node1");
		System.out.println("已删除");
	}

	/**
	 * @功能: 异步删除节点
	 * @作者: 高志红
	 */
	@Test
	public void delete4() throws Exception {
		client.delete()
		.deletingChildrenIfNeeded()
		.withVersion(0)
		.inBackground(new BackgroundCallback() {
			@Override
			public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
				System.out.println(curatorEvent.getPath());
				System.out.println(curatorEvent.getType());
			}
		})
		.forPath("/node1");
		TimeUnit.SECONDS.sleep(1);
		System.out.println("已删除");
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}

查询节点


import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * 标题:查询节点
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorGet {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
		.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 命名空间
		.namespace("get")
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 查询节点内容
	 * @作者: 高志红
	 */
	@Test
	public void get1() throws Exception {
		byte[] bytes = client.getData()
		// 第一个参数:节点路径
		.forPath("/node1");
		System.out.println(new String(bytes));
	}

	/**
	 * @功能: 查询节点属性
	 * @作者: 高志红
	 */
	@Test
	public void get2() throws Exception {
		Stat stat = new Stat();
		client.getData()
		// 读取属性
		.storingStatIn(stat)
		.forPath("/node1");
		System.out.println(stat);
	}

	/**
	 * @功能: 异步查询节点
	 * @作者: 高志红
	 */
	@Test
	public void get3() throws Exception {
		client.getData()
		.inBackground(new BackgroundCallback() {
			@Override
			public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
				System.out.println(curatorEvent.getPath());
				System.out.println(curatorEvent.getType());
				System.out.println(new String(curatorEvent.getData()));
			}
		})
		.forPath("/node1");
		TimeUnit.SECONDS.sleep(1);
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}


查询子节点

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 标题:查询子节点
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorGetChildren {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
		.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 查询子节点内容
	 * @作者: 高志红
	 */
	@Test
	public void getChildren1() throws Exception {
		List<String> childrens = client.getChildren()
		// 第一个参数:节点路径
		.forPath("/get");
		childrens.forEach(System.out::println);
	}

	/**
	 * @功能: 异步查询子节点
	 * @作者: 高志红
	 */
	@Test
	public void getChildren2() throws Exception {
		client.getChildren()
		.inBackground(new BackgroundCallback() {
			@Override
			public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
				curatorEvent.getChildren().forEach(System.out::println);
			}
		})
		.forPath("/get");
		TimeUnit.SECONDS.sleep(3);
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}

查询节点是否存在

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * 标题:检查节点是否存在
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorExists {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
		.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 命名空间
		.namespace("get")
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 判断节点是否存在
	 * @作者: 高志红
	 */
	@Test
	public void exists1() throws Exception {
		Stat stat = client.checkExists()
		// 第一个参数:节点路径
		.forPath("/node2");
		System.out.println(stat);
	}


	/**
	 * @功能: 异步判断节点是否存在
	 * @作者: 高志红
	 */
	@Test
	public void exists2() throws Exception {
		client.checkExists()
		.inBackground(new BackgroundCallback() {
			@Override
			public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
				System.out.println(curatorEvent.getPath());
				System.out.println(curatorEvent.getType());
				System.out.println(curatorEvent.getStat());
			}
		})
		.forPath("/node1");
		TimeUnit.SECONDS.sleep(3);
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}


修改节点

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * 标题:修改节点
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorSet {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
		.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 命名空间
		.namespace("set")
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 更新节点
	 * @作者: 高志红
	 */
	@Test
	public void set1() throws Exception {
		Stat stat = client.setData()
		// 第一个参数:节点路径
		// 第二个参数:节点数据
		.forPath("/node1", "hello".getBytes());
		System.out.println(stat);
	}

	/**
	 * @功能: 更新节点,并进行版本检测
	 * @作者: 高志红
	 */
	@Test
	public void set2() throws Exception {
		Stat stat = client.setData()
		// 版本号 -1 标识忽略版本号
		.withVersion(1)
		.forPath("/node1", "world".getBytes());
		System.out.println(stat);
	}

	/**
	 * @功能: 异步修改节点
	 * @作者: 高志红
	 */
	@Test
	public void set3() throws Exception {
		client.setData()
		.withVersion(2)
		.inBackground(new BackgroundCallback() {
			@Override
			public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
				System.out.println(curatorEvent.getPath());
				System.out.println(curatorEvent.getType());
			}
		})
		.forPath("/node1", "哈哈哈".getBytes());
		TimeUnit.SECONDS.sleep(1);
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}

事件监听

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * 标题:事件监听机制
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorWatcher {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
		.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 监视某个节点的数据变化
	 * @作者: 高志红
	 */
	@Test
	public void watcher1() throws Exception {
		// 参数1:连接对象
		// 参数2:监视的节点路径
		final NodeCache nodeCache = new NodeCache(client, "/watcher1");
		// 启动解释器对象
		nodeCache.start();
		nodeCache.getListenable().addListener(new NodeCacheListener() {
			// 节点变化时回调的方法
			@Override
			public void nodeChanged() throws Exception {
				System.out.println(nodeCache.getCurrentData().getPath());
				System.out.println(new String(nodeCache.getCurrentData().getData()));
				System.out.println(nodeCache.getCurrentData().getStat());
			}
		});
		TimeUnit.SECONDS.sleep(30);
		// 关闭监视器对象
		nodeCache.close();
	}

	/**
	 * @功能: 监视某子节点的数据变化
	 * @作者: 高志红
	 */
	@Test
	public void watcher2() throws Exception {
		// 参数1:连接对象
		// 参数2:监视的节点路径
		// 参数3:事件中是否可以获取节点的数据
		final PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/watcher1", true);
		// 启动解释器对象
		pathChildrenCache.start();
		pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
			// 当子节点方法变化时回调的方法
			@Override
			public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
				// 节点的事件类型
				System.out.println(pathChildrenCacheEvent.getType());
				// 节点的路径
				System.out.println(pathChildrenCacheEvent.getData().getPath());
				// 节点的数据
				System.out.println(new String(pathChildrenCacheEvent.getData().getData()));
			}
		});
		TimeUnit.SECONDS.sleep(30);
		// 关闭监视器对象
		pathChildrenCache.close();
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}

事务

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.Collection;

/**
 * 标题:事务
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorTransaction {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
		.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 命名空间
		.namespace("create")
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 事务
	 * @作者: 高志红
	 */
	@Test
	public void transaction1() throws Exception {
		// 开启事务
		Collection<CuratorTransactionResult> collection = client.inTransaction()
		.create()
		.withMode(CreateMode.PERSISTENT)
		.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
		.forPath("/node1", "node1".getBytes())
		.and()
		.create().forPath("/node2", "node2".getBytes())
		.and()
		// 提交事务
		.commit();
		System.out.println(collection);
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}

分布式锁

package cn.cl;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * 标题:分布式锁
 * 作者:何处是归程
 * 时间:2020/4/16 - 18:07
 */
public class CuratorLock {
	CuratorFramework client;

	/**
	 * @功能: 获取连接
	 * @作者: 高志红
	 */
	@Before
	public void before() {
		// 创建连接对象
		client = CuratorFrameworkFactory
		.builder()
		// IP地址端口号
				.connectString("39.98.67.88:2181,39.98.67.88:2182,39.98.67.88:2183")
		// 会话超时时间
		.sessionTimeoutMs(5000)
		// 重连机制
		// new RetryOneTime(3000):每三秒重连一次,只重连一次
		// new RetryNTimes(3, 3000):每每三秒重连一次,共重连3次
		// new RetryUntilElapsed(10000, 3000):每三秒重连一次,10秒后停止重连
		// new ExponentialBackoffRetry(1000, 3):重连3次,每次重连的间隔会越来越长
		.retryPolicy(new ExponentialBackoffRetry(1000, 3))
		// 构建连接对象
		.build();
		// 打开连接
		client.start();
	}

	/**
	 * @功能: 排他锁
	 * @作者: 高志红
	 */
	@Test
	public void lock1() throws Exception {
		// 参数1:连接对象
		// 参数2:节点路径
		InterProcessLock interProcessLock = new InterProcessMutex(client, "/lock1");
		System.out.println("等待获取锁对象");
		// 获取锁
		interProcessLock.acquire();
		for (int i = 0; i < 5; i++) {
			TimeUnit.SECONDS.sleep(1);
			System.out.println(i);
		}
		System.out.println("等待释放锁");
		// 释放锁
		interProcessLock.release();
	}

	/**
	 * @功能: 读写锁 - 读锁
	 * @作者: 高志红
	 */
	@Test
	public void lock2() throws Exception {
		// 读写锁
		InterProcessReadWriteLock readWriteLock = new InterProcessReadWriteLock(client, "/lock1");
		// 获取读锁对象
		InterProcessMutex interProcessMutex = readWriteLock.readLock();
		System.out.println("等待获取锁对象");
		// 获取锁
		interProcessMutex.acquire();
		for (int i = 0; i < 10; i++) {
			TimeUnit.SECONDS.sleep(1);
			System.out.println(i);
		}
		System.out.println("等待释放锁");
		// 释放锁
		interProcessMutex.release();
	}

	/**
	 * @功能: 读写锁 - 写锁
	 * @作者: 高志红
	 */
	@Test
	public void lock3() throws Exception {
		// 读写锁
		InterProcessReadWriteLock readWriteLock = new InterProcessReadWriteLock(client, "/lock1");
		// 获取读锁对象
		InterProcessMutex interProcessMutex = readWriteLock.writeLock();
		System.out.println("等待获取锁对象");
		// 获取锁
		interProcessMutex.acquire();
		for (int i = 0; i < 10; i++) {
			TimeUnit.SECONDS.sleep(1);
			System.out.println(i);
		}
		System.out.println("等待释放锁");
		// 释放锁
		interProcessMutex.release();
	}

	/**
	 * @功能: 关闭连接
	 * @作者: 高志红
	 */
	@After
	public void after() {
		if (client != null) {
			client.close();
		}
	}
}

Zookeeper集群安装

Step1:配置JAVA环境,检验环境:java -version

Step2:下载并解压zookeeper

# cd /usr/local
# wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz
# tar -zxvf zookeeper-3.4.12.tar.gz
# cd zookeeper-3.4.12

Step3:重命名 zoo_sample.cfg文件

# cp conf/zoo_sample.cfg conf/zoo-1.cfg

Step4:修改配置文件zoo-1.cfg,原配置文件里有的,修改成下面的值,没有的则加上

# vim conf/zoo-1.cfg
dataDir=/tmp/zookeeper-1
clientPort=2181
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890

配置说明

  • tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。
  • initLimit:这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒
  • syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 5*2000=10秒
  • dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
  • clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
  • server.A=B:C:D:其中 A 是一个数字,表示这个是第几号服务器;B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。

Step5:标识Server ID
创建三个文件夹/tmp/zookeeper-1,/tmp/zookeeper-2,/tmp/zookeeper-2,在每个目录中创建文件myid 文件,写入当前实例的server id,即1.2.3。

# cd /tmp/zookeeper-1
# vim myid
1
# cd /tmp/zookeeper-2
# vim myid
2
# cd /tmp/zookeeper-3
# vim myid
3

Step6:启动三个zookeeper实例

# bin/zkServer.sh start conf/zoo-1.cfg
# bin/zkServer.sh start conf/zoo-2.cfg
# bin/zkServer.sh start conf/zoo-3.cfg

Step7:检测集群状态,也可以直接用命令“zkCli.sh -server IP:PORT”连接zookeeper服务端检测

image.png

Zookeeper的工作原理

Zookeeper入门看这篇就够了_技术分享
zookeeper原理详解 - 知乎 (zhihu.com)
我们能用zookeeper做什么
ZooKeeper面试题(2020最新版)
5分钟让你了解 ZooKeeper 的功能和原理
ZooKeeper概念详解,最全整理_春风化雨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值