Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't my Redis Lua script atomically update keys on different Redis Cluster nodes?

I have a Redis Cluster consisting of multiple nodes. I want to update 3 different keys in a single atomic operation. My Lua script is like:

local u1 = redis.call('incrby', KEYS[1], ARGV[1])
local u2 = redis.call('incrby', KEYS[2], ARGV[1])
local u3 = redis.call('incrby', KEYS[3], ARGV[1])

And I fired it with:

EVAL script 3 key1 key2 key3 arg

But I got the error message:

WARN Resp(AppErr CROSSSLOT Keys in request don't hash to the same slot)

The above operations cannot be done, and the updates will fail. It seems I cannot modify the keys in different nodes with a single Lua script. But according to the doc:

All Redis commands must be analyzed before execution to determine which keys the command will operate on. In order for this to be true for EVAL, keys must be passed explicitly. This is useful in many ways, but especially to make sure Redis Cluster can forward your request to the appropriate cluster node.

Note this rule is not enforced in order to provide the user with opportunities to abuse the Redis single instance configuration, at the cost of writing scripts not compatible with Redis Cluster.

So I think as long as I follow the key passing rule, the script should be compatible with Redis Cluster. I wonder what's the problem here and what should I do to update all keys in a single script.

like image 735
J Freebird Avatar asked Jul 06 '16 22:07

J Freebird


People also ask

Are Redis Lua scripts Atomic?

Redis has the ability to execute Lua scripts on the server side. Lua scripts are executed atomically, that is, no other script or command will run while a script is running, which gives us the same transactional semantics as MULTI / EXEC .

Which Lua command causes script to terminate when Redis returns?

pcall(), the only difference is that if a Redis command call will result into an error, redis. call() will raise a Lua error that in turn will force EVAL to return an error to the command caller, while redis. pcall will trap the error returning a Lua table representing the error."

What is Redis Evalsha?

Redis EVALSHA command evaluates a script cached on the server side by its SHA1 digest. Scripts are cached on the server side using the SCRIPT LOAD command. The command is otherwise identical to EVAL.


1 Answers

I'm afraid you've misunderstood the documentation. (And I agree that it's not very clear.)

Redis operations, whether commands or Lua scripts, can only work when all the keys are on the same server. The purpose of the key passing rule is to allow Cluster servers to figure out where to send the script and to fail fast if all the keys don't come from the same server (which is what happened in your case).

So it's your responsibility to make sure that all the keys you want to operate on are located on the same server. The way to do that is to use hash tags to force keys to hash to the same slot. See the documentation for more details on that.

like image 139
Kevin Christopher Henry Avatar answered Dec 28 '22 08:12

Kevin Christopher Henry