服务注册中心之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
前言 在现在云计算和大数据快速发展的今天,业务快速发展和变化.我们以前的单一应用难以应对这种快速的变化, 因此我们需要将以前单一的大应用不断进行差分,分成若干微小的应用或者服务,这就是微服务的思想.但 ...
随机推荐
- Spring-boot在windows上安装CLI(Command Line Interface)的步骤!
首先去下载安装包,我这里整了一个zip包,一个tar包,下载地址:https://github.com/zhangyawei117/Spring-boot-CLI.git 下载完了之后,把zip包解压 ...
- 记录一下msf的学习使用
刚刚用Metasploit Pro scan了一下云端服务器.RHOST直接输IP就好. 得到反馈如下: [*] [2019.04.04-14:27:35] Scan initiated: Speed ...
- K-DTree学习
应用于K维数据的快速查找,比如横坐标,纵坐标,价格……,本模板以16青岛区域赛K题为例 —— 三维K - D Tree 模板 我们应该都见过平衡树吧,那就是1-D树,变成k维之后,我们连续分割1 - ...
- 项目设计day1
项目内容:一个实时监控斗鱼TV某个主播弹幕的设计 通过python爬虫获取当前弹幕,通过flume采集数据,接下来数据分为线上和线下两种方案: 线上:实时分析,分为两种方案:(1) flume+kaf ...
- Python OR & AND
These are the Boolean operations, ordered by ascending priority: Operation Result Notes x or y if x ...
- YxCMS 1.4.7 最新版漏洞分析
i春秋作家:F0rmat 原文来自:YxCMS 1.4.7 最新版漏洞分析 0x01前言 很感谢关注我专辑的表哥,我会坚持写下去的,最近会慢一点,一月四篇是正常的. 在先知看到的,大部分都是后台漏洞, ...
- IDEA远程Debug
进行远程debug是我们排查线上bug的一个最常用的工具,本篇博文就简单介绍一下如何使用IDEA来进行远程debug 1. 修改Tomcat配置文件 修改bin目录下的catalina.sh文件,在文 ...
- Java 线程池的原理及实现
1.线程池简介: 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力. 假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线 ...
- java中的http请求的封装(GET、POST、form表单形式)
目前JAVA实现HTTP请求的方法用的最多的有两种:一种是通过HTTPClient这种第三方的开源框架去实现.HTTPClient对HTTP的封装性比较不错,通过它基本上能够满足我们大部分的需求,Ht ...
- 使用线程统计信息(Thread Statistics)
可在session log中使用线程统计信息来判断source,target或组的性能瓶颈 默认情况下,Integration Service在运行session时,使用一个reader thread ...