Redis分布式锁超时了,任务还没执行完怎么办?

面试官:你们项目中有使用分布式锁么?

 

 

我:有使用。

 

 

面试官:你们使用分布式锁主要是为了干啥?

 

 

我:多节点并发访问同一份数据的时候,防止造成脏数据。

 

 

面试官:都有哪些方案实现分布式锁?你们用的是哪一种?

 

 

我:有基于zk的临时顺序节点的方案,有redis的setnx和指定expire超时时间的方案。

 

 

面试官:你们是用哪种方案呢?

 

 

我:用的是redis的一个封装组件Redisson。

 

 

面试官:你们redis是用的哪种集群模式?

 

 

我:用的是redis的cluster集群模式。

 

 

面试官:Redisson可以配置哪些模式?

 

 

我:单节点模式、cluster模式、哨兵模式

 

 

面试官:那分布式锁的锁超时时间是怎么配置的?

 

 

我:这个超时时间需要根据业务场景进行压测然后根据压测结果进行评估,在压测结果上进行稍微放大1~2倍。

 

 

面试官:那假如分布式锁设置的超时时间是2s,但是2s内还没执行完成,锁自动释放了,这种怎么处理呢?

 

 

我:这个,有点记不清了。

 

 

面试官:好的。你们redis cluster集群模式中,如果主挂了怎么办?

 

 

我:我们是三主三从的集群模式,如果半数以上主节点与故障主节点通信超过,认为当前该主节点挂掉,主下面的从就会变为主。如果主下面没有从,那么集群就会进入fail状态。从节点就是主节点的备份。

 

 

面试官:redis的持久化机制有几种,分别有什么优缺点?

 

 

我:redis的持久化分为:RDB和AOF,一种是快照,一种是追加。快照的话是一段时间进行数据的备份,追加是只要有指令执行,就记录记录指令信息。后面可以根据指令进行数据的恢复。

 

 

快照模式如果挂了的话很有可能在快照期间数据丢失了,优点是恢复数据比较快,镜像的话恢复会比较慢,优点是数据数据存的比较全,配置好持久化策略可以做到数据完全不丢失。

 

 

面试官:那你们是怎么用的?

 

 

我:我们是两种都用,定期备份数据。挂了之后方便快速恢复同时保证了数据的完整性。

 

 

真是打破砂锅问到底啊,兄弟集美们,夺命连环十八问。

 

 

不过一码归一码,还是让我回忆起很多知识。也顺带总结起来,下次遇到这块问题的时候也不至于啥都说不出来。

 

 

接下来,把Redisson在锁超时后业务还没执行完成的情况细聊下。

 

 

二、Redisson锁超时看门狗机制

 

 

Redisson的宗旨是促进使用者对 Redis 的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

 

 

先上Github地址,中文文档,贼6。

 

 

Redisson中文文档

 

 

https://github.com/redisson/redisson/wiki

 

 

接下来主要分析:如果锁已经超时了,但是线程还没执行完任务该如何处理?

 

 

可重入锁(Reentrant Lock)

 

 

基于Redis的Redisson分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。

 

 

RLock lock = redisson.getLock("anyLock"); //最常见的使用方法 lock.lock(); 复制代码

 

 

大家都知道,如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。

 

 

为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。

 

 

默认情况下,看门狗的检查锁的超时时间是30秒钟,

 

 

也可以通过修改Config.lockWatchdogTimeout 来另行指定。

 

 

另外Redisson还通过加锁的方法提供了 leaseTime 的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

 

 

// 加锁以后10秒钟自动解锁// 无需调用unlock方法手动解锁lock.lock(10, TimeUnit.SECONDS);// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);if (res) {   try {     ...   } finally {       lock.unlock();   }}

 

 

拓展:

 

 

Redisson同时还为分布式锁提供了异步执行的相关方法:

 

 

RLock lock = redisson.getLock("anyLock");lock.lockAsync();lock.lockAsync(10, TimeUnit.SECONDS);Future<Boolean> res = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);

 

 

RLock对象完全符合Java的Lock规范。也就是说只有拥有锁的进程才能解锁,其他进程解锁则会抛出 IllegalMonitorStateException 错误。但是如果遇到需要其他进程也能解锁的情况,请使用分布式信号量 Semaphore 对象。

posted @ 2022-04-27 17:32  piaobodeyun0000  阅读(376)  评论(0编辑  收藏  举报