Chapter 11: db-mux — How It Works and Why It's 2.5× Faster

db-mux Write Path

// Application calls db-mux:
redis_connection_mux_set(mux, key, value, callback);

// Inside db-mux:
// 1. Get pre-allocated buffer from pool (NO heap allocation)
buffer_t *buf = buffer_pool_get(pool);

// 2. Build RESP3 wire format DIRECTLY into buffer
//    (manual formatting, no snprintf, no SDS)
resp_write_array_header(buf, 3);       // *3\r\n
resp_write_bulk_string(buf, "SET", 3); // $3\r\nSET\r\n
resp_write_bulk_string(buf, key, klen); // $N\r\nkey\r\n
resp_write_bulk_string(buf, val, vlen); // $N\r\nval\r\n

// 3. Hand pre-formatted buffer to hiredis (ZERO re-encoding)
redisAsyncFormattedCommand(ctx, cb, priv, buf->data, buf->len);
// hiredis just appends to obuf — no formatting work

// 4. Enable POLLOUT directly (no defer)
evl_fd_add_events(fd, POLLOUT);

// Total: 0 heap allocations per command

Why It's Faster: Side-by-Side

Stepdb-proxydb-mux
Key serializationmalloc + copyWrite directly to pooled buffer
RESP formattinghiredis does it (malloc SDS, snprintf)App does it (no alloc, manual format)
Hand to hiredisredisAsyncCommandArgv (re-formats)redisAsyncFormattedCommand (just append)
EVL integrationCreates defer per writeDirectly enables POLLOUT
Allocations/cmd2-30
CPU at 300K/s~80%~29%

The MSET Extension

// db-mux multicommand API (new for this feature):
mux_multi_t *multi = redis_connection_mux_multi_start(mux);

redis_connection_mux_multi_add(multi, "teid:123", teid_val);
redis_connection_mux_multi_add(multi, "ueip:456", ueip_val);
redis_connection_mux_multi_add(multi, "l2tp:789", l2tp_val);

redis_connection_mux_multi_exec(multi, callback);
// Builds ONE MSET command with all keys → ONE Redis command
// ONE callback when done (no pending counter needed)

Trade-off: Latency vs CPU

⚠️ db-mux Has Higher Per-Command Latency

db-mux buffers an entire chunk before poll handles any events. Responses pile up in the socket buffer. RTT is ~1000µs vs db-proxy's ~300µs at 100K/sec. But CPU is 2.5× lower. For PCG where CPU is the constraint (not individual command latency), this is the right trade-off.

Key Takeaways