The Redlock algorithm is a distributed locking mechanism designed for Redis to ensure mutual exclusion across clients in a distributed system. It operates by acquiring locks on a majority of Redis nodes to guard against node failures and network partitions. Despite its popularity, Redlock has sparked debate regarding its safety guarantees and implementation complexity.
Distributed locks
Distributed locks are crucial for coordinating access to shared resources in distributed applications. Traditional locking mechanisms often rely on a central coordinator, which can become a single point of failure. Redlock offers a decentralized approach by leveraging multiple independent Redis instances.
How Redlock Works
To acquire a lock, a client generates a unique token and sends a SET key value NX PX ttl command to each of the N Redis instances. The client considers the lock acquired only if it successfully locks a majority (quorum) of the instances. The total time to acquire the lock must be less than the TTL specified to prevent expired locks from being mistaken as held. When the client completes its critical section, it releases the lock by sending a DEL key command to all instances—but only if the stored token matches—to prevent releasing someone else’s lock.
Algorithm
- Acquire: The client tries to acquire the lock on each instance sequentially with a unique identifier and expiration time.
- Validate: It computes the elapsed time and verifies if the quorum was achieved within the TTL to ensure lock validity.
- Commit/Abort: If the quorum is met and the timing constraints hold, the client holds the lock; otherwise, it rolls back by deleting partial locks from the instances.
sequenceDiagram
participant Client
participant Redis1
participant Redis2
participant Redis3
participant Redis4
participant Redis5
Note over Client: Step 1: Generate unique lock ID & start timer
Client->>Redis1: SET resource_name lock_id NX PX 3000
Client->>Redis2: SET resource_name lock_id NX PX 3000
Client->>Redis3: SET resource_name lock_id NX PX 3000
Client->>Redis4: SET resource_name lock_id NX PX 3000
Client->>Redis5: SET resource_name lock_id NX PX 3000
Note over Client: Step 2: Wait for quorum (e.g., 3/5 successes)
alt Quorum Achieved within timeout
Note over Client: Step 3: Lock acquired
else Quorum NOT achieved
Note over Client: Step 3: Roll back<br/>delete partial locks
Client->>Redis1: DEL resource_name (if lock_id matches)
Client->>Redis2: DEL resource_name (if lock_id matches)
Client->>Redis3: DEL resource_name (if lock_id matches)
Client->>Redis4: DEL resource_name (if lock_id matches)
Client->>Redis5: DEL resource_name (if lock_id matches)
end
Note over Client: Step 4: Perform work under lock
Note over Client: Step 5: Release lock
Client->>Redis1: DEL resource_name (if lock_id matches)
Client->>Redis2: DEL resource_name (if lock_id matches)
Client->>Redis3: DEL resource_name (if lock_id matches)
Client->>Redis4: DEL resource_name (if lock_id matches)
Client->>Redis5: DEL resource_name (if lock_id matches)
It seems like Two‑Phase Commit?
Redlock resembles a two‑phase commit in that it performs a prepare phase (acquiring locks) followed by a commit or abort (keeping or releasing locks) based on quorum success. Unlike traditional 2PC, Redlock does not rely on a central coordinator and can tolerate some instance failures without blocking the system.
| Redlock | 2PC | |
|---|---|---|
| Quorum vs All-or-Nothing | Redlock tolerates partial failure (just needs majority) | 2PC requires full agreement |
| Coordinator role | No formal coordinator; the client drives the logic | Central coordinator (e.g., transaction manager) |
| Durability guarantees | Redis isn't strongly consistent | 2PC assumes stronger consistency and logging |
| Failure tolerance | More optimistic, faster (but less safe in edge cases) | More rigid but safer in distributed systems |
Pros and Cons
Pros
- Provides fault tolerance by ensuring locks remain valid even if some Redis nodes fail.
- Uses TTLs to prevent deadlocks by automatically expiring locks if clients crash before releasing them.
Cons
- Requires careful coordination of multiple Redis instances, increasing operational complexity.
- May not guarantee mutual exclusion under certain failure scenarios, like network partitions during replication.
Best Practices
Operators should deploy an odd number of independent Redis masters with synchronized clocks to minimize TTL drift. Clients should handle lock acquisition failures gracefully by implementing retry logic with exponential backoff to avoid thundering herd problems.
Implementations
According to redis:
- Redlock-rb (Ruby implementation). There is also a fork of Redlock-rb that adds a gem for easy distribution.
- RedisQueuedLocks (Ruby implementation).
- Redlock-py (Python implementation).
- Pottery (Python implementation).
- Aioredlock (Asyncio Python implementation).
- RedisMutex (PHP implementation with both Redis extension and Predis library clients support).
- Redlock-php (PHP implementation).
- cheprasov/php-redis-lock (PHP library for locks).
- rtckit/react-redlock (Async PHP implementation).
- Redsync (Go implementation).
- Redisson (Java implementation).
- Redis::DistLock (Perl implementation).
- Redlock-cpp (C++ implementation).
- Redis-plus-plus (C++ implementation).
- Redlock-cs (C#/.NET implementation).
- RedLock.net (C#/.NET implementation). Includes async and lock extension support.
- ScarletLock (C# .NET implementation with configurable datastore).
- Redlock4Net (C# .NET implementation).
- node-redlock (NodeJS implementation). Includes support for lock extension.
- Deno DLM (Deno implementation)
- Rslock (Rust implementation). Includes async and lock extension support.
Conclusion
Redlock remains a valuable tool for distributed locking in Redis when used with care and understanding of its trade‑offs. By following best practices and acknowledging its limitations, teams can leverage Redlock to maintain data consistency in distributed systems.
