Mastering Redis Distributed Locks with Redisson: From Simple Locks to Redlock
This article explains how to implement ordinary Redis distributed locks and the advanced Redlock algorithm using Redisson across single‑node, sentinel, and cluster architectures, provides complete Java code examples, and addresses common questions about expiration, high availability, and comparisons with Zookeeper.
Redis Architectures
Redis currently has several common deployment architectures: single‑node, master‑slave, sentinel, and cluster.
Single‑node mode
Master‑slave mode
Sentinel mode
Cluster mode
We first explain how to implement a simple distributed lock with Redisson based on these architectures, noting that Redlock is built on top of the ordinary lock.
Ordinary Distributed Lock
Redis ordinary distributed lock principles are well known; this section focuses on the implementation using Redisson.
Single‑node mode
Source code:
// Construct Config for Redisson distributed lock
Config config = new Config();
config.useSingleServer().setAddress("redis://172.29.1.180:5379").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient = Redisson.create(config);
RLock disLock = redissonClient.getLock("DISLOCK");
boolean isLock;
try {
// Try to acquire the lock
isLock = disLock.tryLock(500, 15000, TimeUnit.MILLISECONDS);
if (isLock) {
// TODO: if get lock success, do something;
Thread.sleep(15000);
}
} catch (Exception e) {
} finally {
// Release the lock in any case
disLock.unlock();
}The lock key in Redis is stored as a hash where the field is UUID:threadId and the value is the re‑entry count (1 for a non‑re‑entrant lock).
172.29.1.180:5379> hgetall DISLOCK
1) "01a6d806-d282-4715-9bec-f51b9aa98110:1"
2) "1"Sentinel mode
Configuration is similar, only the server definition changes:
Config config = new Config();
config.useSentinelServers()
.addSentinelAddress("redis://172.29.3.245:26378",
"redis://172.29.3.245:26379",
"redis://172.29.3.245:26380")
.setMasterName("mymaster")
.setPassword("a123456")
.setDatabase(0);Cluster mode
Cluster configuration example:
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://172.29.3.245:6375",
"redis://172.29.3.245:6376",
"redis://172.29.3.245:6377",
"redis://172.29.3.245:6378",
"redis://172.29.3.245:6379",
"redis://172.29.3.245:6380")
.setPassword("a123456")
.setScanInterval(5000);Summary
Ordinary distributed lock implementation is straightforward; regardless of the architecture, the lock is obtained by executing a Lua script via the EVAL command.
Redlock Distributed Lock
Implementation of Redlock using three Redis instances (single‑node architecture shown):
Config config1 = new Config();
config1.useSingleServer().setAddress("redis://172.29.1.180:5378").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient1 = Redisson.create(config1);
Config config2 = new Config();
config2.useSingleServer().setAddress("redis://172.29.1.180:5379").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient2 = Redisson.create(config2);
Config config3 = new Config();
config3.useSingleServer().setAddress("redis://172.29.1.180:5380").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient3 = Redisson.create(config3);
String resourceName = "REDLOCK";
RLock lock1 = redissonClient1.getLock(resourceName);
RLock lock2 = redissonClient2.getLock(resourceName);
RLock lock3 = redissonClient3.getLock(resourceName);
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
boolean isLock;
try {
isLock = redLock.tryLock(500, 30000, TimeUnit.MILLISECONDS);
System.out.println("isLock = " + isLock);
if (isLock) {
// TODO: if get lock success, do something;
Thread.sleep(30000);
}
} catch (Exception e) {
} finally {
// Release the lock in any case
redLock.unlock();
}The key change is creating a RedissonRedLock with three underlying RLock instances.
For sentinel or cluster mode, you need three (or five) nodes; at least ⌈N/2⌉+1 nodes must succeed for the lock to be considered acquired.
Implementation Principle
RedissonRedLockextends RedissonMultiLock; its tryLock method iterates over all locks, attempts to acquire each via Lua, respects a failure‑limit ( N-(N/2+1)), and releases any partially acquired locks on errors.
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
int failedLocksLimit = failedLocksLimit();
List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size());
for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {
RLock lock = iterator.next();
boolean lockAcquired;
try {
lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);
} catch (RedisConnectionClosedException|RedisResponseTimeoutException e) {
unlockInner(Arrays.asList(lock));
lockAcquired = false;
} catch (Exception e) {
lockAcquired = false;
}
if (lockAcquired) {
acquiredLocks.add(lock);
} else {
if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {
break;
}
}
}
return true;
}Common Questions
How to set expiration time? If the lock expires before the task finishes, another thread may acquire it. Extending the TTL (renewal) adds complexity and is not provided by most frameworks.
High availability of Redis locks? There is ongoing debate about the safety of Redis locks; see discussions between Martin Kleppmann and antirez.
Zookeeper vs Redis? Redis offers better performance, while Zookeeper provides stronger guarantees for distributed lock correctness; the choice depends on business requirements.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
