Usa ColibriDB desde tu código.

Todas las formas de hablar con un clúster: llamadas HTTP, comandos Redis y las bibliotecas cliente, con ejemplos listos para copiar. La página Connect de tu consola Admin muestra las direcciones y credenciales exactas de tu clúster.

Conexión

Las aplicaciones hablan con los proxies, que envían cada clave al nodo que la tiene y siguen los failovers por ti. Elige la vía que mejor encaje con tu stack; todas ven los mismos datos.

Punto de accesoPuerto por defectoPara quéAutenticación
Proxy HTTP5006curl, cualquier lenguaje, los clientes Python y TypeScriptToken Bearer, Basic, JWT (OIDC) o un usuario ACL
Proxy binario6400El cliente .NET: la menor latenciaAPI key o un usuario ACL
RESP en los nodos6379redis-cli y cualquier cliente Redis (StackExchange.Redis, redis-py, ioredis, go-redis)AUTH con la clave del clúster o un usuario ACL
Los ejemplos usan dos variables
# De Admin → Connect: la dirección del proxy HTTP y un token
export COLIBRI_URL=https://db.example.com:5006
export COLIBRI_TOKEN=your-proxy-token

Claves por HTTP

El valor es el cuerpo de la petición tal cual, cualquier byte hasta el límite configurado. La clave es un solo segmento de la ruta: escribe una / dentro de una clave como %2F.

curl
# Escribe un valor que expira en una hora
curl -X PUT "$COLIBRI_URL/kv/user:42?ttlSeconds=3600" \
  -H "Authorization: Bearer $COLIBRI_TOKEN" \
  --data-binary '{"name":"Ada","plan":"pro"}'

# Léelo (404 si la clave no existe)
curl "$COLIBRI_URL/kv/user:42" -H "Authorization: Bearer $COLIBRI_TOKEN"

# Escribe solo si la clave no existe: un candado simple (409 si alguien ya lo tiene)
curl -X PUT "$COLIBRI_URL/kv/lock:report?nx=true&ttlSeconds=30" \
  -H "Authorization: Bearer $COLIBRI_TOKEN" --data-binary "worker-7"

# Lista claves por prefijo, de 100 en 100 (los valores vienen en base64; pasa nextCursor para seguir)
curl "$COLIBRI_URL/kv?prefix=user:&limit=100" -H "Authorization: Bearer $COLIBRI_TOKEN"

# Bórrala
curl -X DELETE "$COLIBRI_URL/kv/user:42" -H "Authorization: Bearer $COLIBRI_TOKEN"
LlamadaQué haceRespuestas
GET /kv/{key}Lee el valor200 con los bytes · 404
PUT /kv/{key}Escribe el valor. ?ttlSeconds=N lo hace expirar, ?nx=true escribe solo si no existe, ?xx=true solo si existe204 · 409 (nx) · 404 (xx) · 413 demasiado grande
DELETE /kv/{key}Borra la clave204 · 404
GET /kv?prefix=&limit=&cursor=Recorre las claves por páginas{ items:[{key, value}], nextCursor }
GET /healthEstado y rol, sin credenciales200

Hashes, sets, sorted sets y listas

Las mismas operaciones atómicas que los comandos Redis, con cuerpos JSON (Content-Type: application/json). El texto viaja como texto; agrega ?encoding=base64 para enviar y recibir valores binarios.

curl
# Un hash: escribe campos, incrementa uno, léelos todos
curl -X PUT "$COLIBRI_URL/hash/cart:7" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"fields":{"sku-1":"2","sku-9":"1"}}'
curl -X POST "$COLIBRI_URL/hash/cart:7/incr" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"field":"sku-1","by":3}'
curl "$COLIBRI_URL/hash/cart:7" -H "Authorization: Bearer $COLIBRI_TOKEN"
# → {"key":"cart:7","count":2,"fields":{"sku-1":"5","sku-9":"1"}}

# Un sorted set: agrega puntajes, lee el top 10
curl -X PUT "$COLIBRI_URL/zset/leaderboard" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"members":[{"member":"ada","score":120},{"member":"bob","score":95}]}'
curl "$COLIBRI_URL/zset/leaderboard?start=0&stop=9&rev=true" -H "Authorization: Bearer $COLIBRI_TOKEN"

# Una lista como cola: agrega al final, saca del inicio
curl -X POST "$COLIBRI_URL/list/jobs/push" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"side":"right","values":["job-1","job-2"]}'
curl -X POST "$COLIBRI_URL/list/jobs/pop" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"side":"left","count":1}'

# Un set: agrega miembros, comprueba uno
curl -X PUT "$COLIBRI_URL/set/tags:42" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"members":["vip","beta"]}'
curl "$COLIBRI_URL/set/tags:42?member=vip" -H "Authorization: Bearer $COLIBRI_TOKEN"
TipoLlamadasEquivale a
/hash/{key}GET (?field=…), PUT { fields }, DELETE ?field=…, POST /incr { field, by }HGETALL, HSET, HDEL, HINCRBY
/set/{key}GET (?member=…), PUT { members }, DELETE ?member=…, POST /pop { count }SMEMBERS, SADD, SREM, SPOP
/zset/{key}GET ?start&stop&rev o ?min&max, PUT { members:[{member, score}] }, POST /incr, POST /popZRANGE, ZADD, ZINCRBY, ZPOPMIN
/list/{key}GET ?start&stop, POST /push { side, values }, POST /pop { side, count }, POST /trimLRANGE, LPUSH/RPUSH, LPOP/RPOP, LTRIM

Comandos Redis

Activa RESP en los nodos (Admin → Configuration) y usa redis-cli o el cliente Redis que ya tienes. Con TLS activo, conéctate con --tls o una URL rediss://.

redis-cli
redis-cli -h db.example.com -p 6379 --tls -a "$COLIBRI_PASSWORD"

SET user:42 '{"name":"Ada"}' EX 3600
GET user:42
HSET cart:7 sku-1 2 sku-9 1
ZADD leaderboard 120 ada 95 bob
ZREVRANGE leaderboard 0 9 WITHSCORES
MULTI
INCR visits:today
EXPIRE visits:today 86400
EXEC

La compatibilidad está verificada con una suite de pruebas y con los clientes StackExchange.Redis, redis-py e ioredis, sobre RESP2 y RESP3:

ÁreaEstadoNotas
Conexión, AUTH, PING, HELLO 2 y 3, pipelining Soportado Las escrituras de un pipeline comparten un group commit; vea Escrituras en pipeline más abajo
Strings, TTL, opciones de SET, INCR, APPEND, GETRANGE y SETRANGE Soportado La expiración es perezosa más un barrido periódico
Claves: KEYS, SCAN, RENAME, COPY y TOUCH Soportado Los comandos de varias claves requieren claves en un mismo shard; use un {hash tag}
Hashes Soportado Se reescribe toda la colección en cada escritura, tope de 4 MiB
Sets, sorted sets y listas Parcial Con uniones, intersecciones, variantes STORE, LMOVE y rangos léxicos; aún sin operaciones bloqueantes
Bitmaps Soportado SETBIT, GETBIT, BITCOUNT, BITPOS y BITOP; sin BITFIELD
MULTI, EXEC y WATCH Parcial Las claves deben estar en un mismo shard; use {hash tags}. EXEC es atómico y seguro ante caídas
Pub/sub Soportado De todo el clúster con el relay configurado; si no, local al nodo
Notificaciones de keyspace Soportado Eventos para escrituras de todos los protocolos
RESP3 Soportado Mapas, sets, doubles y push tras HELLO 3
Caché del lado del cliente (CLIENT TRACKING) No soportado
Streams, Lua y EVAL, HyperLogLog, geo No soportado
FLUSHDB, FLUSHALL, SELECT mayor que 0, CLUSTER No soportado Rechazados

Bibliotecas cliente

Los paquetes cliente vienen con tu licencia. Siguen los cambios de líder, reintentan lecturas de forma segura y nunca repiten una escritura que pudo haberse aplicado.

protocolo binario
using ColibriDB.Client;

await using var db = new ColibriClient(new ColibriClientOptions
{
    Host = "db.example.com",
    Port = 6400,
    ApiKey = Environment.GetEnvironmentVariable("COLIBRI_KEY"),
});

await db.PutAsync("user:42", "{\"name\":\"Ada\"}");
string? user = await db.GetStringAsync("user:42");
var many = await db.GetManyAsync(["user:1", "user:2", "user:3"]);
API HTTP, solo biblioteca estándar
import os
from colibridb import ColibriClient

with ColibriClient(os.environ["COLIBRI_URL"], bearer=os.environ["COLIBRI_TOKEN"]) as db:
    db.put("user:42", '{"name":"Ada"}', ttl_seconds=3600)
    db.get_text("user:42")                      # '{"name":"Ada"}'
    db.put("lock:report", "worker-7", nx=True)  # False if the key exists
    db.hash_set("cart:7", {"sku-1": "2"})
    db.zset_add("leaderboard", {"ada": 120, "bob": 95})
    for key, value in db.iter_scan("user:"):
        print(key, value)
API HTTP, sin dependencias
import { ColibriClient } from "@colibridb/client";

const db = new ColibriClient({
  baseUrl: process.env.COLIBRI_URL!,
  bearer: process.env.COLIBRI_TOKEN!,
});

await db.put("user:42", JSON.stringify({ name: "Ada" }), { ttlSeconds: 3600 });
const user = await db.getText("user:42");
await db.put("lock:report", "worker-7", { nx: true }); // false if the key exists
await db.zsetAdd("leaderboard", new Map([["ada", 120], ["bob", 95]]));
for await (const [key, value] of db.iterScan("user:")) {
  console.log(key, value);
}
ClienteProtocoloGET en loopbackNotas
.NETBinario, puerto 6400unos 37 µsConexiones en pool y con pipelining; TLS y mTLS. Este protocolo no tiene TTL ni scan: usa HTTP para eso
PythonHTTP, puerto 5006unos 75 µsPython 3.9+, una conexión keep-alive por hilo; hashes, sets, sorted sets, listas y vectores
TypeScriptHTTP, puerto 5006unos 65 µsNode, Deno, Bun y navegadores; los mismos métodos tipados que Python

Errores y reintentos

Los errores llegan como JSON Problem Details (type, title, detail). Los clientes manejan las redirecciones y los reintentos seguros por ti; con HTTP directo, esto significa cada código y qué hacer.

CódigoSignificadoQué hacer
401 · 403Faltan credenciales o son incorrectas, o la ACL niega esa claveRevisa el token o los patrones de claves del usuario
404La clave no existe (o xx=true no encontró nada)Trátalo como ausencia
409nx=true encontró la clave, o la clave guarda otro tipoLee la clave o usa otro nombre
413El valor o la colección supera el límiteDivide el valor; no se escribió nada
421El nodo no es el líder del grupo de esa claveRepite en X-Colibri-Leader-Url; no se aplicó nada
429Límite de peticiones del usuario ACLEspera y reintenta
503Elección, migración o sin quórum (Retry-After)Reintenta lecturas; escrituras solo con X-Colibri-Fenced: raft-not-applied
504No se sabe si la escritura se aplicóLee la clave antes de repetir la escritura
507La cuota del tenant está llenaLecturas y borrados siguen funcionando; libera espacio o sube la cuota

Escrituras en pipeline y durabilidad

Un cliente que envía escrituras seguidas por una conexión las ve confirmadas juntas, y las respuestas siguen el orden de las peticiones. Estos son los ajustes y lo que garantizan.

AjustePor defectoRangoNotas
Node__PipelinedWrites 128 0 a 4096 Escrituras SET y PUT simples en vuelo por conexión, en RESP y en el protocolo binario. 0 lo desactiva.
Node__PipelinedWriteBytes 1 MiB 1 B a 256 MiB Bytes de clave y valor en vuelo por conexión. Una sola escritura mayor no se difiere.
ProxyBinary__PipelinedFrames 128 0 a 1024 Frames GET, PUT y DELETE que el proxy binario reenvía a un nodo antes de leer las respuestas. 0 o 1 lo desactiva.
ProxyBinary__PipelinedBytes 1 MiB 0 a 1 GiB Bytes de petición en un lote reenviado. 0 lo desactiva.
ProxyBinary__PipelinedResponseBytes 2 MiB 64 KiB a 1 GiB Respuestas que un lote puede guardar fuera de orden. Si se supera, el proxy deja de leer esa conexión del nodo hasta que le toque.
ProxyBinary__MaxIdleBackendConnectionsPerNode 1024 0 a 10000 Conexiones ociosas que se mantienen abiertas por nodo. Manténgalo igual o por encima del número real de clientes concurrentes.
ProxyBinary__BackendIdleTimeoutSeconds 240 1 a 299 Segundos de inactividad tras los cuales se cierra una conexión a un nodo. Queda por debajo del idle timeout de 300 s del nodo.
  • Cualquier otro comando, una clave repetida o un error de protocolo cierra primero la tanda, así que un comando que sigue a una escritura en el mismo pipeline la ve.
  • Con WalPolicy Always, una tanda cuesta un fsync en vez de uno por escritura. Los grupos Raft siempre usan Always.
  • Con WalPolicy Interval, el fsync periódico corre en una tarea en segundo plano y las escrituras no lo esperan. La ventana de pérdida sigue siendo como máximo WalFlushIntervalMs.
  • Si falla el fsync del log de replicación de archivo, el shard sigue atendiendo y la replicación se degrada: la salud del nodo informa Degraded, la métrica colibri.engine.replication_faulted_shards cuenta el shard y queda un marcador .gap junto al log. La reproducción rechaza un log con un hueco, así que hay que resincronizar la réplica.
  • La API de log, la replicación y el índice vectorial nunca ven una posición del log antes de que sus datos sean legibles. Si aplicar una escritura al índice falla tras el commit, el shard se detiene en vez de responder con un error engañoso.
  • Un fsync fallido durante la rotación de un segmento nunca se informa como duradero.

La arquitectura, la seguridad, la operación y la referencia completa de configuración vienen con tu licencia. Pídenoslas