ZooKeeper Distributed lock
- https://segmentfault.com/a/1190000016351095
- http://www.dengshenyu.com/java/分布式系统/2017/10/23/zookeeper-distributed-lock.html
Test
Enumerable.Range(1, 5).ToList().ForEach(i =>
{
Task.Run(() =>
{
var lockHelper = new ZooKeeperLockHelper("localhost:5181");
lockHelper.OnAcquireLock += (id) =>
{
var random = new Random().Next(10);
Log.Debug("NodeId {@id} executing.....Sleep {@ms} ms", id, random * 1000);
Thread.Sleep(random * 1000);
Log.Debug("NodeId {@id} executing success", id);
return Task.CompletedTask;
};
lockHelper.AcquireLock();
});
});
using org.apache.zookeeper;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace RedisDemo
{
public class ZooKeeperLockHelper : Watcher, IDisposable
{
#region event
public event Func<long, Task> OnAcquireLock;
#endregion
private bool _disposed;
private ZooKeeper _zooKeeper;
private Event.KeeperState _currentState;
private AutoResetEvent _notifyEvent = new AutoResetEvent(false);
private string _connectionString;
private bool _hasAcquireLock;
private string _lockPath;
private long _currentNodeId;
private static readonly string DEFAULT_PATH = "/zk";
private static readonly string NODE_NAME = "node-";
public ZooKeeperLockHelper(string connectionString)
{
_connectionString = connectionString;
this.Initialize(_connectionString, TimeSpan.FromSeconds(60));
}
public void AcquireLock(string path = "")
{
if (this._hasAcquireLock)
{
FireAcquireLock(this._currentNodeId).Wait();
return;
}
if (!WaitConnected(TimeSpan.FromSeconds(10)))
{
throw new Exception($"{_connectionString} Cannot Connect ZooKeeper");
}
_lockPath = path;
if (string.IsNullOrEmpty(_lockPath))
{
_lockPath = DEFAULT_PATH;
}
var nodePath = _lockPath + "/" + NODE_NAME;
var spath = this._zooKeeper.createAsync(
nodePath, Encoding.UTF8.GetBytes("data"),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL).Result;
this._currentNodeId = ParseNodeId(spath);
var reuslt = this._zooKeeper.getChildrenAsync(_lockPath, true).GetAwaiter().GetResult();
Log.Debug("#-> Begin Acquire Lock CurrentId {@id}", _currentNodeId);
if (this.IsMinNodeId(reuslt, this._currentNodeId))
{
lock (this)
{
if (!this._hasAcquireLock)
{
Log.Debug("NodeId {@id} Direct Acquire Lock", _currentNodeId);
this._hasAcquireLock = true;
this.FireAcquireLock(this._currentNodeId).Wait();
}
}
}
}
protected bool IsMinNodeId(ChildrenResult childrenResult, long nodeId)
{
if (nodeId == 0 || childrenResult == null || childrenResult.Children.Count == 0)
return false;
var nodeIds = new List<long>();
foreach (var item in childrenResult.Children)
{
nodeIds.Add(ParseNodeId(item));
}
if (nodeIds.Count > 0 && nodeIds.Min() == nodeId)
{
return true;
}
return false;
}
protected long ParseNodeId(string path)
{
var m = Regex.Match(path, "(\\d+)");
if (m.Success)
{
return long.Parse(m.Groups[0].Value);
}
return 0L;
}
protected void Initialize(String connectionString, TimeSpan sessionTimeout)
{
this._zooKeeper = new ZooKeeper(connectionString, (int)sessionTimeout.TotalMilliseconds, this);
}
public Task FireAcquireLock(long id)
{
this.OnAcquireLock(id).Wait();
this.CloseConnection();
Log.Debug("NodeId {@id} Close ZooKeeper Success", id);
return Task.CompletedTask;
}
public bool WaitConnected(TimeSpan timeout)
{
var continueWait = false;
while (this._currentState != Event.KeeperState.SyncConnected)
{
continueWait = _notifyEvent.WaitOne(timeout);
if (!continueWait)
{
return false;
}
}
return true;
}
protected void CloseConnection()
{
if (_disposed)
{
return;
}
_disposed = true;
if (_zooKeeper != null)
{
try
{
this._zooKeeper.closeAsync().ConfigureAwait(false).GetAwaiter().GetResult();
}
catch { }
}
}
#region Watcher Impl
public override Task process(WatchedEvent @event)
{
if (@event.getState() == Event.KeeperState.SyncConnected)
{
if (String.IsNullOrEmpty(@event.getPath()))
{
this._currentState = @event.getState();
this._notifyEvent.Set();
}
var path = @event.getPath();
if (!string.IsNullOrEmpty(path))
{
if (path.Equals(this._lockPath))
{
Log.Debug("NodeId {@id} Start Watcher Callback", this._currentNodeId);
if (this._hasAcquireLock)
{
Log.Debug("NodeId {@id} Has Acquire Lock return", this._currentNodeId);
return Task.CompletedTask;
}
Task.Run(() =>
{
var childrenResult = _zooKeeper.getChildrenAsync(this._lockPath, this).Result;
if (IsMinNodeId(childrenResult, this._currentNodeId))
{
lock (this)
{
if (!this._hasAcquireLock)
{
Log.Debug("NodeId {@id} Acquire Lock", this._currentNodeId);
this._hasAcquireLock = true;
this.FireAcquireLock(this._currentNodeId).Wait();
}
}
}
});
//_zooKeeper.getChildrenAsync(_lockPath, this);
}
}
}
return Task.CompletedTask;
}
public void Dispose()
{
this.CloseConnection();
}
#endregion
}
}
ZooKeeper Distributed lock的更多相关文章
- distributed lock manager (DLM)(分布式管理锁)
A distributed lock manager (DLM) provides distributed software applications with a means to synchron ...
- Redis Distributed lock
using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using ...
- 基于ZooKeeper的分布式锁和队列
在分布式系统中,往往需要一些分布式同步原语来做一些协同工作,上一篇文章介绍了Zookeeper的基本原理,本文介绍下基于Zookeeper的Lock和Queue的实现,主要代码都来自Zookeeper ...
- zookeeper实现分布式锁服务
A distributed lock base on zookeeper. zookeeper是hadoop下面的一个子项目, 用来协调跟hadoop相关的一些分布式的框架, 如hadoop, hiv ...
- How to do distributed locking
How to do distributed locking 怎样做可靠的分布式锁,Redlock 真的可行么? 本文是对 Martin Kleppmann 的文章 How to do distribu ...
- 基于Apache Curator框架的ZooKeeper使用详解
一 简介 Apache Curator是一个比较完善的ZooKeeper客户端框架,通过封装的一套高级API 简化了ZooKeeper的操作.通过查看官方文档,可以发现Curator主要解决了三类问题 ...
- 基于zookeeper实现的分布式锁
基于zookeeper实现的分布式锁 2011-01-27 • 技术 • 7 条评论 • jiacheo •14,941 阅读 A distributed lock base on zookeeper ...
- zookeeper生产最广泛使用java客户端curator介绍及其它客户端比较
关于zookeeper的原理解析,可以参见zookeeper核心原理详解,本文所述大多数实践基于对zookeeper原理的首先理解. Curator是Netflix公司开源的一个Zookeeper客户 ...
- 01 . 消息队列之(Kafka+ZooKeeper)
消息队列简介 什么是消息队列? 首先,我们来看看什么是消息队列,维基百科里的解释翻译过来如下: 队列提供了一种异步通信协议,这意味着消息的发送者和接受者不需要同时与消息保持联系,发送者发送的消息会存储 ...
随机推荐
- canvas手势解锁源码
先放图 demo.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- Tensor--tensorflow的数据类型
在tensorflow2.0版本之前,1.x版本的tensorflow的基本数据类型有计算图(Computation Graph)和张量(Tensor)两种,但tensorflow2.0之后的版本取消 ...
- 【spring boot】SpringBoot初学(2.2)– SpEL表达式读取properties属性到Java对象
前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置:(注意测试方法在,test下的SpelValueApplicationTest.c ...
- Django中非视图函数获取用户对象
今天遇到了一个问题:在Django中怎么从非视图函数中获取用户对象?怎么保证不同的请求获取到不同的用户对象? 平常我们获取用户对象使用的是: request.user 不得不说,这确实很方便. 但是, ...
- 【整理】IC失效机理(持续更新)
IC 四种常见失效机理如下: EM -- electron migration,电子迁移)TDDB -- time dependent dielectric breakdown,与时间相关电 ...
- WeUI基础样式库——写一个移动端界面
WeUI是一套基础样式库,同微信原生视觉体验一致,由微信官方设计团队为微信内网页和微信小程序量身设计的.我们来看看这个基础库样式到底长什么样. 这些密密麻麻的就是压缩后的样式库.密密麻麻地看起来简直要 ...
- 使用uni-app开发小程序,关于小程序更新后与用户本地不会及时更新解决办法
1.原因分析 在小程序更新开发版本之后,用户本地并没有对之前版本的小程序进行删除,那么再进入小程序的时候的版本是不会发生变化的,这是由于发版是异步执行,因此新版本将会覆盖的比较慢,本质是小程序的启动方 ...
- react-父子子孙组件嵌套-context
方案一 import React from 'react' import ReactTypes from 'prop-types' /* // 最外层的父组件 export default class ...
- Java如何自定义注解
本文主要是记录所学,以供后续参考.注解是Java 1.5引入的,Java自定义注解是通过运行时靠反射获取注解,注解相当于是一种嵌入在程序中的元数据,可以使用注解解析工具或编译器对其进行解析,也可以指定 ...
- SSRF服务器端请求伪造
SSRF漏洞原理 SSRF(Server-Side Request Forgery:服务器端请求伪造)是一种由恶意访问者构造形成由服务端发起请求的一个安全漏洞一般情况下,SSRF访问的目标是从外网无法 ...