version
zookeeper3.5.x可以使用curator4.x及以上的版本,zookeeper3.4.x需要使用更低的curator版本,建议使用zookeeper3.5.x
curator需要的依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>x.x.x</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-nop -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
curator使用
创建连接
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("192.168.186.128:2181")
.sessionTimeoutMs(30000)
.retryPolicy(new ExponentialBackoffRetry(1000,3))
.build();
client.start();
创建节点
client.create()
.creatingParentsIfNeeded() //如果没有父节点的,则创建父节点
.withMode(CreateMode.PERSISTENT) //设置创建节点的模式,是永久节点还是临时节点
.forPath("path","data".getBytes(); //创建节点的路径和设置节点的数据,数据只能是byte[]类型
获取数据
Stat stat = new Stat();
byte[] data = client.getDate()
.storingStatIn(stat) //获取数据的状态
.forPath(paht);
更新数据
client.setDate()
.withVersion(int version) //如果版本不是最新的版本,则不能更新数据。
.forPath(path);
删除节点
client.delete()
.guaranteed() //保证zookeeper一定删除该节点
.deletingChildrenIfNeeded() //如果有子节点,则递归删除子节点
.withVersion(stat.getVersion()) //要删除数据的版本,如果版本过期则不能删除
.forPath(path);
异步接口
public interface BackgroundCallback{
public void processResult(CuratorFramework client,CurtorEvent event) throws Exception;
}
CurtorEvent event 参数中定义了服务器端向客户端发送的一系列事件参数,其中比较重要的是事件类型和响应码。
- 事件类型(CuratorEventType)
getType()返回的类型有:
类型 | 描述 |
---|---|
CREATE | Framework#create() 触发 |
DELETE | delete() |
EXISTS | checkExists() |
GET_DATA | getData() |
SET_DATA | setData() |
CHILDREN | getChildren() |
SYNC | sync(String,object) |
GET_ACL | getACL() |
WATCHED | |
CLOSING |
- 响应码(int)
响应码 | 描述 |
---|---|
0 | ok |
-4 | 连接断开 |
-110 | 节点已经存在 |
-112 | 会话过期 |
用法
例如
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.inBackground(new BackgroundCallBack(){
@Override
public void processResult(CuratorFramework client,CuratorEvent event){
....
}
})
使用场景
事件监听
curatoe引入了Cache来实现duizookeeper服务器的监听。Cache是对Curator中事件监听的包装,可以看作是本地缓存试图与远程zookeeper视图的一个比对过程。实现了反复注册监听。Cache主要是分为两类:节点监听、子节点监听。
- NodeCache
NodeCache 不仅仅可以监听节点的数据变化,也可以监听该节点是否存在,如果不存在,则在创建该节点时触发NodeCacheListener,但是节点删除时不能触发。
构造方法
public NodeCache(CuratorFramework client,String path);
public NodeCache(CuratorFramwork client,String path,boolean dataIsCompressed)
回调接口
public interface NodeCacheListener{
public void nodeChanged() throws Exception;
}
使用
fianl NodeCache cache = new NodeCache(client,path,false); //类型需要时final
cache.start(true); //当使用true时,在cache第一次启动时hui立即从zookeeper获取数据。
cache.getListenable().addListener(new NodeCacheListener(){
public void nodeChanged() throws Exception{
String data = new String(cache.getCurrentData().gatData());
.....
}
})
- PathChildrenCache
PathChildrenCache 用于监听zookeeper数据节点的子节点的变化情况。
构造方法
public PathChildrenCache(CuratorFramework client,String path,boolean cacheData);
public PathChildrenCache(CuratorFramework client,String path,boolean cacheData,ThreadFactory threadFactory);
public PathChildrenCache(CuratorFramework client,String path,boolean cacheData,boolean dataIsCompressed, ThreadFactory threadFactory);
public PathChildrenCache(CuratorFramework client,String path,boolean cacheData,ExecutorService executorService);
public PathChildrenCache(CuratorFramework client,String path,boolean cacheData,boolean dataIsCompressed,ExecutorService executorService);
回调接口
public interface PathChildrenCacheListener{
public void childEvent(CuratorFramework client,PathChildrenCacheEvent event) throws Exception;
}
在PathChildrenCacheEvent 中定义了所有的事件类型,主要包括:新增节点(CHILD_ADDED)、子节点变更(CHILD_UPDATED)、子节点删除(CHILD_REMOVED)三类
使用
PathChildrenCache cache = new PathChildrenCache(client,path,true);
cache.start()
cache.getListenerable().addListener(new PathChildrenCacheListener(){
public void childEvent(CuratorFramework client,PathChildrenCacheEvent) throws Exception{
......
}
})
Master 选举
对于一个复杂的任务,仅仅需要从集群中选取一台主机进行处理。诸如此类的问题统统称为Master选举。
解决思路
在zookeeper服务器中选取一个节点,多台机器同时向该节点创建一个相同的子节点,由于zookeeper的特性,最终只会有一个机器创建成功,创建成功的这个机器就作为Master。
实现
//master选举的根节点
static String master_path = "/curator_master";
//创建服务器
static CuratorFramework client = new CuratorFrameworkFactory.builder()
.connectString(host:port)
.retryPolicy(new ExponentialBackoffRetry(1000,3)).build();
public static void main(String[] args) throws Exception{
client.start();
LeaderSelector selector = new LeaderSelectro(client,master_path,new LeaderSelectorListenerAdapter(){
public void takeLeadership(CuratorFramework client) thrwos Exception{
......//处理逻辑。
}
}
}
在curator 竞争到master以后会调用takeLeadership(curatroFramework client) 方法,在这个方法中实现业务逻辑。当业务逻辑执行完毕以后会立即释放Master权力,然后进行新一轮的Master选举。
分布式锁
解决思路
利用zookeeper的特性,多台机器在同一个节点下创建相同的一个节点。zookeeper保证最终只有一台机器可以创建成功。而创建成功的机器获取到执行权。
实现
//创建锁的根节点。
static String lock_path = "curator_path";
static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(Host:port)
.retryPolicy(new ExponentialBackoffRetry(1000),3)).build();
public static void main(String[] args) throws Exception{
client.start();
final InterProcessMutex lock = new InterProcessMutex(client,lock_path); //分布式锁。
}
分布式计数器
解决思路
在zookeeper指定的数据节点上通过分布式锁来更新数据。
实现
static String atomic_path= "atomicInteger_path";
static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(Host:port)
.retryPolicy(new ExponentialBackoffRetry(1000),3)).build();
public static void main(String[] args) throws Exception{
client.start();
DistributedAtomicInterger atomicInteger = new DistributedAtomicInteger(client,atomic_path,new RetryNTimes(3,1000));
AtomicValue<Integer> rc = atomicInteger.add(1);
rc.succeeded();
}
分布式Barrier
实现1
static String path = "path";
static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(Host:prot)
.retryPolicy(new ExponentialBackoffRetry(1000,3)).build();
client.start();
DistributedBarrier barrier= new DistributedBarrier(client,path);
//处理逻辑
barrier.setBarrier(); //设置栅栏,所有的程序运行到这里都回等待。
barrier.waitOnBarrier(); //设置程序等待。
//唤醒等待的程序继续运行
barrier.removeBarrier();
实现2
static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(Host:prot)
.retryPolicy(new ExponentialBackoffRetry(1000,3)).build();
client.start();
//最有以个参数表示要等待多少个线程达到此处才开始继续运行。如果不足则等待。
DistributedDoubleBarrier barrier = new DistributedDoubleBarrier(client,path,5);
//处理逻辑
。。。
barrier.enter(); //当不满足到达的个数时等带,当满足时,自动继续运行。
//其他处理逻辑
。。。
barrier.leaver(); //另外一处等待点,和enter()位置的逻辑相同。