Distributed Locks: Why They Are Needed, Required Conditions, and Three Implementation Approaches (Database, Redis, Zookeeper)
This article explains the necessity of distributed locks in multi‑node applications, outlines the essential properties a distributed lock must satisfy, and compares three common implementation methods—database‑based exclusive locks, Redis‑based locks, and Zookeeper‑based locks—highlighting their advantages, drawbacks, and usage patterns.
1. Why Use Distributed Locks
When an application runs on a single JVM, Java concurrency primitives such as ReentrantLock or synchronized can safely protect shared variables. However, once the system is scaled to a cluster of machines, each JVM has its own memory space, so a variable that appears shared is actually duplicated, leading to inconsistent results if no cross‑process coordination is applied.
Therefore, a mechanism is needed that guarantees only one thread across the entire distributed system can execute a critical section at any given time.
2. Required Conditions for a Distributed Lock
1) Only one thread on one machine can hold the lock at a time; 2) High‑availability acquisition and release; 3) High‑performance acquisition and release; 4) Re‑entrancy; 5) Automatic expiration to avoid dead‑locks; 6) Non‑blocking behavior (immediate failure when the lock cannot be obtained).
3. Three Implementation Methods
The three typical ways to implement a distributed lock are based on a relational database, a cache system such as Redis, and Zookeeper.
1) Database‑Based Exclusive Lock
Scheme 1
Table structure includes a unique method_name column. Inserting a row with a specific method name will succeed for only one concurrent request because the database enforces uniqueness.
INSERT INTO method_lock (method_name, desc) VALUES ('methodName', 'methodName');Scheme 2
More elaborate table with fields state , version , and timestamps. The lock is acquired by selecting a row where state=1 and then updating it to state=2 with a version check. If the update affects zero rows, the lock is already held.
DROP TABLE IF EXISTS `method_lock`;
CREATE TABLE `method_lock` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key',
`method_name` varchar(64) NOT NULL COMMENT 'locked method name',
`state` tinyint NOT NULL COMMENT '1: unlocked; 2: locked',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`version` int NOT NULL COMMENT 'version number',
PRIMARY KEY (`id`),
UNIQUE KEY `uidx_method_name` (`method_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='locked methods';
SELECT id, method_name, state, version FROM method_lock WHERE state=1 AND method_name='methodName';
UPDATE method_lock SET state=2, version=2, update_time=NOW() WHERE method_name='methodName' AND state=1 AND version=2;Drawbacks : strong dependency on database availability (single point of failure), no automatic expiration, non‑blocking only via insert failure, and non‑reentrant.
Possible solutions : use a standby database, add a cleanup task for stale rows, implement a retry loop for insertion, and store owner thread information to enable re‑entrancy.
2) Redis‑Based Lock
Acquiring the lock uses the command:
SET resource_name my_random_value NX PX 30000In Java, a typical implementation looks like:
try {
lock = redisTemplate.opsForValue().setIfAbsent(lockKey, LOCK);
logger.info("cancelCouponCode是否获取到锁:" + lock);
if (lock) {
// TODO business logic
redisTemplate.expire(lockKey, 1, TimeUnit.MINUTES); // set expiration
return res;
} else {
logger.info("cancelCouponCode没有获取到锁,不执行任务!");
}
} finally {
if (lock) {
redisTemplate.delete(lockKey);
logger.info("cancelCouponCode任务结束,释放锁!");
} else {
logger.info("cancelCouponCode没有获取到锁,无需释放锁!");
}
}Drawbacks : In a master‑slave setup, a race can occur if the master crashes after granting the lock but before replicating it to the slave, leading to two clients believing they hold the lock (a safety failure).
3) Zookeeper‑Based Lock
Zookeeper stores data as a hierarchical tree of znodes. A distributed lock is built on ephemeral sequential nodes under a persistent parent node (e.g., /ParentLock ).
Lock acquisition steps :
Create an ephemeral sequential node (e.g., Lock1 ) under /ParentLock .
List all children of /ParentLock and sort them. If the created node has the smallest sequence number, the client obtains the lock.
If not the smallest, register a watcher on the immediate predecessor node. When that node disappears, the client re‑checks the list; if it becomes the smallest, it acquires the lock.
This creates a waiting queue similar to Java's ReentrantLock . Lock release occurs either when the client explicitly deletes its node after completing the task, or automatically when the client crashes (the ephemeral node disappears), triggering the next waiting client.
Using Apache Curator simplifies this process; InterProcessMutex provides a re‑entrant distributed lock with acquire() and release() methods. See https://github.com/apache/curator/ for details.
Drawbacks : Performance is lower than Redis because each lock operation involves creating and deleting znodes through the Zookeeper leader, and network partitions can cause temporary loss of lock ownership.
4) Summary
The table below (illustrated in the original article) compares the pros and cons of database, Redis, and Zookeeper locks. In short, no solution satisfies all criteria; the choice depends on the specific scenario.
From the perspective of learning difficulty (low to high): Database > Cache (Redis) > Zookeeper.
From implementation complexity (low to high): Zookeeper >= Cache > Database.
From performance (high to low): Cache > Zookeeper >= Database.
From reliability (high to low): Zookeeper > Cache > Database.
Ultimately, developers should select the method that best balances consistency, availability, performance, and operational complexity for their use case.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.