服务注册中心之ZooKeeper系列(三) 实现分布式锁
通过ZooKeeper的有序节点、节点路径不回重复、还有节点删除会触发Wathcer事件的这些特性,我们可以实现分布式锁。
一、思路
- zookeeper中创建一个根节点Locks,用于后续各个客户端的锁操作。
- 当要获取锁的时候,在Locks节点下创建“Lock_序号”的零时有序节点(临时节点为了客户端突发断开连接,则此节点消失)。
- 如果没有得到锁,就监控排在自己前面的序号节点,等待它的释放。
- 当前面的锁被释放后,触发Process方法,然后继续获取当前子节点,判断当前节点是不是第一个,是 返回锁,否 获取锁失败。
二、实现
在实现是要了解一个类 AutoResetEvent。AutoResetEvent 常常被用来在两个线程之间进行信号发送。它有两个重要的方法:
Set() :发送信号到等待线程以继续其工作。
bool WaitOne():等待另一个线程发信号,只有收到信号,线程才继续往下执行 ,会一直等待下去,返回值表示是否收到信号。
bool WaitOne(int millisecondsTimeout):等待指定时间,如果没有收到信号继续执行,返回值表示是否收到信号。
下面为具体实现方法:
public class ZooKeeperLock
{
private MyWatcher myWatcher; private string lockNode; private org.apache.zookeeper.ZooKeeper zooKeeper; public ZooKeeperLock()
{
myWatcher = new MyWatcher();
} /// <summary>
/// 获取锁
/// </summary>
/// <param name="millisecondsTimeout">等待时间</param>
/// <returns></returns>
public async Task<bool> TryLock(int millisecondsTimeout = )
{
try
{
zooKeeper = new org.apache.zookeeper.ZooKeeper("127.0.0.1", , new MyWatcher()); //创建锁节点
if (await zooKeeper.existsAsync("/Locks") == null)
await zooKeeper.createAsync("/Locks", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); //新建一个临时锁节点
lockNode = await zooKeeper.createAsync("/Locks/Lock_", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); //获取锁下所有节点
var lockNodes = await zooKeeper.getChildrenAsync("/Locks"); lockNodes.Children.Sort(); //判断如果创建的节点就是最小节点 返回锁
if (lockNode.Split("/").Last() == lockNodes.Children[])
return true;
else
{
//当前节点的位置
var location = lockNodes.Children.FindIndex(n => n == lockNode.Split("/").Last());
//获取当前节点 前面一个节点的路径
var frontNodePath = lockNodes.Children[location - ];
//在前面一个节点上加上Watcher ,当前面那个节点删除时,会触发Process方法
await zooKeeper.getDataAsync("/Locks/" + frontNodePath, myWatcher); //如果时间为0 一直等待下去
if (millisecondsTimeout == )
myWatcher.AutoResetEvent.WaitOne();
else //如果时间不为0 等待指定时间后,返回结果
{
var result = myWatcher.AutoResetEvent.WaitOne(millisecondsTimeout); if (result)//如果返回True,说明在指定时间内,前面的节点释放了锁(但是可能是中间节点主机宕机 导致,所以不一定触发了Process方法就是得到了锁。需要重新判断是不是第一个节点)
{
//获取锁下所有节点
lockNodes = await zooKeeper.getChildrenAsync("/Locks");
//判断如果创建的节点就是最小节点 返回锁
if (lockNode.Split("/").Last() == lockNodes.Children[])
return true;
else
return false;
}
else
return false; }
}
}
catch (KeeperException e)
{
await UnLock();
throw e;
}
return false;
} /// <summary>
/// 释放锁
/// </summary>
/// <returns></returns>
public async Task UnLock()
{
try
{
myWatcher.AutoResetEvent.Dispose();await zooKeeper.deleteAsync(lockNode);
}
catch (KeeperException e)
{
throw e;
}
} }
Process方法实现:
public class MyWatcher : Watcher
{
public AutoResetEvent AutoResetEvent; public MyWatcher()
{
this.AutoResetEvent = new AutoResetEvent(false);
} public override Task process(WatchedEvent @event)
{
if (@event.get_Type() == EventType.NodeDeleted)
{
AutoResetEvent.Set();
}
return null;
}
}
本文源代码在:分布式实现代码
如果你认为文章写的不错,就点个【推荐】吧
服务注册中心之ZooKeeper系列(三) 实现分布式锁的更多相关文章
- 服务注册中心之ZooKeeper系列(一)
一.服务注册中心介绍 分布式服务框架部署在多台不同的机器上.例如服务A是订单相关的处理服务,服务B是订单的客户的相关信息服务.此时有个需求需要在服务A中获取订单客户的信息.如下图: 此时就面临以下几个 ...
- 服务注册中心之ZooKeeper系列(二) 实现一个简单微服务之间调用的例子
上一篇文章简单介绍了ZooKeeper,讲了分布式中,每个微服务都会部署到多台服务器上,那服务之间的调用是怎么样的呢?如图: 1.集群A中的服务调用者如何发现集群B中的服务提供者呢? 2.集群A中的服 ...
- 基于ZooKeeper的三种分布式锁实现
[欢迎关注公众号:程序猿讲故事 (codestory),及时接收最新文章] 今天介绍基于ZooKeeper的分布式锁的简单实现,包括阻塞锁和非阻塞锁.同时增加了网上很少介绍的基于节点的非阻塞锁实现,主 ...
- Zookeeper系列3 实现分布式锁
基本思路 1 client调用create()方法创建“/locks/_lock_”临时顺序节点,注意节点类型是EPHEMERAL_SEQUENTIAL 2 client调用getChildren(& ...
- [源码阅读] 阿里SOFA服务注册中心MetaServer(1)
[源码阅读] 阿里SOFA服务注册中心MetaServer(1) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(1) 0x00 摘要 0x01 服务注册中心 1.1 服务注册中心简 ...
- [源码阅读] 阿里SOFA服务注册中心MetaServer(2)
[源码阅读] 阿里SOFA服务注册中心MetaServer(2) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(2) 0x00 摘要 0x01 MetaServer 注册 1.1 ...
- [源码阅读] 阿里SOFA服务注册中心MetaServer(3)
[源码阅读] 阿里SOFA服务注册中心MetaServer(3) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(3) 0x00 摘要 0x01 概念 1.1 分布式一致性 1.2 ...
- spring cloud 入门系列三:使用Eureka 搭建高可用服务注册中心
在上一篇中分享了如何使用Eureka 进行服务治理,里面搭建的服务注册中心是单体的, 但是在实际的应用中,分布式系统为了防止单体服务宕机带来严重后果,一般都会采用服务器集群的形式,服务注册中心也是一样 ...
- 服务注册中心Eureka vs Zookeeper vs Consul
前言 在现在云计算和大数据快速发展的今天,业务快速发展和变化.我们以前的单一应用难以应对这种快速的变化, 因此我们需要将以前单一的大应用不断进行差分,分成若干微小的应用或者服务,这就是微服务的思想.但 ...
随机推荐
- 添加sqljdbc的maven依赖JAVA环境配置
sqljdbc是微软sql server的jdbc驱动 使用sqljdbc需要从微软的官方网站下载jar包: http://www.microsoft.com/en-us/download/detai ...
- CSS3新增特性及知识学习线路
- aji unorder_map
- 【python-时间戳】时间与时间戳之间的转换
对于时间数据,如2016-05-05 20:28:54,有时需要与时间戳进行相互的运算,此时就需要对两种形式进行转换,在Python中,转换时需要用到time模块,具体的操作有如下的几种: 将时间转换 ...
- ubuntu16.04下安装g2o
根本不需要编译源码直接一行命令就可以 sudo apt-get install libpcl-dev 如果没有安装pcl_viewer就再加一行命令 sudo apt-get install pcl- ...
- Leetcode35 Search Insert Position 解题思路(python)
本人编程小白,如果有写的不对.或者能更完善的地方请个位批评指正! 这个是leetcode的第35题,这道题的tag是数组,python里面叫list,需要用到二分搜索法 35. Search Inse ...
- 【分布式缓存系列】Redis实现分布式锁的正确姿势
一.前言 在我们日常工作中,除了Spring和Mybatis外,用到最多无外乎分布式缓存框架——Redis.但是很多工作很多年的朋友对Redis还处于一个最基础的使用和认识.所以我就像把自己对分布式缓 ...
- Dubbo 源码分析 - 集群容错之 Router
1. 简介 上一篇文章分析了集群容错的第一部分 -- 服务目录 Directory.服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由.上一篇文章关于服务路由相关逻辑没有 ...
- Jquery中attr()与prop()的区别
在jQuery中,attr()函数和prop()函数都用于设置或获取指定的属性,它们的参数和用法也几乎完全相同.但是,这两个函数的用处却并不相同.下面我们来详细介绍这两个函数之间的区别. 1.操作对象 ...
- DOM1级问题与DOM2级事件
前几天有小伙伴问过我一个问题,为什么有DOM 0级事件以及DOM2级事件,但是却没有DOM1级事件呢?那我们今天就来说一说DOM的级别问题. 同时推荐伙伴们可以看看尚学堂有关JavaScript BO ...