全局式分布式锁要求任何时刻没有两个客户端会获得同一个锁对象,这可以通过使用ZooKeeper实现。像优先级队列一样,首先需要定义一个锁节点。

在ZooKepeer的发布中src/recipes/lock(https://github.com/apache/zookeeper/tree/master/src/recipes/lock)的目录有ZooKeeper的Lock实现。

要获得锁的客户端进行如下操作:

1.调用Create方法并使用"_locknode_/guid-lock-"作为路径,并设置sequence和ephemeral标志位。guid是防止create的结果缺失,详见下面说明。

2.在锁节点上调用getChildren方法,不用设置watch(这是为了防止羊群效应)。

3.如果第一步所创建的路径拥有最小的序号,该客户端获得锁并退出协议。

4.客户端调用exists并设置watch标志在比自身小的节点上。

5.如果exists返回false,返回第二步。不然等到上一步设置的watch事件触发再回到第二步。

解锁的步骤非常简单:客户端希望释放锁只需要简单地删除第一步所创建的锁。

这里有几点值得注意:

  • 由于每个节点只会被一个客户端watch,所以删除一个节点只会唤醒一个客户端。这样可以避免羊群效应。
  • 没有轮询或超时的问题
  • 使用该方式实现锁可以方便地看见锁的竞争、中断锁占用、调试锁等

可恢复错误和GUID

  • 如果调用create时发生了一个可恢复的错误,客户端可以调用getChildren并通过guid检查节点的名字,来得知自己创建的节点。这个解决了引言中提到的问题,即create成功返回但是服务器在获得节点名字之前宕机的情况。

共享锁

可以通过修改部分协议来实现共享锁。

获得读锁 获得写锁
1.调用create创建"guid-/read-"节点。这是将会用到的读锁。需要确保使用sequence和ephemeral标志位。

2.在锁节点上调用getChildren,注意不要设置watch标志,避免羊群效应。

3.如果没有比第一步创建的节点小的"write-"开头的节点,则客户端获得锁并退出协议。

4.否则在次小的write节点上调用exists方法并设置watch标志。

5.如果exists方法返回false则返回第二步。

6.不然等待上面watch事件触发再返回第二步
1.调用create创建"guid-/write-"节点。这是后面需要的写锁。需要确保使用sequence和ephemeral标志位。

2.在锁节点上调用getChildren,注意不要设置watch标志,避免羊群效应。

3.如果没有比第一步创建的更小的节点,客户端获得锁并退出协议。

4.在次小的节点上调用exists方法并设置watch标志。

5.如果exists返回false回到第二步,不然等到watch事件触发再返回第二步。

###注意:
>* 该recipe可能产生羊群效应,即,当有一群客户端等待读锁时,客户端会在写锁释放时一起被唤醒。事实上,这个过程应该是正确的:所有等待的读客户端获得了锁。而羊群效应是指有一群节点被唤醒,而事实上只能允许少数可以运行。
>* 详见[上面](#可恢复错误和guid)提到的关于的guid使用。
##可恢复的共享锁
对共享锁协议做一些小幅改动就可以实现锁的可恢复:
在上面读写锁的第一步,在调用create之后,立即调用getData并使用watch标识,如果客户端收到这个watch事件,再次调用getData并使用watch标识并查看内容是否包含"unlock"字符串,unlock表示客户端必须释放当前锁。根据共享锁协议,你可以向获得锁客户端调用setData写入"unlock"字符串,申请其释放锁。
注意这个协议需要锁持有者同意释放锁。这很重要,尤其是如果锁持有者需要在释放之前做某些操作时。当然你可以在你的协议中规定,在锁持有者一定时间后如仍未删除锁节点,可以由他人强制删除。
##Curator实现
###共享锁
```
public InterProcessSemaphoreMutex(CuratorFramework client,String path)
/**
client 客户端实例
path 锁节点地址
**/
public void acquire() //获得锁
public void release() //释放锁
```
###可重入共享锁
```
public InterProcessMutex(CuratorFramework client,String path)
/**
client 客户端实例
path 锁节点地址
**/
public void acquire() //获得锁
public void release() //释放锁
public void makeRevocable(RevocationListener listener) //撤销锁
public static void attemptRevoke(CuratorFramework client,String path) //请求对应路径锁撤销
```
###可重入读写锁
```
public InterProcessReadWriteLock(CuratorFramework client,String basePath)
/**
client 客户端实例
basePath 锁基础路径
**/
public InterProcessLock readLock() //读锁
public InterProcessLock writeLock() //写锁
```
[返回引言](http://www.cnblogs.com/resentment/p/6129339.html)

[译]ZOOKEEPER RECIPES-Locks的更多相关文章

  1. ZooKeeper Recipes and Solutions 翻译

    ZooKeeper 秘诀 与解决方案 A Guide to Creating Higher-level Constructs with ZooKeeper Out of the Box Applica ...

  2. ZooKeeper Recipes and Solutions

    原文地址:http://zookeeper.apache.org/doc/current/recipes.html 参考:https://zookeeper.apache.org/doc/trunk/ ...

  3. [译]ZooKeeper recipes-引言

    ZooKeeper高级应用 本系列将指导使用ZooKeeper来实现高级功能,所有功能都在客户端完成,不需要ZooKeeper的特殊支持.希望可以得到社区的支持将这些加入到一个标准的客户端类库中(Cu ...

  4. [译]ZOOKEEPER RECIPES-Queues

    队列 分布式队列是一种常见的数据结构.为了在ZooKepeer中实现分布式队列,第一步是要使用一个znode代表队列本身.分布式客户端通过create()方法将内容放入一个名叫"queue- ...

  5. [译]ZOOKEEPER RECIPES-Leader Election

    选主 使用ZooKeeper选主的一个简单方法是,在创建znode时使用Sequence和Ephemeral标志.主要思想是,使用一个znode,比如"/election",每个客 ...

  6. [译]ZOOKEEPER RECIPES-TWO PHASED COMMIT

    两段式提交 两段式提交协议可以让所有分布式系统中的客户端达成协议同时提交或回滚事务. 在ZooKeeper中你可以通过协调者(coordinator)创建一个事务节点来实现两段式提交.例如" ...

  7. [译]ZOOKEEPER RECIPES-Barriers

    Barrier 在分布式系统中常使用Barrier来阻塞进程,当满足一定条件后再恢复进行后续操作.Barrier在Zookeeper中可以通过设计一个Barrier节点来实现.Barrier 节点存在 ...

  8. <译>Zookeeper官方文档

    apache原文地址:http://zookeeper.apache.org/doc/trunk/zookeeperOver.html ZooKeeper ZooKeeper: A Distribut ...

  9. [译]Zookeeper的优点与局限性

    1.Zookeeper的优点与局限性 在学习了Zookeeper(后文都简称zk)的介绍和功能后,您已经很好地理解了zk. 现在,在这个zk教程中,我们将讨论zk的优点和局限性. zk有几个功能对用户 ...

随机推荐

  1. a标签点击跳转失效--IE6、7的奇葩bug

    一般运用a标签包含img去实现点击图片跳转的功能,这是前端经常要用到的东西. 今天遇到个神奇的bug:如果在img上再包裹一层div,而且div设置了width和height,则图片区域点击时,无任何 ...

  2. wordpress多站点配置

    wordpress作为全球第一的个人博客搭建平台一直在国内外有着较高的人气,从3.0版本开始就已经支持多站点的搭建.该功能可以让子站点运行主站点的程序,不需要再每个站点分别存放网站程序.最近更新的4. ...

  3. 清空Github上某个文件的历史版本

    title: 清空Github上某个文件的历史版本 author: 青南 date: 2015-01-08 16:04:53 categories: [经验] tags: [Github,histor ...

  4. 实现代理设置proxy

    用户在哪些情况下是需要设置网络代理呢? 1. 内网上不了外网,需要连接能上外网的内网电脑做代理,就能上外网:多个电脑共享上外网,就要用代理: 2.有些网页被封,通过国外的代理就能看到这被封的网站:3. ...

  5. Android权限管理之RxPermission解决Android 6.0 适配问题

    前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...

  6. 算法与数据结构(八) AOV网的关键路径

    上篇博客我们介绍了AOV网的拓扑序列,请参考<数据结构(七) AOV网的拓扑排序(Swift面向对象版)>.拓扑序列中包括项目的每个结点,沿着拓扑序列将项目进行下去是肯定可以将项目完成的, ...

  7. Oracle数据库该如何着手优化一个SQL

    这是个终极问题,因为优化本身的复杂性实在是难以总结的,很多时候优化的方法并不是用到了什么高深莫测的技术,而只是一个思想意识层面的差异,而这些都很可能连带导致性能表现上的巨大差异. 所以有时候我们应该先 ...

  8. 就这么漂来漂去---一个毕业三个月的java程序员的裸辞风波

    注:这并不是一篇技术文章,而是记录了我这几个月经历的入职,裸辞,找工作的心路历程,简单介绍一个博主的情况,我是16年毕业生,校招进了一家北京的公司,java开发,和很多年轻人一样,干了一段时间,我发现 ...

  9. SharpMap简析

    1.背景 因为项目需求,需要基于开源项目来对SHP进行相关操作.涉及到的主要功能就是加载SHP读取其中的属性信息和几何信息.于是选择了Sharpmap来进行,在使用中对其相关功能做了初步了解,做个总结 ...

  10. hbase集群安装与部署

    1.相关环境 centos7 hadoop2.6.5 zookeeper3.4.9 jdk1.8 hbase1.2.4 本篇文章仅涉及hbase集群的搭建,关于hadoop与zookeeper的相关部 ...