Redis Cluster and Lua script (eval)

2,744 views
Skip to first unread message

HeartSaVioR

unread,
Mar 26, 2014, 9:53:38 PM3/26/14
to redi...@googlegroups.com
Hello again.

Since I'm collaborating with Jedis, I'm curious about lua script with Redis Cluster.

It's not in Redis Cluster Specification docs.
But it's working now, with some constraints or problem.
(maybe bug or not currently implemented?).

Issue I've found is, "get key which exists in cluster but another node holds doesn't return MOVED"

A. prepare 3 Redis instances (say A, B, C), and group to cluster using redis-trib
B. connect A, try `set hello world` (get hello => "world")
C. connect B, try `get hello` => (error) MOVED 866 127.0.0.1:7379
D. connect A, try `eval "return redis.call('get', 'hello')" 0` => "world"
E. connect B, try `eval "return redis.call('get', 'hello')" 0` => nil

So I have a question.
Does Redis Cluster eventually support lua script? And does it throw MOVED, CROSSSLOT, etc?

Thanks in advance!

Sincerely.
Jungtaek Lim (HeartSaVioR)

Marc Gravell

unread,
Mar 27, 2014, 5:10:20 AM3/27/14
to redi...@googlegroups.com
When using scripts, you are meant to explicitly declare all keys used in the call, for example this (example is redis-cli, not Jedis) correctly reports -MOVED:

eval "return redis.call('get', KEYS[1])" 1 "Hello"

I don't know the Jedis API to see how easy that is to do. But yes, it does feel like it should report such errors from inside the script, too.

Marc


--
You received this message because you are subscribed to the Google Groups "Redis DB" group.
To unsubscribe from this group and stop receiving emails from it, send an email to redis-db+u...@googlegroups.com.
To post to this group, send email to redi...@googlegroups.com.
Visit this group at http://groups.google.com/group/redis-db.
For more options, visit https://groups.google.com/d/optout.



--
Regards,

Marc

Marc Gravell

unread,
Mar 27, 2014, 5:15:13 AM3/27/14
to redi...@googlegroups.com
Sorry, I meant to include a link; the importance of declaring keys, *especially* in the context of cluster, is discussed on the EVAL page: http://redis.io/commands/eval

But to be explicit - I agree with you that there is a bug here, as you can achieve inconsistent state:

redis cluster:7001> eval "return redis.call('set','Hello','World')" 0
OK
redis cluster:7001> keys Hello
1) "Hello"
redis cluster:7001> get Hello
(error) MOVED 3030 192.168.0.15:7000

(so now the server has a key that it shouldn't have, and doesn't readily admit to having)
--
Regards,

Marc

Salvatore Sanfilippo

unread,
Mar 27, 2014, 5:39:31 AM3/27/14
to Redis DB
On Thu, Mar 27, 2014 at 10:15 AM, Marc Gravell <marc.g...@gmail.com> wrote:
> But to be explicit - I agree with you that there is a bug here, as you can
> achieve inconsistent state:

Hello Marc,

this is definitely not desirable, but there are solutions (having the
effect of slowing down EVAL), I'm still not sure how much the slowdown
will be.

Basically luaRedisGenericCommand() in script.c handles the calling of
Redis commands from Lua.
This function already does a number of checks, creates the argument
vector, and so forth.
It will do an additional check: will match the keys called by Lua with
the keys declared by EVAL, and if they don't match, an error will be
returned.

To do this when Lua is called a dictionary will be populated with the
key names, and for every called function we have to use our API to
extract keys from command names.

I think that the slowdown will be around 5-10%. This feature probably
is worth to be exposed to normal instances, on demand, via some
eval-strict-mode parameter. I can see how in certain environments it
could be desirable to force to only use keys declared in scripts.

Salvatore

--
Salvatore 'antirez' Sanfilippo
open source developer - GoPivotal
http://invece.org

To "attack a straw man" is to create the illusion of having refuted a
proposition by replacing it with a superficially similar yet
unequivalent proposition (the "straw man"), and to refute it
-- Wikipedia (Straw man page)

HeartSaVioR

unread,
Mar 27, 2014, 6:37:51 AM3/27/14
to redi...@googlegroups.com
Thanks for explanation, Marc!

I've just read EVAL document page deeply, and found your meaning.

In order for this to be true for EVAL also keys must be explicit. This is useful in many ways, but especially in order to make sure Redis Cluster is able to forward your request to the appropriate cluster node (Redis Cluster is a work in progress, but the scripting feature was designed in order to play well with it). However 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 lua script with Redis Cluster is already documented, and problem I made is just constraints.

But user can confuse it's somewhat not natural, so I'm happy with Salvatore's "eval-strict-mode" thought.

Regards.
Jungtaek Lim (HeartSaVioR)

2014년 3월 27일 목요일 오후 6시 15분 13초 UTC+9, Marc Gravell 님의 말:

Marc Gravell

unread,
Mar 27, 2014, 7:51:15 AM3/27/14
to redi...@googlegroups.com
I genuinely don't know whether Jedis has specific "cluster" support, but it is worth noting that in a cluster-aware client library you will also get much better performance by declaring your keys - as it will be able to route to the correct node (or at least, what the library *believes* is the correct node) on the first try, rather than having to respond to -MOVED / -ASK - and it can potentially apply sanity checking (single-slot checking) before the command is sent. This also applies to things like twemproxy (although "eval" in twemproxy *demands* at least one key, for routing reasons).

Marc
Reply all
Reply to author
Forward
0 new messages