Fundamentals 6 min read

How ZooKeeper Implements Distributed Locks with Sequential Nodes

Distributed locks prevent concurrent conflicts over shared resources in distributed systems, and this article explains ZooKeeper’s approach using ordered sequential nodes, illustrating the lock acquisition and release process with command-line examples and a complete Java implementation.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
How ZooKeeper Implements Distributed Locks with Sequential Nodes

Scenario

In a distributed system multiple subsystems may need to modify the same data concurrently, leading to conflicts because there is no logical ordering of operations.

To protect the shared resource a distributed lock is required.

ZooKeeper Solution

ZooKeeper stores data in a hierarchical tree similar to a file system, allowing creation of ordered nodes. When systems A, B, and C request a lock they each create an ordered sequential node under a common /Lock parent.

The node creation command is: create -s -e /Lock/data_A test Although each system runs the same command, the -s option creates an ordered node and the -e option creates an ephemeral node, so ZooKeeper assigns a unique sequence number (e.g., data_A00000000, data_A00000001, data_A00000002).

Each client reads the list of children of /Lock, sorts them, and the client whose node has the smallest sequence number acquires the lock and proceeds to use the shared resource.

When the client finishes, it deletes its node, causing ZooKeeper to notify the remaining clients. They re‑read the list, and the next smallest node gains the lock. Because the nodes are ephemeral, if a client crashes ZooKeeper automatically removes its node, preventing deadlocks.

Example Code

The following Java class demonstrates a simple distributed lock using ZooKeeper’s EPHEMERAL_SEQUENTIAL mode.

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

public class DistributedLock {
    private final ZooKeeper zk;
    private final String lockBasePath;
    private final String lockName;
    private String lockPath;

    public DistributedLock(ZooKeeper zk, String lockBasePath, String lockName) {
        this.zk = zk;
        this.lockBasePath = lockBasePath;
        this.lockName = lockName;
    }

    public void lock() throws IOException {
        try {
            lockPath = zk.create(lockBasePath + "/" + lockName, null, Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL_SEQUENTIAL);
            final Object lock = new Object();
            synchronized (lock) {
                while (true) {
                    List<String> nodes = zk.getChildren(lockBasePath, new Watcher() {
                        @Override
                        public void process(WatchedEvent event) {
                            synchronized (lock) {
                                lock.notifyAll();
                            }
                        }
                    });
                    Collections.sort(nodes);
                    if (lockPath.endsWith(nodes.get(0))) {
                        return;
                    } else {
                        lock.wait();
                    }
                }
            }
        } catch (KeeperException e) {
            throw new IOException(e);
        } catch (InterruptedException e) {
            throw new IOException(e);
        }
    }

    public void unlock() throws IOException {
        try {
            zk.delete(lockPath, -1);
            lockPath = null;
        } catch (KeeperException e) {
            throw new IOException(e);
        } catch (InterruptedException e) {
            throw new IOException(e);
        }
    }
}

Images in the original article illustrate the node creation, ordering, and lock release steps.

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.

JavaconcurrencyZooKeeperdistributed-lockephemeral nodesequential node
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.