初识Zookeeper
Zookeeper是Apache Hadoop项目下的一个子项目,是一个树形目录服务。翻译过来就是动物园管理员,用来管理Hadoop、Hive、Pig等动物的。Zookeeper是一个分布式的、开源的、分布式应用程序的协调服务。
最常用的功能:配置管理、分布式锁、集群管理。
(个人感觉和Nacos差不多)
安装Zookeeper
Zookeeper安装配置 - ZooKeeper教程™ (yiibai.com)
Zookeeper集群搭建-Windows - 掘金 (juejin.cn)
zookeeper 集群搭建 - YSOcean - 博客园 (cnblogs.com)
操作Zookeeper
数据模型
zookeeper拥有一个层次化树形结构
其中每一个节点都被称为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 【节点】
…
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服务端检测
Zookeeper的工作原理
Zookeeper入门看这篇就够了_技术分享
zookeeper原理详解 - 知乎 (zhihu.com)
我们能用zookeeper做什么
ZooKeeper面试题(2020最新版)
5分钟让你了解 ZooKeeper 的功能和原理
ZooKeeper概念详解,最全整理_春风化雨