Redis系列---Redission分布式锁

文章目录

类型

使用Redission,lock的机制其实是使用了ttl,一直等ttl为0再get。无论是redission还是redis的setNx,只要是锁,都必须有加锁和释放锁两个动作,二者缺一不可,并且需要把释放锁放到final中,这样可以保证锁一定被释放。 lock和unlock必须搭配使用,缺一不可。

redission中常用的lock就两个,一个是lock一个是trylock。两者都是阻塞加锁, 前者会一直阻塞,相应的该方法不存在返回值,因为无意义;后者可以传入一个等待时间,等待时间内持续阻塞,相应的该方法存在返回值,因为要确认是否成功加了锁。根据业务场景自己判断使用哪种锁,二者其实相似,trylock就是lock的进阶,加了一个等待时间而已。

java 复制代码
trylock:
	public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit)
	public boolean tryLock(long waitTime, TimeUnit unit)
	public boolean tryLock() 
						
lock:
	public void lock()
	public void lock(long leaseTime, TimeUnit unit) 
	private void lock(long leaseTime, TimeUnit unit, boolean interruptibly)
	
waitTime等待/阻塞时间,tryLock若没有则等同于lock;
leaseTime锁持续时间;
unit时间单位。
其实大部分的重载方法都是将参数少/无参的方法加了一些默认值,最后return参数最多的方法。 

原理

  • 如果没有指定leaseTime(加锁时长),则意味着让看门狗(守护线程,且该守护线程是连接级别,不是线程)管理锁的过期时间,该时间由配置文件控制,默认为30S,然后在过期时间的1/3时刻进行监听一次,线程还在则加时,加时也是走配置文件。
  • 如果指定了leaseTime,则意味着自己管理过期时间,看门狗不会介入,即不会自动续期,到了leaseTime之后,如果程序没有执行完毕,依旧会释放锁。此时,其他线程就可以继续对key加锁
  • 如果线程A加锁成功,线程B又来加锁,此时线程B会获取到线程A还有多少秒释放锁,然后线程B会通过semaphore信号量来等待一定的时间
  • 线程B在等待了一定的时间之后,会重新尝试进行加锁,加锁成功,就返回,如果失败,就重复3步

使用

  • 关于lock和trylock的使用,按场景需要进行抉择
  • 关于leaseTime是否指定,也就是说要不要使用看门狗控制过期时间,这个很难抉择, 各有利弊,如果可以自己估算业务时间,建议别用看门狗,因为看门狗存在失效或者死锁的可能,但是如果实在估算不出程序执行时间,只能冒险用看门狗了。

看门狗

Redisson中的看门狗(Watchdog)机制用于自动延长锁的持有时间,以防止锁在业务逻辑执行过程中过期。它的工作原理如下:

  • 锁续期:当一个线程获取锁后,Redisson会启动一个后台任务(看门狗),定期检查锁的持有时间,并在锁即将过期时自动延长锁的持有时间。
  • 自动释放:如果线程正常释放锁,看门狗会停止续期任务。如果线程异常退出,看门狗也会在锁过期后自动释放锁。

然而,虽然看门狗机制设计得很好,但在某些极端情况下,仍然可能出现死锁。以下是一些可能导致死锁的场景:

  • 资源竞争:在高并发环境下,多个线程竞争同一个锁,可能会导致某些线程长时间等待锁,从而增加死锁的风险。
  • 系统资源耗尽:如果系统资源(如线程池、内存)耗尽,可能会导致看门狗无法正常工作,从而引发死锁。
  • 网络问题:如果Redis服务器出现网络问题,导致看门狗无法及时续期锁,可能会导致锁过期,从而引发死锁。

为了避免这些潜在的死锁问题,可以采取以下措施:

  • 合理设置锁的超时时间:确保锁的超时时间足够长,以覆盖大部分业务逻辑的执行时间。
  • 监控和告警:监控系统的运行状态,及时发现和处理资源耗尽、网络问题等异常情况。
  • 优化业务逻辑:尽量减少锁的持有时间,避免长时间占用锁。

总结就是

  • Redisson中的看门狗机制通常不会导致死锁,但在高并发、资源耗尽或网络问题等极端情况下,仍然可能出现死锁。
  • 通过合理设置锁的超时时间、监控系统状态和优化业务逻辑,可以有效降低死锁的风险。

与setNx比较

在一定程度上redission比setNX更优秀,因为它的所有操作都是通过的lua脚本:

  • 先判断key是否存在,如果key不存在,就加锁,并且设置过期时间
  • 如果key已经存在,并且当前加锁的key是重入了,那就将key对应的加锁次数加1
  • 如果key已存在,并且当前加锁的key和线程和已加锁的不一样,无法重入,那就返回当前key的过期时间
相关推荐
靖顺2 小时前
【OceanBase 诊断调优】—— packet fly cost too much time 的根因分析
数据库·oceanbase
liuxin334455662 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
B1nna3 小时前
Redis学习(三)缓存
redis·学习·缓存
yuanbenshidiaos4 小时前
C++--------------树
java·数据库·c++
dengjiayue6 小时前
MySQL 查询大偏移量(LIMIT)问题分析
数据库·mysql
言之。6 小时前
【MySQL】在MySQL中如何定位慢查询?
数据库·mysql
DashVector6 小时前
如何通过HTTP API插入Doc
数据库·人工智能·http·阿里云·向量检索
DashVector6 小时前
如何通过HTTP API分组检索Doc
服务器·数据库·http·数据库开发·数据库架构
Suwg2096 小时前
【MySQL】踩坑笔记——保存带有换行符等特殊字符的数据,需要进行转义保存
数据库·笔记·mysql
2401_857610036 小时前
中文学习系统:成本效益分析与系统优化
java·数据库·学习·架构