Apache ZooKeeper Fundamentals: Deployment, API Usage, and High Availability

Understanding Core Concepts

Apache ZooKeeper is an open-source coordination service designed for distributed applications. It operates as a hierarchical namespace, similar to a standard filesystem, where every entry is identified as a ZNode (ZooKeeper node). These nodes facilitate synchronization, configuraton management, and naming services across networked machines.

Key responsibilities include:

  • Centralized configuraton storage
  • Distributed locking primitives
  • Service discovery and leadership election

Local Environment Setup

Prerequisites

ZooKeeper runs on the Java Virtual Machine (JVM). Ensure JDK 7 or newer is installed before proceeding.

Installation Steps

  1. Download the binary release from the Apache archive.
  2. Move the archive to the target directory, typically /opt/zookeeper/.
  3. Extract the contents using tar -zxvf.
# Navigate to install directory
cd /opt/
mkdir zookeeper
tar -zxvf apache-zookeeper-3.x.x-bin.tar.gz -C /opt/zookeeper/

Configuration

Locate the configuration file in the conf subdirectory. Rename zoo_sample.cfg to zoo.cfg and modify the data directory path.

# config file excerpt
dataDir=/var/lib/zookeeper/data
clientPort=2181

Starting the Service

Execute the server script to initialize the process.

cd bin
./zkServer.sh start

Verify the status with:

./zkServer.sh status

The output should indicate standalone mode for a single instance.

Command-Line Interface Operations

Server Commands

Manage the lifecycle of the server via CLI scripts.

  • Start: ./zkServer.sh start
  • Status: ./zkServer.sh status
  • Stop: ./zkServer.sh stop

Client Interaction

Launch the CLI tool to connect and manipulate the registry.

./zkCli.sh -server localhost:2181

Node Management

Nodes are classified into four types based on persistence and sequencing behavior:

  • PERSISTENT: Survives restarts unless explicitly deleted.
  • EPHEMERAL: Auto-removed when the session ends.
  • PERSISTENT_SEQUENTIAL: Auto-incrementing suffix appended.
  • EPHEMERAL_SEQUENTIAL: Transient with sequential ordering.

Basic operations include:

ls /      # List children
create /node-path value    # Create node
data = get /node-path     # Retrieve value
set /node-path new-value  # Update value
delete /node-path         # Remove node

Java Integration with Curator

Curator simplifies interacting with ZooKeeper by handling reconnection logic and providing high-level abstractions.

Establishing Connection

Initialize the framework with retry policies and session timeouts.

public class ZkClientConfig {
    private static final String QUORUM_ADDRESS = "localhost:2181";
    
    public static void main(String[] args) throws Exception {
        RetryPolicy policy = new ExponentialBackoffRetry(3000, 3);
        CuratorFramework zkClient = CuratorFrameworkFactory.builder()
            .connectString(QUORUM_ADDRESS)
            .sessionTimeoutMs(60000)
            .connectionTimeoutMs(15000)
            .retryPolicy(policy)
            .namespace("my-app")
            .build();
        
        zkClient.start();
        // Perform operations here
    }
}

Data Operations

Perform CRUD actions on ZNodes using fluent interfaces.

Create:

// Create persistent node with data
String createdPath = zkClient.create()
    .forPath("/services/order-service", "active".getBytes());

// Create ephemeral node
zkClient.create().withMode(CreateMode.EPHEMERAL)
    .forPath("/temp/lock");

Read:

// Get current data
byte[] data = zkClient.getData().forPath("/services/order-service");

// Monitor state changes
Stat stat = new Stat();
zkClient.getData().storingStatIn(stat).forPath("/services/order-service");

Update & Delete:

// Optimistic locking update
int version = stat.getVersion();
zkClient.setData().withVersion(version)
    .forPath("/services/order-service", "inactive".getBytes());

// Recursive delete
zkClient.delete().deletingChildrenIfNeeded().forPath("/temp/old-data");

Watcher Mechanisms

Curator offers cache implementations to avoid manual listener registration.

  1. NodeCache: Monitors specific paths for data changes.
  2. PathChildrenCache: Observes child creation/deletion under a path.
  3. TreeCache: Tracks the entire subtree structure.

Example with NodeCache:

NodeCache cache = new NodeCache(zkClient, "/config/db-host");
cache.getListenable().addListener(() -> {
    System.out.println("Config updated: " + new String(cache.getCurrentData().getData()));
});
cache.start(true);

Distributed Synchronization

Implementing locks across JVM boundaries requires coordination via the cluster. The core strategy involves creating ephemeral ordered nodes to determine lock ownership based on hierarchy.

Implementation Example

Using InterProcessMutex provides a semaphore-style lock mechanism suitable for non-reentrant scenarios.

public class DistributedTicketController {
    private int availableSlots = 5;
    private InterProcessMutex mutex;
    
    public DistributedTicketController(CuratorFramework client, String lockPath) {
        this.mutex = new InterProcessMutex(client, lockPath);
    }
    
    public void sellSlot() throws Exception {
        if (mutex.acquire(5, TimeUnit.SECONDS)) {
            try {
                if (availableSlots > 0) {
                    availableSlots--;
                    System.out.println("Sold: " + availableSlots);
                }
            } finally {
                mutex.release();
            }
        }
    }
}

Cluster Architecture and Fault Tolerance

High availability is achieved through quorum configurations. A cluster consists of three or more servers communicating over specific ports for voting and data replication.

Configuration Requirements

Each instance requires a unique ID recorded in data/myid. The zoo.cfg must list all peers using the format server.ID=IP:SyncPort:LeaderElectionPort.

# Example cluster configuration
server.1=192.168.1.10:2881:3881
server.2=192.168.1.11:2882:3882
server.3=192.168.1.12:2883:3883

Failure Scenarios

  • Follower Loss: If a follower stops, the remaining quorum functions normally.
  • Majority Loss: If more than half the nodes fail, the leader cannot maintain a majority vote and shuts down to prevent data inconsistency.
  • Leader Failure: A new election occurs automatically among surviving followers to select a replacement.

System Roles

  • Leader: Processes write transactions and coordinates consensus.
  • Follower: Handles read requests and participates in elections.
  • Observer: Handles reads but does not vote, used to scale read throughput without affecting write performance.

Tags: apache-zookeeper distributed-coordination curator-framework java-client high-availability

Posted on Fri, 04 Sep 2026 16:09:20 +0000 by leeperryar