6

I'm a bit mixed up about the difference between a Redis transaction and pipeline and ultimately how to use pipelines with Booksleeve. I see that Booksleeve has support for the Redis transaction feature (MULTI/EXEC), but there is no mention in its API/tests about a pipelining feature. However, it's clear in other implementations that there is a distinction between pipelines and transactions, namely in atomicity, as evidenced in the redis-ruby version below, but in some places the terms seem to be used interchangeably.

redis-ruby implementation:

r.pipelined {
  # these commands will be pipelined
  r.get("insensitive_key")
}

r.multi {
  # these commands will be executed atomically
  r.set("sensitive_key")
}

I'd just use MULTI/EXEC instead but they seem to block all other users until the transaction has completed (not necessary in my case), so I worry about their performance. Has anyone used pipelines with Booksleeve or have any ideas about how to implement them?

bosgood
  • 1,984
  • 18
  • 21

3 Answers3

6

In BookSleeve, everything is always pipelined. There are no synchronous operations. Not a single one. As such, every operation returns some form of Task (could be a vanilla Task, could be a Task<string>, Task<long>, etc), which at some point in the future (i.e. when redis responds) will have a value. You can use Wait at your calling code to perform a synchronous wait, or ContinueWith / await (C# 5 language feature) to perform an asynchronous callback.

Transactions are no different; they are pipelined. The only subtle change with transactions is that they are additionally buffered at the call-site until complete (since it is a multiplexer, we can't start pipelining transaction-related messages until we have a complete unit-of-work, as it would adversely impact other callers on the same multiplexer).

So: the reason there is no explicit .pipelined is that everything is pipelined and asynchronous.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
4

Pipelining is a protocol level communication strategy and has nothing to do with atomicity. It is entirely orthogonal to notion of 'transactions'. (For example, you can use MULTI .. EXEC in a pipelined connection.)

What is pipelining?

The most basic connector to redis would be a synchronous client interacting in a request-reply manner. Client sends a request, and then waits for response from Redis before sending the next request.

In pipelining, the client can keep sending requests without pausing to see the Redis response for each request. Redis is, of course, a single threaded server and a natural serialization point, and thus request order is preserved and reflected in the response order. This means, the client can have one thread sending requests (typically by dequeuing from a request queue) and another thread is constantly processing responses from Redis. Note that of course you can still use pipelining with a single threaded client, but you do lose some of the efficiencies. The two threaded model allows for full utilization of your local CPU and the network bandwidth (e.g. saturation).

If you are following this so far, you must ask yourself: well, how are the request and responses matched on the client side? Good question! There are various ways to approach this. In JRedis, I wrap requests in a (java) Future object, to deal with the asynchrony of the request/response processing. Everytime a request is sent, a corresponding Future object is wrapped by a pending response object and is queued. The response listener simply dequeues from this queue 1 item at a time and parses the response (stream) and updates the future object.

Now the end user of the client can either be exposed to a synchronous or an asynchronous interface. If the interface is synchronous, the implementation naturally must block on the Future's response.

If you have followed so far, then it should be clear that a single threaded app using synchronous semantics with pipelining defeats the entire purpose of pipelining (since the app is blocking on the response and is not busy feeding the client additional requests.) But if the app is multithreaded, a synchronous interface to the pipeline allows you to use a single connection while processing N client-app threads. (So here, it is a implementation strategy to help build a thread-safe connection.)

If the interface to pipeline is asynchronous, then even a single threaded client app can benefit. Throughput increases at least by an order of magnitude.

(Caveats with pipelining: It is non-trivial to write a fault-tolerant pipelined client.)

Ideally I should use a diagram, but pay attention to what happens at the end of the clip: http://www.youtube.com/watch?v=NeK5ZjtpO-M

alphazero
  • 27,094
  • 3
  • 30
  • 26
  • Thanks for your detailed explanation. However, my question mainly refers to how to use this feature specifically with the Booksleeve Redis client (if possible), not how it's implemented in general. – bosgood Dec 07 '11 at 20:57
  • I was addressing the "a bit mixed up about the difference between a Redis transaction and pipeline". As to Booksleeve (don't know it) likely this is a good start: http://code.google.com/p/booksleeve/source/browse/Async/CustomAwaiter.cs – alphazero Dec 07 '11 at 21:24
  • @alphazero actually, that Async project is merely an illustration of using the C# 5 `async` language feature with BookSleeve. ***Everything*** in BookSleeve is async and pipelined. – Marc Gravell Oct 11 '12 at 06:54
1

Here is the link to Redis Transactions Documentation

Regarding BookSleeve, please refer to this post from Marc.

"CreateTransaction() creates a staging area to build commands (using exactly the same API) and capture future results. Then, when Execute() is called the buffered commands are assembled into a MULTI/EXEC unit and sent down in a contiguous block (the multiplexer will send all of these together, obviously)."

If you create your commands inside a transaction they will automatically be "pipelined".

Carlos Mendes
  • 1,900
  • 1
  • 18
  • 33
  • However, there is still a distinction here between "transactions" and "pipelining", the former being a formal feature supported by redis while the latter is simply the ability of a client to send multiple (separate) requests together. I'm asking about the latter, as I don't need atomicity, and Booksleeve is billed as ["pipelined .NET bindings for redis"](http://code.google.com/p/booksleeve). Thanks for your answer though, this is what I'm currently using. – bosgood Dec 07 '11 at 20:56