Distributed Lock Implementations with Redis: From Local Locks to Bronze, Silver, Gold, Platinum, and Diamond Solutions
This article explains why local in‑memory locks fail in distributed environments, introduces the concept of distributed locks, and walks through five progressive Redis‑based lock implementations—bronze, silver, gold, platinum, and diamond—detailing their principles, code examples, advantages, and shortcomings.
The previous article covered using local memory caching to improve performance, but local locking ( synchronized or lock) does not work in distributed scenarios, so this piece explores how to introduce a distributed lock.
1. Problems with local locks – When multiple micro‑services handle high‑concurrency requests, each service may acquire a local lock while accessing the database, leading to data inconsistency because locks are not shared across the cluster.
2. What is a distributed lock? – A lock that works across a distributed cluster so that only one thread can access a critical section at a time. The article uses the analogy of a single door that only one person can enter.
3. Redis SETNX – The SETNX command (set if not exists) can be used to implement a simple lock. Example command: set <key> <value> NX Running the command inside a Docker container:
docker exec -it <container_id> redis-cli set wukong 1111 NXIf the key does not exist, Redis returns OK; otherwise it returns nil.
4. Bronze scheme – Use SETNX to acquire the lock and delete it after the business logic finishes. Sample Java code:
// 1. try to acquire lock
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "123");
if (lock) {
// 2. business logic
List<TypeEntity> list = getDataFromDB();
// 3. release lock
redisTemplate.delete("lock");
return list;
} else {
// 4. wait and retry
sleep(100);
return getTypeEntityListByRedisDistributedLock();
}The bronze scheme suffers from deadlock if the business code crashes before releasing the lock.
5. Silver scheme – Adds an automatic expiration time to the lock to avoid deadlock:
// acquire lock
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "123");
if (lock) {
// set expiration (10 seconds)
redisTemplate.expire("lock", 10, TimeUnit.SECONDS);
// business logic
List<TypeEntity> list = getDataFromDB();
redisTemplate.delete("lock");
return list;
}However, because acquiring the lock and setting the expiration are two separate steps, a failure between them can still leave the lock without an expiration.
6. Gold scheme – Performs lock acquisition and expiration atomically using the extended SET command:
set <key> <value> NX PX <milliseconds>Java example:
setIfAbsent("lock", "123", 10, TimeUnit.SECONDS);Its drawback is that all clients use the same lock value, so a client that finishes later may unintentionally delete another client’s lock.
7. Platinum scheme – Generates a unique UUID for each lock instance and stores it as the lock value, then only deletes the lock if the stored value matches the UUID:
// 1. generate UUID
String uuid = UUID.randomUUID().toString();
// 2. try to acquire lock with expiration
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 10, TimeUnit.SECONDS);
if (lock) {
// business logic
List<TypeEntity> list = getDataFromDB();
// 4. verify ownership before deleting
String current = redisTemplate.opsForValue().get("lock");
if (uuid.equals(current)) {
redisTemplate.delete("lock");
}
return list;
} else {
// wait and retry
sleep(100);
return getTypeEntityListByRedisDistributedLock();
}Even with unique IDs, the check‑then‑delete steps are not atomic, which can still cause a race condition.
8. Diamond scheme – Solves the atomicity issue by using a Lua script that checks the lock value and deletes it in a single Redis operation:
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
endJava execution example:
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
Arrays.asList("lock"), uuid);The article concludes that the diamond scheme provides a safe distributed lock, and hints that the next article will cover Redisson as a more robust solution.
Summary – By iteratively improving from a simple SETNX lock to a Lua‑script‑based atomic operation, the article demonstrates how to handle lock acquisition, expiration, uniqueness, and atomic release in a Redis‑backed distributed system.
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.
Wukong Talks Architecture
Explaining distributed systems and architecture through stories. Author of the "JVM Performance Tuning in Practice" column, open-source author of "Spring Cloud in Practice PassJava", and independently developed a PMP practice quiz mini-program.
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.
