Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Single-instance Redis lock with SETNX

Tags:

redis

go

locking

I need to connect to a single Redis instance from an application client.

Since the client will be replicated in Kubernetes, I'm studying Redis documentation about locks to prevent races between the client replicas.

After some googling and reading around, I zeroed in on these two resources:

  • the SETNX command described here: https://redis.io/commands/setnx
  • the Redlock algorithm described here: https://redis.io/topics/distlock

Interestingly the SETNX docs explicitly advise against using SETNX to implement locks, stating that it has basically become obsolete:

The following pattern is discouraged in favor of the Redlock algorithm [...]

We document the old pattern anyway because certain existing implementations link to this page as a reference.

However the Redlock algorithm is specifically tailored for distributed locks, thus when one seeks to lock on multiple Redis instances - they actually refer to multiple masters.

To go a bit further, the library redsync (golang) declares the New function as follows:

func New(pools []Pool) *Redsync {
    return &Redsync{
        pools: pools,
    }
}

It looks unmistakably designed to support locking on a Redis cluster.

In my use case, I'm going to connect to only one Redis instance.

Probably I can just use the redsync package and pass an slice of length one, yet to me it looks like the SETNX pattern could work equally fine on a single Redis instance.

Am I seeing this correctly? Thank you

like image 805
blackgreen Avatar asked Jun 13 '19 22:06

blackgreen


People also ask

Can you lock a key 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.

What is distributed lock in Redis?

Locking is a very common concept in programming. Wikipedia's definition describes it pretty accurately: In computer science, a lock is a synchronization mechanism for enforcing limits on access to a resource in an environment where there are many threads of execution.

What is Redis multi?

Redis Transactions allow the execution of a group of commands in a single step, they are centered around the commands MULTI , EXEC , DISCARD and WATCH . Redis Transactions make two important guarantees: All the commands in a transaction are serialized and executed sequentially.

Is Redis TTL in seconds or milliseconds?

Redis TTL command is used to get the remaining time of key expiry in seconds.

Can setnx be used as a locking primitive?

That said, SETNX can be used, and was historically used, as a locking primitive. For example, to acquire the lock of the key foo, the client could try the following: If SETNX returns 1 the client acquired the lock, setting the lock.foo key to the Unix time at which the lock should no longer be considered valid.

How do I lock a resource 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.

What happens if setnx returns 0?

If SETNX returns 0 the key is already locked by some other client. We can either return to the caller if it's a non blocking lock, or enter a loop retrying to hold the lock until we succeed or some kind of timeout expires.

How do I reduce latency when using N Redis?

In order to meet this requirement, the strategy to talk with the N Redis servers to reduce latency is definitely multiplexing (putting the socket in non-blocking mode, send all the commands, and read all the commands later, assuming that the RTT between the client and each instance is similar).


Video Answer


1 Answers

Yes, it's true that the Redlock algorithm is designed for a distributed Redis system, and that if you're using a single instance it should be fine to use the simpler locking methods described in the SET and SETNX documentation.

However, a more important point is this: you probably don't need to use locks to avoid conflicts between multiple Redis clients. Redis locks are usually used to secure some external distributed resource (see my answer here for a bit more on this). Within Redis itself locks are generally not necessary; thanks to Redis' single-threaded nature, many commands are already atomic, and you have the ability to use transactions or Lua scripts to compose arbitrarily complex atomic operations.

So my advice is to deisgn your client code to use atomicity to avoid conflicts rather than trying to use a lock (distributed or otherwise).

like image 187
Kevin Christopher Henry Avatar answered Oct 19 '22 05:10

Kevin Christopher Henry