DISTRIBUTED SYSTEMS / SYSTEM CONCEPT BRIEF

Distributed locks

A distributed lock ensures that only one process across many machines performs a task or modifies a resource at a time, for example running a scheduled job once or preventing two workers from processing the same order.

AdvancedPhase 05 / Topic 9 of 17RequirementsTrade-offsFailure modes
01

Overview

A distributed lock ensures that only one process across many machines performs a task or modifies a resource at a time, for example running a scheduled job once or preventing two workers from processing the same order. Unlike a local mutex, it must handle process crashes, network delays, and clock differences.

Locks are acquired with a lease (an expiry time) so a crashed holder does not block forever. But a lease alone is not safe: a paused process may resume after its lease expired and another holder took over. Correct designs use fencing tokens, increasing numbers checked by the protected resource, so stale holders are rejected.

A meeting room key with a timer

Whoever holds the key uses the room. The key automatically becomes invalid after an hour in case someone leaves with it. To stop someone with an expired key from walking in, the room checks a key number and only accepts the newest one.

02

When to use it

  • Ensure a cron job runs on exactly one instance.
  • Serialize access to an external resource that lacks its own concurrency control.
  • Leader-like roles among workers.
  • Prevent duplicate processing when idempotency is not possible.
03

Where it shows up in interviews

Single execution

Recognize it when: only one instance may run this job.

  • Design a distributed job scheduler
  • Design a billing run
Resource mutual exclusion

Recognize it when: two workers must not modify the same thing.

  • Design a ticket booking hold
  • Design a collaborative document lock
04

Where it is used in real software

Redis SET NX PX

The common lightweight lock; Redlock extends it to multiple Redis nodes, though its safety is debated.

ZooKeeper and etcd

Provide consensus-backed locks with sessions, sequential nodes, and revision numbers usable as fencing tokens.

Google Chubby

A lock service used by Bigtable and GFS for leader election and coarse-grained locks.

05

Key terms

Lease
A lock that expires automatically after a TTL.
Fencing token
Monotonically increasing number issued with the lock and checked by the resource.
Owner token
A unique value so only the owner can release the lock.
Lock renewal
Extending a lease while work continues (heartbeat).
Redlock
Acquire a lock on a majority of independent Redis nodes.
06

How it works, step by step

  1. 1
    Acquire atomically with a TTL

    SET key owner NX PX 30000, or an etcd lease.

  2. 2
    Get a fencing token

    An increasing number from the lock service.

  3. 3
    Pass the token to the resource

    The resource rejects tokens lower than the highest seen.

  4. 4
    Renew while working

    Extend the lease before it expires.

  5. 5
    Release only if owner

    Compare-and-delete with the owner token.

Why fencing tokens are needed
Step 1 / 4
Worker A
Lock service
Worker B
Storage

STEP 1A acquires the lock with fencing token 33.

07

Lock implementations

Choose by safety needs

Step 1 / 4
ImplementationSafetyPerformanceUse for
Single Redis SET NXLost on failoverVery fastEfficiency locks (avoid duplicate work)
RedlockDebated under clock skewFastEfficiency locks
etcd / ZooKeeperStrong, with fencing tokensSlower (consensus)Correctness locks
Database row lockStrong within one DBModerateResources in the same database

NOWImplementation: Single Redis SET NX | Safety: Lost on failover | Performance: Very fast | Use for: Efficiency locks (avoid duplicate work)

Ask whether the lock is for efficiency (occasional duplicate is fine) or correctness (duplicates corrupt data). Correctness locks need consensus and fencing.

08

Implementation

import { Etcd3 } from "etcd3"; const etcd = new Etcd3({ hosts: process.env.ETCD_HOSTS!.split(",") }); export async function runExclusive(name: string, work: (fencingToken: string) => Promise<void>) {  const lock = etcd.lock(`locks/${name}`).ttl(30);  // lease renewed automatically while held  await lock.acquire();  try {    const token = (await lock.leaseId())!;          // use the lease ID or key revision as fencing token    await work(token);  } finally {    await lock.release();  }} // Storage side: reject stale tokens// UPDATE jobs SET result = $1, fence = $2 WHERE id = $3 AND fence < $2
09

Complexity and performance

Redis lock acquire~1 RTT

Sub-millisecond.

Consensus lock acquire~majority RTT + fsync

Milliseconds.

10

Trade-offs

Safety vs speed

Consensus-backed locks are safe but slower and need operating etcd or ZooKeeper; Redis locks are fast but can be lost.

Lease length

Short leases recover quickly after crashes but risk expiring during long work; long leases block others after a crash.

11

Variants and related techniques

Optimistic concurrency

Avoid locks by using version checks on writes.

Idempotency

Make duplicate execution harmless instead of preventing it.

12

Common mistakes

  • Releasing someone else's lock.

    Fix: Store a unique owner token and delete only if it matches (atomic script).

  • No TTL.

    Fix: A crashed holder would block forever.

  • Trusting leases for correctness.

    Fix: Process pauses can outlive the lease; use fencing tokens.

13

Interview questions

How would you implement a distributed lock?

Acquire atomically with a TTL and a unique owner ID (Redis SET NX PX for efficiency, etcd or ZooKeeper for correctness), renew the lease while working, release with compare-and-delete, and protect resources with fencing tokens.

What is a fencing token?

A number that increases every time the lock is granted. The protected resource remembers the highest token it has seen and rejects operations with lower tokens, stopping stale lock holders.

14

Practice problems

ProblemDifficultyWhat it trains
Implement a Redis lock with safe releaseMediumOwner tokens.
Design a distributed cron schedulerHardLocks and fencing.