项目场景:
多节点应用获取单号,使用Redisson(3.10.1)分布式锁保证单号不会重复。
问题描述
有一台应用已经获取到分布式锁,还没解锁就突然宕机,虽然看门狗默认设置internalLockLeaseTime/lockWatchdogTimeout = 30000毫秒,正常情况会超时解锁,但没有生效(原因不明),此时出现死锁。
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6372")
.setPassword("123456")
.setDatabase(5)
.setConnectTimeout(10000)
.setTimeout(10000)
.setPingConnectionInterval(3000);
RedissonClient redissonClient = Redisson.create(config);
System.out.println("=================================================");
test(redissonClient, false);
// redissonClient.shutdown();
}
private static void test(RedissonClient redissonClient, Boolean flag) {
// 分布式锁
RLock lock = redissonClient.getLock("BILL_NO:AAA");
System.out.println("1、开始 " + lock.getName());
Boolean isDead = true;
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
System.out.println("2、执行业务 " + lock.getName());
isDead = false;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (flag && lock.isLocked() && lock.isHeldByCurrentThread()) {
System.out.println("3、解锁 " + lock.getName());
lock.unlock();
} else {
System.out.println("3、不解锁 " + lock.getName());
}
System.out.println("4、结束 " + lock.getName());
// if (isDead) {
// System.out.println("kill lock " + lock.getName());
// lock.delete();
// }
}
}
======================================================================================
1、开始 BILL_NO:AAA
2、执行业务 BILL_NO:AAA
3、不解锁 BILL_NO:AAA
4、结束 BILL_NO:AAA
解决方案:
一般情况只有应用线程持有这把锁,才会通过看门狗续期,默认30s会过期回收。无法回收的情况下,说明没有设置超期时间,可以以下处理:
1、redisson会在db-5创建分布式锁key,可以直接删除key。
2、使用java脚本,执行 lock.delete()。