How it works
The explanation, with examples you can run.
The single-instance lock
Acquire with a random token, only if the key does not exist, with a time limit:
> SET lock:invoice:7 3f9a1c NX PX 30000OK> SET lock:invoice:7 other NX PX 30000(nil) # someone else holds itRelease only if the key still holds your token, atomically:
> EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end" 1 lock:invoice:7 3f9a1c(integer) 1The token matters. Without it, a client whose lock has already expired would delete the next holder's lock. The TTL matters too: without one, a crashed holder keeps the lock forever.
Redlock
A single Redis instance is a single point of failure, and with asynchronous replication a failover can lose a lock key that was just written, so two clients can hold the "same" lock. Redlock, described in the Redis docs, uses N independent masters (typically 5). The client tries to set the key on all of them with the same token and TTL, and holds the lock only if it succeeded on a majority within a time that is small compared with the TTL. The remaining validity is the TTL minus the time spent acquiring.
The debate
In 2016 Martin Kleppmann published an analysis arguing that Redlock is unsafe for correctness. His main points:
- Any lock with automatic expiry can be held by two clients when one pauses (a GC pause, a page fault, a delayed network packet) for longer than the TTL. The paused client wakes up and acts as though it still holds the lock.
- The fix is a fencing token: a number that increases every time the lock is granted, sent with every write, and checked by the storage, which rejects a token older than one it has already seen. Redlock does not produce such a counter.
- Redlock's safety depends on timing assumptions: bounded network delay, bounded pauses, and clocks that do not jump. Algorithms built on consensus (such as ZooKeeper or etcd) stay safe when those assumptions fail and only lose liveness.
Salvatore Sanfilippo (antirez), Redis's creator, replied that fencing is not specific to Redlock: if the storage can check tokens, it can often provide the needed safety on its own, and the random token can be used for check-and-set. He argued that Redlock checks the elapsed time after acquiring, which limits the effect of delays before that point, and that clock jumps can be avoided operationally; he agreed implementations should use monotonic time. The Redis docs now link both pieces and recommend fencing tokens for long-running work.
Choosing
- Efficiency lock (avoid doing the same work twice; a rare duplicate is tolerable): a single Redis instance with
SET NX PXand a token is simple and usually fine. - Correctness lock (two holders would corrupt data): make the protected resource enforce it, with fencing tokens, a conditional write, a unique constraint or a database row lock, or use a coordination service built on consensus. Redlock alone should not be the only thing standing between you and corrupt data.
In every case, set the TTL well above the expected work time, renew it for long jobs (only if you still hold the token), and design the work to be idempotent.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.