最近准备在项目中引入分布式锁,故而研究基于zookeeper的curator框架。

网上资料不多,自己研究其源码发现,这个框架已经帮我做了很多现成的实现。

下面介绍下锁的实现:

通过源码中LockingExample例子作为切入(推荐多利用现有资源,最快切入),为减小篇幅,代码仅保留关键部分。

curator已经为我们准备好了锁的实现 ----InterProcessMutex,基于zookeeper跨jvm的公平互斥锁实现.

-----------------------------------------------------------------------------------------------------------------------------

1.看下锁的定义,将线程对象和锁对象(线程、路径、锁的数量)关联

    private final ConcurrentMap<Thread, LockData> threadData = Maps.newConcurrentMap();

    private static class LockData
{
final Thread owningThread;
final String lockPath;
final AtomicInteger lockCount = new AtomicInteger(1); private LockData(Thread owningThread, String lockPath)
{
this.owningThread = owningThread;
this.lockPath = lockPath;
}
}

2.获得锁:

  • 如果线程已经有锁,则增加锁的数量,返回  String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
  • 否则尝试获取锁,获得则加入线程持有锁的MAP,否则返回未获得锁。
    private final LockInternals internals;    

    @Override
public boolean acquire(long time, TimeUnit unit) throws Exception
{
return internalLock(time, unit);
}
private boolean internalLock(long time, TimeUnit unit) throws Exception
{
Thread currentThread = Thread.currentThread(); LockData lockData = threadData.get(currentThread);
if ( lockData != null )
{
lockData.lockCount.incrementAndGet();
return true;
} String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
if ( lockPath != null )
{
LockData newLockData = new LockData(currentThread, lockPath);
threadData.put(currentThread, newLockData);
return true;
}
return false;
}

3.可以看到,逻辑是基于LockInternals,来看一下他是怎么做到的

  • 通过dirver在锁目录下创建EPHEMERAL_SEQUENTIAL节点
  • 循环尝试获取,基于监听,wait,notifyAll
  1. 获取锁目录下子节点的有序集合
  2. 通过dirver尝试得到PredicateResults(含有是否得到锁及需要监视的目录)
  3. 更新监听信息,开始下一轮尝试
    String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception
{while ( !isDone )
{
isDone = true;
try
{
ourPath = driver.createsTheLock(client, path, localLockNodeBytes);
hasTheLock = internalLockLoop(startMillis, millisToWait, ourPath);
}
}
}
private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception
{
boolean haveTheLock = false;
boolean doDelete = false;
try
{
if ( revocable.get() != null )
{
client.getData().usingWatcher(revocableWatcher).forPath(ourPath);
} while ( (client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock )
{
List<String> children = getSortedChildren();
String sequenceNodeName = ourPath.substring(basePath.length() + 1); // +1 to include the slash PredicateResults predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);
if ( predicateResults.getsTheLock() )
{
haveTheLock = true;
}
else
{
String previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();
System.out.println("ourpath : " + ourPath + " : " + previousSequencePath); synchronized(this)
{
try
{
// use getData() instead of exists() to avoid leaving unneeded watchers which is a type of resource leak
client.getData().usingWatcher(watcher).forPath(previousSequencePath);
if ( millisToWait != null )
{
millisToWait -= (System.currentTimeMillis() - startMillis);
startMillis = System.currentTimeMillis();
if ( millisToWait <= 0 )
{
doDelete = true; // timed out - delete our node
break;
}
wait(millisToWait);
}
else
{
wait();
}
}
catch ( KeeperException.NoNodeException e )
{
}
}
}
}
}
catch ( Exception e )
{
doDelete = true;
throw e;
}
finally
{
if ( doDelete )
{
deleteOurPath(ourPath);
}
}
return haveTheLock;

4.分析下前文中的driver实现,即StandardLockInternalsDriver 关键代码

  • 创建锁是基于目录下创建的EPHEMERAL_SEQUENTIAL节点,即与客户端生命周期相同,并且名字后自动加创建的序列号
  • 得到PredicateResult,如果当前节点为最小节点,则得到锁,getsTheLock为true,否则得到该序列的前一个节点,设为pathToWatch,监控之
    @Override
public PredicateResults getsTheLock(CuratorFramework client, List<String> children, String sequenceNodeName, int maxLeases) throws Exception
{
int ourIndex = children.indexOf(sequenceNodeName);
validateOurIndex(sequenceNodeName, ourIndex);
boolean getsTheLock = ourIndex < maxLeases;
String pathToWatch = getsTheLock ? null : children.get(ourIndex - maxLeases);
return new PredicateResults(pathToWatch, getsTheLock);
} @Override
public String createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes) throws Exception
{
String ourPath;
if ( lockNodeBytes != null )
{
ourPath = client.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, lockNodeBytes);
}
else
{
ourPath = client.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);
}
return ourPath;
}

先发布,后续有心得再续。

curator 实现分布式一致性锁的更多相关文章

  1. Curator Zookeeper分布式锁

    Curator Zookeeper分布式锁 pom.xml中添加如下配置 <!-- https://mvnrepository.com/artifact/org.apache.curator/c ...

  2. 《从Paxos到ZooKeeper 分布式一致性原理与实践》读书笔记

    一.分布式架构 1.分布式特点 分布性 对等性.分布式系统中的所有计算机节点都是对等的 并发性.多个节点并发的操作一些共享的资源 缺乏全局时钟.节点之间通过消息传递进行通信和协调,因为缺乏全局时钟,很 ...

  3. 我读《从Paxos到zookeeper分布式一致性原理与实践》

    从年后拿到这本书开始阅读,到准备系统分析师考试之前,终于读完了一遍,对Zookeeper有了一个全面的认识,整本书从理论到应用再到细节的阐述,内容安排从逻辑性和实用性上都是很优秀的,对全面认识Zook ...

  4. 分布式一致性算法--Paxos

    Paxos算法是莱斯利·兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法.Paxos算法解决的问题是一个分布式系统如何就某个值(决议)达成一致.在工程实践意义上来说, ...

  5. 《从Paxos到ZooKeeper分布式一致性原理与实践》学习笔记

    第一章 分布式架构 1.1 从集中式到分布式 集中式的特点: 部署结构简单(因为基于底层性能卓越的大型主机,不需考虑对服务多个节点的部署,也就不用考虑多个节点之间分布式协调问题) 分布式系统是一个硬件 ...

  6. 分布式一致性算法2PC和3PC

    为了解决分布式一致性问题,产生了不少经典的分布式一致性算法,本文将介绍其中的2PC和3PC.2PC即Two-Phase Commit,译为二阶段提交协议.3PC即Three-Phase Commit, ...

  7. 分布式一致性算法——paxos

    一.什么是paxos算法 Paxos 算法是分布式一致性算法用来解决一个分布式系统如何就某个值(决议)达成一致的问题. 人们在理解paxos算法是会遇到一些困境,那么接下来,我们带着以下几个问题来学习 ...

  8. 基于Zookeeper实现的分布式互斥锁 - InterProcessMutex

    Curator是ZooKeeper的一个客户端框架,其中封装了分布式互斥锁的实现,最为常用的是InterProcessMutex,本文将对其进行代码剖析 简介 InterProcessMutex基于Z ...

  9. 搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法

    搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法 2PC 由于BASE理论需要在一致性和可用性方面做出权衡,因此涌现了很多关于一致性的算法和协议.其中比较著名的有二阶提交协议(2 Phas ...

随机推荐

  1. Authentication required (packagist.phpcomposer.com) 账号密码到哪里获取?

    安装好composer后,执行composer install 报这个错 面对这个错有两种方法.1,他说你的composr 版本不够稳定,composer update 一下,或者 composer ...

  2. Java Web项目如何做到升级不断掉服务,同时涉及到的相关问题

    Java Web项目如何做到升级不断掉服务,同时涉及到的相关问题 原文地址:https://m.oschina.net/question/737237_2203576 现在容器用的是tomcat,做维 ...

  3. [UE4]C++实现动态加载的问题:LoadClass<T>()和LoadObject<T>() 及 静态加载问题:ConstructorHelpers::FClassFinder()和FObjectFinder()

    转自:http://aigo.iteye.com/blog/2281558 动态加载UObject和动态加载UClass分别用LoadObject<T>(),和LoadClass<T ...

  4. sas 经验小结(1)

    1.重要的事情说三遍:在SAS中,对数据集操作要在OPTIONS中使用Compress=yes 能有效的降低文件的大小. 在SAS运行LOG中,可以看如下提示: NOTE: 压缩的数据集 T.PHON ...

  5. sas 命令行打开SAS IDE 的代码

    "C:\Program Files\SASHome\SASFoundation\9.4\sas.exe" -CONFIG "C:\Program Files\SASHom ...

  6. Shiro 五张表

    参考博客: http://blog.csdn.net/frankcheng5143/article/details/50836619 Filter:运行过程中改变进入资源的请求和资源返回的响应中的有效 ...

  7. Java - 24 Java 封装

    Java 封装 在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护屏障,防止该类的代码和数据被外 ...

  8. jQuery设置div的自适应布局

    一.HTML代码: <div class="ui-wraper" id="Wraper"> </div> 二.CSS代码: html { ...

  9. oi造数据

    #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #includ ...

  10. 部署django项目,sqlite3数据库出错sqlite3.NotSupportedError: URIs not supported

    如果遇到这个错误 sqlite3.NotSupportedError: URIs not supported 修改类似 该路径 的 base.py文件 /root/.virtualenvs/fkPy3 ...