Understanding Distributed Locks and Implementations with Redis and Redisson
This article explains the concept of distributed locks, compares them with local JVM locks, outlines essential properties, demonstrates simple Redis-based lock implementations using SETNX and Lua scripts, discusses lock expiration and renewal, and introduces Redisson's advanced features such as automatic watchdog renewal and the Redlock algorithm.
Distributed Lock Introduction
In a single‑JVM environment, threads synchronize using local locks such as ReentrantLock or the synchronized keyword. When multiple services run in separate JVMs, local locks cannot guarantee mutual exclusion, so a distributed lock is required.
Basic Properties of a Distributed Lock
Mutual exclusion : only one client can hold the lock at any time.
High availability : the lock service must remain available and eventually release the lock even if the client crashes.
Re‑entrancy : the same client can acquire the lock multiple times.
Simple Redis‑Based Lock
Redis provides the SETNX command (equivalent to Java's setIfAbsent ) to create a lock only if the key does not exist.
> SETNX lockKey uniqueValue
(integer) 1
> SETNX lockKey uniqueValue
(integer) 0Releasing the lock is done with DEL :
> DEL lockKey
(integer) 1To avoid accidental deletion, a Lua script can compare the stored value before deleting:
// release lock only if the stored value matches
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
endLock Expiration and Automatic Renewal
Setting an expiration prevents dead locks:
SET lockKey uniqueValue EX 3 NXHowever, if the critical section exceeds the timeout, the lock may expire prematurely. Redisson solves this with a watchdog that automatically renews the lock.
Redisson Watchdog Mechanism
Redisson’s default watchdog timeout is 30 seconds (configurable via setLockWatchdogTimeout ).
// default 30 seconds, can be changed
private long lockWatchdogTimeout = 30 * 1000;
public Config setLockWatchdogTimeout(long lockWatchdogTimeout) {
this.lockWatchdogTimeout = lockWatchdogTimeout;
return this;
}
public long getLockWatchdogTimeout() {
return lockWatchdogTimeout;
}The renewal logic runs periodically (every internalLockLeaseTime/3 ) and uses an asynchronous Lua script to extend the TTL atomically:
private void renewExpiration() {
// schedule next renewal
Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
CompletionStage
future = renewExpirationAsync(threadId);
future.whenComplete((res, e) -> {
if (e != null) {
log.error("Can't update lock " + getRawName() + " expiration", e);
EXPIRATION_RENEWAL_MAP.remove(getEntryName());
return;
}
if (res) {
renewExpiration(); // recursive renewal
} else {
cancelExpirationRenewal(null);
}
});
}
}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
ee.setTimeout(task);
} protected CompletionStage
renewExpirationAsync(long threadId) {
return evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return 1; " +
"end; " +
"return 0;",
Collections.singletonList(getRawName()),
internalLockLeaseTime, getLockName(threadId));
}When a lock is acquired without an explicit lease time, Redisson automatically enables the watchdog:
// acquire lock with automatic renewal
RLock lock = redisson.getLock("lock");
lock.lock();
// business logic
...
lock.unlock();Specifying a lease time disables the watchdog:
// manual lease time, no watchdog
lock.lock(10, TimeUnit.SECONDS);Re‑entrant Distributed Locks
Re‑entrancy allows the same thread to acquire the lock multiple times. Java’s synchronized and ReentrantLock are examples. Redisson provides a re‑entrant lock ( RLock ) along with other lock types such as spin, fair, multi‑lock, red‑lock, and read‑write lock.
Redlock Algorithm for Redis Clusters
In a Redis cluster, a single node failure can cause lock loss. The Redlock algorithm acquires locks on a majority of independent Redis instances to achieve fault tolerance. However, it has performance drawbacks and safety concerns under clock drift, and many practitioners recommend using ZooKeeper for truly reliable distributed locking.
References
Redisson GitHub: https://github.com/redisson/redisson
Redisson 3.17.6 release: https://github.com/redisson/redisson/releases/tag/redisson-3.17.6
Redlock algorithm description: https://redis.io/topics/distlock
Martin Kleppmann’s critique: https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.