Why Use Distributed Locks? Implementations with Redis and Zookeeper

The article explains the stock‑oversell problem in a single‑machine e‑commerce system, shows why native Java locks fail in multi‑node deployments, and then details practical distributed‑lock solutions using Redis (including SET NX PX, Lua‑based release, RedLock algorithm and Redisson) and Zookeeper (ephemeral sequential nodes and Curator), before comparing their advantages, drawbacks, and offering selection guidance.

Java Captain
Java Captain
Java Captain
Why Use Distributed Locks? Implementations with Redis and Zookeeper

When multiple requests concurrently modify a shared resource such as product inventory, a single‑machine system can suffer from overselling because native Java locks (synchronized, ReentrantLock) only protect threads within the same JVM.

In a distributed deployment the same lock does not work across machines, so a distributed lock is required – a globally unique lock that all nodes can acquire.

Redis‑based Distributed Lock

The simplest approach stores a lock key in Redis using the atomic command: SET anyLock unique_value NX PX 30000 Lock release is performed with a Lua script to ensure atomic check‑and‑delete:

if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end

Key points:

Use SET key value NX PX milliseconds to guarantee atomicity.

The lock value must be unique so that only the owner can release it.

Consider Redis deployment mode (single‑node, master‑slave with Sentinel, or cluster) because single‑node introduces a single‑point‑of‑failure.

RedLock is an algorithm that tries to acquire the lock on a majority of nodes in a Redis cluster, measures the elapsed time, and releases the lock if the acquisition fails.

Redisson Client

Redisson abstracts the above details. Example configuration for a Redis cluster:

Config config = new Config();
config.useClusterServers()
    .addNodeAddress("redis://192.168.31.101:7001")
    .addNodeAddress("redis://192.168.31.101:7002")
    .addNodeAddress("redis://192.168.31.101:7003")
    .addNodeAddress("redis://192.168.31.102:7001")
    .addNodeAddress("redis://192.168.31.102:7002")
    .addNodeAddress("redis://192.168.31.102:7003");
RedissonClient redisson = Redisson.create(config);
RLock lock = redisson.getLock("anyLock");
lock.lock();
lock.unlock();

Redisson uses Lua scripts for all operations, provides a watchdog that automatically extends the lock’s TTL while it is held, and thus avoids dead‑locks caused by client crashes.

Zookeeper‑based Distributed Lock

Zookeeper offers ordered, temporary znodes and event watches, which make it a natural fit for distributed coordination.

Typical algorithm:

Create an ephemeral sequential node under a lock directory (e.g., /lock/node‑).

List all children of the directory and check if the created node has the smallest sequence number.

If it is the smallest, the lock is acquired.

Otherwise, set a watch on the predecessor node; when that node is deleted, repeat step 2.

When the lock holder releases the lock, it deletes its znode, triggering the watch of the next node in line.

Curator Library

Curator simplifies Zookeeper usage. Acquiring a lock is as easy as:

InterProcessMutex lock = new InterProcessMutex(client, "/anyLock");
lock.acquire();
lock.release();

Under the hood Curator creates the ephemeral sequential node, watches the predecessor, and deletes the node on release. The core lock‑acquisition loop looks like:

private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception {
    // ... get sorted children, check if our node is smallest ...
    // if not, watch previous node and wait
    // finally delete our node if needed
    return haveTheLock;
}

Comparison of Redis and Zookeeper Locks

Redis is extremely fast and widely adopted, but its eventual‑consistency model and single‑point‑of‑failure (in non‑cluster mode) can lead to edge‑case correctness issues; the basic lock requires busy‑waiting, and even RedLock cannot guarantee 100 % safety in complex scenarios.

Zookeeper provides strong consistency, ordered nodes, and watches, so lock acquisition is event‑driven rather than polling, making it more robust for coordination, though a high volume of lock operations can stress the ZK ensemble.

Recommendation

If a Zookeeper cluster is available, it is generally preferred for distributed locks because of its consistency guarantees and efficient watch‑based waiting. When only a Redis cluster exists or the overhead of managing Zookeeper is undesirable, Redis (or Redisson) remains a practical choice, especially when high performance is required and the workload does not hit the edge cases where Redis locks may fail.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

concurrencyZooKeeperdistributed-lockredisson
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.