抓狂突然间获取Redis锁失败(获取redis锁突然失败)
最近在写微服务架构的时候,遇到了一个奇怪的问题,一直没能摸出头脑来。我的代码设计在对数据库表进行操作前,需要先获取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());}
上面的问题就是和加锁超时时间还有解锁粒度有关,经过修改,重新发布后,再也没遇到这个问题了,总算把它解决了,虽然这让我很费时间,但还是挺开心解决了把。