Acquiring locks when updating a Redis key / value

I use the AcquireLock method from ServiceStack Redis when updating and getting the key / value as follows:

public virtual void Set(string key, T entity) { using (var client = ClientManager.GetClient()) { using (client.AcquireLock(key + ":locked", DefaultLockingTimeout, DefaultLockExpire)) { client.Set(key, entity); } } } 

I extended the AcqurieLock method to accept an additional parameter to expire the lock key. So I wonder if I need AcquireLock at all or not? My class uses AcquireLock in every operation, e.g. Get <>, GetAll <>, ExpireAt, SetAll <>, etc.

But this approach does not work every time. For example, if working in a lock throws an exception, the key remains locked. For this situation, I added the DefaultLockExpire parameter to the AcquireLock method to expire the "locked" key.

Is there a better solution or when do we need to acquire locks such as locks in multi-threaded programming.

+4
source share
3 answers

As the “Real Bill” answer said, you don't need locks for Radish itself. What the ServiceStack client offers in terms of blocking is not for Redis, but for your application. In a C # application, you can localize locally with lock(obj) so that something cannot happen at the same time (only one thread can access the locked section at a time), but this only works if you have one web server. If you want to prevent something happening at the same time, you need a blocking mechanism that lives outside the web server. Redis is well suited for this.

We have a case when it is checked, if the customer already has a shopping cart, and if not, create it. Between checking and creating it, there is a time when another request could also find that the cart does not exist and can also begin to create it. That classic lock case, but a simple lock , will not work here, as the request may have arrived from a completely different web server. To do this, we use the ServiceStack Redis client (with some abstraction) to block using Redis and allow only one request to enter the "create basket" section.

So, to answer your real question: no, you do not need a lock to get / set values ​​for Redis.

+4
source

I would not use locks for get / set operations. Redis will perform these actions atomically, so there is no chance that it will be "modified by you" when configured or received. I created systems in which hundreds of clients simultaneously update / work with values ​​and never need a lock to perform these operations (especially with expiration).

I don’t know how Service Stack redis implements locking, so I can’t say why it fails. However, I’m not sure that I will trust him, because for data operations there is no true lock necessary for the Redis side. Redis is single-threaded, so locking does not make sense.

If you perform complex operations in which you get the value, work on things based on it, and then update it after a while and cannot change the value, in the meantime I would recommend reading and compiling http://redis.io/topics / transactions to find out if Redis is right for you, whether you need refinancing code to fix the problem, or at least find a better way to do it.

For example, SETNX might be the route you need to get what you want, but without the details I cannot say that it will work.

+3
source

As @JulianR notes, a lock in ServiceStack.Redis is only for distributed locks at the application level (i.e., to replace using a database or an empty .lock file in a distributed file system) and it only works with other ServiceStack.Redis clients in another process using the same key / API to get the lock.

You will never need to do this for regular Redis operations, as they are all atomic. If you want a combination of redis operations to occur atomically than to combine them into a Redis Transaction transaction or, alternatively, you can execute them on the server side of the Lua script - both allow atomic execution of batch operations.

+1
source

All Articles