Nyx con Ejemplos

nyx-kv pipelining

El pipelining envía múltiples comandos sin esperar entre ellos, y luego lee todas las respuestas. Esto amortiza los round-trips de red y logra 250K+ ops/seg en localhost.

Código

// nyx-kv pipelining -- batch commands for high throughput

fn resp_cmd(parts: Array) -> String {
    var sb: StringBuilder = StringBuilder.new()
    sb.append("*")
    sb.append(int_to_string(parts.length()))
    sb.append("\r\n")
    var i: int = 0
    while i < parts.length() {
        let p: String = parts[i]
        sb.append("$")
        sb.append(int_to_string(p.length()))
        sb.append("\r\n")
        sb.append(p)
        sb.append("\r\n")
        i = i + 1
    }
    return sb.to_string()
}

fn main() -> int {
    let fd: int = tcp_connect("127.0.0.1", 6380)
    if fd < 0 {
        print("connection failed")
        return 1
    }

    // Build a batch of SET commands and send them all at once
    var batch: StringBuilder = StringBuilder.new()
    var i: int = 0
    while i < 10 {
        let key: String = "item:" + int_to_string(i)
        let val: String = "value_" + int_to_string(i * i)
        batch.append(resp_cmd(["SET", key, val]))
        i = i + 1
    }

    // Single write sends all 10 commands
    tcp_write(fd, batch.to_string())

    // Read 10 replies in order (each is "+OK")
    var replies: int = 0
    i = 0
    while i < 10 {
        let r: String = tcp_read_line(fd)
        if r.length() > 0 { replies = replies + 1 }
        i = i + 1
    }
    print("pipelined 10 SET commands, got " + int_to_string(replies) + " replies")

    // Pipelining yields 250K+ ops/sec on localhost (vs 85K/s non-pipelined)
    print("benchmark: 250K+ ops/s on localhost loopback")

    tcp_close(fd)
    return 0
}

Salida

pipelined 10 SET commands, got 10 replies
benchmark: 250K+ ops/s on localhost loopback

Explicación

Sin pipelining, cada comando paga un round-trip completo: el cliente escribe, el kernel envía el paquete, el servidor parsea, ejecuta, responde, y recién ahí el cliente puede escribir el siguiente comando. En localhost este round-trip cuesta unos pocos microsegundos — en una WAN, es la diferencia entre 200 y 200000 ops/seg.

Con pipelining, el cliente concatena N comandos en una sola escritura TCP, y luego hace una única lectura grande de N respuestas. Como el servidor procesa los comandos en orden y las respuestas RESP se delimitan a sí mismas, hacer coincidir las solicitudes con las respuestas es trivial. El único límite es el buffer de envío TCP — en la práctica, lotes de unos pocos miles de comandos son seguros y eficientes.

El pipelining no es una transacción — los comandos de otros clientes todavía pueden intercalarse en el servidor. Si se necesita atomicidad entre múltiples operaciones, hay que usar MULTI/EXEC o un script Lua.

← Anterior Siguiente →

Source: examples/by-example/77-kv-pipelined.nx