基于临时序号节点来实现分布式锁

为什么要用临时节点呢?如果拿到锁的服务宕机了,会话失效ZK自己也会删除掉临时的序号节点,这样也不会阻塞其他服务。

流程:

1.在一个持久节点下面创建临时的序号节点作为锁节点,如:/lock/lockId00000001 /lock/lockId00000002

2.获取持久节点下面所有子节点,判断其最小的是不是自己,如果是自己则表示获取锁成功。

3.如果最小的结点不是自己,则阻塞等待,并对lock结点添加监听,如果结点数发生变化了,则说明有释放了锁。但是这里如果存在大量监听,当结点发生变化的时候,可能就会出现羊群效应。因为大家都监听了,同时会通知很多客户端,会造成ZK性能突然下降。

所以这里可以只监听自己前面的那个节点,排队执行,03监听02,02监听01

4.当锁释放,节点监听到变化之后,执行第2步。

释放锁只需要删除对应的临时节点,如果获取到锁的服务宕机了,因为是临时节点也会自己删除的。

代码实现:

package com.nijunyang.zookeeper.zklock;

import lombok.Data;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient; import java.util.List;
import java.util.stream.Collectors; /**
* Description:
* Created by nijunyang on 2020/11/29 21:51
*/
public class ZKLock {
private static final String SERVER = "192.168.0.67:2181";
private ZkClient zkClient;
private static final String ROOT_PATH = "/lock"; public ZKLock() {
zkClient = new ZkClient(SERVER, 5000, 20000);
buildRoot();
} private void buildRoot() {
if (!zkClient.exists(ROOT_PATH)) {
zkClient.createPersistent(ROOT_PATH);
}
} /**
* 加锁
*
* @param lockId
* @param timeout
* @return
*/
public Lock lock(String lockId, long timeout) {
Lock lockNode = createLock(lockId);
// 尝试激活锁
tryActiveLock(lockNode);
if (!lockNode.isActive()) {
try {
synchronized (lockNode) {
lockNode.wait(timeout);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (!lockNode.isActive()) {
throw new RuntimeException("获取锁超时");
}
return lockNode;
} /**
* 释放锁
*
* @param lock
*/
public void unlock(Lock lock) {
if (lock.isActive()) {
zkClient.delete(lock.getPath());
}
} /**
* 激活锁
* @param lockNode
*/
private void tryActiveLock(Lock lockNode) {
// 判断当前是否为最小节点
List<String> list = zkClient.getChildren(ROOT_PATH)
.stream()
.sorted()
.map(p -> ROOT_PATH + "/" + p)
.collect(Collectors.toList());
String firstNodePath = list.get(0); //第一个节点是当前节点,将锁设置为激活
if (firstNodePath.equals(lockNode.getPath())) {
lockNode.setActive(true);
} else {
//第一个节点不是当前节点,则监听前面一个节点
String upNodePath = list.get(list.indexOf(lockNode.getPath()) - 1);
zkClient.subscribeDataChanges(upNodePath, new IZkDataListener() {
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
}
@Override
public void handleDataDeleted(String dataPath) throws Exception {
//监听之后继续尝试加锁,加锁成功唤醒之前的等待
tryActiveLock(lockNode);
synchronized (lockNode) {
if (lockNode.isActive()) {
lockNode.notify();
}
}
zkClient.unsubscribeDataChanges(upNodePath, this);
}
});
}
}
/**
* 创建锁节点
*
* @param lockId
* @return Lock
*/
private Lock createLock(String lockId) {
String nodePath = zkClient.createEphemeralSequential(ROOT_PATH + "/" + lockId, "write");
return new Lock(lockId, nodePath);
} @Data
public static class Lock { private String lockId;
private String path;
/**
* 是否激活锁
*/
private boolean active; public Lock(String lockId, String path) {
this.lockId = lockId;
this.path = path;
}
}
}

Zookeeper(5)---分布式锁的更多相关文章

  1. zookeeper实现分布式锁服务

    A distributed lock base on zookeeper. zookeeper是hadoop下面的一个子项目, 用来协调跟hadoop相关的一些分布式的框架, 如hadoop, hiv ...

  2. [ZooKeeper.net] 3 ZooKeeper的分布式锁

    基于ZooKeeper的分布式锁 ZooKeeper 里实现分布式锁的基本逻辑: 1.zookeeper中创建一个根节点(Locks),用于后续各个客户端的锁操作. 2.想要获取锁的client都在L ...

  3. 基于 Zookeeper 的分布式锁实现

    1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...

  4. zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

  5. zookeeper 实现分布式锁安全用法

    zookeeper 实现分布式锁安全用法 标签: zookeeper sessionExpire connectionLoss 分布式锁 背景 ConnectionLoss 链接丢失 SessionE ...

  6. 基于Zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

  7. 转载 [ZooKeeper.net] 3 ZooKeeper的分布式锁

    [ZooKeeper.net] 3 ZooKeeper的分布式锁   基于ZooKeeper的分布式锁  源码分享:http://pan.baidu.com/s/1miQCDKk ZooKeeper ...

  8. Redis与Zookeeper实现分布式锁的区别

    Redis实现分布式锁 1.根据lockKey区进行setnx(set not exist,如果key值为空,则正常设置,返回1,否则不会进行设置并返回0)操作,如果设置成功,表示已经获得锁,否则并没 ...

  9. Zookeeper系列四:Zookeeper实现分布式锁、Zookeeper实现配置中心

    一.Zookeeper实现分布式锁 分布式锁主要用于在分布式环境中保证数据的一致性. 包括跨进程.跨机器.跨网络导致共享资源不一致的问题. 1. 分布式锁的实现思路 说明: 这种实现会有一个缺点,即当 ...

  10. 10分钟看懂!基于Zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

随机推荐

  1. 动态规划入门——动态规划与数据结构的结合,在树上做DP

    本文由TechFlow原创,本博文仅作为知识点学习,不会用于任何商业用途! 今天我们来看一个有趣的问题,通过这个有趣的问题,我们来了解一下在树形结构当中做动态规划的方法. 这个问题题意很简单,给定一棵 ...

  2. salesforce零基础学习(九十八)Salesforce Connect & External Object

    本篇参考: https://trailhead.salesforce.com/en/content/learn/modules/lightning_connect https://help.sales ...

  3. TCP性能分析与调优策略

    网络传输 传播延迟: 消息从发送端到接收端需要的时间,是信号传播距离和速度的函数 传输延迟: 把消息中的所有比特转移到链路中需要的时间,是消息长度和链路速率的函数 处理延迟: 处理分组首部.检查位错误 ...

  4. thinkphp之无限分类

    namespace Home\Controller; use Home\Controller; class CategoryController extends Controller { //无限分类 ...

  5. laravel 控制器中获取不到session

    protected $middleware = [ \Illuminate\Session\Middleware\StartSession::class, ]; 在 kernel.php中 加入Sta ...

  6. epoll内核源码详解(转 作者:赛罗·奥特曼 来源:牛客网)

    发现自己发的一篇面经后,很多小伙伴向我索要epoll的内核源码实现,那我就在牛客网发下这源码还有自己总结的流程. 另外 网上很多博客说epoll使用了共享内存,这个是完全错误的 ,可以阅读源码,会发现 ...

  7. 调用外部接口支持https请求

    1,创建RestTemplateConfig.java文件,内容如下: package com.htsec.monitor.internet.config;import com.htsec.monit ...

  8. 利用s3-test进行ceph的接口兼容性测试

    前言 ceph的rgw能够提供一个兼容性的s3的接口,既然是兼容性,当然不可能是所有接口都会兼容,那么我们需要有一个工具来进行接口的验证以及测试,这个在其他测试工具里面有类似的posix接口验证工具, ...

  9. Java中5种List的去重方法及它们的效率对比,你用对了吗?

    01.使用两个for循环实现List去重(有序) /**使用两个for循环实现List去重(有序)     *     * @param list     * */    public static  ...

  10. IGH_Master主站配置驱动伺服电机和变频器总结

    IGH_Master主站配置驱动伺服电机和变频器总结 Ethercat是倍福公司提出的一种工业现场总线协议,具有很好的实时性,IGH是一种开源的Ethercat主站实现协议,本文总结了一下使用IGH_ ...