Pipelining
Every command is a request and a reply. When a client waits for each reply before sending the next command, most of the time goes to the network round trip rather than to HotKV doing the work. Pipelining sends a batch of commands back to back and reads all the replies afterwards, so a batch of a hundred commands costs roughly one round trip instead of a hundred.
Pipelining is a client-side technique: the server reads commands from a connection in order and replies in the same order, whether they arrive one at a time or many at once. There is nothing to turn on.
When to use it
Section titled “When to use it”- Loading or updating many keys at once (imports, cache warm-up, backfills).
- Reading a known set of keys, when one multi-key command such as MGET does not fit.
- Any loop that sends commands whose arguments do not depend on the previous reply.
A pipeline is not a transaction. Other clients’ commands can run between the commands of your batch, and if one command fails the others still run. For all-or-nothing execution, wrap the batch in MULTI and EXEC or use a Lua script.
Pipelining with redis-cli
Section titled “Pipelining with redis-cli”redis-cli --pipe reads commands from standard input, sends them without
waiting, and reports how many replies it got. It is the quickest way to bulk
load a file of commands:
cat > data.txt <<'EOF'SET user:1 "Ada"SET user:2 "Grace"INCR stats:importsEOF
cat data.txt | redis-cli --pipeAll data transferred. Waiting for the last reply...Last reply received from server.errors: 0, replies: 3For large imports, generate the file in the RESP wire format instead of inline commands, which handles values containing spaces, quotes or binary data. Each command is an array of bulk strings:
*3\r\n$3\r\nSET\r\n$6\r\nuser:1\r\n$3\r\nAda\r\nPipelining with the SDKs
Section titled “Pipelining with the SDKs”Each HotKV SDK queues commands on a pipeline object and sends them in one write when you execute it. The replies come back in the order you queued the commands.
import hotkv
client = hotkv.HotKV(host="localhost", port=6379)
with client.pipeline(transaction=False) as pipe: pipe.set("user:1", "Ada") pipe.set("user:2", "Grace") pipe.incr("stats:imports") pipe.get("user:1") results = pipe.execute()
print(results) # [True, True, 1, b'Ada']client.pipeline() without arguments wraps the batch in MULTI/EXEC;
pass transaction=False for a plain pipeline. execute(raise_on_error=False)
returns a failed command’s error in place of its result instead of raising.
import { HotKV } from "@hotkv/client";
const client = new HotKV({ url: "hotkv://127.0.0.1:6379" });
const pipe = client.pipeline();pipe.set("user:1", "Ada");pipe.set("user:2", "Grace");pipe.incr("stats:imports");const name = pipe.get("user:1"); // settles once exec() runs
const results = await pipe.exec(); // [error, value] per command, in orderconsole.log(await name); // "Ada"A failed command never aborts the rest of the batch: its entry in the
exec() result carries the error.
pipe := client.Pipeline()pipe.Set(ctx, "user:1", "Ada")pipe.Set(ctx, "user:2", "Grace")pipe.Incr(ctx, "stats:imports")name := pipe.Get(ctx, "user:1")
if _, err := pipe.Exec(ctx); err != nil { log.Fatal(err)}value, _ := name.Result()fmt.Println(value) // "Ada"The Go pipeline has typed methods for common commands and pipe.Do(ctx, ...)
for any other command.
import com.hotkv.Pipeline;import com.hotkv.Response;
Pipeline pipeline = client.pipeline();pipeline.set("user:1", "Ada");pipeline.set("user:2", "Grace");Response<Long> imports = pipeline.incr("stats:imports");Response<String> name = pipeline.get("user:1");pipeline.sync();
System.out.println(name.get() + " " + imports.get());A failed command does not fail the batch: its Response.get() throws the
error for that command only.
Batch size
Section titled “Batch size”Very large batches make the client hold every reply in memory until it reads them, and make the server buffer replies for a client that is not reading yet. Batches of a few hundred to a few thousand commands get almost all of the benefit. For bulk loads, send several batches one after another rather than one huge one.
Pipelining in a cluster
Section titled “Pipelining in a cluster”In a cluster, each command must go to the node that serves its key’s slot.
The SDKs’ cluster clients and redis-cli -c route single commands for you; if
you build pipelines by hand, group the commands by node, or give related keys
the same hash tag so they share a slot. See Clustering.
Was this page helpful?
Thanks for the feedback.