6.Curator测试以及常用场景的实现

来源:互联网 发布:电子处方单软件 编辑:程序博客网 时间:2024/06/07 02:59

1.介绍

curator是zk的一套客户端框架解决了zk一些细节的开发工作包括反复注册watcher、连接重连、节点已存在异常等。对于实现分布式锁、master选举、分布式计数器、分布式屏障等可以很简单的实现


2.zk实例创建、节点增删改查和异步回调接口

依赖
<!-- curator依赖 -->    <dependency>    <groupId>org.apache.curator</groupId>    <artifactId>curator-framework</artifactId>    <version>2.10.0</version></dependency><!-- curator依赖 -->

测试类

package com.tyf.test;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.api.CuratorEventType;import org.apache.curator.retry.ExponentialBackoffRetry;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.data.Stat;//实现异步接口处理回调public class test_curator implements BackgroundCallback{public CuratorFramework client;//创建zk实例public void create_session()throws Exception{//重试策略(默认四种)初始sleep时间1秒,最大重试次数3RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);//创建会话,使用bulider还可以创建带有命名空间的隔离的会话client = CuratorFrameworkFactory.newClient("192.168.88.131:2181",  5000,//会话过期时间  3000,//连接超时时间  retryPolicy);client.start();System.out.println(client.isStarted());}//创建节点public void create_node() throws Exception{client.create().creatingParentsIfNeeded().//顺便创建父节点    withMode(CreateMode.EPHEMERAL).//临时节点    forPath("/zk/nodes", "data".getBytes());//节点}//读取节点内容public void get_data() throws Exception{//获取zk实例this.create_session();//创建节点this.create_node();//获取节点byte[] bytes = client.getData().storingStatIn(new Stat()).forPath("/zk/nodes");System.out.println(new String(bytes));}//更新节点数据public void update_data() throws Exception{//获取zk实例this.create_session();//创建节点this.create_node();//读取节点Stat stat = new Stat();client.getData().storingStatIn(stat).forPath("/zk/nodes");//更新节点数据client.setData().forPath("/zk/nodes");//指定某个版本更新client.setData().withVersion(stat.getVersion()).forPath("/zk/nodes");}//删除结点public void delete_node() throws Exception{//获取zk实例this.create_session();//创建节点this.create_node();//读取节点Stat stat = new Stat();client.getData().storingStatIn(stat).forPath("/zk/nodes");//删除结点client.delete().deletingChildrenIfNeeded().withVersion(stat.getVersion()).forPath("/zk/nodes");}//接口回调()public void processResult(CuratorFramework curator, CuratorEvent event) throws Exception {//事件类型主要有一下几种,通过event获取CuratorEventType type1 = CuratorEventType.CREATE;CuratorEventType type2 = CuratorEventType.DELETE;CuratorEventType type3 = CuratorEventType.EXISTS;CuratorEventType type4 = CuratorEventType.CHILDREN;CuratorEventType type5 = CuratorEventType.CLOSING;//获取事件类型event.getType();//响应码有下面几种,通过event获取//0:ok(接口调用成功)//-4:connectionLoss(客户端与服务端连接断开)//-110:nodeExists(节点存在)//-112:sessionExpired(会话过期)event.getResultCode();}public static void main (String ss[]) throws Exception{Thread.sleep(Integer.MAX_VALUE);}}

3.事件监听

原生zk使用watcher实现事件监听,但是需要反复注册监听不方便。使用curator可以实现节点监听和子节点监听
只用nodeCache这个类
依赖
<!-- curator依赖 -->    <dependency>    <groupId>org.apache.curator</groupId>    <artifactId>curator-framework</artifactId>    <version>2.10.0</version></dependency><!-- curator依赖 --><!-- nodeCache依赖 --><dependency>    <groupId>org.apache.curator</groupId>    <artifactId>curator-recipes</artifactId>    <version>2.10.0</version></dependency><!-- nodeCache依赖 -->

测试
package com.tyf.test;import org.apache.curator.RetryPolicy;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.cache.NodeCache;import org.apache.curator.framework.recipes.cache.NodeCacheListener;import org.apache.curator.retry.ExponentialBackoffRetry;import org.apache.zookeeper.CreateMode;/* *  * 事件监听 *  *///实现异步接口处理回调public class test_curator {public CuratorFramework client;//创建zk实例public void create_session()throws Exception{//重试策略(默认四种)初始sleep时间1秒,最大重试次数3RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);//创建会话,使用bulider还可以创建带有命名空间的隔离的会话client = CuratorFrameworkFactory.newClient("192.168.88.131:2181",  5000,//会话过期时间  3000,//连接超时时间  retryPolicy);client.start();}//创建节点public void create_node() throws Exception{client.create().creatingParentsIfNeeded().//顺便创建父节点    withMode(CreateMode.EPHEMERAL).//临时节点    forPath("/zk/nodes", "data".getBytes());//节点}//更新节点数据public void update_data() throws Exception{//读取节点//Stat stat = new Stat();//client.getData().storingStatIn(stat).forPath("/zk/nodes");//更新节点数据client.setData().forPath("/zk/nodes","newData".getBytes());//指定某个版本更新//client.setData().withVersion(stat.getVersion()).forPath("/zk/nodes");}public static void main (String ss[]) throws Exception{test_curator cura = new test_curator();//创建回话cura.create_session();//创建节点cura.create_node();//创建nodeCache用于监听节点(false指定不进行数据压缩)final NodeCache nodeCache = new NodeCache(cura.client, "/zk/nodes", false);//带true参数启动nodeCache.start(true);//添加监听器,节点数据改变会触发nodeCache.getListenable().addListener(new NodeCacheListener() {public void nodeChanged() throws Exception {//获取最新的节点数据System.out.println("数据更新了"+new String(nodeCache.getCurrentData().getData()));}});//更新节点数据,查看监听器执行是否执行cura.update_data();Thread.sleep(Integer.MAX_VALUE);}}


4.master选举

分布式中,有一个复杂任务可以由一台机器计算结果,集群其他机器共享计算结果。master在zk中主要是利用同名临时节点只能有一个创建成功,类似于分布式锁的实现,创建成功的就是master或者是持有锁
cruator中直接封装所有master选举的逻辑成为一个类LeaderSelector

依赖
<!-- curator依赖 -->    <dependency>    <groupId>org.apache.curator</groupId>    <artifactId>curator-framework</artifactId>    <version>2.10.0</version></dependency><!-- curator依赖 -->



测试
package com.tyf.curator;import org.apache.curator.RetryPolicy;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.leader.LeaderSelector;import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter;import org.apache.curator.retry.ExponentialBackoffRetry;public class leader_test {public CuratorFramework client;public String name;public leader_test(String name){this.name = name;}//创建zk实例public void create_session()throws Exception{//重试策略(默认四种)初始sleep时间1秒,最大重试次数3RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);//创建会话,使用bulider还可以创建带有命名空间的隔离的会话client = CuratorFrameworkFactory.newClient("192.168.88.131:2181",  5000,//会话过期时间  3000,//连接超时时间  retryPolicy);client.start();}//创建leader竞争类,竞争成功就执行监听器的回调函数//回调函数执行完会进入下一轮选举public void  compete_leader() throws Exception{//创建zk实例this.create_session();//创建leader竞争类LeaderSelector selector = new LeaderSelector(client, "/master-nodes", new LeaderSelectorListenerAdapter() {//竞争成功会执行的函数,函数执行完后进行下一轮选举public void takeLeadership(CuratorFramework curator) throws Exception {System.out.println("当前的竞争者:"+name);}});//保证释放master之后还可以进入下一次选举selector.autoRequeue();selector.start();}public static void main(String [] args) throws Exception{new leader_test("竞争者1").compete_leader();new leader_test("竞争者2").compete_leader();new leader_test("竞争者3").compete_leader();Thread.sleep(Integer.MAX_VALUE);}}
结果



5.分布式锁

利用同名临时节点只能一个创建成功,curator封装了节点的特性封装了一个分布式锁类InterProcessMutex可以直接使用

锁类测试
package com.tyf.curator;import java.util.Date;import org.apache.curator.RetryPolicy;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.locks.InterProcessMutex;import org.apache.curator.retry.ExponentialBackoffRetry;public class lock_test {public CuratorFramework client;public String name;public lock_test(String name){this.name = name;}//创建zk实例public void create_session()throws Exception{//重试策略(默认四种)初始sleep时间1秒,最大重试次数3RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);//创建会话,使用bulider还可以创建带有命名空间的隔离的会话client = CuratorFrameworkFactory.newClient("192.168.88.131:2181",  5000,//会话过期时间  3000,//连接超时时间  retryPolicy);client.start();}//抢锁public void get_lock() throws Exception{//创建zk实例this.create_session();//创建分布式锁类InterProcessMutex lock = new InterProcessMutex(client, "/locks");//获取锁lock.acquire();System.out.println(name+"获取锁 :"+new Date());//调用业务逻辑this.working();//释放锁,让别人获取lock.release();System.out.println(name+"释放锁 :"+new Date());}//持锁后调用的工作方法public void working() throws Exception{System.out.println(name+"工作中");Thread.sleep(5000);}}
利用屏障模拟五个工程同时抢锁测试类
package com.tyf.curator;import java.util.concurrent.CyclicBarrier;public class cyclic_barrier implements Runnable{//创建线程屏障//设置为类变量,五个实例公用这一个屏障对象public static CyclicBarrier barrier=new CyclicBarrier(5);//抢锁者public lock_test lock;//抢锁者namepublic String name;public cyclic_barrier(String name){this.name=name;}public void run() {try {//创建zk实例lock = new lock_test(name);System.out.println(name+"准备好了");//设置屏障barrier.await();//一起抢锁lock.get_lock();} catch (Exception e) {e.printStackTrace();}}public static void main(String args[]){new Thread(new cyclic_barrier("抢锁者1")).start();new Thread(new cyclic_barrier("抢锁者2")).start();new Thread(new cyclic_barrier("抢锁者3")).start();new Thread(new cyclic_barrier("抢锁者4")).start();new Thread(new cyclic_barrier("抢锁者5")).start();}}

结果



6.分布式计数器

利用分布式锁可以简单地实现在线人数的统计,思路就是客户端获取到了分布式锁之后更改节点数据将数据加1然后释放锁。curator里面直接封装了一个分布式计数器类
DistributedAtomicInteger从名称就可以看出是分布式环境中一种原子类整数类型

自增客户端
package com.tyf.curator;import org.apache.curator.RetryPolicy;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.atomic.AtomicValue;import org.apache.curator.framework.recipes.atomic.DistributedAtomicInteger;import org.apache.curator.retry.ExponentialBackoffRetry;import org.apache.curator.retry.RetryNTimes;public class integer_test {public CuratorFramework client;public String name;public integer_test(String name){this.name = name;}//创建zk实例public void create_session()throws Exception{//重试策略(默认四种)初始sleep时间1秒,最大重试次数3RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);//创建会话,使用bulider还可以创建带有命名空间的隔离的会话client = CuratorFrameworkFactory.newClient("192.168.88.131:2181",  5000,//会话过期时间  3000,//连接超时时间  retryPolicy);client.start();}//计数值加1public void get_count() throws Exception{//创建zk实例this.create_session();//创建分布式原子类整数(两种构造函数分别用互斥锁和乐观锁实现的)DistributedAtomicInteger count = new DistributedAtomicInteger(client,"/online_count",new RetryNTimes(3, 1000));//自增增操作System.out.println("操作前节点数据"+count.get().preValue());AtomicValue<Integer> rc =  count.add(1);System.out.println("add是否成功"+rc.succeeded());System.out.println("操作后节点数据"+count.get().preValue());}}

测试类模拟五个用户同时修改数据
package com.tyf.curator;import java.util.concurrent.CyclicBarrier;public class cyclicBarrier implements Runnable{//创建线程屏障//设置为类变量,五个实例公用这一个屏障对象public static CyclicBarrier barrier=new CyclicBarrier(5);//抢锁者public integer_test count;//抢锁者namepublic String name;public cyclicBarrier(String name){this.name=name;}public void run() {try {//创建客户端实例count = new integer_test(name);System.out.println(name+"准备好了");//设置屏障barrier.await();//一起addcount.get_count();} catch (Exception e) {e.printStackTrace();}}public static void main(String args[]) throws Exception{new Thread(new cyclicBarrier("用户1")).start();new Thread(new cyclicBarrier("用户2")).start();new Thread(new cyclicBarrier("用户3")).start();new Thread(new cyclicBarrier("用户4")).start();new Thread(new cyclicBarrier("用户5")).start();Thread.sleep(Integer.MAX_VALUE);}}

结果


7.分布式线程屏障,curator有两种实现

(1)DistributedBarrir方式(被动等待屏障释放)
同一个jvm中使用的是CyclicBarrier,在分布式情况下curator封装了DistributedBarrir。主要是每个客户端zk实例使用相同的节点创建DistributedBarrir来使用同一个屏障达到跨jvm的线程屏障功能

package com.tyf.curator;import java.util.Date;import java.util.Timer;import java.util.TimerTask;import org.apache.curator.RetryPolicy;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.barriers.DistributedBarrier;import org.apache.curator.retry.ExponentialBackoffRetry;public class barrier_test implements Runnable{public CuratorFramework client;public String name;//屏障public static DistributedBarrier barrier;//客户端构造public barrier_test(String name) throws Exception{//设置名称this.name = name;//创建回话RetryPolicy retryPolicy = new ExponentialBackoffRetry(5000, 5);//创建会话,使用bulider还可以创建带有命名空间的隔离的会话client = CuratorFrameworkFactory.newClient("192.168.88.131:2181",  Integer.MAX_VALUE,//会话过期时间  Integer.MAX_VALUE,//连接超时时间  retryPolicy);client.start();//创建屏障barrier = new DistributedBarrier(client, "/barrier_node");barrier.setBarrier();}//在自己的线程方法中使用分布式屏障public void run() {try {System.out.println("客户端"+name+"准备好了,当前时间"+new Date());//这里的等待需要别人释放屏障,大家才会一起向下执行barrier.waitOnBarrier();System.out.println("客户端"+name+"当前时间:"+new Date());} catch (Exception e) {e.printStackTrace();}}public static void main(String args[]) throws Exception{new Thread(new barrier_test("name1")).start();new Thread(new barrier_test("name2")).start();new Thread(new barrier_test("name3")).start();new Thread(new barrier_test("name4")).start();new Thread(new barrier_test("name5")).start();//上面5个客户端都在屏障前等待屏障释放//10秒后释放屏障Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {try {barrier.removeBarrier();} catch (Exception e) {e.printStackTrace();}}}, 10 * 1000);}}
结果

可以看到五个客户端同时获取并打印系统时间
(2)DistributedDoubleBarrier(指定数目自动释放屏障)

客户端类

package com.tyf.curator;import java.util.Date;import java.util.Timer;import java.util.TimerTask;import org.apache.curator.RetryPolicy;import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.CuratorFrameworkFactory;import org.apache.curator.framework.recipes.barriers.DistributedBarrier;import org.apache.curator.framework.recipes.barriers.DistributedDoubleBarrier;import org.apache.curator.retry.ExponentialBackoffRetry;public class barrier_test implements Runnable{public CuratorFramework client;public String name;//屏障public static DistributedDoubleBarrier barrier;//客户端构造public barrier_test(String name) throws Exception{//设置名称this.name = name;//创建回话RetryPolicy retryPolicy = new ExponentialBackoffRetry(5000, 5);//创建会话,使用bulider还可以创建带有命名空间的隔离的会话client = CuratorFrameworkFactory.newClient("192.168.88.131:2181",  Integer.MAX_VALUE,//会话过期时间  Integer.MAX_VALUE,//连接超时时间  retryPolicy);client.start();//创建屏障,指定等待数目5个以上开始向下执行barrier = new DistributedDoubleBarrier(client, "/barrier_node", 5);}//在自己的线程方法中使用分布式屏障public void run() {try {//进入屏障barrier.enter();System.out.println("客户端"+name+"进入屏障时间"+ new Date());//离开屏障barrier.leave();System.out.println("客户端"+name+"离开屏障时间"+ new Date());} catch (Exception e) {e.printStackTrace();}}public static void main(String args[]) throws Exception{try {//每隔五秒创建一个客户端for(int i=0;i<5;i++){new Thread(new barrier_test(new Integer(i).toString())).start();Thread.sleep(5000);}} catch (Exception e) {}}}

结果


阅读全文
0 0