本文为博主原创,未经允许不得转载:

  1. zookeeper 分布式锁应用场景及特点分析

  2. zookeeper 分布式原理

  3. curator 实现分布式锁

  

1. zookeeper 分布式锁:

  (1)优点:ZooKeeper分布式锁(如InterProcessMutex),能有效的解决分布式问题,不可重入问题,使用起来也较为简单。

  (2)缺点:ZooKeeper实现的分布式锁,性能并不太高。为啥呢?

    因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。大家知道,ZK中创建和删除节点只能通过Leader服务器来执行,

  然后Leader服务器还需要将数据同不到所有的Follower机器上,这样频繁的网络通信,性能的短板是非常突出的。

    总之,在高性能,高并发的场景下,不建议使用ZooKeeper的分布式锁。而由于ZooKeeper的高可用特性,所以在并发量不是太高的场景,推荐

  使用ZooKeeper的分布式锁。

  对比 redis 分布式锁:

    (1)基于ZooKeeper的分布式锁,适用于高可靠(高可用)而并发量不是太大的场景;

    (2)基于Redis的分布式锁,适用于并发量很大、性能要求很高的、而可靠性问题可以通过其他方案去弥补的场景。

2. zookeeper 分布式锁原理:

  非公共锁方式实现流程:

  

    如上实现方式在并发问题比较严重的情况下,性能会下降的比较厉害,主要原因是,所有的连接都在对同一个节点进行监听,当服务器检测到删除事件时,
  要通知所有的连接,所有的连接同时收到事件,再次并发竞争,这就是羊群效应。这种加锁方式是非公平锁的具体实现

  

  zookeeper 公平锁实现:

                                                    

  流程:

    1. 请求进来,直接在 /lock 节点下穿件一个临时顺序节点

    2. 判断自己是不是 lock 节点下最小的节点: 如果是最小的,则获取锁,反之对前面的节点进行监听

    3. 获得锁的请求,处理完释放锁,即delete 节点,然后后继第一个节点收到通知,并重复第二步判断。

  

  借助于临时顺序节点,可以避免同时多个节点的并发竞争锁,缓解了服务端压力。这种实现方式所有加锁请求都进行排队加锁,是公平锁的具体实现
 
3. 使用curator 封装分布式锁
  

    Curator 是一套由netflix 公司开源的,Java 语言编程的 ZooKeeper 客户端框架,Curator项目是现在ZooKeeper 客户端中使用最多,Curator 把我们平时
  常用的很多 ZooKeeper 服务开发功能做了封装,例如 Leader 选举、分布式计数器、分布式锁。这就减少了技术人员在使用 ZooKeeper 时的大部分底层细节
  开发工作。在会话重新连接、Watch 反复注册、多种异常处理等使用场景中,用原生的 ZooKeeper处理比较复杂。而在使用 Curator 时,由于其对这些功能都
  做了高度的封装,使用起来更加简单,不但减少了开发时间,而且增强了程序的可靠性。 
    
  引入curator 相关的pom 依赖:
    将 Curaotr 框架引用到工程项目里,在配置文件中分别引用了两个 Curator 相关的包,第一个是 curator-framework 包,该包是对 ZooKeeper 底层 API 的一些封装。
  另一个是 curator-recipes 包,该包封装了一些 ZooKeeper 服务的高级特性,如:Cache 事件监听、选举、分布式锁、分布式 Barrier。 
  

 <dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator‐recipes</artifactId>
<version>5.0.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.8</version>
</dependency>

封装的工具类:

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; @Component
public class BaseJob {
Log log = LogFactory.getLog(this.getClass());
@Value("${zookeeper.connectstring}")
private String zookeeperHost;
@Value("${zookeeper.parent.path}")
private String zookeeperPath = "/dlocks/zk/demo";
@Value("${curator.leadership.wait}")
private int leaderShipWait = 60000;
@Value("${curator.leadership.release}")
private int leaderShipRelease = 360000; protected static String Zookeeper_KEY = "zk/lag/count";

public boolean getZkLock(String tokenKey) {
return getZkLock(tokenKey, leaderShipRelease);
} public boolean getZkLock(String tokenKey, final int lShipRelease) {
CuratorFramework client = null;
LeaderLatch ll = null;
try {
RetryPolicy policy = new ExponentialBackoffRetry(4000, 3);
client = CuratorFrameworkFactory.newClient(zookeeperHost, policy);
client.start();
ll = new LeaderLatch(client, String.format("%s/ppcloud/"+tokenKey+"/lock", zookeeperPath));
ll.start();
boolean get = ll.await(leaderShipWait, TimeUnit.MILLISECONDS);
if (get) {
final CuratorFramework client2 = client;
final LeaderLatch ll2 = ll;
new Thread(new Runnable() { public void run() {
try {
Thread.sleep(lShipRelease);
} catch (Throwable e1) {
}
try {
ll2.close();
} catch (Throwable t) {
}
try {
client2.close();
} catch (Throwable e) {
}
}
}).start();
return true;
} else {
ll.close();
client.close();
log.error(String.format("Zookeeper return:%s", get));
//hack code temp
//return true;
} } catch (Throwable e) {
log.error(String.format("Zookeeper failed:%s", ExceptionUtils.getStackTrace(e)));
try {
if (ll != null) {
ll.close();
}
} catch (Exception e2) {
}
try {
if (client != null) {
client.close();
}
} catch (Exception e2) {
}
}
return false;
}
}

zookeeper分布式锁原理及使用 curator 实现分布式锁的更多相关文章

  1. 【分布式锁】02-使用Redisson实现公平锁原理

    前言 前面分析了Redisson可重入锁的原理,主要是通过lua脚本加锁及设置过期时间来保证锁执行的原子性,然后每个线程获取锁会将获取锁的次数+1,释放锁会将当前锁次数-1,如果为0则表示释放锁成功. ...

  2. 一般实现分布式锁都有哪些方式?使用redis如何设计分布式锁?使用zk来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高?

    #(1)redis分布式锁 官方叫做RedLock算法,是redis官方支持的分布式锁算法. 这个分布式锁有3个重要的考量点,互斥(只能有一个客户端获取锁),不能死锁,容错(大部分redis节点创建了 ...

  3. 分布式事务(3)---RocketMQ实现分布式事务原理

    分布式事务(3)-RocketMQ实现分布式事务原理 之前讲过有关分布式事务2PC.3PC.TCC的理论知识,博客地址: 1.分布式事务(1)---2PC和3PC原理 2.分布式事务(2)---TCC ...

  4. 女朋友也能看懂的Zookeeper分布式锁原理

      前言 关于分布式锁,在互联网行业的使用场景还是比较多的,比如电商的库存扣减,秒杀活动,集群定时任务执行等需要进程互斥的场景.而实现分布式锁的手段也很多,大家比较常见的就是redis跟zookeep ...

  5. zookeeper(4)--zookeeper分布式锁原理

    目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency).可用性( ...

  6. Redis、Zookeeper实现分布式锁——原理与实践

    Redis与分布式锁的问题已经是老生常谈了,本文尝试总结一些Redis.Zookeeper实现分布式锁的常用方案,并提供一些比较好的实践思路(基于Java).不足之处,欢迎探讨. Redis分布式锁 ...

  7. 关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁

    首先分布式锁和我们平常讲到的锁原理基本一样,目的就是确保,在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法.变量. 在一个进程中,也就是一个jvm 或者说应用中,我们很容易去处理控制,在j ...

  8. zookeeper 分布式锁原理

    zookeeper 分布式锁原理: 1 大家也许都很熟悉了多个线程或者多个进程间的共享锁的实现方式了,但是在分布式场景中我们会面临多个Server之间的锁的问题,实现的复杂度比较高.利用基于googl ...

  9. Zookeeper--0300--java操作Zookeeper,临时节点实现分布式锁原理

    删除Zookeeper的java客户端有  : 1,Zookeeper官方提供的原生API, 2,zkClient,在原生api上进行扩展的开源java客户端 3, 一.Zookeeper原生API ...

  10. zookeeper分布式锁原理

    一.分布式锁介绍分布式锁主要用于在分布式环境中保护跨进程.跨主机.跨网络的共享资源实现互斥访问,以达到保证数据的一致性. 二.架构介绍在介绍使用Zookeeper实现分布式锁之前,首先看当前的系统架构 ...

随机推荐

  1. 牛客小白月赛2 D题虚虚实实

    题目链接:https://www.nowcoder.com/acm/contest/86/D 解题思路:这题目就是判断是否存在欧拉路径.由无向图存在欧拉路径的充分必要条件可知先判断是否联通,再判断是否 ...

  2. wife-wife【原型链污染】

    wife-wife[原型链污染][难度:4] 题目界面 登录界面 注册界面 思路:在注册界面,利用原型链污染漏洞,获得管理员权限. 步骤 在注册界面输入用户名-密码-邀请码,勾选admin选项,抓包 ...

  3. Scrapy创建项目、爬虫文件

    创建项目 执行命令 scrapy startproject <项目名> 项目结构 创建爬虫文件 方式一:通过命令生成 scrpay genspider <爬虫名(必须唯一)> ...

  4. 【云原生 | Kubernetes 系列】— Kubernetes存储方案

    目录 [云原生 | Kubernetes 系列]- Kubernetes存储方案 一.基本存储 EmptyDir HostPath NFS 搭建nfs服务器 二.高级存储 PV和PVC pv pvc ...

  5. DVWA File Upload(文件上传)全等级

    File Upload(文件上传) 目录: File Upload(文件上传) 一句话木马的构成 1. Low 1.上传一句话木马1.php 2.中国蚁剑 2.Medium 3. High 4.Imp ...

  6. Java 集合(三)ConcurrentHashMap

    一般来讲,通常使用的 HashMap 不是线程安全的,因为没有任何机制来保证每个操作的原子性.在 ConcurrentHashMap 出现之前,可以通过给 HashMap 的每个操作加上唯一的互斥锁来 ...

  7. RV1126 DSI 调试

    一.基本信息 开发板:RV1126 linux版本:4.19.111 显示屏:HX070JGI50(7寸) 显示器分别率:1024 * 600 二.MIPI协议 连接示意图(图片来源,正点资料) MI ...

  8. 中文语音识别转文字的王者,阿里达摩院FunAsr足可与Whisper相颉顽

    君不言语音识别技术则已,言则必称Whisper,没错,OpenAi开源的Whisper确实是世界主流语音识别技术的魁首,但在中文领域,有一个足以和Whisper相颉顽的项目,那就是阿里达摩院自研的Fu ...

  9. 实时数据流无忧:用 SpringBoot 和 SSE 打造动态前端更新的终极指南

    用 SpringBoot 和 SSE 打造动态前端更新的终极指南 你知道什么是开发者的梦魇吗?慢!慢!慢!在一个需要实时数据更新的应用中,如果数据像乌龟一样慢吞吞地爬行,那用户体验就会像坐过山车一样直 ...

  10. Ocelot(.NET API Gateway)

    一.介绍 Ocelot 是一个.NET API 网关 面向使用.NET运行微服务/面向服务的体系结构的人员,这些体系结构需要统一的系统入口点. Ocelot将HttpRequest对象操作到由其配置指 ...