⏱️ Lectura: 16 min

En septiembre de 2014, Philip O’Toole subió a GitHub un proyecto de fin de semana: combinar SQLite con un log de Raft para que las escrituras se replicaran en un clúster. Doce años después, ese experimento dio nombre a una categoría entera de software, el SQLite distribuido, con dos adquisiciones y financiamiento de riesgo detrás.

📑 En este artículo
  1. TL;DR
  2. ¿Qué es SQLite distribuido?
  3. Por qué importa la replicación de SQLite con Raft
  4. Cómo funciona: Raft, streaming de WAL y CRDTs
    1. El primer enfoque: consenso con Raft
    2. El segundo enfoque: streaming del WAL
    3. El tercer enfoque: fusión sin líder
  5. El mapa completo: de rqlite a las plataformas gestionadas
  6. Comparativa: rqlite, dqlite, LiteFS, Litestream y Turso/libSQL
  7. Cómo empezar con rqlite
  8. Casos de uso reales
  9. Errores comunes y buenas prácticas
  10. Profundizando: por qué el teorema CAP importa acá
  11. Preguntas frecuentes
    1. ¿rqlite reemplaza a Postgres o MySQL?
    2. ¿dqlite se puede usar fuera de LXD o MicroK8s?
    3. ¿Litestream da alta disponibilidad?
    4. ¿LiteFS depende de Fly.io para funcionar?
    5. ¿Turso y libSQL son compatibles al 100% con SQLite?
    6. ¿Cuándo conviene cr-sqlite en lugar de rqlite?
  12. Referencias
    1. 📚 Artículos relacionados

O’Toole publicó este año una retrospectiva completa de la historia, desde rqlite hasta las plataformas gestionadas actuales (ver Referencias). Este artículo toma ese repaso como punto de partida para explicar la categoría y comparar las opciones vigentes: rqlite, dqlite, Litestream, LiteFS y Turso/libSQL, y cuándo conviene cada una.

TL;DR

  • SQLite distribuido combina SQLite con replicación (Raft, streaming de WAL o CRDTs) para sobrevivir a la caída de un nodo.
  • rqlite, publicado en 2014, fue el primer proyecto abierto en sumar Raft a SQLite para formar un clúster CP.
  • dqlite ofrece el mismo patrón que rqlite pero como librería en C, embebida en LXD y MicroK8s de Canonical.
  • Litestream prescinde del consenso: solo transmite el WAL a S3 para recuperar un nodo único tras una caída.
  • LiteFS y Turso/libSQL muestran las otras dos rutas: réplicas por sistema de archivos y un fork del motor para el edge.

¿Qué es SQLite distribuido?

SQLite distribuido es la categoría de sistemas que toman el motor de base de datos SQLite, diseñado para un solo archivo en un solo proceso, y le agregan una capa de replicación entre varios nodos para que la caída de una máquina no implique perder datos ni disponibilidad del servicio.

La propuesta no es nueva en el diseño, pero sí en el empaquetado: antes de 2014 la replicación de bases relacionales exigía Postgres, MySQL o un sistema distribuido completo como Cassandra. El SQLite distribuido ofrece lo mismo a una escala mucho menor, con un binario único y sin un equipo de operaciones dedicado.

Por qué importa la replicación de SQLite con Raft

SQLite guarda toda la base en un solo archivo y un solo proceso escribe a la vez. Es rápido, simple y perfecto para una app de escritorio, un sitio con tráfico moderado o un dispositivo embebido. Pero si la máquina que lo corre se cae, el archivo se pierde con ella salvo que exista un backup reciente.

Ese problema concreto fue el que O’Toole enfrentó en 2014 en jut.io: un sistema en clúster necesitaba almacenamiento relacional chico, y no había forma clara de decidir qué nodo debía guardarlo. Replicar SQLite con un protocolo de consenso resolvía la pregunta sin montar una base de datos completa aparte. La necesidad era específica, no un rediseño general de la arquitectura.

Doce años después, el mismo argumento sigue vigente para microservicios pequeños, agentes de borde y aplicaciones que no justifican operar Postgres en alta disponibilidad, pero sí necesitan sobrevivir la pérdida de un nodo sin intervención manual.

Cómo funciona: Raft, streaming de WAL y CRDTs

La retrospectiva de O’Toole identifica tres enfoques distintos para resolver el mismo problema, y los tres aparecieron en orden cronológico.

flowchart TD
A["SQLite + replicación"] --> B["Consenso: rqlite, dqlite"]
A --> C["Streaming de WAL: Litestream, LiteFS"]
A --> D["Fusión sin líder: cr-sqlite"]
B --> E["CP: consistente, pausa en partición"]
C --> F["Un escritor, recuperación barata"]
D --> G["AP: siempre escribible, fusiona después"]

El primer enfoque: consenso con Raft

rqlite y dqlite usan Raft, un protocolo de consenso donde un nodo líder recibe las escrituras, las replica a los demás nodos del clúster y solo confirma la operación cuando una mayoría la reconoce. Si el líder cae, el clúster elige uno nuevo entre los nodos con el log más actualizado.

Esto hace que ambos sean sistemas CP según el teorema CAP: priorizan la consistencia sobre la disponibilidad, así que una partición de red donde el clúster pierde la mayoría deja de aceptar escrituras hasta que la mayoría se restablece.

sequenceDiagram
participant C as Cliente
participant L as "Nodo líder"
participant F1 as "Nodo seguidor 1"
participant F2 as "Nodo seguidor 2"
C->>L: POST /db/execute
L->>F1: replica entrada de log
L->>F2: replica entrada de log
F1-->>L: ack
F2-->>L: ack
Note over L: mayoría confirmó, commit
L-->>C: 200 OK

El segundo enfoque: streaming del WAL

Litestream no usa consenso. Observa el write-ahead log (WAL) de SQLite, el archivo donde el motor anota cada cambio antes de aplicarlo a la base, y lo transmite de forma continua a un almacenamiento como S3. Si el nodo único se cae, la base se reconstruye desde ese WAL guardado: no hay clúster ni quórum, solo un escritor y una copia casi en tiempo real.

LiteFS, construido por el mismo autor de Litestream (Ben Johnson) tras ser contratado por Fly.io, replica a nivel de sistema de archivos y usa leases de Consul para decidir qué nodo es el primario en cada momento.

flowchart LR
A["SQLite local"] --> B["Escribe en el WAL"]
B --> C["Litestream observa el WAL"]
C --> D[("S3 u otro almacenamiento de objetos")]
E["Nodo cae"] --> F["Restaura desde el WAL guardado"]
D --> F
F --> A

El tercer enfoque: fusión sin líder

cr-sqlite agrega CRDTs a SQLite como extensión: varios nodos pueden escribir al mismo tiempo sin coordinarse y fusionar sus cambios después sin conflictos irreconciliables. Es el corner AP del diseño, siempre disponible para escribir, a costa de una consistencia que se resuelve después, no en el momento.

El mapa completo: de rqlite a las plataformas gestionadas

Antes de rqlite, Expensify ya replicaba SQLite internamente con un protocolo estilo Paxos y lo liberó como Bedrock en 2016. ActorDB, un sistema en Erlang, replicaba SQLite por actor casi al mismo tiempo que rqlite. Ninguno de los dos se adoptó masivamente fuera de su origen, pero confirman que la idea ya estaba en el aire en 2014.

Canonical construyó dqlite en 2017 para darle a LXD y luego a MicroK8s un almacén replicado embebido sin depender de etcd. dqlite nació en Go y se reescribió en C con su propia librería de Raft. La diferencia con rqlite es sobre todo de empaquetado: dqlite es una librería que se embebe dentro de otro programa, rqlite es un servidor que corre al lado de cualquier aplicación.

Ben Johnson publicó Litestream a comienzos de 2021. Su argumento, documentado en la retrospectiva de O’Toole, fue que la mayoría de las aplicaciones no necesitan un clúster: corren en una sola máquina y solo necesitan una forma de recuperarse si esa máquina muere. Fly.io lo contrató en 2022 y lanzó LiteFS, la primera versión de SQLite replicado como función de plataforma en lugar de algo que el desarrollador despliega por su cuenta.

libSQL tomó un camino distinto: en vez de agregar una capa externa, bifurcó el propio motor de SQLite para modificar su núcleo, algo que el proyecto SQLite, cerrado a contribuciones externas, no permite. ChiselStrike construyó sobre ese fork un servicio con réplicas en el edge y se convirtió en Turso, que levantó capital de riesgo con esa propuesta. En 2026, Supabase adquirió Turso. SQLite Cloud, en paralelo, ofrece SQLite alojado con replicación Raft, la opción más parecida al diseño original de rqlite pero envuelta como servicio administrado.

Cloudflare siguió otro camino: anunció D1 en 2022 como SQLite sin servidor dentro de su red de borde y más tarde agregó almacenamiento SQLite a Durable Objects. En ese punto el clúster de SQLite dejó de ser algo que alguien corre y pasó a ser un producto que alguien compra.

rqlite fue publicado en 2014, el primer proyecto que combinó SQLite con Raft. Foto de Chris Ried en Unsplash

Comparativa: rqlite, dqlite, LiteFS, Litestream y Turso/libSQL

La elección depende del tipo de disponibilidad que necesita la aplicación: tolerar la caída de un nodo con recuperación casi instantánea, o apenas necesitar una copia de seguridad barata. La tabla resume cuándo conviene cada opción.

Opción Cuándo usarla Ventaja Limitación
rqlite Clúster chico que necesita seguir escribiendo si un nodo cae, vía HTTP Servidor standalone, API HTTP simple, sin dependencias externas Escrituras solo por el líder, latencia de red en cada confirmación
dqlite Embeber un almacén replicado dentro de otro programa (como LXD) Librería en C, se integra sin levantar un proceso aparte Pensado para integrarse en un producto, no para usarse suelto
Litestream Un solo servidor que solo necesita recuperación ante desastre Cero coordinación, corre casi gratis junto a la app No da alta disponibilidad: restaurar desde S3 toma tiempo
LiteFS Apps en Fly.io con un escritor primario y réplicas de lectura Replicación a nivel de archivo, transparente para SQLite Atada al ecosistema de Fly.io y a Consul para los leases
Turso / libSQL Lecturas de baja latencia desde el edge, con escritura centralizada Réplicas globales gestionadas, fork con funciones propias Depende de un proveedor y de un fork que diverge del SQLite oficial

Cómo empezar con rqlite

De esta lista, rqlite es la más simple de probar en una laptop porque es un solo binario sin dependencias. Esta guía usa Linux; en macOS alcanza con brew install rqlite, y en Windows lo más simple es correrlo dentro de WSL con los mismos pasos.

Descargá el binario desde la página de releases en GitHub (ajustá versión y arquitectura) y extraelo:

curl -LO https://github.com/rqlite/rqlite/releases/latest/download/rqlite-linux-amd64.tar.gz
tar xzf rqlite-linux-amd64.tar.gz
cd rqlite-*/

Arrancá un primer nodo. El flag -node-id identifica al nodo dentro del clúster y el último argumento es el directorio donde guarda sus datos:

./rqlited -node-id 1 ~/node1

Con el nodo corriendo, abrí otra terminal y creá una tabla y una fila con la API HTTP sobre el puerto 4001:

curl -XPOST localhost:4001/db/execute -H "Content-Type: application/json" -d '[
  "CREATE TABLE registros (id INTEGER PRIMARY KEY, nodo TEXT)",
  "INSERT INTO registros (nodo) VALUES (\"node1\")"
]'

La respuesta esperada es un JSON con el resultado de cada statement y cuánto tardó en confirmarse:

{"results":[{},{"last_insert_id":1,"rows_affected":1}],"time":0.00234}

Para leer el dato, usá el endpoint de consulta:

curl -G 'localhost:4001/db/query' --data-urlencode 'q=SELECT * FROM registros'

Que devuelve algo como:

{"results":[{"columns":["id","nodo"],"types":["integer","text"],"values":[[1,"node1"]]}],"time":0.0004}

Para confirmar que el nodo participa de un clúster de Raft (aunque sea de uno solo) y quién es el líder, consultá el endpoint de estado:

curl localhost:4001/status | python3 -m json.tool | grep -A2 '"raft"'

Debería mostrar "state": "Leader" en un nodo único. Si sumás un segundo nodo con -join http://localhost:4001 y volvés a consultar su status, ese campo pasa a "state": "Follower", confirmando que la replicación está activa.

Casos de uso reales

  • Clúster de borde chico: rqlite o dqlite para un servicio que debe seguir atendiendo lecturas y escrituras si cae una de tres máquinas, sin levantar Postgres en alta disponibilidad.
  • Apps de un solo servidor con backup barato: Litestream corriendo junto a una app Rails o Django que vive en una sola VM, para no perder datos si la VM se destruye.
  • Multi-región con un escritor primario: LiteFS para apps en Fly.io que leen desde la región más cercana al usuario pero escriben siempre contra el primario.
  • Producto embebido en otro software: dqlite dentro de LXD o MicroK8s, donde el desarrollador final nunca interactúa directamente con el almacén replicado.
  • Lecturas globales de baja latencia: Turso o SQLite Cloud cuando el equipo prefiere pagar por un servicio gestionado en vez de operar el clúster.
Fly.io lanzó LiteFS en 2022, ocho años después de la primera propuesta de rqlite. Foto de Mohammad Rahmani en Unsplash

Errores comunes y buenas prácticas

El error más frecuente es tratar a rqlite o dqlite como reemplazo transparente del archivo SQLite local. No lo es: las escrituras pasan por una API HTTP (rqlite) o por la librería embebida (dqlite), no por el driver sqlite3 de siempre. Migrar una app existente implica cambiar la capa de acceso a datos, no solo el archivo de configuración.

Otro error es ignorar los niveles de consistencia de lectura. rqlite permite leer con nivel none (de cualquier nodo, puede estar desactualizado), weak (confirma que el nodo sigue siendo líder) o strong (pasa por el log de Raft, más lento pero garantiza la última escritura confirmada). Usar none en un reporte financiero porque es la opción por defecto es el tipo de bug que no aparece hasta que un follower se atrasa.

⚠️ Ojo: un clúster de rqlite o dqlite con número par de nodos no mejora la tolerancia a fallas frente a tener uno menos: Raft necesita mayoría, y 4 nodos tolera la misma caída que 3, con más latencia de red por cada escritura.

Con Litestream, el error típico es asumir que reemplaza a un clúster: solo da recuperación ante desastre de un solo nodo, no alta disponibilidad continua. Si la VM se cae, hay un hueco real (el tiempo de restaurar desde S3 y levantar el proceso) antes de volver a servir tráfico.

Con libSQL y Turso, conviene revisar qué extensiones del fork usa la app antes de asumir compatibilidad total con SQLite estándar: al ser un fork, algunas funciones no existen en el SQLite original y viceversa.

Profundizando: por qué el teorema CAP importa acá

Raft garantiza que, mientras una mayoría de nodos esté disponible y se comunique, el clúster tiene exactamente un líder y todas las escrituras confirmadas sobreviven incluso si ese líder cae después. Esa garantía tiene un costo: si la red se particiona y ningún lado tiene mayoría, ningún lado acepta escrituras hasta que la partición se resuelve. rqlite y dqlite eligen ese costo de forma explícita, la decisión de diseño que O’Toole señala como la que no cambió en doce años.

El corner de streaming (Litestream, LiteFS) no enfrenta ese dilema porque no hay múltiples escritores compitiendo por confirmar al mismo tiempo: hay un escritor y una cola de cambios que se replica hacia afuera. La contrapartida es que la recuperación no es instantánea, depende de cuánto WAL hay que reproducir.

El corner de fusión (cr-sqlite) resuelve el problema de otra forma: en vez de impedir escrituras concurrentes, las permite y resuelve los conflictos con una regla determinista según el CRDT elegido. Es el diseño correcto para apps local-first, donde cada dispositivo escribe sin conexión y sincroniza después, pero sería un mal ajuste para un caso que necesita una única verdad inmediata, como un balance bancario.

📖 Resumen en Telegram: Ver resumen

Tu próximo paso: levantá un clúster de rqlite de tres nodos en tu laptop, matá el proceso del líder a mitad de una escritura y confirmá con curl localhost:4003/status que otro nodo asumió el rol antes de los diez segundos default de elección.

📬 Recibí lo nuevo en tu email

Te avisamos de artículos grandes (1-2 por mes).

Preguntas frecuentes

¿rqlite reemplaza a Postgres o MySQL?

No para cargas grandes. rqlite sirve para volúmenes de datos chicos donde se necesita alta disponibilidad simple, no el conjunto completo de funciones (índices avanzados, extensiones, tamaños grandes) de una base relacional completa.

¿dqlite se puede usar fuera de LXD o MicroK8s?

Sí, es una librería en C de uso general, pero su diseño y documentación están pensados para embeberse dentro de otro programa, no para correr como servicio independiente del modo en que corre rqlite.

¿Litestream da alta disponibilidad?

No. Litestream da recuperación ante desastre de un solo nodo: si ese nodo se cae, hay que restaurar desde el almacenamiento externo antes de volver a servir tráfico, con el tiempo que eso tome.

¿LiteFS depende de Fly.io para funcionar?

LiteFS es open source y se puede correr fuera de Fly.io, pero su integración de leases con Consul y su documentación asumen ese entorno; fuera de él hay que resolver esa coordinación por cuenta propia.

¿Turso y libSQL son compatibles al 100% con SQLite?

libSQL es un fork de SQLite, así que agrega y modifica funciones que el proyecto SQLite original no acepta como contribución externa. La compatibilidad es alta pero no total: conviene revisar qué extensiones usa la app antes de migrar.

¿Cuándo conviene cr-sqlite en lugar de rqlite?

Cuando la app necesita que varios dispositivos escriban sin conexión y sincronicen después (local-first), no cuando necesita una única fuente de verdad inmediata como sí ofrece rqlite con Raft.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

Imagen destacada: Foto de imgix en Unsplash

¿Te sirvió? ¿Te dio otro error? Contalo abajo: las preguntas se responden y le sirven al siguiente que llegue.

Dejar un comentario

Andrés Morales

Desarrollador e investigador en inteligencia artificial. Escribe sobre modelos de lenguaje, frameworks, herramientas para devs y lanzamientos open source. Cubre papers de ML, ecosistema de startups tech y tendencias de programación.

0 Comentarios

Deja un comentario

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Podés incluir código entre <code>…</code> o, para varias líneas, <pre><code>…</code></pre>.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.