redisson中分布式锁一定要加leaseTime

star2017 1年前 ⋅ 521 阅读

背景

最近项目中redis加锁失败,出现了 attempt to unlock lock, not locked by current thread by node id: f4b01cb0-f7c6-4ce7-b6a1-6c09ca56c597 thread-id异常,导致 tryLock里面的方法没有执行,引起了事故。

分析

以下是伪代码

RedissonClient redission = redissonComponent.getRedisson();
String key = RedisConstant.getKey("testLock");
    RLock lock = redission.getLock(key);
    try {
        //30秒内,只能有一个线程触发
        if (lock.tryLock(30, TimeUnit.SECONDS)) {
           //我是执行代码
        }
    } catch (Exception e) {
        logger.error("异常", e);
    } finally {
        lock.unlock();
    }

这个代码已经在线上执行了很久了,突然就出现问题了,首先想到的是是不是redis出现问题了,看了下网络和状态都是正常的。然后看lock.unlock的方法,异常就是从这里抛出来的:
image.png
是因为等了30秒,没有获取到锁,所以抛出来,这里去解锁的时候需要判断当前线程是否有锁。

if(lock.isLocked()){
 lock.unlock();
}

这样就不会抛异常了,但是还是没有解决加锁失败的问题。继续查看redisson的源码,发现如果不设置leaseTime的话,那么锁的key是不会过期的,如代码:
image.png
image.png
image.png
在查看redis里面的key,结果如下:

ip:6389[1]> hgetall testLock 
adc001e3-89b4-4e40-bc64-e45f7f027d42:293
1
ip:6389[1]> pttl testLock
24204
ip:6389[1]> pttl testLock
21096
ip:6389[1]> pttl testLock
29175
ip:6389[1]> pttl testLock
20325
ip:6389[1]> pttl testLock
28518

发现testLock的过期时间一直在刷新,这就导致其他线程加锁不成功。

解决

  1. 使用的时候加个leaseTime;
  2. 解锁的时候判断下锁是否还在;
RedissonClient redission = redissonComponent.getRedisson();
String key = RedisConstant.getKey("testLock");
    RLock lock = redission.getLock(key);
    try {
        //30秒内,只能有一个线程触发
        if (lock.tryLock(30,30, TimeUnit.SECONDS)) {
           //我是执行代码
        }
    } catch (Exception e) {
        logger.error("异常", e);
    } finally {
        if(lock.isLocked()){
            lock.unlock();
	}
    }
本文为博主原创文章,未经博主允许不得转载。
更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: