7 Distributed Lock Implementations and Real‑World Pitfalls
The article explains why local locks fail in multi‑machine deployments, defines the three essential properties of a correct distributed lock, walks through seven Redis‑based lock solutions with code samples, highlights common production pitfalls, and provides a decision tree for selecting the right approach.
Why Distributed Locks?
In monolithic Java, synchronized or ReentrantLock works because memory is shared. When the system is split across many machines, JVM memory is isolated, so local locks cannot enforce mutual exclusion.
Distributed lock principle : move the lock marker to a shared store (Redis, ZooKeeper, Etcd) so that all processes can see it.
Mutual exclusion : only one client holds the lock at any time.
Dead‑lock avoidance : the lock is released automatically if the client crashes.
Fault tolerance : the system remains operational if the lock service fails.
Seven Redis‑Based Lock Schemes
Scheme 1: SETNX + EXPIRE (historical)
Boolean locked = redis.setnx("lock:order", "thread-1");
if (locked) {
redis.expire("lock:order", 30);
// business logic …
redis.del("lock:order");
}Fatal issue : SETNX and EXPIRE are separate commands; if the process crashes between them the lock never expires, causing a dead lock.
Scheme 2: SETNX + value storing expiration time
long expires = System.currentTimeMillis() + 30000;
if (redis.setnx("lock:order", String.valueOf(expires)) == 1) {
// lock acquired
}Problems
Relies on clock synchronization; drift breaks the lock.
No unique identifier; another client may delete the lock unintentionally.
Concurrent getSet calls can overwrite the expiration.
Production pitfall : an 8‑second clock skew between two servers caused two threads to hold the same lock simultaneously, resulting in 200 oversold orders.
Scheme 3: Lua script (atomic SETNX + EXPIRE)
if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then
redis.call('expire', KEYS[1], ARGV[2])
return 1
else
return 0
endRedis executes Lua scripts single‑threaded, guaranteeing atomicity.
Pros : solves atomicity problem of Scheme 1.
Cons : value still lacks a unique identifier, so accidental deletion remains possible.
Scheme 4: SET EX PX NX (Redis 2.6.12+)
SET lock:order "uuid-thread-1" NX PX 30000Parameters NX – set only if the key does not exist. PX – expiration in milliseconds. value – unique identifier (UUID + thread ID).
This single command provides atomic acquisition with server‑side TTL and a verifiable value.
Scheme 5: SET EX PX NX + verify unique value on release
Lock acquisition uses Scheme 4. Unlocking uses a Lua script that checks the stored value before deleting:
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
endResult : only the owner can release the lock, eliminating accidental deletions.
Production pitfall: without value verification, a timed‑out lock held by thread B was deleted by thread A after A finished its business, corrupting data.
Scheme 6: Redisson framework (production‑grade default)
Redisson implements the previous safeguards and adds:
Re‑entrancy : a hash records the re‑entry count (+1 on lock, –1 on unlock).
Watchdog (auto‑renewal) : default 30 s TTL, refreshed every 10 s while the lock is held.
Atomic release : internal Lua script ensures only the owner can unlock.
Blocking wait : publish‑subscribe wakes waiting threads when the lock is released.
RLock lock = redisson.getLock("stockLock");
lock.lock(30, TimeUnit.SECONDS);
try {
// business logic
} finally {
lock.unlock();
}One line of code replaces dozens of manual steps.
Scheme 7: RedLock (multi‑node disaster‑recovery)
Single‑node Redis can lose locks during master‑slave failover. RedLock acquires the lock on N independent Redis nodes and requires a majority to succeed:
1. Record start time T1
2. Request lock on 5 nodes (timeout << lock TTL)
3. If (T2‑T1 < lock TTL) && (successful nodes > N/2) → lock acquired
4. Otherwise release on all nodesKey constraints
Node count must be odd (3/5/7).
Lock acquisition time must be < lock TTL.
Successful nodes must exceed N/2.
Production pitfall: network jitter caused lock acquisition to exceed the TTL, leading to many failures in latency‑sensitive scenarios.
Seven Real‑World Pitfalls
Atomicity break : SETNX followed by a crash leaves the lock forever – fix with SET NX PX or Lua.
Clock drift : client‑side expiration can release the lock early – use server‑side TTL.
Accidental deletion : A’s timeout lets B acquire the lock, but A later deletes it – store a UUID and verify on release.
Business timeout without renewal : a 30 s lock expires while a 50 s task runs – Redisson’s watchdog auto‑renews.
Master‑slave failover loss : lock data not replicated – adopt RedLock multi‑node strategy.
Non‑re‑entrant dead lock : same thread cannot reacquire – Redisson records re‑entry count in a hash.
Connection pool exhaustion : high concurrency saturates Redis connections – configure pool size and use pipelining.
Selection Decision Tree
Need strong consistency (finance/payments)?
→ ZooKeeper / Etcd (CP, sacrifice performance for safety)
Need high performance (flash sale/inventory)?
→ Redis + Redisson (AP, performance first)
Single‑node sufficient?
→ SET key value NX PX + Lua release (Scheme 4 + 5)
Multi‑node disaster recovery?
→ RedLock or Redisson ClusterFinal Three Rules
Lock acquisition and expiration must be atomic.
Before releasing, verify that you are the lock owner.
Business may exceed lock TTL; the lock must support renewal.
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.
Programmer1970
Formerly called 'Code to 35'. Add our main WeChat ID to access a wealth of shared resources (algorithms, interview prep, tech stacks: Java, Python, Go, big data). We mainly share serious development techniques, focusing on output-driven input. Occasionally we post life snippets and gossip. Our aim is to attract precise traffic and test advertising opportunities.
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.
