El problema fundamental que aborda la 'SQLite distribuida' es la necesidad de una base de datos relacional ligera, embebible y con garantías de alta disponibilidad o tolerancia a fallos, más allá de la capacidad de una única instancia de SQLite. Tradicionalmente, las bases de datos distribuidas han sido sistemas complejos y pesados, mientras que SQLite ofrece simplicidad y eficiencia local. La tesis central es que la combinación de SQLite con protocolos de consenso o mecanismos de replicación externos permite extender sus beneficios a entornos distribuidos, resolviendo el dilema de tener almacenamiento relacional robusto sin la sobrecarga de un RDBMS distribuido completo.
Esta necesidad se hizo evidente a partir de 2014 con el auge de arquitecturas de microservicios y sistemas distribuidos que requerían almacenamiento de estado ligero y replicado. La simplicidad de SQLite lo hacía atractivo, pero su naturaleza de archivo único limitaba su uso en escenarios de alta disponibilidad. La aplicación de algoritmos de consenso como Raft o estrategias de replicación basadas en el Write-Ahead Log (WAL) de SQLite surge como una solución pragmática para dotar a SQLite de resiliencia y disponibilidad en un clúster.
Arquitectura del Sistema
La arquitectura de rqlite, el sistema pionero, se basa en un nodo SQLite estándar acoplado a un log de consenso Raft. Cada escritura en la base de datos se convierte en una entrada en el log de Raft, que luego es replicada y acordada por una mayoría de nodos en el clúster. Una vez que una entrada es confirmada por Raft, se aplica al motor SQLite local. Este diseño asegura que todas las escrituras pasen por el nodo líder de Raft, garantizando la consistencia fuerte (CP en el modelo CAP).
Otros enfoques incluyen dqlite, que es una biblioteca embebible en C con su propia implementación de Raft, y LiteFS, que replica SQLite a nivel del sistema de archivos utilizando leases de Consul. Litestream, por otro lado, adopta una estrategia diferente: no utiliza consenso, sino que monitorea el WAL de SQLite y lo transmite a un almacenamiento de objetos como S3 para recuperación ante desastres, priorizando la disponibilidad y la recuperación sobre la consistencia fuerte en tiempo real. Finalmente, proyectos como cr-sqlite exploran el espacio AP (Availability and Partition tolerance) al integrar CRDTs (Conflict-free Replicated Data Types) en SQLite, permitiendo múltiples escritores y la fusión de divergencias sin un líder central.
Flujo de Escritura en rqlite (CP System)
- 1 Cliente Envía solicitud de escritura (SQL INSERT/UPDATE) al líder de rqlite.
- 2 Líder rqlite Convierte la escritura en una entrada de log de Raft.
- 3 Raft (Líder) Propone la entrada de log a los seguidores.
- 4 Raft (Seguidores) Confirman la recepción y persistencia de la entrada de log.
- 5 Raft (Líder) Recibe confirmación de la mayoría, marca la entrada como 'committed'.
- 6 Líder rqlite Aplica la entrada de log al motor SQLite local.
- 7 Seguidores rqlite Aplican la entrada de log al motor SQLite local una vez 'committed'.
- 8 Líder rqlite Responde al cliente con confirmación de escritura.
Flujo de Replicación de Litestream (WAL Streaming)
- 1 Aplicación Realiza escrituras en la instancia local de SQLite.
- 2 SQLite Escribe cambios en el Write-Ahead Log (WAL).
- 3 Litestream Monitorea el WAL de SQLite en busca de nuevos cambios.
- 4 Litestream Empaqueta y comprime los segmentos del WAL.
- 5 Litestream Transmite los segmentos del WAL a almacenamiento de objetos (ej. S3).
- 6 Almacenamiento de Objetos Persiste los segmentos del WAL para recuperación.
| Capa | Tecnología | Justificación |
|---|---|---|
| storage | SQLite | Motor de base de datos relacional embebido y ligero, utilizado como capa de persistencia local en cada nodo. |
| orchestration | Raft | Protocolo de consenso distribuido para replicar el log de operaciones de SQLite y asegurar la consistencia y tolerancia a fallos en el clúster. vs Paxos Implementaciones como goraft y Hashicorp Raft. |
| storage | Write-Ahead Log (WAL) | Mecanismo de persistencia de SQLite que permite la replicación asíncrona de cambios a través de streaming, como en Litestream. |
| storage | CRDTs | Tipos de datos replicados sin conflictos, utilizados en cr-sqlite para permitir escrituras concurrentes y fusión automática sin un líder central, priorizando disponibilidad. |
| storage | S3 | Almacenamiento de objetos duradero y de bajo costo, utilizado por Litestream para persistir el WAL de SQLite para recuperación ante desastres. |
Trade-offs
Ganancias
- ▲ Tolerancia a fallos y alta disponibilidad para SQLite
- ▲ Consistencia fuerte (CP) en rqlite/dqlite
- ▲ Recuperación ante desastres de bajo costo en Litestream
- ▲ Disponibilidad y fusión automática en cr-sqlite (AP)
Costes
- △ Complejidad operativa (CP systems)
- △ Latencia de escritura (CP systems)
- ▲ Consistencia eventual (AP systems)
Fundamentos Teóricos
El concepto de replicación de estado a través de un log de consenso está profundamente arraigado en la investigación de sistemas distribuidos. El algoritmo Raft, utilizado por rqlite y dqlite, es una implementación simplificada y más comprensible del consenso distribuido, popularizado por el paper "In Search of an Understandable Consensus Algorithm" de Diego Ongaro y John Ousterhout (2014). Este trabajo buscaba hacer el consenso más accesible que Paxos, el algoritmo seminal de Leslie Lamport (1990), que aunque teóricamente sólido, es notoriamente difícil de implementar correctamente.
La evolución hacia soluciones como cr-sqlite, que incorporan CRDTs, se conecta con la investigación en consistencia eventual y replicación multi-maestro. Los CRDTs, formalizados por Marc Shapiro et al. (2011), ofrecen un marco matemático para construir tipos de datos que pueden ser replicados y actualizados concurrentemente en múltiples nodos, garantizando la convergencia sin necesidad de un coordinador central ni de un protocolo de consenso pesado, lo que es ideal para aplicaciones 'local-first' y entornos con alta tolerancia a la latencia y particiones de red.