Time Is Not Universal in Distributed Systems
Every computer has a hardware clock driven by a crystal oscillator. These oscillators are imprecise — they drift slightly fast or slow depending on temperature, voltage, and manufacturing variance. A server's clock might gain or lose tens of milliseconds per minute without correction.
NTP (Network Time Protocol) corrects this by periodically syncing a machine's clock to a reference time server. But NTP corrections can be abrupt — jumping a clock forward or backward by seconds. From the perspective of a running process, time just skipped.
This matters enormously for lease-based locking, because leases are fundamentally time-based contracts.
The Clock Drift Attack Scenario
t=0s Worker A acquires lock on Redis. TTL = 10 seconds.
t=1s Worker A calculates: "I hold the lock until wall-clock time 12:00:10."
t=3s NTP daemon on Worker A's machine detects clock is 6 seconds slow.
NTP jumps Worker A's clock forward by 6 seconds.
t=3s Worker A's clock now reads 12:00:09 (jumped from 12:00:03).
t=4s Redis (on a correctly-synced machine) reaches 12:00:10. TTL expires.
Redis deletes the lock key.
t=5s Worker B acquires the lock. Starts processing.
t=6s Worker A's clock reads 12:00:10. Worker A thinks: "I still have 0 seconds left,
but I'm almost done." Worker A continues processing.
Result: Worker A and Worker B are both processing simultaneously.
Worker A never knew its clock was wrong. It followed the rules perfectly. The lock still failed.
Implications for System Design
Clock drift means that any system relying purely on TTLs for safety guarantees is probabilistically safe, not mathematically safe. The probability of failure is low (NTP jumps of multiple seconds are rare on well-maintained infrastructure), but it is non-zero.
For systems where correctness is non-negotiable — financial ledgers, inventory systems, seat reservations — the industry solution is Fencing Tokens. A fencing token is a monotonically increasing number issued by the lock server each time a lock is granted. The protected resource (e.g., a database) rejects any write from a client presenting a token lower than the highest token it has already seen. Even if Worker A wakes up late and tries to write, the database rejects it because Worker B's newer token has already been registered.
Fencing tokens are natively supported by consensus-based systems like ZooKeeper (via zxid) and etcd (via revision numbers). Redis does not natively support them, which is the core of Kleppmann's critique of Redlock.