需要引入maven依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.4.2</version>
</dependency>
package com.test.zookeeper.curator;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.curator.RetryPolicy;
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.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.framework.recipes.leader.LeaderSelector;
import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
public class Curator {
static String connectionString = "192.168.66.138:2181";
static String path = "/zk-book/c1";
static String master_path = "/curator_recipes_master_path";
static String lock_path = "/curator_recipes_lock_path";
static CuratorFramework client = CuratorFrameworkFactory
.builder().connectString(connectionString)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.sessionTimeoutMs(5000).build();
static CountDownLatch semaphore = new CountDownLatch(2);
static ExecutorService tp = Executors.newFixedThreadPool(2);
public static void main(String[] args) throws Exception {
//create_session_sample();
//create_session_sample_fluent();
//create_Node_Sample();
//del_Node_Sample();
//get_Data_Sample();
//set_Data_Sample();
//create_Node_Background_Sample();
//nodeCache_Sample();
//pathChilrendCache_Sample();
//recipes_MasterSelect();
//recipes_Lock();
System.in.read();
}
/**
* 分布式锁
* 这里是一个客户端多个线程去执行,如果多个客户端模拟也是一样的,因为都是在相同的节点下
*/
static void recipes_Lock(){
client.start();
final InterProcessMutex lock = new InterProcessMutex(client, lock_path);
final CountDownLatch down = new CountDownLatch(1);
for(int i=0; i<10; i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
down.await();
lock.acquire();
} catch (Exception e) {
}
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss|SSS");
String orderNo = format.format(new Date());
System.out.println("生成的订单号是: "+orderNo);
try {
lock.release();
} catch (Exception e) {
}
}
}).start();
}
down.countDown();
}
/**
* 选举,一个集群进行Master选举,这里是让一个客户端去进行选举
* 举例,假设集群当中有10台机器,有一个定时任务只需要一台机器去运行
* 那么这个时候我们通常的办法是把一些配置放到库里面,比如指定某台机器某个端口运行
* 这种办法会导致集群所有机器都去运行定时任务判断是否符合配置的ip和端口,办法笨重
* 一旦数据库指定运行的定时任务机器挂掉了,那么定时任务可能要等待后台恢复或者人工干预切换服务
* 但是如果使用curator的选举的办法,利用zk的特性创建节点的特性,进行第一个创建的成为master直到放弃
* Master权利为止,那么其他机器就还有机会参与选举,下面的案例是一个客户端进行参与选举,这里只有一个
* 客户端当然能活的Master权利, 如果多个客户端同时运行就未可知了,在一个客户端获得Master权利之后会调用
* takeLeadership方法,知道结束后才会释放,那么期间其他客户端都在等待Master释放,一旦Master释放
* takeLeadership方法结束,那么其他机器就有机会成为Master
*/
static void recipes_MasterSelect(){
client.start();
@SuppressWarnings("resource")
LeaderSelector selector = new LeaderSelector(client, master_path,
new LeaderSelectorListenerAdapter() {
@Override
public void takeLeadership(CuratorFramework client) throws Exception {
System.out.println("成为Master角色");
Thread.sleep(3000);
System.out.println("完成Master操作,释放Master权利");
}
});
selector.autoRequeue();
selector.start();
}
/**
* 子节点数据变化监听 这里监听/zk-book下面的子节点变化
* PathChildrenCache是无法对子节点的子节点进行监听的 比如对/zk-book进行监听只能监听到下一级
* 不能监听到下下级,比如/zk-book/c1/01, 01节点的变化是不能监听的
* @throws Exception
*/
static void pathChilrendCache_Sample() throws Exception{
String path = "/zk-book";
client.start();
@SuppressWarnings("resource")
PathChildrenCache cache = new PathChildrenCache(client, path, true);
cache.start(StartMode.POST_INITIALIZED_EVENT);
cache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
switch(event.getType()){
case CHILD_ADDED:
System.out.println("CHILD_ADDED"+event.getData().getPath());
break;
case CHILD_UPDATED:
System.out.println("CHILD_UPDATED"+event.getData().getPath());
break;
case CHILD_REMOVED:
System.out.println("CHILD_REMOVED"+event.getData().getPath());
break;
default:
break;
}
}
});
client.create().withMode(CreateMode.PERSISTENT).forPath(path);
Thread.sleep(2000);
client.create().withMode(CreateMode.PERSISTENT).forPath(path+"/c1");
Thread.sleep(2000);
client.delete().forPath(path+"/c1");
Thread.sleep(2000);
client.delete().forPath(path);
}
/**
* 事件监听 对节点变化事件监听
*
* @throws Exception
*/
static void nodeCache_Sample() throws Exception{
client.start();
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, "init".getBytes());
@SuppressWarnings("resource")
final NodeCache cache = new NodeCache(client, path, false);
cache.start();
cache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("Node data update, new data : "+
new String(cache.getCurrentData().getData()));
}
});
client.setData().forPath(path, "u".getBytes());
Thread.sleep(2000);
client.delete().deletingChildrenIfNeeded().forPath(path);
}
/**
* 异步创建节点
* @throws Exception
*/
static void create_Node_Background_Sample() throws Exception{
client.start();
System.out.println("Main thread name : "+Thread.currentThread().getName());
//此处传入线程池
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println("Event[code: "+event.getResultCode()+", type: "+event.getType()+"]");
System.out.println("Thread processResult : "+Thread.currentThread().getName());
semaphore.countDown();
}
}, tp).forPath(path, "init".getBytes());
//此处没有传入线程池
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println("Event[code: "+event.getResultCode()+", type: "+event.getType()+"]");
System.out.println("Thread processResult : "+Thread.currentThread().getName());
semaphore.countDown();
}
}).forPath(path, "init".getBytes());
semaphore.await();
tp.shutdown();
}
/**
* 更新数据
* @throws Exception
*/
static void set_Data_Sample() throws Exception{
client.start();
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, "init".getBytes());
Stat stat = new Stat();
System.out.println(new String(
client.getData().storingStatIn(stat).forPath(path)));
System.out.println("Success set node for : "+path+", new version : "+
client.setData().withVersion(stat.getVersion()).forPath(path).getVersion());
try {
client.setData().withVersion(stat.getVersion()).forPath(path);
} catch (Exception e) {
System.out.println("Fail set node due to "+e.getMessage());
}
}
/**
* 获取数据
* @throws Exception
*/
static void get_Data_Sample() throws Exception{
client.start();
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, "init".getBytes());
Stat stat = new Stat();
System.out.println(new String(
client.getData().storingStatIn(stat).forPath(path)));
}
/**
* 删除节点
* @throws Exception
*/
static void del_Node_Sample() throws Exception{
client.start();
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, "init".getBytes());
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath(path);
client.delete().deletingChildrenIfNeeded()
.withVersion(stat.getVersion()).forPath(path);
}
/**
* 创建节点
* @throws Exception
*/
static void create_Node_Sample() throws Exception{
client.start();
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, "init".getBytes());
}
/**
* 使用fluent风格创建简单会话
*/
static void create_session_sample_fluent(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory
.builder().connectString(connectionString)
.retryPolicy(retryPolicy)
.sessionTimeoutMs(5000).build();
client.start();
}
/**
* 创建简单会话
*/
static void create_session_sample(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory
.newClient(connectionString, 5000, 3000, retryPolicy);
client.start();
}
}
另外还有一些工具类比如ZKPaths,EnsurePath,可以参考他们api,使用起来比较简单
参考《从paxos到zookeeper分布式一致性原理与实践》