我不理解从JdbcLockRegistry获取的分布式锁的行为。
@Bean
public LockRepository lockRepository(DataSource datasource) {
return new DefaultLockRepository(datasource);
}
@Bean
public LockRegistry lockRegistry(LockRepository repository) {
return new JdbcLockRegistry(repository);
}我的项目运行在PostgreSQL上,Spring Boot版本是2.2.2,这是演示用例:
@GetMapping("/isolate")
public String isolate() throws InterruptedException {
Lock lock = registry.obtain("the-lock");
if (lock.tryLock(10, TimeUnit.SECONDS)) { // close
try {
Thread.sleep(30 * 1000L);
} finally {
lock.unlock(); // open
}
} else {
return "rejected";
}
return "acquired";
}注:当使用Hazelcast分布式锁时,该用例有效。
观察到的行为是,通过在第一个实例上调用API,在数据库中适当地注册了第一个锁。然后,在30秒内,在另一个实例(其他端口)上请求第二个on,它将更新现有int_lock表的行(client_id更改),而不是失败。因此,第一个端点在30秒后交付(无解锁失败),第二个端点在其自己的30秒后交付。没有相互排斥的关系。
以下是单个采集的日志:
Trying to acquire lock...
Executing prepared SQL update
Executing prepared SQL statement [DELETE FROM INT_LOCK WHERE REGION=? AND LOCK_KEY=? AND CREATED_DATE<?]
Executing prepared SQL update
Executing prepared SQL statement [UPDATE INT_LOCK SET CREATED_DATE=? WHERE REGION=? AND LOCK_KEY=? AND CLIENT_ID=?]
Executing prepared SQL update
Executing prepared SQL statement [INSERT INTO INT_LOCK (REGION, LOCK_KEY, CLIENT_ID, CREATED_DATE) VALUES (?, ?, ?, ?)]
Processing...
Executing prepared SQL update
Executing prepared SQL statement [DELETE FROM INT_LOCK WHERE REGION=? AND LOCK_KEY=? AND CLIENT_ID=?]虽然听起来很奇怪,获取过程是从删除开始的。我已经尝试为DefaultLockRepository设置一个恒定的客户端id,但没有任何改进。有没有人知道如何解决这个问题?谢谢你的帮助。
发布于 2019-12-11 22:49:14
好的。默认情况下,存储库的TTL是10s,就像我在那个特定用例中的超时一样。所以锁显然在超时之前就死了(删除)。下面是一个解决方法:
@Bean
public LockRepository lockRepository(DataSource datasource) {
DefaultLockRepository repository = new DefaultLockRepository(datasource);
repository.setTimeToLive(60 * 1000);
return repository;
}发布于 2019-12-13 23:44:28
为了维护锁,我尝试利用Lock#lock调用的DefaultLockRepository#acquire,它在插入新锁之前(以及在清理过期锁之后,如前所述)尝试更新:
@GetMapping("/isolate")
public String isolate() throws InterruptedException {
Lock lock = registry.obtain("the-lock");
log.warn("Trying to acquire lock...");
if (lock.tryLock(10, TimeUnit.SECONDS)) { // close lock
try {
for (int i=0; i < 6; i++) { // very...
log.warn("Processing...");
Thread.sleep(5 * 1000L); // ... long task
lock.lock(); //DEBUG holding (lock update)
}
} finally {
if (!repository.isAcquired("the-lock")) {
throw new IllegalStateException("lock lost");
} else {
lock.unlock(); // open lock
}
}
} else {
return "rejected";
}
return "acquired";
}但这并没有像预期的那样工作(在这个测试中,ttl是默认的10秒);尽管我可以在PostgreSQL的控制台中看到锁定日期的变化,但我最终总是得到一个锁丢失的IllegalStateException。
https://stackoverflow.com/questions/59287676
复制相似问题