ZooKeeper 分布式锁 Curator 源码 03:可重入锁并发加锁

本文涉及的产品
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
注册配置 MSE Nacos/ZooKeeper,182元/月
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介: 在了解了加锁和锁重入之后,最需要了解的还是在分布式场景下或者多线程并发加锁是如何处理的?

前言


在了解了加锁和锁重入之后,最需要了解的还是在分布式场景下或者多线程并发加锁是如何处理的?


并发加锁

网络异常,图片无法展示
|

先来看结果,在多线程对 /locks/lock_01 加锁时,是在后面又创建了新的临时节点。

这块在加锁方法 CreateBuilderImpl#pathInForeground 中已经介绍过

网络异常,图片无法展示
|

这里判断 /locks/lock_01 路径已经存在,会直接创建新的临时顺序节点。

真正判断锁是否获取成功,其实是在 LockInternals#attemptLock 方法中的 internalLockLoop 方法中。

网络异常,图片无法展示
|


加锁结果及监听

internalLockLoop 方法的主要作用是判断加锁结果,以及获取锁失败时,对其他节点的监听。

网络异常,图片无法展示
|

  1. 获取父节点 /locks/lock_01 下的所有子节点,按照从小到大排序,判断自己是不是获取到锁,没有获取到就监听自己前一个节点;
  2. 支持设置超时时间,超时直接返回失败;
  3. 不支持设置超时时间或者还没有超时,则直接 wait 等待。

是否获取锁的代码在 StandardLockInternalsDriver#getsTheLock

网络异常,图片无法展示
|

这块就是判断是否为最小节点,因为在 getSortedChildren 中已经对所有节点排序,所以方法中的 List<String> children 是有序的。

maxLeases 是在 InterProcessMutex 初始化的时候,指定的值为 1。

最终这里的结果是,判断自己是不是最小,不是最小,就将 pathToWatch 设置为前一个节点

只监听自己的前一个节点,可以避免羊群效应!

为什么要进行等待呢?

因为是为了防止无效自旋,因为这里有监听机制,会监听上一个节点是否释放。

网络异常,图片无法展示
|

网络异常,图片无法展示
|

这块是 ZooKeeper 的 Watcher 监听机制,在节点释放的时候,会进行回调,然后使用 Java 的 notifyAll 方法通知所有的 wait 线程。然后这里的 while trye 会继续执行,重新检查是否获得锁等。


总结


本文主要介绍了基于 ZooKeeper 的分布式锁框架 Curator 在并发场景下的锁竞争问题。

重点需要了解的是:

  1. 为了避免羊群效应,临时顺序节点,加锁失败后监听的是前一个节点
  2. 为了避免无效自旋,这里使用了 Java 的 wait/notifyAll 机制;
  3. 可以看出,默认加锁就是公平锁
目录
相关文章
|
2月前
|
消息中间件 分布式计算 资源调度
《聊聊分布式》ZooKeeper与ZAB协议:分布式协调的核心引擎
ZooKeeper是一个开源的分布式协调服务,基于ZAB协议实现数据一致性,提供分布式锁、配置管理、领导者选举等核心功能,具有高可用、强一致和简单易用的特点,广泛应用于Kafka、Hadoop等大型分布式系统中。
|
7月前
|
NoSQL 调度 Redis
分布式锁—3.Redisson的公平锁
Redisson公平锁(RedissonFairLock)是一种基于Redis实现的分布式锁,确保多个线程按申请顺序获取锁,从而实现公平性。其核心机制是通过队列和有序集合管理线程的排队顺序。加锁时,线程会进入队列并等待,锁释放后,队列中的第一个线程优先获取锁。RedissonFairLock支持可重入加锁,即同一线程多次加锁不会阻塞。新旧版本在排队机制上有所不同,新版本在5分钟后才会重排队列,而旧版本在5秒后就会重排。释放锁时,Redisson会移除队列中等待超时的线程,并通知下一个排队的线程获取锁。通过这种机制,RedissonFairLock确保了锁的公平性和顺序性。
|
3月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
217 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
4月前
|
NoSQL Redis
分布式锁设计吗,你是如何实现锁类型切换、锁策略切换基于限流的?
本方案基于自定义注解与AOP实现分布式锁,支持锁类型(如可重入锁、公平锁等)与加锁策略(如重试、抛异常等)的灵活切换,并结合Redisson实现可重入、自动续期等功能,通过LUA脚本保障原子性,兼顾扩展性与实用性。
89 0
|
5月前
|
缓存 NoSQL Java
【📕分布式锁通关指南 11】源码剖析redisson之读写锁的实现
Redisson 的 `RedissonReadWriteLock` 提供了高效的分布式读写锁实现,适用于读多写少的场景。通过 Redis 与 Lua 脚本结合,确保读锁并行、写锁互斥,以及读写之间的互斥,保障了分布式环境下的数据一致性。它支持可重入、自动过期和锁释放机制,提升了系统并发性能与资源控制能力。
114 0
|
7月前
|
NoSQL 调度 Redis
分布式锁—5.Redisson的读写锁
Redisson读写锁(RedissonReadWriteLock)是Redisson提供的一种分布式锁机制,支持读锁和写锁的互斥与并发控制。读锁允许多个线程同时获取,适用于读多写少的场景,而写锁则是独占锁,确保写操作的互斥性。Redisson通过Lua脚本实现锁的获取、释放和重入逻辑,并利用WatchDog机制自动续期锁的过期时间,防止锁因超时被误释放。 读锁的获取逻辑通过Lua脚本实现,支持读读不互斥,即多个线程可以同时获取读锁。写锁的获取逻辑则确保写写互斥和读写互斥,即同一时间只能有一个线程获取写锁,
376 17
|
7月前
|
监控 NoSQL Java
分布式锁—2.Redisson的可重入锁
本文主要介绍了Redisson可重入锁RedissonLock概述、可重入锁源码之创建RedissonClient实例、可重入锁源码之lua脚本加锁逻辑、可重入锁源码之WatchDog维持加锁逻辑、可重入锁源码之可重入加锁逻辑、可重入锁源码之锁的互斥阻塞逻辑、可重入锁源码之释放锁逻辑、可重入锁源码之获取锁超时与锁超时自动释放逻辑、可重入锁源码总结。
|
9月前
【📕分布式锁通关指南 08】源码剖析redisson可重入锁之释放及阻塞与非阻塞获取
本文深入剖析了Redisson中可重入锁的释放锁Lua脚本实现及其获取锁的两种方式(阻塞与非阻塞)。释放锁流程包括前置检查、重入计数处理、锁删除及消息发布等步骤。非阻塞获取锁(tryLock)通过有限时间等待返回布尔值,适合需快速反馈的场景;阻塞获取锁(lock)则无限等待直至成功,适用于必须获取锁的场景。两者在等待策略、返回值和中断处理上存在显著差异。本文为理解分布式锁实现提供了详实参考。
313 11
【📕分布式锁通关指南 08】源码剖析redisson可重入锁之释放及阻塞与非阻塞获取
|
8月前
|
存储 安全 NoSQL
【📕分布式锁通关指南 09】源码剖析redisson之公平锁的实现
本文深入解析了 Redisson 中公平锁的实现原理。公平锁通过确保线程按请求顺序获取锁,避免“插队”现象。在 Redisson 中,`RedissonFairLock` 类的核心逻辑包含加锁与解锁两部分:加锁时,线程先尝试直接获取锁,失败则将自身信息加入 ZSet 等待队列,只有队首线程才能获取锁;解锁时,验证持有者身份并减少重入计数,最终删除锁或通知等待线程。其“公平性”源于 Lua 脚本的原子性操作:线程按时间戳排队、仅队首可尝试加锁、实时发布锁释放通知。这些设计确保了分布式环境下的线程安全与有序执行。
240 0
【📕分布式锁通关指南 09】源码剖析redisson之公平锁的实现
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2