Apache Curator简单使用(三)
来源:互联网 发布:app软件制作教程 编辑:程序博客网 时间:2024/05/23 00:02
转载自:http://www.chengxuyuans.com/Java+/72042.html
共享锁: 全局同步分布式锁, 同一时间两台机器只有一台能获得同一把锁。
共享读写锁: 用于分布式的读写互斥处理, 同时生成两个锁:一个读锁, 一个写锁, 读锁能被多个应用持有, 而写锁只能一个独占, 当写锁未被持有时, 多个读锁持有者可以同时进行读操作。
共享信号量: 在分布式系统中的各个JVM使用同一个zk lock path, 该path将跟一个给定数量的租约(lease)相关联, 然后各个应用根据请求顺序获得对应的lease, 相对来说, 这是最公平的锁服务使用方式。
多共享锁:内部构件多个共享锁(会跟一个znode path关联), 在acquire()过程中, 执行所有共享锁的acquire()方法, 如果中间出现一个失败, 则将释放所有已require的共享锁; 执行release()方法时, 则执行内部多个共享锁的release方法(如果出现失败将忽略)。
如下展示如何设计一个分布式重入锁,其中一个path表示一个锁资源.
所谓"重入",就是同一个线程多次获取锁时,如果此线程已经持有了锁(即创建了zk临时节点),事实上将不会再次创建zk的临时节点,而是直接返回。
因为"重入锁",基于临时节点的特性,因此必须关注client链接重建的问题;粗糙的解决办法,就是每次链接重建(session过期),重新实例化lock对象。
Curator实现Leader选举有两种方式,第一种是LeaderLatch,这种是有阻塞的,所有client一起去争leader,没有选上的client会一直阻塞,等待上一leader退出或则挂掉。一旦leader位置为空了,继续争夺leader。第二种是LeaderSelector监听器实现Leader选举功能。同一时刻,只有一个Listener会进入takeLeadership()方法,说明它是当前的Leader。注意:当Listener从takeLeadership()退出时就说明它放弃了“Leader身份”, 这时Curator会利用Zookeeper再从剩余的Listener中选出一个新的Leader。autoRequeue()方法使放弃 Leadership的Listener有机会重新获得Leadership,如果不设置的话放弃了的Listener是不会再变成Leader的。
LeaderLatch示例:
LeaderSelector示例:
分布式锁Lock
Curator中的支持的锁服务有多种类型,详见http://ifeve.com/zookeeper-lock/。共享锁: 全局同步分布式锁, 同一时间两台机器只有一台能获得同一把锁。
共享读写锁: 用于分布式的读写互斥处理, 同时生成两个锁:一个读锁, 一个写锁, 读锁能被多个应用持有, 而写锁只能一个独占, 当写锁未被持有时, 多个读锁持有者可以同时进行读操作。
共享信号量: 在分布式系统中的各个JVM使用同一个zk lock path, 该path将跟一个给定数量的租约(lease)相关联, 然后各个应用根据请求顺序获得对应的lease, 相对来说, 这是最公平的锁服务使用方式。
多共享锁:内部构件多个共享锁(会跟一个znode path关联), 在acquire()过程中, 执行所有共享锁的acquire()方法, 如果中间出现一个失败, 则将释放所有已require的共享锁; 执行release()方法时, 则执行内部多个共享锁的release方法(如果出现失败将忽略)。
如下展示如何设计一个分布式重入锁,其中一个path表示一个锁资源.
public class DistributedLock{ private InterProcessMutex lock;//重入的,排他的. private Map<Thread,Boolean> lockedThread = new WeakHashMap<Thread,Boolean>(); private String lockPath; private ConnectionStateListener stateListener = new StateListener(); private RevocationListener<InterProcessMutex> revocationListener; public DistributedLock(CuratorFramework client,String path){ lockPath = path; revocationListener = new RevocationListener<InterProcessMutex>() { @Override public void revocationRequested(InterProcessMutex forLock) { if(!forLock.isAcquiredInThisProcess()){ return; } try{ forLock.release(); }catch(Exception e){ e.printStackTrace(); } } }; lock = createLock(client); lock.makeRevocable(revocationListener); client.getConnectionStateListenable().addListener(stateListener); } public boolean lock(){ try{ lock.acquire(); lockedThread.put(Thread.currentThread(),Boolean.TRUE); } catch (Exception e){ // } return false; } public void unlock(){ try{ lock.release(); }catch (Exception e){ // } } private InterProcessMutex createLock(CuratorFramework client){ lock = new InterProcessMutex(client,lockPath); //协同中断,如果其他线程/进程需要此锁中断时,调用此listener. lock.makeRevocable(revocationListener); client.getConnectionStateListenable().addListener(stateListener); return lock; } class StateListener implements ConnectionStateListener{ @Override public void stateChanged(CuratorFramework client, ConnectionState newState) { if(Boolean.FALSE.equals(lockedThread.get(Thread.currentThread()))){ return;//如果当前lock没有获取锁,则忽略 } switch (newState){ case LOST: //一旦丢失链接,就意味着zk server端已经删除了锁数据 lockedThread.clear(); lock = createLock(client);//must be rebuild break; default: System.out.println(newState.toString()); } } }}底层的机制非常的简单: "获取锁"的操作,就是在zookeeper中创建一个EPHEMERAL_SEQUENTIAL节点,同时对此节点的临近节点注册一个watcher; 当"临近节点"被删除时,表示其他进程已经释放了锁,此watcher将会触发,并唤醒当前线程,然后acquire方法返回.."释放锁"的操作,就是 删除此临时节点.此时临近的下一个节点将获得锁。
所谓"重入",就是同一个线程多次获取锁时,如果此线程已经持有了锁(即创建了zk临时节点),事实上将不会再次创建zk的临时节点,而是直接返回。
因为"重入锁",基于临时节点的特性,因此必须关注client链接重建的问题;粗糙的解决办法,就是每次链接重建(session过期),重新实例化lock对象。
Barrier
栅栏, 可以用来协同分布式环境中的线程.让他们有条件的阻塞,且同时唤醒.DistributedBarrier barrier = new DistributedBarrier(client,"/barrier");barrier.setBarrier(); //设置barrierSystem.out.println("setBarrier...");barrier.waitOnBarrier();//等待其他进程移除barrier,此后所有的waitOnBarrier进程都将解除阻塞.//barrier.removeBarrier(); //移除barrier,解除阻塞.
DistributedDoubleBarrier barrier = new DistributedDoubleBarrier(client,"/d-barrier",12);System.out.println("enter...");barrier.enter();//阻塞,直到12个成员加入System.out.println("running...");barrier.leave();//阻塞,直到12个成员离开其中DistributedDoubleBarrier为双端栅栏,可以让N个线程(进程)同时开始,并且同时退出。对于DistributedBarrier内部机制非常简单: setBarrier()方法就是创建"栅栏"节点,removeBarrier()方法就是删除此节点;当执行setBarrier之后,所有的 waitOnBarrier()操作都将阻塞,直到删除节点的事件触发。DistributedBarrier 会监控连接状态,当连接断掉时waitOnBarrier()方法会抛出异常。
leader选举
Curator实现Leader选举有两种方式,第一种是LeaderLatch,这种是有阻塞的,所有client一起去争leader,没有选上的client会一直阻塞,等待上一leader退出或则挂掉。一旦leader位置为空了,继续争夺leader。第二种是LeaderSelector监听器实现Leader选举功能。同一时刻,只有一个Listener会进入takeLeadership()方法,说明它是当前的Leader。注意:当Listener从takeLeadership()退出时就说明它放弃了“Leader身份”, 这时Curator会利用Zookeeper再从剩余的Listener中选出一个新的Leader。autoRequeue()方法使放弃 Leadership的Listener有机会重新获得Leadership,如果不设置的话放弃了的Listener是不会再变成Leader的。LeaderLatch示例:
// 选举Leader 启动 LeaderLatch latch = new LeaderLatch(client, "/leader"); latch.addListener(new LeaderLatchListener(){ @Override public void isLeader() { System.out.println("I am leader"); } @Override public void notLeader() { System.out.println("I not leader"); } }); latch.start();// latch.await();// System.out.println("I am leader"); System.out.println(latch.hasLeadership()); TimeUnit.SECONDS.sleep(20); latch.close();latch会参与竞选leader,如果被选举为leader,会调用isLeader()方法,hasLeadership()会返回true。
LeaderSelector示例:
final LeaderSelector leaderSelector = new LeaderSelector(client, "/leader", new LeaderSelectorListenerAdapter() { @Override public void takeLeadership(CuratorFramework client) throws Exception { System.out.println("I am leader, working..."); TimeUnit.SECONDS.sleep(3); System.out.println("I am leader, end."); } }); leaderSelector.autoRequeue(); leaderSelector.start(); TimeUnit.SECONDS.sleep(1000);除了LeaderSelectorListenerAdapter外,还可以使用LeaderSelectorListener,LeaderSelectorListener将会额外监控stateChanged。
LeaderSelectorListener selectorListener = new LeaderSelectorListener() { //此方法将会在Selector的线程池中的线程调用 @Override public void takeLeadership(CuratorFramework client) throws Exception { System.out.println("I am leader..."); //如果takeLeadership方法被调用,说明此selector实例已经为leader //此方法需要阻塞,直到selector放弃leader角色 } //这个方法将会在Zookeeper主线程中调用---watcher响应时 @Override public void stateChanged(CuratorFramework client, ConnectionState newState) { System.out.println("Connection state changed..."); //对于LeaderSelector,底层实现为对leaderPath节点使用了"排他锁", //"排他锁"的本质,就是一个"临时节点" //如果接收到LOST,说明此selector实例已经丢失了leader信息. if (newState == ConnectionState.LOST) { //需要做特殊处理 } } };
0 0
- Apache Curator简单使用(三)
- Apache Curator简单使用(一)
- Apache Curator简单使用(二)
- Apache Curator Lock 简单示例
- zookeeper Curator框架简单使用
- Apache Curator Leader选举 简单示例
- zookeeper使用(三)--Curator客户端操作zookeeper
- [curator] Netflix Curator 使用
- [curator] Netflix Curator 使用
- Zookeeper之Curator框架简单使用-yellowcong
- zookeeper学习之三(Curator客户端)
- zookeeper学习之三(Curator客户端)
- zookeeper学习之三(Curator客户端)
- zookeeper学习之三(Curator客户端)
- zookeeper学习之三(Curator客户端)
- zookeeper学习之三(Curator客户端)
- 使用Apache Curator实现服务的注册和发现
- Apache Curator Leader Election
- SDIO接口介绍
- python 爬虫数据清洗
- shell脚本的两种执行方式区别举例
- 卡尔曼滤波
- 原生的ajax
- Apache Curator简单使用(三)
- 第十五周-字符串逆序输出
- Spark转换算子和执行算子
- skyline加载wfs,wms服务参考
- CMake常见错误
- rsync 通过密码文件实现远程同步
- BUG生命周期和管理
- 第十五周-C语言习题 字符串长度
- 计算机视觉方向的一些顶级会议和期刊