Jedis Lua scripts - Atomicity

1,037 views
Skip to first unread message

Kashyap Mhaisekar

unread,
May 18, 2015, 1:29:40 PM5/18/15
to redi...@googlegroups.com
Hi,,
I am using LUA script in Redis through Storm where 100 threads are parallely trying to call INCR on a key in Redis.

Now, each thread can call the LUA script 10 times and hence there are 1000 iterations. After execution, i expect the counter to have a value of 1000 as the lua script is called 1000 times but what I find is that the value is a random number.

Question:
When multiple lua scripts are called at same time on a redis instance, will the lua calls get queued? or will they be ignored? Is there some queueing that can be enforced here?

My script that is called in parallel:
List<String> keys = new ArrayList<String>();
keys.add("incr");
List<String> args = new ArrayList<String>();
args.add("jvm:incr");
String pubtojvm = "local pubsubresults={} "+
qualOffers+
"local ofrcnt=redis.call('INCR',ARGV[1]) "+
"return pubsubresults";

Please help.

Regards,
Kashyap

Josiah Carlson

unread,
May 18, 2015, 3:17:30 PM5/18/15
to redi...@googlegroups.com
When I call a Lua script from the Redis client, Redis benchmark, or any other properly working client, the numbers are *exactly* what I expect.

Are you checking for successful execution from all of your calls? Are you getting errors/timeouts/delays like you had reported previously? Can you provide any further information?

 - Josiah


--
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.

Kashyap Mhaisekar

unread,
May 18, 2015, 5:46:19 PM5/18/15
to redi...@googlegroups.com

No exceptions but the jedis.eval(...) gives back a null at times. I don't see connection starvations (like exceptions stating that connections not present in pool) nor timeout exceptions (socket timeouts or read timeouts) either.

I have the following code for connection pooling and evaluation of "eval"

config = new JedisPoolConfig();

config.setMaxActive(300);

config.setTestOnBorrow(false);

config.setTestOnReturn(false);

config.setMaxIdle(100);


// Tests whether connections are dead during idle periods

config.setTestWhileIdle(false);

pool = new JedisPool(config,

"serverhost", <Someport>,50,null,6);

and the code for calling eval is as follows -

public static Object eval(String script, int redisDB, List<String> keys, List<String> args) {

Jedis jedis = null;

Object value = null;

try {

jedis = pool.getResource();

//jedis.select(redisDB);

long t1 = System.currentTimeMillis();

value = jedis.eval(script,keys,args);

long t2 = System.currentTimeMillis();

System.out.println(Thread.currentThread().getName()+": Redis EVAL: "+(t2-t1)+" @ "+t2);

} catch (JedisConnectionException e) {

if (null != jedis) {

pool.returnBrokenResource(jedis);

jedis = null;

}

} finally {

if (null != jedis)

pool.returnResource(jedis);

}


return value;

}

Script is what is shared before...  Only difference is as follows -

List<String> keys = new ArrayList<String>();
keys.add("incr");
List<String> args = new ArrayList<String>();
args.add("jvm:incr");
String pubtojvm = "local pubsubresults={} "+
qualOffers+
"local ofrcnt=redis.call('INCR',ARGV[1]) "+
"return pubsubresults";

1. If I call this method "sequentially" for 10000 times, the INCR works perfectly and the final value is 10000.

2. If I call this method parallely, say in 100 threads each calling this method 10 times, the final INCR value is never 1000 but always close to it (something like 954, 977, 989 and sometimes 992).

3. If I call this in a DEBUG mode and space it out, then the value is perfectly 1000.

This made me think whether all eval functions are getting executed or not? Is there is a queue of "commands" being maintained at REDIS side?


Thank you..

Kashyap

Josiah Carlson

unread,
May 18, 2015, 6:18:59 PM5/18/15
to redi...@googlegroups.com
I can run 100 threads performing 10000 operations each thread, and I don't have any issues counting to 1 million. Something is broken with your code, your client, your network, and/or your error handling.

You should count the number of errors you experience to see if that corresponds with your missing counts. If you find that they do correspond, or if you find some detail in the errors that can tell you why your numbers weren't incremented, I'm sure that information would be useful to help figure out what is the underlying cause for your failures.

 - Josiah

Kashyap Mhaisekar

unread,
May 18, 2015, 6:24:48 PM5/18/15
to redi...@googlegroups.com

Thanks Josiah. One question though - Am using Jedis java client . Did you ever experience issue with this client?

Regards
Kashyap

Josiah Carlson

unread,
May 18, 2015, 6:37:30 PM5/18/15
to redi...@googlegroups.com
I don't use Jedis (or Java), but a lot of people do. Unless you have a specific reason to suspect Jedis (like you get stack traces/crashes related to parsing the network protocol), there are no indicators to me that this is an issue with Jedis. You can feel free to email the Jedis mailing list for help, they may be able to point out some incorrect use/etc.

Incidentally, your Lua script is not using the KEYS array passed, but is instead using the ARGV array as KEYS. This probably doesn't matter right now, but may make a difference if at some point you start sharding or using Redis cluster.

 - Josiah

Kashyap Mhaisekar

unread,
May 18, 2015, 7:07:40 PM5/18/15
to redi...@googlegroups.com

Will do. Thanks. But one question.

Redis runs on one thread. But when a command is getting executed, are the other commands queued or are they ignored? Both for normal commands and for Lua based execution.

Thanks!
Kashyap

Josiah Carlson

unread,
May 18, 2015, 9:28:13 PM5/18/15
to redi...@googlegroups.com
Redis will do different things depending on the context. In the case of non-scripting commands, Redis generally executes them directly as they are received from the network buffers, leaving all other commands from all other clients sitting in the network buffers (queued, but not by Redis). In the case of MULTI/EXEC, Redis will explicitly queue the passed commands locally until EXEC or DISCARD is called (queued by Redis).

If you have enabled Lua script execution timeouts via the configuration option, after the script has "timed out", Redis will periodically handle network/event processing to allow for "SCRIPT KILL" or "SHUTDOWN NOSAVE" calls to be executed after the timeout. But at the same time, Redis will also return errors to clients stating that only those two commands are allowed after a timeout (but before the script has returned).

Look at your error responses.

 - Josiah

Kashyap Mhaisekar

unread,
May 22, 2015, 2:32:36 PM5/22/15
to redi...@googlegroups.com
Josiah,
When initializing connection pool for Redis, I changed the timeout value from 200 (default) to 20 and hence there was Socket timeouts which was a reason why the INCR was not happening.
Reverting it back to default has resolved this issue. Thanks for your time.

Regards,
Kashyap
Reply all
Reply to author
Forward
0 new messages