Mastering Redis Distributed Locks: From Single‑Node to Redlock Cluster Implementation
Learn how to implement Redis distributed locks in both single‑node and cluster environments, covering lock acquisition and release commands, key pitfalls like master‑slave failover, and the advanced Redlock algorithm with step‑by‑step guidance, Lua scripts, and a PHP lock class example.
Single‑Node Lock
Acquire lock using SET with NX and PX (or EX) options, providing a unique value (e.g., a UUID). Release the lock with a Lua script that deletes the key only if the stored value matches the caller’s identifier.
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
endCommand syntax: SET key value PX milliseconds NX (or EX seconds).
The value must be unique for each lock holder.
Unlock must verify the value to avoid releasing another client’s lock.
The lock exists only on the master node; a master‑slave failover can cause the lock to be lost.
Redlock Algorithm for Redis Cluster
Redlock requires a majority of independent Redis master nodes to grant the lock. A common deployment uses five masters.
Record startTime (current Unix time in milliseconds).
For each master, attempt SET key uniqueValue PX ttl NX with a network timeout shorter than the lock TTL (e.g., 5‑50 ms for a 10 s lock).
If a response is not received within the timeout, move to the next master.
When locks are obtained on at least N/2+1 masters, record endTime and compute costTime = endTime - startTime. The lock is considered acquired only if costTime < ttl.
If the majority is not reached or costTime exceeds the TTL, run the unlock Lua script on all masters to release any partial locks.
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
endPHP Example Using Redis and Lua Scripts
The class below demonstrates lock acquisition and release. It generates a unique identifier, retries acquisition for a configurable period, and uses the Lua scripts above to ensure atomicity.
class RedisLock
{
/**
* Acquire a distributed lock.
*
* @param string $lock_name Lock key (without prefix)
* @param int $acquire_time Number of seconds to keep retrying
* @param int $lock_timeout TTL of the lock in seconds
* @return string|false Unique identifier on success, false on failure
*/
public static function acquireLock($lock_name, $acquire_time = 3, $lock_timeout = 20)
{
$identifier = md5($_SERVER['REQUEST_TIME'] . mt_rand(1, 10000000));
$key = 'AGENT_ORDER_LOCK:' . $lock_name;
$end_time = time() + $acquire_time;
$script = <<<luascript
local result = redis.call('setnx', KEYS[1], ARGV[1])
if result == 1 then
redis.call('expire', KEYS[1], ARGV[2])
return 1
elseif redis.call('ttl', KEYS[1]) == -1 then
redis.call('expire', KEYS[1], ARGV[2])
return 0
end
return 0
luascript;
while (time() < $end_time) {
$res = location_redis()->evaluate($script, [$key, $identifier, $lock_timeout], 1);
if ($res == '1') {
return $identifier;
}
usleep(100000); // 100 ms pause before next attempt
}
return false;
}
/**
* Release a previously acquired lock.
*
* @param string $lock_name Lock key (without prefix)
* @param string $identifier Identifier returned by acquireLock()
* @return bool True if the lock was released
*/
public static function releaseLock($lock_name, $identifier)
{
$key = 'AGENT_ORDER_LOCK:' . $lock_name;
$script = <<<luascript
local result = redis.call('get', KEYS[1])
if result == ARGV[1] then
if redis.call('del', KEYS[1]) == 1 then
return 1
end
end
return 0
luascript;
$res = location_redis()->evaluate($script, [$key, $identifier], 1);
return $res == 1;
}
}Reference Diagram
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
