SD System Design In Depth
0%
lesson system-designcoordination

Redis Redlock and fencing tokens

Module 3.2: Distributed Coordination, Consensus & Leases Updated Sep 17, 2026
📄 Cheat Sheet
How Distributed Lock works | ft Redis | System Design
ByteMonk How Distributed Lock works | ft Redis | System Design Watch on YouTube ↗

ByteMonk builds a Redis lock step by step (SET NX PX, unique value, safe release), then Redlock's majority approach and its pitfalls. It matches this lesson's scope.

0:00 / --:--

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
end

Worked 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

OptionMutual exclusion under failoverFencing token availableLatencyUse for
Single Redis, SET NX PXNo: lost if the primary fails before replicationNoUnder 1 msDeduplicating cron runs, cache rebuilds
Redlock across 5 mastersBetter, but depends on timingNoA few msEfficiency where occasional double work is fine
etcd or ZooKeeper lockYes (linearizable)Yes: revision or zxidA few ms (consensus write)Leader election, correctness with a fenced resource
Database row plus version columnYesThe version itselfOne DB transactionBalance 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.
Check yourself Question 1 of 3
Compare-and-delete release recall
From: The single-instance Redis lock, done right

Why does the lesson release a Redis lock with a Lua script that compares the stored value to your token before calling DEL, instead of a plain DEL?

Key Takeaways

Ownership tokens make lock release safe from deleting another client's lock.
Redlock relies on independent nodes and elapsed-time assumptions.
Correctness-critical external writes still need downstream fencing or conditional updates.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue