Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a distributed lock with Redis?

Tags:

redis

locking

On the redis documentation, I found a primitive lock can be implemented via SETNX:

http://redis.io/commands/setnx

  • C4 sends SETNX lock.foo in order to acquire the lock

  • The crashed client C3 still holds it, so Redis will reply with 0 to C4.

  • C4 sends GET lock.foo to check if the lock expired. If it is not, it will sleep for some time and retry from the start.

  • Instead, if the lock is expired because the Unix time at lock.foo is older than the current Unix time, C4 tries to perform:

    GETSET lock.foo

  • Because of the GETSET semantic, C4 can check if the old value stored at key is still an expired timestamp. If it is, the lock was acquired.

  • If another client, for instance C5, was faster than C4 and acquired the lock with the GETSET operation, the C4 GETSET operation will return a non expired timestamp. C4 will simply restart from the first step. Note that even if C4 set the key a bit a few seconds in the future this is not a problem.

However, as some users commented, using a UNIX timestamp as the expiration requires the client 's and server's time to be perfectly synchronized. Is there a better alternative to create a global/distributed lock in Redis?

like image 449
dyip1 Avatar asked Dec 23 '13 02:12

dyip1


People also ask

How do you implement a distributed lock in Redis?

The simplest way to use Redis to lock a resource is to create a key in an instance. The key is usually created with a limited time to live, using the Redis expires feature, so that eventually it will get released (property 2 in our list). When the client needs to release the resource, it deletes the key.

Is Redis a distributed cache?

Redis is an open source in-memory data store, which is often used as a distributed cache. You can configure an Azure Redis Cache for an Azure-hosted ASP.NET Core app, and use an Azure Redis Cache for local development.

Does Redis have locking?

Redis is a good option locking since has a simple key-based data model, each shard is single-threaded, and is quite quick. There is a well-established, canonical implementations of locking using Redis called Redlock.

When would you use a distributed lock?

Distributed locks provide mutually exclusive access to shared resources in a distributed environment. Distributed locks are used to improve the efficiency of services or implement the absolute mutual exclusion of accesses.


2 Answers

Use SET instead of SETNX. SET accepts arguments for expiration time in seconds and milliseconds instead of UNIX timestamp value.

The old SETNX based pattern is documented only for historical reasons.

From SETNX description:

NOTE: Starting with Redis 2.6.12 it is possible to create a much simpler locking primitive using the SET command to acquire the lock, and a simple Lua script to release the lock. The pattern is documented in the SET command page.

like image 197
zavg Avatar answered Sep 25 '22 01:09

zavg


Using redis >= 2.6 the LUA script solution would be great. Lua script always executed atomically so:

--lockscript, parameters: lock_key, lock_timeout
local lock = redis.call('get', KEYS[1])
if not lock then    
    return redis.call('setex', KEYS[1], ARGV[1], "locked");
end
return false

The another solution based on new options of SET command

SET lock_key "locked" EX lock_timeout NX 

Using redis < 2.6 the pattern with multi can be used:

MULTI
SETNX tmp_unique_lock some_value
EXPIRE tmp_unique_lock
RENAMENX tmp_unique_lock real_lock
EXEC
like image 29
Nick Bondarenko Avatar answered Sep 23 '22 01:09

Nick Bondarenko