- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章分析ZooKeeper分布式锁的实现由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
方案 | 实现思路 | 优点 | 缺点 |
---|---|---|---|
利用 mysql 的实现方案 | 利用数据库自身提供的锁机制实现,要求数据库支持行级锁 | 实现简单 | 性能差,无法适应高并发场景;容易出现死锁的情况;无法优雅的实现阻塞式锁 |
利用 redis 的实现方案 | 使用 setnx 和 lua 脚本机制实现,保证对缓存操作序列的原子性 | 性能好 | 实现相对复杂,有可能出现死锁;无法优雅的实现阻塞式锁 |
利用 zookeeper 的实现方案 | 基于 zookeeper 节点特性及 watch 机制实现 | 性能好,稳定可靠性高,能较好地实现阻塞式锁 | 实现相对复杂 |
这里使用 zookeeper 来实现分布式锁,以50个并发请求来获取订单编号为例,描述两种方案,第一种为基础实现,第二种在第一种基础上进行了优化.
流程描述:
具体代码:
ordernumgenerator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/
*
*
*
@description 生成随机订单号
*
/
public
class
ordernumgenerator {
private static
long
count
=
0
;
/
*
*
*
使用日期加数值拼接成订单号
*
/
public string getordernumber() throws exception {
string date
=
datetimeformatter.ofpattern(
"yyyymmddhhmmss"
).
format
(localdatetime.now());
string number
=
new decimalformat(
"000000"
).
format
(count
+
+
);
return
date
+
number;
}
}
|
lock:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/
*
*
*
@description 自定义锁接口
*
/
public interface lock {
/
*
*
*
获取锁
*
/
public void getlock();
/
*
*
*
释放锁
*
/
public void unlock();
}
|
abstractlock:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/
*
*
*
@description 定义一个模板,具体的方法由子类来实现
*
/
public abstract
class
abstractlock implements lock {
/
*
*
*
获取锁
*
/
@override
public void getlock() {
if
(trylock()) {
system.out.println(
"--------获取到了自定义lock锁的资源--------"
);
}
else
{
/
/
没拿到锁则阻塞,等待拿锁
waitlock();
getlock();
}
}
/
*
*
*
尝试获取锁,如果拿到了锁返回true,没有拿到则返回false
*
/
public abstract boolean trylock();
/
*
*
*
阻塞,等待获取锁
*
/
public abstract void waitlock();
}
|
zookeeperabstractlock:
1
2
3
4
5
6
7
8
9
10
11
|
/
*
*
*
@description 定义需要的服务连接
*
/
public abstract
class
zookeeperabstractlock extends abstractlock {
private static final string server_addr
=
"192.168.182.130:2181,192.168.182.131:2181,192.168.182.132:2181"
;
protected zkclient zkclient
=
new zkclient(server_addr);
protected static final string path
=
"/lock"
;
}
|
zookeeperdistrbutelock:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
/
*
*
*
@description 真正实现锁的细节
*
/
public
class
zookeeperdistrbutelock extends zookeeperabstractlock {
private countdownlatch countdownlatch
=
null;
/
*
*
*
尝试拿锁
*
/
@override
public boolean trylock() {
try
{
/
/
创建临时节点
zkclient.createephemeral(path);
return
true;
} catch (exception e) {
/
/
创建失败报异常
return
false;
}
}
/
*
*
*
阻塞,等待获取锁
*
/
@override
public void waitlock() {
/
/
创建监听
izkdatalistener izkdatalistener
=
new izkdatalistener() {
@override
public void handledatachange(string s,
object
o) throws exception {
}
@override
public void handledatadeleted(string s) throws exception {
/
/
释放锁,删除节点时唤醒等待的线程
if
(countdownlatch !
=
null) {
countdownlatch.countdown();
}
}
};
/
/
注册监听
zkclient.subscribedatachanges(path, izkdatalistener);
/
/
节点存在时,等待节点删除唤醒
if
(zkclient.exists(path)) {
countdownlatch
=
new countdownlatch(
1
);
try
{
countdownlatch.await();
} catch (interruptedexception e) {
e.printstacktrace();
}
}
/
/
删除监听
zkclient.unsubscribedatachanges(path, izkdatalistener);
}
/
*
*
*
释放锁
*
/
@override
public void unlock() {
if
(zkclient !
=
null) {
system.out.println(
"释放锁资源"
);
zkclient.delete(path);
zkclient.close();
}
}
}
|
测试效果:使用50个线程来并发测试zookeeper实现的分布式锁 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/
*
*
*
@description 使用
50
个线程来并发测试zookeeper实现的分布式锁
*
/
public
class
orderservice {
private static
class
ordernumgeneratorservice implements runnable {
private ordernumgenerator ordernumgenerator
=
new ordernumgenerator();;
private lock lock
=
new zookeeperdistrbutelock();
@override
public void run() {
lock.getlock();
try
{
system.out.println(thread.currentthread().getname()
+
", 生成订单编号:"
+
ordernumgenerator.getordernumber());
} catch (exception e) {
e.printstacktrace();
}
finally
{
lock.unlock();
}
}
}
public static void main(string[] args) {
system.out.println(
"----------生成唯一订单号----------"
);
for
(
int
i
=
0
; i <
50
; i
+
+
) {
new thread(new ordernumgeneratorservice()).start();
}
}
}
|
方案二在方案一的基础上进行优化,避免产生“羊群效应”,方案一一旦临时节点删除,释放锁,那么其他在监听这个节点变化的线程,就会去竞争锁,同时访问 zookeeper,那么怎么更好的避免各线程的竞争现象呢,就是使用临时顺序节点,临时顺序节点排序,每个临时顺序节点只监听它本身的前一个节点变化.
流程描述:
具体代码 。
具体只需要将方案一中的 zookeeperdistrbutelock 改变,增加一个 zookeeperdistrbutelock2,测试代码中使用 zookeeperdistrbutelock2 即可测试,其他代码都不需要改变.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
/
*
*
*
@description 真正实现锁的细节
*
/
public
class
zookeeperdistrbutelock2 extends zookeeperabstractlock {
private countdownlatch countdownlatch
=
null;
/
*
*
*
当前请求节点的前一个节点
*
/
private string beforepath;
/
*
*
*
当前请求的节点
*
/
private string currentpath;
public zookeeperdistrbutelock2() {
if
(!zkclient.exists(path)) {
/
/
创建持久节点,保存临时顺序节点
zkclient.createpersistent(path);
}
}
@override
public boolean trylock() {
/
/
如果currentpath为空则为第一次尝试拿锁,第一次拿锁赋值currentpath
if
(currentpath
=
=
null || currentpath.length()
=
=
0
) {
/
/
在指定的持久节点下创建临时顺序节点
currentpath
=
zkclient.createephemeralsequential(path
+
"/"
,
"lock"
);
}
/
/
获取所有临时节点并排序,例如:
000044
list
<string> childrenlist
=
zkclient.getchildren(path);
collections.sort(childrenlist);
if
(currentpath.equals(path
+
"/"
+
childrenlist.get(
0
))) {
/
/
如果当前节点在所有节点中排名第一则获取锁成功
return
true;
}
else
{
int
wz
=
collections.binarysearch(childrenlist, currentpath.substring(
6
));
beforepath
=
path
+
"/"
+
childrenlist.get(wz
-
1
);
}
return
false;
}
@override
public void waitlock() {
/
/
创建监听
izkdatalistener izkdatalistener
=
new izkdatalistener() {
@override
public void handledatachange(string s,
object
o) throws exception {
}
@override
public void handledatadeleted(string s) throws exception {
/
/
释放锁,删除节点时唤醒等待的线程
if
(countdownlatch !
=
null) {
countdownlatch.countdown();
}
}
};
/
/
注册监听,这里是给排在当前节点前面的节点增加(删除数据的)监听,本质是启动另外一个线程去监听前置节点
zkclient.subscribedatachanges(beforepath, izkdatalistener);
/
/
前置节点存在时,等待前置节点删除唤醒
if
(zkclient.exists(beforepath)) {
countdownlatch
=
new countdownlatch(
1
);
try
{
countdownlatch.await();
} catch (interruptedexception e) {
e.printstacktrace();
}
}
/
/
删除对前置节点的监听
zkclient.unsubscribedatachanges(beforepath, izkdatalistener);
}
/
*
*
*
释放锁
*
/
@override
public void unlock() {
if
(zkclient !
=
null) {
system.out.println(
"释放锁资源"
);
zkclient.delete(currentpath);
zkclient.close();
}
}
}
|
以上就是分析zookeeper分布式锁的实现的详细内容,更多关于zookeeper分布式锁的资料请关注我其它相关文章! 。
原文链接:https://www.cnblogs.com/itwxe/p/14948383.html 。
最后此篇关于分析ZooKeeper分布式锁的实现的文章就讲到这里了,如果你想了解更多关于分析ZooKeeper分布式锁的实现的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我最近安装了一个带有 Exhibitor 的新 ZK 节点,它开始正常。当我执行 telnet localhost 2181 然后运行 stats 以查看版本时,即使我安装了 3.4.11,我仍然
每 the zookeeper docs , 可以创建一种以“ super ”用户身份访问 Zookeeper 集合的方法。这样做的方向在配置和连接方法方面都有些模糊。它确实巧妙地表明这只能通过 Ja
场景如下: Znode 创建:create/config 12345(例如创建于12/12/12) 更新此配置,设置/config 34567(例如在 2013 年 12 月 12 日修改) 一个月后
使用Zookeeper API,是否可以知道当前服务器是否是Zookeeper集群的leader? 文档提到领导者看到了所有追随者中最高的zxid。。是否有可能以某种方式检查? 最佳答案 您可以从不同
我正在学习 ZooKeeper 并研究备份存储在 ZooKeeper 中的数据的选项。 ZooKeeper 写入两个数据文件,快照和事务日志。人们经常提到快照是“模糊的”,需要重放事务日志以获取最新状
用例:一个池中有 100 个服务器;我想在每个服务器上启动一个 ZooKeeper 服务,服务器应用程序(ZooKeeper 客户端)将使用 ZooKeeper 集群(读/写)。那么就没有单点故障。
我正在运行 3 节点 zookeeper 集群来处理 Storm 和 kafka.Zookeeper 数据目录占用了我系统中的所有空间。我不知道如何清理它。因为,我不想完全删除数据,因为我会丢失进程的
我是 Zookeeper 的新手,试图了解它是否适合我的用例。 我有 1000 万个分层数据,我想将它们存储在 Zookeeper 中。 10M 键值对,键值对大小分别为 1KB。 因此,在没有复
在 here 有人说: "even if you read from a different follower every time, you'll never see version 3 of th
Zookeeper 临时节点是否写入磁盘? 我知道在 Zookeeper 确认写入客户端之前,正常的 Zookeeper 节点已写入磁盘。 但是,临时节点仅在客户端 session 期间持续,因此如果
在开发阶段使用zookeeper大约6个月后,虽然运行良好,但其数据目录的大小增长到 6 GIG !而且还在增加。下面列出了一些系统规范: zookeeper version: 3.4.6 numbe
我试图了解 Apache ZooKeeper 在裂脑情况下的内部工作原理。假设有一个由 5 个服务器组成的集群:A、B、C、D 和 E,其中 A 是领导者。现在假设子簇 {A, B} 与子簇 {C,
动物园管理员专家。 我问的问题对你来说可能很基础,但我是 ZK 的新手,我还没有掌握该工具,所以请原谅。考虑到这一点,这是我的问题。 假设我有一个由 5 个服务器组成的 ZK 集群,我有 3 个法定人
我正在尝试了解 Zookeeper 中的分层仲裁。文档 here 举了一个例子,但我仍然不确定我是否理解它。我的问题是,如果我有一个双节点 Zookeeper 集群(我知道不推荐这样做,但为了这个例子
我们使用的是2.3.0版本的curator-framework连接pom文件中的zookeeper。 org.apache.curator curator-fram
我们在开发机器上有一个独立的 zookeeper 设置。除了这台 testdev 机器之外,它适用于所有其他开发机器。 尝试通过 testdev 连接到 zookeeper 时,我们一遍又一遍地收到此
zookeeper 事务日志变得非常大(数千兆字节!)并且集群的每台机器中始终存在一个或最多两个事务日志文件,因为知道可能存在多个快照! .. 引入 autopurge.purgeInterval 和
本文整理了Java中org.apache.flink.shaded.zookeeper.org.apache.zookeeper.ZooKeeper.getSessionId()方法的一些代码示例,展
我需要一些帮助来使用 zookeeper-shell.sh 验证 znode(path) 是否存在于 zookeeper 中 示例:bin/zookeeper-shell.sh zk:9091 ls/
我需要使用 tcpdump 调试我的 kafka 消费者和 zookeeper 之间交换的数据。我浏览了 zookeeper 文档,但找不到任何关于 zookeeper 通信协议(protocol)的
我是一名优秀的程序员,十分优秀!