07 · Quack cliente-servidor¶
Cuadernos asociados
cuadernos/06_quack_servidor.ipynb (déjalo ejecutándose) y cuadernos/07_quack_cliente.ipynb. Volver al 00 - Índice de la demo.
La idea¶
Imaginar una máquina con 400 GB de Parquet junto al lago de datos (Data Lake) y nuestro portátil con 16 GB 😳😳. En tales circunstacias, mover los datos es absurdo: mejor mover el cómputo.
sequenceDiagram
autonumber
participant CLI as Cuaderno cliente
participant SRV as Servidor Quack
participant FS as Parquet / S3
Note over SRV: CALL quack_serve('quack:localhost:9494', token='...')
CLI->>SRV: ATTACH 'quack:localhost:9494' AS qk (TOKEN '...')
CLI->>SRV: CONNECT qk
CLI->>SRV: SELECT producto, sum(importe) GROUP BY ALL
SRV->>FS: Lee y agrega EN LOCAL
FS-->>SRV: Páginas Parquet
SRV-->>CLI: Solo el resultado agregado
CLI->>SRV: DISCONNECT
Quack es HTTP puro (puerto por defecto 9494), serialización binaria nativa de DuckDB y una petición-respuesta por consulta. No hay protocolo exótico que abrir en el firewall.
Lado servidor¶
INSTALL quack;
LOAD quack;
CALL quack_serve('quack:localhost:9494', token = 'demo_token_local_2026');
Devuelve tres valores útiles:
- 1º URI lógica
- 2º URL HTTP real
- 3º token efectivo (si no lo pasas, lo genera).
Detalles que importan:
| Parámetro | Efecto |
|---|---|
| Sin URI | Escucha en quack:localhost (9494) |
allow_other_hostname = true |
Permite bind a una IP no local (quack:0.0.0.0:9494) |
ssl_cert_file / ssl_key_file |
TLS propio; si no, certificado autofirmado |
CALL quack_stop('quack:localhost:9494') |
Detiene el servidor |
Desde la CLI, sin escribir SQL
duckdb -serve quack:localhost:9494 levanta el servidor y duckdb -connect quack:localhost:9494 se conecta.
Lado cliente¶
INSTALL quack;
LOAD quack;
ATTACH 'quack:localhost:9494' AS qk (TOKEN 'demo_token_local_2026');
CONNECT qk;
SELECT producto, unidades * precio AS ingreso
FROM ventas
ORDER BY ingreso DESC;
Sin CONNECT también funciona, pero cualificando el catálogo:
Las tres formas de hablar con un servidor¶
| Forma | Sintaxis | Cuándo |
|---|---|---|
| Sesión redirigida | ATTACH + CONNECT qk |
Lo recomendado: escribes SQL sin prefijos |
| Catálogo remoto | SELECT * FROM qk.tabla |
Cuando necesitas mezclar local y remoto |
| Consulta sin estado | FROM quack_query('quack:host', 'SELECT 42', token='...') |
Scripts sueltos, sin ATTACH |
⚠️ Tres trampas que el cuaderno demuestra en vivo¶
1 · Dentro de CONNECT, con.sql() no funciona
InvalidInputException: materialize() is not available while CONNECT-ed; DISCONNECT first.
Mientras la sesión está redirigida, usa con.execute(q).fetchall() / .fetchdf() / .df(). Las relaciones (.sql()) se materializan en el cliente y no están permitidas.
2 · Lo que creas dentro de CONNECT es efímero
Una CREATE TABLE ejecutada dentro de la sesión redirigida no persiste en el servidor: desaparece al hacer DISCONNECT y no aparece en el catálogo qk.. Verificado en el taller. Para escrituras que duren, cualifica el catálogo: CREATE TABLE qk.resumen AS ....
3 · CONNECT sin ATTACH previo no adivina el destino
CONNECT acepta un alias ya adjuntado o una cadena de conexión con esquema (mysql:, postgres:). Para Quack, el camino es siempre ATTACH ... AS alias y luego CONNECT alias.
Comprobar que el trabajo ocurre en remoto¶
Aparece un operador propio (Projection):
╭─ Quack Query By Name ────────╮
│ Server: quack:localhost:9494 │
│ Projections: producto │
│ ~1 row │
╰──────────────────────────────╯
Si el plan muestra Quack Query By Name, el filtro y la proyección viajaron al servidor. Si muestra un SCAN de tabla completa, el pushdown no ocurrió.
Identidad del nodo¶
Devuelve name, provider, hostname, region, uptime, ts_now y un meta JSON con versión y plataforma. Útil cuando hay varios servidores detrás de un proxy. Se rellena con CALL quack_identify(...).
Estado del protocolo¶
Quack es beta
DuckDB 2.0 es LTS, pero el protocolo Quack sigue marcado como beta: nombres de función, parámetros y valores por defecto pueden cambiar. Y no convierte DuckDB en un motor distribuido: varios clientes no forman un clúster que reparta una consulta entre máquinas.
Ejercicios¶
- Levanta el servidor en
9494, conéctate desde otro cuaderno y cuenta las filas de una tabla remota. - Demuestra que
con.sql()falla conCONNECTactivo y escribe la alternativa. - Crea
qk.auditoria(cualificada) y comprueba que sobrevive alDISCONNECT; crea otra sin cualificar y comprueba que no. - Cambia el puerto a
9600y el token, y repite la conexión. - Interpreta el
EXPLAINde una consulta remota: ¿qué operador indica pushdown?
Soluciones en cuadernos/99_soluciones.ipynb.