Redis Redlock vs etcd vs ZooKeeper for Distributed Locks
Two background workers pick up the same financial payout job at the exact same millisecond. Without mutual exclusion across separate servers, both workers process the transaction, issuing a double payment to the customer before anyone notices. Distributed locking prevents this race condition by ensuring only one node executes a critical section across a network boundary.
However, implementing distributed locks correctly is deceptively complex. Network pauses, clock drift, and garbage collection pauses can cause a client to lose its lock without realizing it while still writing to shared storage. This guide breaks down the core architecture, safety trade-offs, and failure modes of Redis Redlock, etcd lease locks, and ZooKeeper ephemeral nodes, helping you choose the right locking mechanism for your reliability requirements.
Mental Model: Leases, Ephemeral Nodes, and Fencing
Every distributed lock relies on time-bound ownership called a lease. Because process crashes and network partitions are inevitable in distributed systems, a lock can never be granted indefinitely. If a client acquires a lock and crashes, the lease must automatically expire after a Time-To-Live (TTL) so other nodes are not blocked forever. To maintain ownership during long operations, the client must actively refresh (heartbeat) its lease.
However, lease expiration creates a dangerous edge case: what happens if Client A experiences a long Garbage Collection (GC) pause or network delay while holding a lock? The lease expires, Client B acquires the lock, and then Client A wakes up thinking it still owns the lock. Both clients now write to the database concurrently, corrupting state. This is why reliable locking systems require fencing tokens — monotonically increasing counters attached to every lock acquisition. Target resources (like storage engines or relational databases) check the fencing token and reject writes from clients presenting an outdated token number.
Understanding distributed consensus is critical when evaluating lock managers. Redis Redlock relies on time synchronization and asynchronous multi-node quorum, whereas etcd (Raft) and ZooKeeper (ZAB) enforce strict linearizability through consensus algorithms. The choice between them depends on whether your system tolerates occasional lock loss for speed or demands strict safety under all network conditions.
Quick reference
- TTL Leases prevent deadlocks by releasing abandoned locks after a configurable timeout.
- Heartbeat threads extend active leases periodically before the TTL window expires.
- Fencing tokens protect backend storage against out-of-order writes caused by GC pauses.
- Consensus-backed locks (etcd/ZooKeeper) guarantee strong consistency across leader elections.
- Redis single-node locks are fast but unsafe during master-replica failovers.
Remember this
Leases ensure availability during crashes, but fencing tokens are mandatory to guarantee safety when process pauses delay execution.
Redis Redlock: Asynchronous Multi-Master Locking
A single Redis instance lock using SET key value NX PX 30000 is blazing fast but vulnerable to data loss during replication failover. If the master grants a lock and crashes before replicating the key to a replica, the promoted replica will grant the same lock to another client. To solve single-point failure without consensus overhead, Salvatore Sanfilippo proposed Redlock.
Redlock deploys $N$ (typically 5) independent Redis master nodes with no inter-node replication. A client attempts to acquire the lock across all 5 nodes sequentially using the same key and random value, setting a small per-node timeout (e.g., 5–50ms). If the client successfully acquires the lock on a majority of nodes ($\\ge 3$) within a total elapsed time less than the lock validity period, the lock is considered granted. The effective lock lifetime is the initial TTL minus the elapsed acquisition time.
While Redlock provides high availability and throughput, it has generated intense debate among distributed systems engineers (notably Martin Kleppmann). Redlock relies heavily on the assumption that system clocks across all 5 nodes drift within an acceptable bound. If clock jump or wall-clock skew occurs — such as during NTP adjustments or VM migration pauses — Redlock can grant duplicate locks. For non-critical tasks like rate-limiting or duplicate email suppression, Redlock is efficient; for strict financial ledgers, it poses real risks.
Quick reference
- Acquires locks sequentially across N independent Redis nodes without inter-node consensus.
- Requires majority quorum (N/2 + 1) within a total elapsed time less than lock TTL.
- Sensitive to wall-clock drift, NTP jumps, and severe process pauses.
- Ideal for high-throughput, low-latency workloads where occasional duplicate execution is acceptable.
- Always release locks using a Lua script to ensure key deletion only occurs if the value matches.
Remember this
Redlock is built for high performance and fault tolerance, but its reliance on physical clocks makes it unsuitable for strict correctness without fencing.
etcd & ZooKeeper: Strongly Consistent Consensus Locks
When data correctness is paramount, consensus-backed coordinate stores like etcd and Apache ZooKeeper offer strict linearizable guarantees. Instead of relying on physical wall clocks, both systems build locking semantics directly on top of consensus protocols (Raft in etcd, ZAB in ZooKeeper).
In etcd, locks are built using Leases and Revision Counters. A client creates a Lease with a TTL and attaches key creation to that Lease via a Compare-And-Swap (Txn) operation. If the key does not exist, etcd writes the key with the Lease ID. etcd returns the revision number of the key, which serves as a natural, monotonically increasing fencing token. If the client dies, the lease expires and etcd automatically deletes the key. Clients watch key revisions to receive instant notification when a lock is released.
In ZooKeeper, locking utilizes Ephemeral Sequential Nodes. A client creates a sequence node under a parent lock path (e.g., /locks/job-1/lock-0000000001). ZooKeeper appends an auto-incrementing integer. The client checks all children under the lock path; if its created node has the lowest sequence number, it holds the lock. If not, the client sets a Watcher on the node with the immediately preceding sequence number. This prevents the 'thundering herd' problem, as each waiting client only wakes up when the specific node before it is deleted.
Quick reference
- etcd uses Raft consensus and Lease transactions to grant linearizable, fault-tolerant locks.
- ZooKeeper relies on ZAB consensus with Ephemeral Sequential Nodes and Watchers.
- Key revision numbers in etcd and sequence IDs in ZooKeeper act as automatic fencing tokens.
- Watcher notifications eliminate polling overhead when waiting for lock releases.
- Consensus overhead limits throughput compared to memory-bound Redis, but guarantees strict safety.
Remember this
etcd and ZooKeeper provide true linearizability and native fencing tokens, making them the gold standard for mission-critical distributed locks.
Decision Framework: Choosing the Right Distributed Lock
Selecting the right distributed lock solution comes down to evaluating your tolerance for lock duplication versus infrastructure complexity and latency requirements. Systems can be categorized into two primary use cases: Efficiency Locks and Correctness Locks.
Efficiency Locks (Redis / Single-node or Redlock) aim to avoid duplicate work. If the lock fails once in a million operations due to a network blip or failover, the system incurs a minor efficiency loss (e.g., rendering a report twice or re-fetching a cache entry), but no data corruption occurs. Redis provides sub-millisecond latencies and handles tens of thousands of lock operations per second with minimal resource consumption.
Correctness Locks (etcd / ZooKeeper) enforce strict single-execution semantics. If a lock fails and two nodes run simultaneously, catastrophic data loss, duplicate billing, or file corruption occurs. Here, latency (5–20ms) and lower throughput (thousands of ops/sec) are acceptable trade-offs for guaranteed consistency under network partitions and node crashes. Refer to our guides on the CAP theorem and database isolation levels to align your locking strategy with overall system consistency goals.
Quick reference
- Choose Single-Node Redis when speed matters most and duplicate execution has low impact.
- Choose Redlock when you need multi-node fault tolerance without maintaining etcd/ZooKeeper clusters.
- Choose etcd when already running Kubernetes or requiring native Raft consistency with revision fencing.
- Choose ZooKeeper in JVM ecosystems or legacy big-data infrastructure (Hadoop, Kafka control planes).
- Always pass fencing tokens down to backend storage engines regardless of lock provider.
Remember this
Use Redis for efficiency locks where speed is critical; use etcd or ZooKeeper for correctness locks where data integrity cannot be compromised.
Key takeaway
To verify distributed lock safety in your system, implement a lock acquisition routine with fencing token generation. Test it by simulating a 10-second GC pause on the lock holder while a second worker attempts acquisition. The storage layer must reject the paused worker's deferred write due to a stale token number.
Related Articles
Explore this topic