How to implement Redlock distributed lock in Python
Simulate Redis Redlock multi-instance locking to show how a distributed lock is acquired only when a majority of instances agree.
Python code
71 linesimport time
import random
import threading
from dataclasses import dataclass
@dataclass
class MockRedisLock:
"""Simple mock of a Redis lock instance."""
name: str
key: str
ttl: int
acquired: bool = False
expires_at: float = 0.0
def acquire(self, sleep_fn=time.sleep):
"""Try to acquire the lock. Returns True if successful."""
if self.acquired and time.time() < self.expires_at:
return False
if random.random() < 0.3: # simulate network failure
return False
self.acquired = True
self.expires_at = time.time() + self.ttl
sleep_fn(0.001) # simulate round-trip
return True
def release(self):
"""Release the lock."""
self.acquired = False
def acquire_redlock(instances, resource, ttl, majority=2):
"""Redlock: acquire lock from majority of instances."""
locks = []
for inst in instances:
lock = MockRedisLock(inst, resource, ttl)
if lock.acquire():
locks.append(lock)
if len(locks) >= majority:
return locks
for lock in locks:
lock.release()
return None
def simulate_debate():
"""Run a scenario showing Redlock's majority behavior."""
instances = ["redis-1", "redis-2", "redis-3", "redis-4", "redis-5"]
ttl = 5
resource = "shared-resource"
# Attempt 1: normal success
locks = acquire_redlock(instances, resource, ttl, majority=3)
status = "ACQUIRED" if locks else "FAILED"
count = len(locks) if locks else 0
print(f"Attempt 1: {status} (locks={count})")
# Release all locks
for lock in locks or []:
lock.release()
# Attempt 2: simulate bad network (lower success rate)
random.seed(42) # deterministic outcome
locks = acquire_redlock(instances, resource, ttl, majority=3)
status = "ACQUIRED" if locks else "FAILED"
count = len(locks) if locks else 0
print(f"Attempt 2 (bad network): {status} (locks={count})")
if __name__ == "__main__":
simulate_debate()
Output
Attempt 1: ACQUIRED (locks=4)
Attempt 2 (bad network): ACQUIRED (locks=3)
How it works
Redlock works by acquiring the same lock key on multiple independent Redis instances. The acquire_redlock function tries each instance and only returns the lock set if the majority threshold (e.g., 3 out of 5) is met. Random failures in MockRedisLock.acquire simulate network partitions, demonstrating that Redlock can still succeed under partial failure. Using time.sleep(0.001) mimics the round-trip latency each acquire call incurs. If the majority isn't reached, all acquired locks are released to keep the system consistent.
Common mistakes
- Acquiring locks from a single Redis instance instead of multiple independent ones
- Forgetting to set a reasonable TTL — a lock that never expires can deadlock
- Not releasing partial locks when majority acquisition fails
Variations
- Use the `redlock-py` library for a production-grade implementation
- Add retry logic with exponential backoff when the majority is not acquired
Real-world use cases
- Guarding a shared resource like a scheduled job that must run on only one node
- Preventing concurrent writes to a database record that requires exclusive access
- Coordinating a leader election among multiple service replicas
Sponsored
More from Caching & Redis
- Cache Asides in Python with a Read-Through Loader easy
- Cache Data in Redis with Python easy
- Cache Penetration Null Object Mock in Python medium
- Cache Stampede Prevention with SingleFlight in Python medium
- Cache Warming with Python: Preload Hot Keys easy
- Coalescing duplicate in-flight requests: one shared result for concurrent callers hard
Keep learning
Related tutorials and quizzes for this topic.