抓狂突然间获取Redis锁失败(获取redis锁突然失败)

2023-05-13 10:39:42 获取 失败 突然间

最近在写微服务架构的时候,遇到了一个奇怪的问题,一直没能摸出头脑来。我的代码设计在对数据库表进行操作前,需要先获取Redis锁,但是发现有时候获取Redis锁失败,导致代码中断,这让我十分抓狂,花了很长时间排查,最后终于弄明白了,原来是一个加锁超时和解锁粒度不当的问题,导致当Redis突然宕机,当前获取锁的线程会一直等待,卡在锁获取处,从而导致整个系统瘫痪。

我们来看一下解决办法。

我们可以增加等待Redis锁的默认超时时间,当锁的获取超过一定时间还没有回复结果的时候,就可以抛出超时异常,从而结束等待状态,避免长时间堵塞。

//等待Redis锁的默认超时时间
long wtTimeOut = 3*1000;
Rlock lock = redissonClient.getLock(lockKey);
try {
//尝试获取锁,等待3秒,上锁以后10秒自动解锁
boolean res = lock.tryLock(wtTimeOut, 10, TimeUnit.SECONDS);
if (res) {
//do something
} else {
//等待超时,抛出异常
throw new RuntimeException("timeOut");
}
} finally {
//释放锁
lock.unlock();
}

第二种解决方案是调整解锁粒度,尽量减少获取锁和释放锁之间的时间间隔,例如在业务处理时,把获取锁和释放锁分离,处理业务的时候不用释放锁,完成之后再进行释放,从而让Redis宕机的机率越小越好。

final CountDownLatch latch = new CountDownLatch(1);
redissonClient.getLock(lockKey).lockAsync(60, TimeUnit.SECONDS, new LockOperationAsync(){
@Override
public void onLockAquire(Rlock lock) {
//获取锁之后,做相应的操作
try {
//业务处理
} finally {
try {
//释放锁
lock.unlock();
} finally {
latch.countDown();
}
}
}
});
//等待锁的释放
try {
latch.awt();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}

上面的问题就是和加锁超时时间还有解锁粒度有关,经过修改,重新发布后,再也没遇到这个问题了,总算把它解决了,虽然这让我很费时间,但还是挺开心解决了把。

相关文章