Curator中的分布式锁解读

news2024/7/6 0:42:55

目录

基本介绍

基本配置

 可重入锁InterProcessMutex

 不可重入锁InterProcessSemaphoreMutex

可重入读写锁InterProcessReadWriteLock 

联锁InterProcessMultiLock 

 信号量InterProcessSemaphoreV2

 栅栏barrier

倒计数器


基本介绍

Curator是netflix公司开源的一套zookeeper客户端,目前是Apache的顶级项目。与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeeper客户端的开发量。Curator解决了很多zookeeper客户端非常底层的细节开发工作,包括连接重连、反复注册wathcer和
NodeExistsException 异常等。

通过查看官方文档,可以发现Curator主要解决了三类问题:

  • 封装ZooKeeper client与ZooKeeper server之间的连接处理
  • 提供了一套Fluent风格的操作API
  • 提供ZooKeeper各种应用场景(recipe, 比如:分布式锁服务、集群领导选举、共享计数器、缓存机制、分布式队列等)的抽象封装,这些实现都遵循了zk的最佳实践,并考虑了各种极端情况

Curator由一系列的模块构成,对于一般开发者而言,常用的是curator-framework和curator-
recipes:

  • curator-framework:提供了常见的zk相关的底层操作
  • curator-recipes:提供了一些zk的典型使用场景的参考。本节重点关注的分布式锁就是该包提供的

基本配置

引入依赖:
最新版本的curator 4.3.0支持zookeeper 3.4.x和3.5,但是需要注意curator传递进来的依赖,需要和实际服务器端使用的版本相符,以我们目前使用的zookeeper 3.4.14为例。

      <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <exclusions>
                <exclusion>
                    <groupId>org.arakhne.afc.slf4j</groupId>
                    <artifactId>slf4j-log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
      </dependency>

 添加curator客户端配置:

@Configuration
public class zkCuratorConfig {
    @Bean
    public CuratorFramework curatorFramework(){
        //后台重试,每个1000ms重试一次,重试3次
        RetryPolicy retryPolicy=new ExponentialBackoffRetry(1000,3);
        //初始化CuratorFramework客户端,如果有多哥zk地址,以逗号分割
        CuratorFramework client = CuratorFrameworkFactory.
                                newClient("192.168.107.135", retryPolicy);
        //启动链接
        client.start();
        return client
    }
}

 可重入锁InterProcessMutex

Reentrant和JDK的ReentrantLock类似, 意味着同一个客户端在拥有锁的同时,可以多次获取,不会被 阻塞。它是由类InterProcessMutex来实现。

// 常用构造方法
public InterProcessMutex(CuratorFramework client, String path)
// 获取锁
public void acquire();
// 带超时时间的可重入锁
public boolean acquire(long time, TimeUnit unit);
// 释放锁
public void release();

改造service测试方法:

    @Autowired

    private CuratorFramework curatorFramework;

    public void checkAndLock() {
        try {
            // 加锁,获取锁失败重试
            InterProcessMutex mutex = new InterProcessMutex(curatorFramework,"/curator/lock");
            mutex.acquire();
            // 先查询库存是否充足
            Stock stock = this.stockMapper.selectById(1L);
            // 再减库存
            if (stock != null && stock.getCount() > 0) {
                stock.setCount(stock.getCount() - 1);
                this.stockMapper.updateById(stock);
            }
            // 释放锁
            mutex.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 注意:如想重入,则需要使用同一个InterProcessMutex对象。

压力测试结果:

 不可重入锁InterProcessSemaphoreMutex

具体实现:InterProcessSemaphoreMutex。与InterProcessMutex调用方法类似,区别在于该锁是不 可重入的,在同一个线程中不可重入。

// 构造函数需要包含的锁的集合,或者一组ZooKeeper的path
public InterProcessMultiLock(List<InterProcessLock> locks);
public InterProcessMultiLock(CuratorFramework client, List<String> paths);
// 获取锁
public void acquire();
public boolean acquire(long time, TimeUnit unit);
// 释放锁
public synchronized void release();

可重入读写锁InterProcessReadWriteLock 

类似JDK的ReentrantReadWriteLock。一个拥有写锁的线程可重入读锁,但是读锁却不能进入写锁。这也意味着写锁可以降级成读锁。从读锁升级成写锁是不成的。主要实现类
InterProcessReadWriteLock:

// 构造方法
public InterProcessReadWriteLock(CuratorFramework client, String basePath);
// 获取读锁对象
InterProcessMutex readLock();
// 获取写锁对象
InterProcessMutex writeLock();

联锁InterProcessMultiLock 

Multi Shared Lock是一个锁的容器。当调用acquire, 所有的锁都会被acquire,如果请求失败,所有的锁都会被release。同样调用release时所有的锁都被release(失败被忽略)。基本上,它就是组锁的代表,在它上面的请求释放操作都会传递给它包含的所有的锁。实现类InterProcessMultiLock:

// 构造函数需要包含的锁的集合,或者一组ZooKeeper的path
public InterProcessMultiLock(List<InterProcessLock> locks);
public InterProcessMultiLock(CuratorFramework client, List<String> paths);
// 获取锁
public void acquire();
public boolean acquire(long time, TimeUnit unit);
// 释放锁
public synchronized void release();

 信号量InterProcessSemaphoreV2

一个计数的信号量类似JDK的Semaphore。JDK中Semaphore维护的一组许可(permits),而Cubator中称之为租约(Lease)。注意,所有的实例必须使用相同的numberOfLeases值。调用acquire会返回一个租约对象。客户端必须在finally中close这些租约对象,否则这些租约会丢失掉。但是,如果客户端session由于某种原因比如crash丢掉, 那么这些客户端持有的租约会自动close, 这样其它客户端可以继续使用这些租约。主要实现类InterProcessSemaphoreV2:

// 构造方法
public InterProcessSemaphoreV2(CuratorFramework client, String path, int
maxLeases);
// 注意一次你可以请求多个租约,如果Semaphore当前的租约不够,则请求线程会被阻塞。
// 同时还提供了超时的重载方法
public Lease acquire();
public Collection<Lease> acquire(int qty);
public Lease acquire(long time, TimeUnit unit);
public Collection<Lease> acquire(int qty, long time, TimeUnit unit)
// 租约还可以通过下面的方式返还
public void returnAll(Collection<Lease> leases);
public void returnLease(Lease lease);

 栅栏barrier

1. DistributedBarrier构造函数中barrierPath参数用来确定一个栅栏,只要barrierPath参数相同
(路径相同)就是同一个栅栏。通常情况下栅栏的使用如下:

  • 1. 主client设置一个栅栏
  • 2. 其他客户端就会调用waitOnBarrier()等待栅栏移除,程序处理线程阻塞
  • 3. 主client移除栅栏,其他客户端的处理程序就会同时继续运行。

DistributedBarrier类的主要方法如下:

setBarrier() - 设置栅栏
waitOnBarrier() - 等待栅栏移除
removeBarrier() - 移除栅栏

2. DistributedDoubleBarrier双栅栏,允许客户端在计算的开始和结束时同步。当足够的进程加入到
双栅栏时,进程开始计算,当计算完成时,离开栅栏。DistributedDoubleBarrier实现了双栅栏的
功能。构造函数如下:

// client - the client
// barrierPath - path to use
// memberQty - the number of members in the barrier
public DistributedDoubleBarrier(CuratorFramework client, String
barrierPath, int memberQty);
enter()、enter(long maxWait, TimeUnit unit) - 等待同时进入栅栏
leave()、leave(long maxWait, TimeUnit unit) - 等待同时离开栅栏

 memberQty是成员数量,当enter方法被调用时,成员被阻塞,直到所有的成员都调用了enter。
当leave方法被调用时,它也阻塞调用线程,直到所有的成员都调用了leave。
注意:参数memberQty的值只是一个阈值,而不是一个限制值。当等待栅栏的数量大于或等于这
个值栅栏就会打开!
与栅栏(DistributedBarrier)一样,双栅栏的barrierPath参数也是用来确定是否是同一个栅栏的,双
栅栏的使用情况如下:

  • 1. 从多个客户端在同一个路径上创建双栅栏(DistributedDoubleBarrier),然后调用enter()方
  • 法,等待栅栏数量达到memberQty时就可以进入栅栏。
  • 2. 栅栏数量达到memberQty,多个客户端同时停止阻塞继续运行,直到执行leave()方法,等待memberQty个数量的栅栏同时阻塞到leave()方法中。
  • 3. memberQty个数量的栅栏同时阻塞到leave()方法中,多个客户端的leave()方法停止阻塞,继续运行。

倒计数器

利用ZooKeeper可以实现一个集群共享的计数器。只要使用相同的path就可以得到最新的计数器值,这是由ZooKeeper的一致性保证的。Curator有两个计数器, 一个是用int来计数,一个用long来计数。SharedCount这个类使用int类型来计数。主要涉及三个类。

* SharedCount
* SharedCountReader
* SharedCountListener

SharedCount代表计数器, 可以为它增加一个SharedCountListener,当计数器改变时此Listener可以监听到改变的事件,而SharedCountReader可以读取到最新的值, 包括字面值和带版本信息的值VersionedValue。 

DistributedAtomicLong
除了计数的范围比SharedCount大了之外, 它首先尝试使用乐观锁的方式设置计数器, 如果不成功(比如期间计数器已经被其它client更新了), 它使用InterProcessMutex方式来更新计数值。此计数器有一系列的操作:
get(): 获取当前值
increment():加一
decrement(): 减一
add():增加特定的值
subtract(): 减去特定的值
trySet(): 尝试设置计数值
forceSet(): 强制设置计数值
你必须检查返回结果的succeeded(), 它代表此操作是否成功。如果操作成功, preValue()代表操作前的值, postValue()代表操作后的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/484309.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言力扣简单题-无重复字符的最长子串

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 无重复字符的最长子串 题目&#xff1a; 代码思路&#xff1a; 代码表示&#xff1a; 无重复字符的最长子…

【C++】lambda表达式

文章目录 lambda表达式lambda概念lambda表达式的格式关于捕获列表常见问题: 使用lambda表达式交换两个数lambda表达式底层原理 lambda表达式 lambda概念 lambda表达式本质是一个匿名函数(因为它没有名字),恰当使用lambda表达式可以让代码变得简洁.并且可以提高代码的可读性 例…

ChatGPT实现HTML网页文本提取

网页自动化工具 既然ChatGPT对于编程语言有非常强大的理解能力&#xff0c;那么它是否可以用来自动化地处理网页呢&#xff1f;答案是肯定的。ChatGPT可以使用机器学习算法来识别网页元素中的文本&#xff0c;并抽取出有用的信息。 例如我们提供一段层数比较多的相对来说较为…

【五一创作】|【C++】AVL树的实现

文章目录 1.AVL树概念2. AVL树性质3.AVL树的实现insert插入情况分析更新平衡因子旋转处理左单旋右单旋在insert中判断左右单旋的条件双旋转左右双旋 整体代码 1.AVL树概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#…

PCIe数据链路层图文详细总结-PCIe专题知识(二)

目录 前言一、简介1.1 接收部件组成1.2 发送部件组成 二、数据链路层功能详细介绍2.1 DLLP介绍2.2 ACK/NAK协议2.3 发送端逻辑2.3.1 发送端TLP包处理总流程2.3.2 使用ACK/NAK协议详解 2.4 接收端逻辑2.4.1 接收端TLP包处理流程2.4.2 如何使用ACK/NAK协议 2.5 数据链路层发送报文…

Java每日一练(20230503)

1. 外观数列 给定一个正整数 n &#xff0c;输出外观数列的第 n 项。 「外观数列」是一个整数序列&#xff0c;从数字 1 开始&#xff0c;序列中的每一项都是对前一项的描述。 你可以将其视作是由递归公式定义的数字字符串序列&#xff1a; countAndSay(1) "1"c…

[AION]我眼中的《永恒之塔私服》

当我第一次看到《永恒之塔私服》我被它那华丽的画面吸引了。      三维做的很逼真&#xff0c;他的三维技术&#xff0c;华丽的三维景象&#xff0c;从maya设计者专业的角度上说&#xff0c;他是一部做工完美的游戏&#xff0c;不管是他的背景还是他的人物。都比以前很多游…

Python每日一练(20230503)

目录 1. 外观数列 &#x1f31f;&#x1f31f; 2. 找出素数对 ※ 3. 子集 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 外观数列 给定一个正整数 n…

Dockercompose编排

目录 一、Dockercompose简介 1、compose概述 2、YAML简介 1、概述 2、YAML支持的数据结构 二、compose部署 1、Docker compose环境安装 Docker compose常用字段 Docker compose常用命令 Docker Compose文件结构 2、准备依赖文件 3、编写配置文件docker-compose.yml…

fps枪械案例

文章目录 一、 介绍二、 知识点三、 鼠标移动控制视角四、 人物行走、奔跑、跳跃、下蹲、音效五、 射击、射速、瞄准、弹痕、枪火、弹壳、文本六、 手臂摇摆七、 步枪切换到手枪八、 切枪效果九、 添加各种动画 一、 介绍 经典fps案例 行走、奔跑、跳跃、切枪、换弹、武器展示…

gitlab搭建以及自动化部署

一、安装gitlab 首先下载gitlab的安装包&#xff0c;地址如下&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/bionic/main/g/gitlab-ce/ 然后安装下载的包即可&#xff0c;一般还需要安装openssh-server等依赖包&#xff0c;在安装gitlab包之前可以…

正则表达式-基本元字符和语法规则

© Ptw-cwl 文章目录 字符匹配元字符.元字符[]元字符[^]元字符*元字符元字符?元字符{}元字符|元字符()元字符^元字符$元字符\元字符\d元字符\w元字符\s元字符\b元字符\B元字符*?、?、??、{n,m}?元字符(?)、(?!)元字符(?:)元字符\1、\2等元字符^、$元字符&#x…

【刷题之路Ⅱ】LeetCode 274275. H指数ⅠⅡ

【刷题之路Ⅱ】LeetCode 274&275. H指数Ⅰ&Ⅱ 一、题目描述二、解题1、方法1——排序1.1、思路分析1.2、代码实现1.3、升级到275题的二分法1.3.1、思路分析1.3.2、代码实现 2、方法2——计数排序2.1、思路分析2.2、代码实现 一、题目描述 原题连接&#xff1a; 274. H…

C语言专升本编程题复习

1.求100以内的素数 int main( ) { int i,j,count0;for(i1;i<100;i){for(j2;j<i;j){if(i%j0)break;}if(ij){count; printf("%d ",i);if(count%50)printf("\n");}} }2.求1000以内的完数 * 完数&#xff1a;等于其因子&#xff08;不含本身&…

【五一创作】SAP入门到放弃系列之批次确定配置

概念&#xff1a; 在后勤涉及物料移动或消耗流程中&#xff0c;从采购到生产到销售&#xff0c;涉及启用批次的物料&#xff0c;需要一次又一次地为出入库业务中的库存指定批次。如果企业的出库库批次管理有一定的管理要求&#xff0c;比如先进先出&#xff0c;就可以针对货物…

基于Java语言开发B/S架构实现的云HIS

一、云HIS系统框架简介 1、技术框架 &#xff08;1&#xff09;总体框架&#xff1a; SaaS应用&#xff0c;全浏览器访问 前后端分离&#xff0c;多服务协同 服务可拆分&#xff0c;功能易扩展 &#xff08;2&#xff09;技术细节&#xff1a; 前端&#xff1a;AngularNg…

级数可视化

泰勒级数 数学家们普遍偏爱多项式&#xff0c;如果评选一下高等数学里面最重要的公式&#xff0c;泰勒公式一定榜上有名&#xff0c;泰勒公式的核心思想就是把一个给定的任意函数&#xff0c;展开成多项式的形式&#xff0c;如果是有限项&#xff0c;就像作泰勒多项式&#xf…

深入了解云计算:发展历程、服务模型、未来趋势

开篇博主 bluetata 的观点&#xff1a;PaaS 服务必将是未来10年云计算权重最高的趋势&#xff08;05/02/2023 15:32&#xff09; 文章目录 一、前言二、认识了解云计算2.1 什么是云计算2.1.1 维基百科上的云计算定义2.1.2 NIST 标准云计算定义2.1.3 如果被面试如何解释云计算 2…

MYSQL-数据库管理(下)

查看数据库信息 show database 查看数据库中的表信息 use 数据库名 #切换到书库中 show tables show tables in mysql 显示数据表的结构&#xff08;字段&#xff09; describe user; Field:字段名称 type:数据类型 Null :是否允许为空 Key :主键 Type:数据类型 Null :是否…

武忠祥老师每日一题||不定积分基础训练(五)

∫ x f ′ ( x ) d x \int xf{}(x)\,{\rm d}x ∫xf′(x)dx ∫ x d f ( x ) \int x\,{\rm d}{f(x)} ∫xdf(x) x f ( x ) − ∫ f ( x ) d x xf(x)-\int f(x)\,{\rm d}x xf(x)−∫f(x)dx 由题知&#xff1a; f ( x ) ( ln ⁡ 2 x ) ′ 2 ln ⁡ x 1 x 2 ln ⁡ x x f(x)({…