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的过期时间
相关推荐
June bug1 小时前
【软考中级·软件评测师】下午题·面向对象测试之架构考点全析:分层、分布式、微内核与事件驱动
经验分享·分布式·职场和发展·架构·学习方法·测试·软考
阿波罗.20122 小时前
Zookeeper 客户端 .net访问框架 ZookeeperNetEx项目开发编译
分布式·zookeeper
AI、少年郎2 小时前
Oracle 进阶语法实战:从多维分析到数据清洗的深度应用(第四课)
数据库·oracle
赤橙红的黄2 小时前
自定义线程池-实现任务0丢失的处理策略
数据库·spring
Bug退退退1232 小时前
RabbitMQ 工作模式
java·分布式·rabbitmq
DataGear3 小时前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
weixin_438335403 小时前
分布式锁实现方式:基于Redis的分布式锁实现(Spring Boot + Redis)
数据库·redis·分布式
暮乘白帝过重山3 小时前
为什么要写RedisUtil这个类
redis·开发·暮乘白帝过重山
码不停蹄的玄黓3 小时前
MySQL Undo Log 深度解析:事务回滚与MVCC的核心功臣
数据库·mysql·undo log·回滚日志
Qdgr_3 小时前
价值实证:数字化转型标杆案例深度解析
大数据·数据库·人工智能