Book a 30-min callBook a call

Distributed locks: leases, fencing tokens and when not to use one

How distributed locks fail under pauses, clock drift and slow networks, why leases need fencing tokens, the Redlock debate, and the alternatives to a lock.

Two client circles and a lock service box handing out tokens, with arrows to a storage card that rejects one write with a cross and accepts the other with a tick.
Written by
BYD Tech
Published
Topic
Deep dives
Reading time
16 min read

Questions people ask

Is Redlock safe to use?

It depends on what the lock protects and whom you ask. Martin Kleppmann argues Redlock is unsafe for correctness because it relies on timing assumptions and has no fencing tokens; Salvatore Sanfilippo argues its assumptions are reasonable and that its random value can be used for a check-and-set. For efficiency locks, a single Redis instance is simpler. For correctness, make the resource check a token or a condition, whatever lock you use.

What is a fencing token?

A number that the lock service returns with every grant, larger than any it returned before. The client sends it with each write, and the storage rejects writes whose token is smaller than the largest it has already accepted. It stops a client that lost its lease during a pause from overwriting newer data.

Why is a TTL on a lock not enough?

The TTL protects liveness: a crashed holder cannot block others forever. It cannot protect safety, because a holder that pauses past the TTL does not know it lost the lock and may still write. Checking the time before writing does not help, since the pause can happen between the check and the write.

Should I use PostgreSQL advisory locks or SELECT FOR UPDATE?

Use `SELECT ... FOR UPDATE` when the thing you are protecting is a row: it locks exactly those rows until the transaction ends. Use an advisory lock when the thing has no row, such as a job or a migration that must run once at a time. Prefer the transaction-level advisory functions so the lock ends with the transaction.

When do I not need a distributed lock?

When the race can be removed or made harmless. A unique constraint, a conditional update on a version column, an idempotency key or routing all writes for a key to one owner usually beats a lock, because none of them depends on a lease that can expire under a slow process.

Building something like this?