0
0
RedisHow-ToBeginner · 4 min read

How to Implement Distributed Lock with Redis

To implement a distributed lock in Redis, use the SET command with the NX option to set a key only if it does not exist, combined with PX to set an expiration time. This ensures only one client holds the lock at a time, preventing conflicts in distributed systems.
📐

Syntax

The basic Redis command to acquire a distributed lock is:

SET key value NX PX milliseconds
  • key: The lock name.
  • value: A unique identifier for the client (e.g., UUID).
  • NX: Only set the key if it does not already exist (lock acquisition).
  • PX milliseconds: Set the lock expiration time in milliseconds to avoid deadlocks.

To release the lock safely, use a Lua script that deletes the key only if the value matches your unique identifier.

redis
SET resource_lock unique_client_id NX PX 30000
Output
"OK" or null if lock not acquired
💻

Example

This example shows how to acquire and release a distributed lock in Redis using Python and the redis-py library.

python
import redis
import uuid

client = redis.Redis()
lock_key = "resource_lock"
lock_value = str(uuid.uuid4())
lock_expire = 30000  # 30 seconds in milliseconds

# Try to acquire the lock
acquired = client.set(lock_key, lock_value, nx=True, px=lock_expire)

if acquired:
    print("Lock acquired")
    # Critical section here

    # Lua script to release lock safely
    release_script = """
    if redis.call('get', KEYS[1]) == ARGV[1] then
        return redis.call('del', KEYS[1])
    else
        return 0
    end
    """
    result = client.eval(release_script, 1, lock_key, lock_value)
    if result == 1:
        print("Lock released")
    else:
        print("Lock not released: value mismatch")
else:
    print("Failed to acquire lock")
Output
Lock acquired Lock released
⚠️

Common Pitfalls

  • Not setting expiration: Without expiration, a lock can stay forever if the client crashes, causing deadlocks.
  • Releasing lock without checking value: Deleting the lock key blindly can remove another client's lock.
  • Using non-unique values: Use unique IDs per client to avoid releasing others' locks.
  • Long critical sections: If your task takes longer than expiration, the lock may expire early, causing race conditions.
redis
Wrong way (no value check):
DEL resource_lock

Right way (Lua script):
if redis.call('get', KEYS[1]) == ARGV[1] then
  return redis.call('del', KEYS[1])
else
  return 0
end
📊

Quick Reference

CommandPurposeNotes
SET key value NX PX millisecondsAcquire lock if not existsReturns OK if lock acquired, null otherwise
DEL keyRelease lock (unsafe)May delete others' locks, avoid this
Lua script with get and delSafe lock releaseDeletes key only if value matches
GET keyCheck lock ownerReturns lock value or null

Key Takeaways

Use SET with NX and PX options to acquire a distributed lock safely in Redis.
Always set an expiration time to prevent deadlocks if the client crashes.
Release locks using a Lua script that checks the lock owner to avoid deleting others' locks.
Use unique values per client to identify and manage locks correctly.
Avoid long-running tasks that exceed the lock expiration time to prevent race conditions.