WierdX — Programming Reference All tutorials →
Developer reference · Practical tutorials · CS fundamentals
Distributed Systems

Distributed Locks Explained: Redis Redlock and the Risks of Naive Locking

A regular mutex only works inside one process. The moment two separate machines need to agree that only one of them may touch a resource at a time, you need a lock that lives somewhere both can see — and that lock can fail in ways an in-process mutex never does.

Published July 6, 2026

A common job for a distributed lock is preventing two instances of a scheduled job from running at the same time, or making sure only one worker processes a given order at once. The simplest implementation uses a key-value store's atomic "set if not exists" operation: a worker tries to set a key, and if it succeeds, it holds the lock; if the key already exists, someone else holds it.

SET lock:order-42 worker-a NX PX 30000

That single command sets the key only if it's absent (NX), with a 30-second expiry (PX) so a crashed worker doesn't hold the lock forever. It looks complete, and for low-stakes coordination it often is. But two failure modes hide inside those 30 seconds, and both have caused real production incidents.

Failure mode one: the lock outlives the work

If worker A takes 35 seconds to finish — a slow database call, a garbage collection pause, a network hiccup — its lock expires at 30 seconds while it's still working. Worker B now acquires the same lock and starts processing order 42 too. Both workers believe they hold exclusive access; neither does. The fix is a fencing token: every time the lock is granted, the store hands back a monotonically increasing number, and the resource being protected (the order record, the file, the queue) must reject any write carrying a token lower than the last one it accepted. That way, even if worker A's stale write arrives after worker B's, the resource itself refuses it.

Failure mode two: releasing someone else's lock

A worker that finishes and calls "unlock" needs to make sure it's deleting its own lock, not one acquired by someone else after its lock already expired. The safe pattern checks the lock's value (a unique worker ID, not just a boolean) and deletes it only if that value still matches, and it does so as a single atomic script rather than two separate commands, because a check-then-delete done as two round trips has its own race condition sitting between the two calls.

Why Redlock exists

A single lock server is a single point of failure: if it goes down, or its data is lost before a replica catches up, two clients can end up believing they hold the same lock. Redlock addresses this by running the lock against an odd number of independent instances (five is the usual recommendation) and requiring a client to successfully acquire the lock on a strict majority of them, within a bounded time budget, before considering the lock held. Losing any single instance no longer breaks correctness, because a majority can still be reached across the rest.

What Redlock does not fix

Redlock still assumes clocks are roughly synchronized and that pauses (garbage collection, virtual machine migration, a suspended laptop resuming) stay shorter than the lock's expiry window. A sufficiently long pause on the client holding the lock can still let its lease expire while it believes it's still safely inside the critical section, and Redlock alone does not give you fencing tokens — you still need the protected resource to reject stale writes for genuinely airtight correctness. This is why some distributed-systems engineers recommend Redlock only for cases where an occasional double-execution is annoying rather than dangerous, and reach for a consensus-based lock service, backed by something like Raft, when correctness truly cannot bend.

A cheaper alternative for lower-stakes coordination

Not every use case needs Redlock's cross-instance majority. A single Redis instance with a short TTL and a unique-value-checked release is often good enough for things like deduplicating a cron job across replicas, where the cost of an occasional double run is a wasted CPU cycle rather than a corrupted record. Reserve the heavier machinery for locks that protect something that can't tolerate being touched twice.