Skip to content

Redis Redlock vs ZooKeeper: Distributed Locking Guide

CoreConceptAugust 1, 20263 min read

In high-concurrency microservices architectures, preventing race conditions when multiple stateless worker instances access shared resources requires Distributed Locking. Unlike single-process mutexes, distributed locks operate over a network, coordinating mutual exclusion across independent nodes.

This guide evaluates the three primary distributed locking implementations: Redlock (Redis), Apache ZooKeeper, and etcd—analyzing their consensus models, fencing token requirements, and failure modes during network partitions.

Consensus & Locking: Redis vs. ZooKeeper vs. etcd

Redis Redlock relies on time-based leases across an odd number ($N \ge 5$) of independent Redis nodes. A lock is acquired if the client obtains a lease from a majority of nodes within a strict timeout window.

By contrast, ZooKeeper and etcd rely on strong consensus algorithms (ZAB for ZooKeeper, Raft for etcd). ZooKeeper uses ephemeral sequential z-nodes and watches, while etcd utilizes lease objects and revision streams to notify waiting clients immediately when a lock releases.

Quick reference

  • Redis Redlock relies on synchronized system clocks across nodes; clock drift can violate mutual exclusion safety.
  • ZooKeeper ephemeral nodes auto-delete when a client connection drops, preventing deadlocks when nodes crash.
  • etcd uses Raft consensus and TTL leases, guaranteeing strong linearizable consistency for lock state.
Redlock Algorithm Lease Acquisition (TypeScript)
1import Redis from "ioredis";2 3const redClient = new Redis("redis://node1:6379");4 5async function acquireLock(lockKey: string, lockValue: string, ttlMs: number): Promise<boolean> {6  // SET key value NX PX ttlMs -> Atomic Set if Not Exists7  const result = await redClient.set(lockKey, lockValue, "PX", ttlMs, "NX");8  return result === "OK";9}10 11async function releaseLock(lockKey: string, lockValue: string): Promise<boolean> {12  // Lua script guarantees atomic release only if lockValue matches owner ID13  const luaScript = `14    if redis.call("get", KEYS[1]) == ARGV[1] then15      return redis.call("del", KEYS[1])16    else17      return 018    end19  `;20  const result = await redClient.eval(luaScript, 1, lockKey, lockValue);21  return result === 1;22}
etcd Lease Locking (Go)
1package main2 3import (4	"context"5	"time"6	clientv3 "go.etcd.io/etcd/client/v3"7	"go.etcd.io/etcd/client/v3/concurrency"8)9 10func main() {11	cli, _ := clientv3.New(clientv3.Config{Endpoints: []string{"localhost:2379"}})12	defer cli.Close()13 14	session, _ := concurrency.NewSession(cli, concurrency.WithTTL(10))15	defer session.Close()16 17	mutex := concurrency.NewMutex(session, "/my-distributed-lock/")18	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)19	defer cancel()20 21	if err := mutex.Lock(ctx); err == nil {22		// Critical section executed safely23		mutex.Unlock(context.Background())24	}25}

Remember this

Redlock provides high performance for soft-realtime tasks; ZooKeeper and etcd deliver strict linearizable safety for financial operations.

Fencing Tokens & Split-Brain Prevention

Even with a valid distributed lock, process pauses (such as long Garbage Collection pauses or network hiccups) can cause a client's lock lease to expire while it is still executing a critical section.

To prevent stale writes from overwriting valid data, systems use Fencing Tokens—monotonically increasing revision numbers returned upon lock acquisition. Shared storage targets (such as PostgreSQL or S3) reject any write carrying an older fencing token than the current database state.

Quick reference

  • Fencing tokens protect storage layers when a worker experiences an unexpected GC pause.
  • etcd revision numbers serve as built-in fencing tokens for downstream storage writes.
  • Compare with ACID Isolation Levels and Saga vs 2PC.

Remember this

Always pass fencing tokens to downstream storage to prevent stale writes after lock lease expiration.

Decision Matrix for Enterprise Microservices

Selecting the right distributed locking engine depends on whether your workload prioritizes throughput or absolute consistency.

For related guides, see our articles on Cache Stampede Prevention and Consistency Models.

Quick reference

  • Choose Redis for high-throughput distributed locks where rare lock loss due to failover is acceptable (e.g., rate limiters, non-financial task deduplication).
  • Choose etcd or ZooKeeper when lock correctness is vital to prevent data corruption (e.g., leader election, financial ledger processing).
  • Keep lock TTLs short and implement heartbeat lease renewals for long-running jobs.

Remember this

Select Redis for speed and etcd/ZooKeeper for strict consensus safety when locking distributed resources.

Key takeaway

Distributed locking is essential for managing shared resources across microservices. By pairing Redlock, ZooKeeper, or etcd with fencing tokens, engineering teams achieve safe, scalable concurrency control.

Share:

Related Articles

System design interviews evaluate a candidate's ability to architect scalable, resilient, and cost-effective distributed

Read

This guide is for backend engineers who know HTTP and database transactions but need to decide where six microservice pa

Read

A trip booking needs a flight, a hotel room, and a card charge to either all succeed or all unwind — but each lives in a

Read

Keep learning

Follow a structured path or browse all courses to go deeper.