Concrete scenario
A duplicate thumbnail is harmless wasted work, while two writers updating an account balance would violate correctness.
Mechanics
Redis locks use unique ownership tokens and atomic compare-and-delete release. Redlock seeks a majority of independent Redis instances within a validity window, but elapsed-time assumptions remain. For correctness-critical external writes, use a consensus-backed coordinator and ensure the downstream resource validates a fencing token or conditional version.
Failure mode
Etcd or ZooKeeper alone cannot stop a paused former owner from writing to an unrelated database. Redlock also cannot make an external resource reject stale clients unless that resource participates in the protocol.
Trade-off
A single Redis lock or Redlock may be adequate for efficiency work. Correctness-critical workflows usually favor durable serialization, conditional database updates, or fenced leases, accepting greater latency and operational cost.
The single-instance Redis lock, done right
-- acquire: only if absent, auto-expire after 30s
SET lock:invoice:42 9f1c-uuid NX PX 30000
-- release: delete only if it is still ours
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
endWorked example: Redlock timing
Five independent Redis masters, lease TTL 10,000 ms, clock drift allowance about 1 percent plus 2 ms.
- The client records its start time, then tries SET NX PX on each node with a short per-node timeout of about 50 ms.
- It gets OK from 3 of 5 nodes, and elapsed time is 120 ms.
- Validity = 10,000 - 120 - (0.01 x 10,000 + 2) = 9,778 ms. The lock is held if a majority was reached and validity is positive.
- If fewer than 3 succeed, the client releases on all nodes and retries after a random delay.
This still assumes no process pause longer than the remaining validity, and no clock jumps on the Redis nodes. Martin Kleppmann's 2016 critique showed that either assumption failing breaks mutual exclusion. Antirez replied that the assumptions are reasonable for many systems. Both agree that fencing requires the resource to participate.
Choosing a lock
| Option | Mutual exclusion under failover | Fencing token available | Latency | Use for |
|---|---|---|---|---|
| Single Redis, SET NX PX | No: lost if the primary fails before replication | No | Under 1 ms | Deduplicating cron runs, cache rebuilds |
| Redlock across 5 masters | Better, but depends on timing | No | A few ms | Efficiency where occasional double work is fine |
| etcd or ZooKeeper lock | Yes (linearizable) | Yes: revision or zxid | A few ms (consensus write) | Leader election, correctness with a fenced resource |
| Database row plus version column | Yes | The version itself | One DB transaction | Balance updates, inventory |
Failure modes
- Node restart without persistence: a Redlock node that restarts empty can grant a lock that another client holds. The Redlock spec recommends delaying restarts for at least one maximum TTL, or using fsync-always AOF.
- Long work under a short TTL: renew the lease (a watchdog, as Redisson does) and abort if renewal fails.