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

  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. NLP项目实战01--之电影评论分类

    介绍: 欢迎来到本篇文章!在这里,我们将探讨一个常见而重要的自然语言处理任务--文本分类.具体而言,我们将关注情感分析任务,即通过分析电影评论的情感来判断评论是正面的.负面的. 展示: 训练展示如下: ...

  2. ElasticSearch快照备份、还原

    快照备份 备份和还原的前提:在配置文件elasticsearch.yml中设置path.repo path.repo: ["D:\\elasticsearch-6.8.23\\elastic ...

  3. ios上架流程 详细通关教程 2021

    记录此文是源于以下需求 1.已有app store开发者账号 (公司账号$99),需上架至app store 2.有商城实体商品支付功能(会员等虚拟支付另说) 3.有硬件交互功能 注:建议预留一周上架 ...

  4. tomcat中文乱码怎么解决

    需要修改Tomcat根目录下面的"logging.properties"文件,把所有的encoding=UTF-8的改成encodng=GBK,保存之后,重启Tomcat服务器,就 ...

  5. CentOS 7 部署 Seafile 服务器(使用 MySQL/MariaDB)

    本文档用来说明通过预编译好的安装包来安装并运行基于 MySQL/MariaDB 的 Seafile 服务器.(MariaDB 是 MySQL 的分支) 提示:如果您是初次部署 Seafile 服务,我 ...

  6. Rust 学习笔记

    rust 学习梳理 数据类型 基于已明确的类型,Rust会推断剩下大部分类型.基于类型推断Rust具备了与动态类型语言近似的易读性,并仍能在编译期捕获类型错误. 函数可以是泛型的:单个函数ujiu可以 ...

  7. Linux 逻辑卷管理

    如果用标准分区在硬盘上创建了文件系统,为已有的文件系统添加额外的空间是一件十分痛苦的事情.只能在已有的硬盘上的可用空间范围内调整分区大小,如果硬盘空间不够的话,就只能换一个大容量的硬盘,然后手动将已有 ...

  8. 如何正确使用Python临时文件

    摘要:临时文件通常用来保存无法保存在内存中的数据,或者传递给必须从文件读取的外部程序.一般我们会在/tmp目录下生成唯一的文件名,但是安全的创建临时文件并不是那么简单,需要遵守许多规则. 1.前言 临 ...

  9. 万字讲解WiFi为何物

    摘要:WiFi是一种基于IEEE802.11系列协议标准实现的无线通信技术. 本文分享自华为云社区<[云驻共创]物联网无线短距离Wi-Fi技术专题>,作者:Mr红凯. 前言 Wi-Fi通往 ...

  10. nodejs升级到最新LTS版本方法汇总:linux/mac/window—npm/yum/ssh

    nodejs不同版本的差异还是蛮多的,比如obj?.a 在nodejs12是不支持的,必须得升级到14才可以.但是centos yum 默认安装的,或者系统集成的nodejs版本都是很老的.项目上传到 ...