0

I am facing concurrency problem with redis, my API is build on Nodejs Fastify and i am using fastify-redis in my API call.

I am using two simple methods of redis ZRANGEBYSCORE and ZINCRBY

The problem is under high concurrency ZINCRBY is executed late which results into giving me same value on multiple request.

How can i prevent this under high concurrency is there any method to lock the KEY which was previously executed.

Here is the example of my code

numbers = await redis.zrangebyscore(
            `user:${req.query.key}:${state}`, //key
            0, // min value
            50, // max value
            "LIMIT",
            0, // offset
            1 // limit
        );

if (numbers.length > 0) {
        await redis.zincrby(`user:${req.query.key}:${state}`, 1, numbers[0]);
        res.send(numbers[0]);
    }

1 Answers1

1

The issue isn't concurrency per se, it's that you have a series of operations that need to be atomic and you haven't done anything to ensure that.

Redis has facilities to try to ensure atomicity, as described here. In your case, since the value from the first operation is used in the second, you couldn't do a simple MULTI and EXEC. You'd have to instead WATCH the key and then retry the operation if it aborted.

The simpler, and recommended approach, though, is just to put your above code into a Lua script, where it can be executed on the server as a single atomic operation.

Kevin Christopher Henry
  • 46,175
  • 7
  • 116
  • 102
  • So if i create a lua script and use these commands form lua script it will ensure that zincrby is executed and all the series of operations in atomic way? – Amanullah Tanweer Jul 10 '21 at 20:41
  • Also do i just need to run MULTI command on ZINCRBY or in a series... one more thing zrangebyscore will return me a value which i will increment, so in a multi command how will i run that? A little help would really clear my concepts – Amanullah Tanweer Jul 10 '21 at 20:43
  • @AmanullahTanweer: Right, you couldn't just use `MULTI`. You'd have to `WATCH` the key and retry the operation if it aborted. But instead just translate your above code into a Lua script and use `EVAL`. That will make the whole operation atomic. – Kevin Christopher Henry Jul 10 '21 at 21:23