ZooKeeper
- ZooKeeper简介
- ZooKeeper安装
- ZooKeeper使用
- ZooKeeper监听机制
- ZooKeeper分布式锁
- ZooKeeper集群介绍
ZooKeeper简介
ZooKeeper安装
ZooKeeper是一个绿色软件,Windows版本的直接解压就可以,进入bin目录可以启动服务端和客户端。
ZooKeeper使用
使用之前先了解ZooKeeper的数据模型:
JavaAPI的相关操作:
使用Java操作需要用到一个客户端Curator:
Curator 介绍
- Curator 是 Apache ZooKeeper 的Java客户端库。
- 常见的ZooKeeper Java API :
原生Java API
ZkClient
Curator - Curator 项目的目标是简化 ZooKeeper 客户端的使用。
- Curator 最初是 Netfix 研发的,后来捐献了 Apache 基金会,目前是 Apache 的顶级项目。
- 官网:http://curator.apache.org
Curator关于节点的操作:
public class ConnectionTest {
private CuratorFramework client = null;
@Before
public void testConnection() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
client =
CuratorFrameworkFactory.builder()
.connectString("localhost:2181")
.sessionTimeoutMs(60 * 1000)
.connectionTimeoutMs(15 * 1000)
.namespace("ys")
.retryPolicy(retryPolicy).build();
client.start();
}
/**
* 创建节点:create 持久 临时 顺序 数据
* 1. 基本创建 :create().forPath("")
* 2. 创建节点 带有数据:create().forPath("",data)
* 3. 设置节点的类型:create().withMode().forPath("",data)
* 4. 创建多级节点 /app1/p1 :create().creatingParentsIfNeeded().forPath("",data)
*/
@Test
public void testCreate() throws Exception {
// 创建节点
client.create().forPath("/app1");
}
@Test
public void testCreateData() throws Exception {
// 创建节点
client.create().forPath("/app2", "ys".getBytes());
}
@Test
public void testCreate2() throws Exception {
// 创建带有类型的节点
client.create().withMode(CreateMode.PERSISTENT).forPath("/app3", "persistent".getBytes());
}
@Test
public void testCreate3() throws Exception {
// 创建带有子节点的多级节点
client.create().creatingParentsIfNeeded().forPath("/app4/a1/b2");
}
/**
* 查询节点:
* 1. 查询数据:get: getData().forPath()
* 2. 查询子节点: ls: getChildren().forPath()
* 3. 查询节点状态信息:ls -s:getData().storingStatIn(状态对象).forPath()
*/
@Test
public void testGet1() throws Exception {
// 查询数据
byte[] bytes = client.getData().forPath("/app2");
System.out.println(new String(bytes));
}
@Test
public void testGet2() throws Exception {
// 查询子节点
List<String> strings = client.getChildren().forPath("/app3");
System.out.println(strings);
}
@Test
public void testCreate5() throws Exception {
// 查询节点状态信息
Stat stat = new Stat();
byte[] bytes = client.getData().storingStatIn(stat).forPath("/app3");
System.out.println(new String(bytes));
}
/**
* 修改数据
* 1. 基本修改数据:setData().forPath()
* 2. 根据版本修改: setData().withVersion().forPath()
* * version 是通过查询出来的。目的就是为了让其他客户端或者线程不干扰我。
*
* @throws Exception
*/
@Test
public void testUpdate() throws Exception {
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath("/app2");
System.out.println(stat.getVersion());
int version = stat.getVersion();
client.setData().withVersion(version).forPath("/app2","after".getBytes());
client.getData().storingStatIn(stat).forPath("/app2");
System.out.println(stat.getVersion());
}
/**
* 删除节点: delete deleteall
* 1. 删除单个节点:delete().forPath("/app1");
* 2. 删除带有子节点的节点:delete().deletingChildrenIfNeeded().forPath("/app1");
* 3. 必须成功的删除:为了防止网络抖动。本质就是重试。 client.delete().guaranteed().forPath("/app2");
* 4. 回调:inBackground
* @throws Exception
*/
@Test
public void testDelete1() throws Exception {
client.delete().forPath("/app2");
}
@Test
public void testDelete2() throws Exception {
client.delete().deletingChildrenIfNeeded().forPath("/app3");
}
@Test
public void testDelete3() throws Exception {
client.delete().guaranteed().forPath("/app1");
}
@Test
public void testDelete4() throws Exception {
client.delete().inBackground((CuratorFramework client, CuratorEvent event)-> System.out.println(event)).forPath("/app1");
}
@After
public void testClose() {
client.close();
}
}
ZooKeeper监听机制
使用JavaAPI实现监听:
public class ListenerTest {
private CuratorFramework client = null;
@Before
public void testConnection() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
client = CuratorFrameworkFactory.builder().connectString("localhost:2181")
.namespace("ys")
.retryPolicy(retryPolicy).build();
client.start();
}
@Test
public void testListener1() throws Exception {
// NodeCache:只监听特定节点的修改、删除、创建事件
NodeCache nodeCache = new NodeCache(client, "/node1");
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("节点变化了");
byte[] data = nodeCache.getCurrentData().getData();
System.out.println(new String(data));
}
});
nodeCache.start(true);
while (true) {
}
}
@Test
public void testListener2() throws Exception {
//1.创建监听对象
PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/node2",true);
//2. 绑定监听器
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
System.out.println("子节点变化了~");
System.out.println(event);
//监听子节点的数据变更,并且拿到变更后的数据
//1.获取类型
PathChildrenCacheEvent.Type type = event.getType();
//2.判断类型是否是update
if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
System.out.println("数据变了!!!");
byte[] data = event.getData().getData();
System.out.println(new String(data));
}
}
});
//3. 开启
pathChildrenCache.start();
while (true){
}
}
@Test
public void testListener3() throws Exception {
//1. 创建监听器
TreeCache treeCache = new TreeCache(client,"/node3");
//2. 注册监听
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
System.out.println("节点变化了");
System.out.println(event);
}
});
//3. 开启
treeCache.start();
while (true){
}
}
@After
public void testClose() {
client.close();
}
ZooKeeper分布式锁
ZooKeeper分布式锁原理:
• 核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该节点。
- 客户端获取锁时,在lock节点下创建临时顺序节点。
- 然后获取lock下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。使用完锁后,将该节点删除。
- 如果发现自己创建的节点并非lock所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件。
- 如果发现比自己小的那个节点被删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是lock子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点
并注册监听。
Curator实现分布式锁API,在Curator中有五种锁方案:
• InterProcessSemaphoreMutex:分布式排它锁(非可重入锁)
• InterProcessMutex:分布式可重入排它锁
• InterProcessReadWriteLock:分布式读写锁
• InterProcessMultiLock:将多个锁作为单个实体管理的容器
• InterProcessSemaphoreV2:共享信号量
ZooKeeper集群介绍
以上就是本次介绍的全部内容了