Spring Integration Distributed Locks: conceptual consistency of TTL as compared to Redisson's lease time

621 Views Asked by At

This is a follow up question of: https://github.com/spring-projects/spring-integration/issues/8687

As discussed in the above link, Spring Integration Distributed Lock's concept of TTL is meant for cross-process only, not for threads in the same process.

Later I have tried Redisson, it has a concept of lease time in its RLock:


    /**
     * Tries to acquire the lock with defined <code>leaseTime</code>.
     * Waits up to defined <code>waitTime</code> if necessary until the lock became available.
     *
     * Lock will be released automatically after defined <code>leaseTime</code> interval.
     *
     * @param waitTime the maximum time to acquire the lock
     * @param leaseTime lease time
     * @param unit time unit
     * @return <code>true</code> if lock is successfully acquired,
     *          otherwise <code>false</code> if lock is already set.
     * @throws InterruptedException - if the thread is interrupted
     */
    boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;

https://github.com/redisson/redisson/blob/c2c00a07c279d55d627717fbb290426e19744a65/redisson/src/main/java/org/redisson/api/RLock.java#L55

I think these 2 concepts TTL and lease time are similar (correct me if I am wrong).

But lease time of Redisson works in a consistent way for both cross-process and threads in same process, while TTL of spring integration does not.

The following junit test can reproduce what I mean: https://github.com/cuipengfei/Spikes/blob/22a9896137dd62bda5f030f5a3d33c67fba67310/jpa/spring-jdbc-distributed-lock-issue/src/test/java/com/github/spring/example/LockTest.java#L38C9-L49

docker run -p 6379:6379 -d redis:7.0.12 --requirepass "mypass"

docker run -e POSTGRES_USER=localtest -e POSTGRES_PASSWORD=localtest -e POSTGRES_DB=orders -p 5432:5432 -d postgres:15.3

# start this docker container before running the above junit test

and change mode to compare: https://github.com/cuipengfei/Spikes/blob/master/jpa/spring-jdbc-distributed-lock-issue/src/test/resources/application.properties#L16-L17

lock.registry.name=redisson
# change this line to redis / jdbc / redisson then run test

When running the test in Redis/jdbc mode of spring integration, thread 2 can not get the lock even after TTL.

While running the test in Redisson mode, thread 2 can get the lock after lease time has past, which I think makes more sense conceptually.

What are the design considerations behind TTL/lease time that led to different choices?

2

There are 2 best solutions below

0
On BEST ANSWER

enter image description here

↑ This is my interpretation.

In the case of Spring Integration, Bob is denied the lock because it values the fact that Alice might still be using it more than the fact that more than 20 seconds have passed. This reduces the chance of interrupting Alice's work.

In contrast, Redisson grants the lock to Bob, prioritizing the expiration of the lock duration over the possibility that Alice is still using it. This provides more consistent behavior for lease time.

4
On

I believe there are might be other, different approaches to implement distributed locks.

If you look into the RedisLockRegistry of Spring Integration, you'll see that it is similar to the JdbcLockRegistry and there is a local guard with a ReentrantLock. So, all the interactions within the same process follow the standard Java Lock algorithm. As I explained to you in that issue: the TTL is really for losing dead locks in a distributed environment. On the other hand, you cannot predict how long your process is going to hold the lock, so releasing it prematurely because of some leaseTime may lead to inconsistency in your system where you'd expect to be guarded by the lock.

I'm not sure what your goal is with this locks exercise.