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