Mastering Distributed Locks with Redis: From Basics to Advanced Solutions
This article examines why local locks fail in distributed micro‑service environments, introduces Redis‑based distributed locking, walks through five incremental lock designs—from a simple SETNX implementation to a Lua‑script atomic solution—highlighting each scheme's trade‑offs, code examples, and practical pitfalls.
Local in‑process locking (e.g., synchronized or lock) cannot guarantee consistency when a request flow is split across multiple micro‑services; each service may acquire its own lock, leading to cache‑breakdown and divergent results.
1. The Problem with Local Locks
When 100,000 front‑end requests are distributed to four services (25,000 each) and a cache miss forces every service to lock its own thread, the lock only protects the local JVM. Service A may update key = 100 while Service B concurrently updates key = 99, leaving the final value nondeterministic.
2. What Is a Distributed Lock?
A distributed lock must work across a cluster so that only one thread can access a critical section at a time. The article uses the everyday analogy of a door lock: only one person may be inside the room; others must wait until the door is unlocked.
3. Redis SETNX
Redis provides the SETNX command (set if not exists). When the key does not exist, it is created; otherwise nothing happens. set <key> <value> NX Example in a Docker container:
docker exec -it <container_id> redis-cli set wukong 1111 NXThe command returns OK on success and nil on failure.
4. Bronze Scheme (Simple SETNX)
4.1 Principle
All threads attempt SETNX. The first succeeds and holds the lock.
Other threads fail and must wait.
When the holder finishes, it deletes the lock.
Waiting threads retry the acquisition.
Java code using Spring’s RedisTemplate:
// 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. Sleep briefly then retry
sleep(100);
return getTypeEntityListByRedisDistributedLock();
}Issue: if the business code throws an exception or the process crashes, the lock is never released, causing a deadlock.
5. Silver Scheme (Lock with Expiration)
5.1 Principle
After acquiring the lock, an expiration time is set so that the lock automatically disappears after a fixed period.
// Set expiration after 10 seconds
redisTemplate.expire("lock", 10, TimeUnit.SECONDS);Full code combines acquisition and expiration:
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "123");
if (lock) {
redisTemplate.expire("lock", 10, TimeUnit.SECONDS);
List<TypeEntity> list = getDataFromDB();
redisTemplate.delete("lock");
return list;
}Problem: acquiring the lock and setting the expiration are two separate steps; if a crash occurs between them, the lock may remain without an expiration, re‑introducing deadlock.
6. Gold Scheme (Atomic SET with Expiration)
6.1 Principle
Redis’ SET command can atomically set a value with an expiration using the NX and PX / EX options.
# Milliseconds expiration
set <key> <value> PX <ms> NX
# Seconds expiration
set <key> <value> EX <seconds> NXJava example:
redisTemplate.opsForValue().setIfAbsent("lock", "123", 10, TimeUnit.SECONDS);This guarantees that the lock is created only if it does not exist and that it will expire after the specified time.
7. Platinum Scheme (Unique Identifier)
7.1 Principle
To avoid a client deleting another client’s lock, a unique UUID is stored as the lock value.
// 1. Generate UUID
String uuid = UUID.randomUUID().toString();
// 2. 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 deletion
String current = redisTemplate.opsForValue().get("lock");
if (uuid.equals(current)) {
redisTemplate.delete("lock");
}
return list;
} else {
// Retry after short sleep
sleep(100);
return getTypeEntityListByRedisDistributedLock();
}Drawback: the check‑then‑delete sequence is still non‑atomic; a lock may expire and be reacquired by another client between the read and delete steps.
8. Diamond Scheme (Lua Script for Atomic Check‑And‑Delete)
8.1 Principle
A Lua script runs inside Redis, atomically comparing the stored value with the expected UUID and deleting the key only if they match.
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
endExecution from Java:
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);This eliminates the race condition described in the platinum scheme.
9. Summary of Schemes
Bronze : Simple SETNX. Deadlock if lock not released.
Silver : Adds expiration, but acquisition and expiration are separate → possible deadlock.
Gold : Atomic SET with expiration solves the previous race.
Platinum : Stores a unique UUID to avoid deleting others' locks, yet check‑then‑delete is non‑atomic.
Diamond : Uses Lua script for atomic check‑and‑delete, providing the safest approach before moving to a dedicated library such as Redisson.
These incremental improvements illustrate how to reason about concurrency hazards, evaluate trade‑offs, and progressively harden a distributed locking mechanism.
Reference material:
http://redis.cn/commands/set.html
https://www.bilibili.com/video/BV1np4y1C7Yf
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.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
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.
