Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can redis disable the replies for pipelined commands?

I'm currently developing a cache that needs increase a few hundred counters for every call like this:

redis.pipelined do
  keys.each{ |key| redis.incr key }
end

In my profiling now I saw that the replies I don't need are still collected by the redis gem and waste some valueable time. Can I tell redis in some way that I'm not interested in the replies? Is there a better way to increment lots of values.

I didn't find a MINCR command, for example..

Thanks in advance!

like image 251
Thomas Fankhauser Avatar asked Oct 23 '12 07:10

Thomas Fankhauser


People also ask

How does Redis pipelining work?

Redis pipelining is a technique for improving performance by issuing multiple commands at once without waiting for the response to each individual command. Pipelining is supported by most Redis clients. This document describes the problem that pipelining is designed to solve and how pipelining works in Redis.

How are Redis pipelining and transaction different?

Transactions vs Pipeline in Redis. The difference is pipelines are not atomic whereas transactions are atomic, meaning 2 transactions do not run at the same time, whereas multiple pipelines can be executed by Redis-server at the same time in an interleaved fashion.

What happens if a command in a Redis transaction fails?

It's important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands. This time due to the syntax error the bad INCR command is not queued at all.

Does Redis support atomic operation?

Redis features two main mechanisms for executing multiple operations atomically: MULTI / EXEC transactions and Lua scripts.


1 Answers

Yes... in 2.6, at least. You could do this in a LUA script, and simply have the LUA script return an empty result. Here it is using the booksleeve client:

const int DB = 0; // any database number
// prime some initial values
conn.Keys.Remove(DB, new[] {"a", "b", "c"});
conn.Strings.Increment(DB, "b");
conn.Strings.Increment(DB, "c");
conn.Strings.Increment(DB, "c");

// run the script, passing "a", "b", "c", "c" to
// increment a & b by 1, c twice
var result = conn.Scripting.Eval(DB,
    @"for i,key in ipairs(KEYS) do redis.call('incr', key) end",
    new[] { "a", "b", "c", "c"}, // <== aka "KEYS" in the script
    null); // <== aka "ARGV" in the script

// check the incremented values
var a = conn.Strings.GetInt64(DB, "a");
var b = conn.Strings.GetInt64(DB, "b");
var c = conn.Strings.GetInt64(DB, "c");

Assert.IsNull(conn.Wait(result), "result");
Assert.AreEqual(1, conn.Wait(a), "a");
Assert.AreEqual(2, conn.Wait(b), "b");
Assert.AreEqual(4, conn.Wait(c), "c");

Or to do the same thing with incrby, passing the "by" numbers as arguments, change the middle portion to:

// run the script, passing "a", "b", "c" and 1, 1, 2
// increment a & b by 1, c twice
var result = conn.Scripting.Eval(DB,
    @"for i,key in ipairs(KEYS) do redis.call('incrby', key, ARGV[i]) end",
    new[] { "a", "b", "c" }, // <== aka "KEYS" in the script
    new object[] { 1, 1, 2 }); // <== aka "ARGV" in the script
like image 182
Marc Gravell Avatar answered Dec 28 '22 21:12

Marc Gravell