Redis Lock, Postgres Advisory Lock, or Zookeeper: Picking One
Distributed locking sounds like a solved problem until two instances of a job both think they hold the lock at the same time, usually because of a network partition or a process that hung right at the worst moment. Every option trades safety guarantees against operational simplicity, and picking one without understanding the tradeoff is how a rare race condition becomes a recurring incident nobody can quite reproduce.
This compares the three approaches most teams actually reach for: a Redis-based lock, a Postgres advisory lock, and a dedicated coordination service like Zookeeper or etcd.
Vendors Covered in this Article
Disclosure: We may earn a commission if you buy through some links on this page. It doesn't change what we recommend.
What a lock is actually protecting you from
Before picking a mechanism, be specific about the failure you are preventing. If two workers processing the same queue item just means duplicate work that gets deduplicated downstream, a lock with a small correctness gap under partition is tolerable. If it means double-charging a customer or corrupting a ledger, you need a mechanism with a real fencing token, not just a lock that two processes might both briefly believe they hold. Most teams reach for a lock without first writing down which of these two situations they are in.
Redis-based locks: fast, but read the fine print on Redlock
A single-instance Redis lock using SET with NX and an expiry is simple and fast, and fine for low-stakes coordination like preventing a duplicate cron run. The multi-instance Redlock algorithm, meant to survive a single Redis node failing, has known edge cases around clock drift and process pauses that can let two clients both believe they hold the lock during a garbage collection pause or a slow network. If the cost of a double-execution is genuinely low, plain Redis locking is a reasonable, fast default. If it isn't, don't reach for Redlock as your safety net; reach for a mechanism with an explicit fencing token instead.
Postgres advisory locks: no new infrastructure, one real limitation
If your system already runs Postgres, an advisory lock, acquired with pg_advisory_lock or its transaction-scoped variant, gives you coordination without adding a new piece of infrastructure to operate. It is tied to a single database session, so it is naturally released if that connection drops, which avoids one whole class of stuck-lock incidents that plague expiry-based systems. The real limitation is scale: every lock holder needs an open database connection, which competes with your regular connection pool, so this fits background jobs and scheduled tasks far better than a high-concurrency request path.
A dedicated coordination service, when correctness actually matters
Zookeeper and etcd were built specifically for this problem and provide real fencing tokens: a monotonically increasing number attached to each lock grant that a downstream system can use to reject a stale write from a client that lost and regained the lock. This is the right tool when the failure mode is financial or data corruption, not duplicate work. The tradeoff is operational: running and monitoring a Raft-based coordination cluster is a real ongoing cost, so most teams below a certain scale reach for a managed version, such as a cloud provider's hosted etcd, rather than self-hosting it.
A simple decision rule
- If a double-execution is cheap to detect and fix downstream, use a plain Redis lock.
- If you already run Postgres and the workload is background jobs rather than high-concurrency requests, use an advisory lock.
- If the cost of two holders believing they own the lock at once is real money or corrupted state, use a coordination service with a fencing token, and reject writes from stale tokens at the point of write, not just at the point of lock acquisition.
Teams most often get this wrong by defaulting to Redlock for the third case because it was already in the stack, without reading the specific edge cases that make it unsuitable there.
What a fencing token actually prevents
Picture a worker that acquires a lock, then stalls for an unusually long garbage collection pause, long enough that the lock's expiry fires and a second worker acquires the same lock and starts its own work. Without a fencing token, both workers can go on to write their results, and whichever write lands last silently wins, even if it came from the stale first worker waking up late. With a fencing token attached to the lock grant, the downstream system storing the result can reject any write that carries an older token than one it has already accepted, so the stale worker's write is rejected even though it genuinely believed it still held the lock. The token is what turns "the lock probably worked" into an actual correctness guarantee.
What Good Looks Like
A sound locking setup matches the mechanism to the actual cost of a failure: cheap workloads get a simple lock, financially sensitive ones get a real fencing token, and nothing relies on Redlock for a correctness guarantee it cannot make.
Building The Capability (5-Stage Skill Ladder)
How to Get Started
Disclosure: We may earn a commission if you buy through some links on this page. It doesn't change what we recommend.
Frequently Asked Questions
Is Redlock safe enough for a payment processing job?
Generally not on its own. Redlock's known edge cases around clock drift and process pauses can allow two holders briefly, which is an acceptable risk for a cache warm job but not for anything touching money. Use a mechanism with a real fencing token for that case instead.
Do Postgres advisory locks survive a database failover?
No, they are tied to the session that acquired them, so a failover drops them along with the connection. That is usually the desired behavior, since it avoids a stuck lock, but design your job so a dropped lock mid-task is safe to retry from the start.
Do we need Zookeeper or etcd if we are a small team?
Probably not yet. The operational cost of running a coordination cluster is real, and most small teams' actual correctness requirements are met by an advisory lock or a well-understood Redis lock. Revisit this once a lock failure would mean real financial or data loss.
About the numbers
This guide doesn't quote a sourced benchmark. Figures in it are estimates or general guidance, so check them against your own numbers.
Related Guides
The Vendor Exit Checklist: What to Verify Before You Depend on a Platform
A checklist for CTOs to run before adopting a platform vendor, covering the export paths, contract terms, and pitfalls that turn dependence into lock-in.
Distributed Locks With Redis: What Actually Fails
Why a simple Redis lock isn't mutual exclusion, what a fencing token fixes and doesn't, and a safer default for most small engineering teams.
Redis Locks, Postgres Advisory Locks, or etcd: Picking a Locking Pattern
How to choose between a Redis lock, a Postgres advisory lock, and a dedicated coordination service like etcd when two processes must not run the same job twice.
Why Your Redis Lock Let Two Jobs Run at Once (and How to Fix It)
A walkthrough of a real double-charge bug caused by a Redis lock's TTL expiring mid-job, and the fencing-token pattern that actually fixes it.
Choosing a Distributed Locking Pattern Without Overbuilding It
A decision guide for choosing a distributed locking approach, from a simple database row lock to a dedicated coordination service, based on what you need.
When a Redis Lock Is Enough, and When It Isn't
Single-instance locks, Redlock, fencing tokens, and when to skip Redis entirely for a database advisory lock instead. A decision guide for CTOs.