Shopping cart

Subtotal $0.00

View cartCheckout

Building better devs

TnewsTnews
Banco de Dados

SQLite Distribuído Existe Há 12 Anos (e Você Nunca Usou)

Email : 16

Imagina o cenário: seu app usa SQLite, funciona perfeitamente, é rápido, é simples, o arquivo fica ali do lado. Até que um dia o servidor morre. E junto com ele, seus dados. Parece dramático? É porque é. E esse problema foi resolvido em 2014. Só que quase ninguém ficou sabendo.

O SQLite distribuído não é conceito novo. O rqlite, o primeiro projeto open source que encapsulou o SQLite num cluster tolerante a falhas, completou 12 anos de existência. Doze anos. Na mesma época em que a gente ainda discutia se Docker era coisa séria, um desenvolvedor chamado Philip O’Toole já estava replicando SQLite entre múltiplos nós com consenso Raft.

E desde então, uma constelação inteira de projetos surgiu ao redor dessa mesma ideia: dqlite, Litestream, cr-sqlite, libSQL, Turso, Cloudflare D1. Cada um com uma abordagem diferente, cada um resolvendo um pedaço diferente do problema. Mas todos partindo da mesma premissa: o SQLite é bom demais pra ficar preso num único servidor.

Neste texto, eu vou te mostrar como esse ecossistema evoluiu, o que cada ferramenta faz de verdade, quando usar cada uma, e por que você provavelmente deveria estar prestando atenção nisso agora.

O que é SQLite distribuído, afinal?

Antes de qualquer coisa, vamos alinhar conceitos. O SQLite “normal” é um banco de dados embutido. Ele roda dentro do seu processo, grava num único arquivo, e não tem servidor. Isso é uma vantagem absurda pra simplicidade, mas cria um problema óbvio: se aquele arquivo se corrompe, se o disco morre, ou se o servidor desliga, acabou.

SQLite distribuído é qualquer solução que replica os dados do SQLite entre múltiplos nós, de forma que a perda de um (ou mais) nós não significa a perda dos dados. Parece simples? A engenharia por trás é qualquer coisa menos simples.

Existem basicamente três abordagens pra resolver isso:

Abordagem Exemplo Consistência Múltiplos writers? Complexidade
Consenso (Raft) rqlite, dqlite Forte (CP) Não, só o líder Média
Streaming do WAL Litestream Eventual Não, um writer Baixa
CRDTs cr-sqlite Eventual (AP) Sim Alta

Cada uma tem tradeoffs reais. Não existe bala de prata aqui.

rqlite: o pioneiro que ninguém conhece

Philip O’Toole publicou o rqlite em 2014 com uma ideia que cabe em uma frase: “pegar o SQLite, colocar um log Raft na frente, e replicar cada escrita pra um cluster, de forma que perder um nó não significasse perder os dados.”

A arquitetura é elegante na simplicidade. Cada nó do cluster tem sua própria instância do SQLite. Todas as escritas passam pelo nó líder, que registra o comando no log Raft. Quando a maioria dos nós confirma que recebeu o comando, ele é aplicado. Se o líder morre, o Raft elege um novo líder automaticamente.


# Subindo um cluster rqlite com 3 nós
rqlited -node-id 1 -http-addr localhost:4001 -raft-addr localhost:4002 ~/node.1

rqlited -node-id 2 -http-addr localhost:4003 -raft-addr localhost:4004 \
  -join http://localhost:4001 ~/node.2

rqlited -node-id 3 -http-addr localhost:4005 -raft-addr localhost:4006 \
  -join http://localhost:4001 ~/node.3

Depois disso, qualquer escrita via HTTP é replicada automaticamente:


# Inserindo dados via API REST
curl -XPOST 'localhost:4001/db/execute?pretty&timings' \
  -H "Content-Type: application/json" \
  -d '[
    "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)",
    "INSERT INTO users(name, email) VALUES(\"Maria\", \"maria@dev.com\")"
  ]'


{
  "results": [
    { "last_insert_id": 0, "rows_affected": 0, "time": 0.000281 },
    { "last_insert_id": 1, "rows_affected": 1, "time": 0.000055 }
  ],
  "time": 0.012345
}

Uma coisa que eu acho particularmente interessante no rqlite é a API HTTP nativa. Não precisa de driver, não precisa de SDK. Um curl resolve. Isso é muito útil em cenários de automação, scripts, e ambientes onde instalar dependências é um problema.

Níveis de consistência nas leituras

O rqlite oferece três níveis de consistência pra leituras, e entender isso é crucial:


# Leitura "none" (mais rápida, pode ler dados stale)
curl 'localhost:4001/db/query?level=none&pretty' \
  -d '["SELECT * FROM users"]'

# Leitura "weak" (confirma que o líder ainda é líder)
curl 'localhost:4001/db/query?level=weak&pretty' \
  -d '["SELECT * FROM users"]'

# Leitura "strong" (garante linearizabilidade via Raft)
curl 'localhost:4001/db/query?level=strong&pretty' \
  -d '["SELECT * FROM users"]'

Nível Latência Garantia Quando usar
none ~1ms Pode ler dados antigos Dashboards, métricas
weak ~2ms Líder provavelmente atual Maioria dos casos
strong ~5-10ms Linearizável Transações financeiras

Depois de mais de 10 anos em produção, o rqlite reportou menos de 10 panics. Dez. Em uma década. Isso diz muito sobre a estabilidade da implementação.

dqlite: a versão embutida da Canonical

Se o rqlite é um servidor que você roda, o dqlite é uma biblioteca que você embute no seu aplicativo. Criado pela Canonical em 2016, ele usa a mesma ideia (SQLite + Raft), mas empacotado como uma lib C que você integra diretamente no código.

O caso de uso mais famoso? O LXD, sistema de containers da Canonical. E o MicroK8s, distribuição leve do Kubernetes. Ambos usam dqlite internamente pra armazenar estado de forma distribuída sem depender de um banco externo.


// Exemplo simplificado de uso do dqlite em C
#include <dqlite.h>

dqlite_node *node;
dqlite_node_create(1, "127.0.0.1:9001", "/var/lib/dqlite", &node);
dqlite_node_start(node);

A diferença prática é: com rqlite, você faz HTTP requests pra um serviço separado. Com dqlite, o banco está dentro do seu processo. Menos latência de rede, mas mais complexidade de integração.

Litestream: replicação sem cluster

Em 2021, Ben Johnson (o mesmo criador do BoltDB) lançou o Litestream com uma filosofia completamente diferente: em vez de montar um cluster Raft, por que não simplesmente copiar o WAL (Write-Ahead Log) do SQLite pra um storage externo?


# Replicando SQLite para S3 em tempo real
litestream replicate /path/to/db.sqlite s3://meu-bucket/backups/

# Restaurando de um backup
litestream restore -o /path/to/restored.db s3://meu-bucket/backups/

É disaster recovery, não alta disponibilidade. O writer continua sendo único. Se ele morre, você precisa subir outro e restaurar do backup. Mas a simplicidade é imbatível: nenhum cluster pra gerenciar, nenhum Raft pra entender, nenhuma eleição de líder.

Pra aplicações que rodam num único servidor e só precisam garantir que os dados não se perdem, o Litestream resolve o problema com uma fração da complexidade.

cr-sqlite: CRDTs e o futuro local-first

Aqui as coisas ficam realmente interessantes. Em 2022, Matt Wonlaw criou o cr-sqlite, uma extensão que adiciona CRDTs (Conflict-free Replicated Data Types) ao SQLite. Traduzindo: múltiplos writers podem modificar o mesmo banco de dados simultaneamente, e os conflitos são resolvidos automaticamente na hora do merge.

Isso é o canto AP (Available + Partition tolerant) do teorema CAP. Enquanto o rqlite sacrifica disponibilidade pra manter consistência forte, o cr-sqlite sacrifica consistência forte pra manter disponibilidade total.


-- Transformando uma tabela normal em CRDT-aware
SELECT crsql_as_crr('users');

-- Depois disso, mudanças em qualquer réplica podem ser mergeadas
-- sem conflito, usando o clock lógico interno
SELECT * FROM crsql_changes() WHERE db_version > ?;

O caso de uso perfeito? Apps local-first. Pense em editores colaborativos, apps mobile que funcionam offline, ferramentas de notas distribuídas. Cada dispositivo tem sua cópia do SQLite, faz mudanças livremente, e quando reconecta, o merge acontece sem intervenção humana.

libSQL e Turso: quando Big Tech entra no jogo

Em 2022, a ChiselStrike fez algo que muita gente achava impossível: forkaram o SQLite. O motivo? O SQLite não aceita contribuições externas. O código é domínio público, mas o desenvolvimento é fechado num grupo seleto de committers.

O fork se chamou libSQL, e sobre ele nasceu a Turso: uma plataforma de SQLite distribuído na edge. A proposta é ter um banco primário (pra escritas) e réplicas de leitura espalhadas por mais de 200 pontos de presença globais, com latência abaixo de 100ms pras leituras.


# Criando um banco no Turso
turso db create meu-app

# Usando via CLI
turso db shell meu-app
> CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price REAL);
> INSERT INTO products VALUES (1, 'Widget', 29.90);


// SDK do Turso/libSQL para aplicações edge
import { createClient } from '@libsql/client';

const db = createClient({
  url: 'libsql://meu-app-usuario.turso.io',
  authToken: 'token-aqui'
});

const result = await db.execute('SELECT * FROM products WHERE price < ?', [50]);

Em 2026, a Supabase adquiriu a Turso. Isso não é detalhe pequeno. A Supabase, que construiu sua reputação como “Firebase open source” em cima do PostgreSQL, agora tem um SQLite distribuído no portfólio. O sinal é claro: SQLite na edge virou mainstream.

Cloudflare D1: SQLite serverless de verdade

A Cloudflare entrou no jogo com o D1, um banco SQLite que roda nativamente nos Workers. Sem servidor pra gerenciar, sem conexão TCP, sem pool de conexões. O banco está lá, na mesma edge que seu código, respondendo em microsegundos.


// Worker do Cloudflare com D1
export default {
  async fetch(request, env) {
    const { results } = await env.DB.prepare(
      "SELECT * FROM users WHERE active = ?"
    ).bind(1).all();

    return Response.json(results);
  }
};

Se você já usa Cloudflare Workers, o D1 é a escolha natural. A integração é nativa, o billing é por operação, e você não precisa pensar em infraestrutura de banco.

Comparativo: qual usar e quando

Essa é a pergunta que todo mundo faz. E a resposta depende do seu cenário:

Solução Tipo Melhor pra Evitar quando
rqlite Servidor, self-hosted Alta disponibilidade simples, IoT, edge Precisa de milhões de writes/s
dqlite Lib embutida Aplicações Go/C que precisam de DB distribuído Não usa Go/C
Litestream Backup contínuo Apps com único writer que precisam de DR Precisa de failover automático
cr-sqlite CRDT extension Apps local-first, offline-first Precisa de consistência forte
Turso/libSQL Plataforma edge Leituras globais de baixa latência Budget apertado, writes pesados
Cloudflare D1 Serverless Apps em Cloudflare Workers Não usa Cloudflare

Por que o SQLite está dominando?

Tem uma tendência clara acontecendo. O SQLite, que por décadas foi “aquele banco de testes” ou “aquele banco do celular”, está virando primeira opção pra produção. E os números explicam por quê.

Num benchmark recente, o SQLite em modo WAL mostrou latência de leitura 4.9x menor que o MySQL pra queries simples. Pra aplicações read-heavy (e a maioria é), isso é uma diferença absurda. (Sobre bancos analíticos, veja também nosso artigo sobre o DuckDB 2.0.) Sem servidor separado, sem conexão TCP, sem overhead de protocolo.

O DHH (sim, o criador do Rails) migrou apps em produção pro SQLite. O Laravel tem suporte nativo ao SQLite como banco principal desde o Laravel 11. O Bun (runtime JavaScript) tem suporte a SQLite built-in. O Turso integra com todos os frameworks populares.

A pergunta não é mais “por que usar SQLite em produção?”. É “por que NÃO usar?”.

Quando NÃO usar SQLite distribuído

Vou ser direto. SQLite distribuído não é pra tudo.

Se você precisa de múltiplos writers com consistência forte e baixa latência, PostgreSQL com streaming replication ainda é a melhor opção. Se você precisa de sharding horizontal com petabytes de dados, CockroachDB ou Vitess fazem mais sentido.

O rqlite, por exemplo, é explícito sobre isso: o objetivo é alta disponibilidade, não performance. As escritas são mais lentas que um SQLite standalone, porque cada write precisa do round-trip Raft. Se seu gargalo é write throughput, replicar SQLite não vai resolver.

Outro ponto: o SQLite tem um limite prático de tamanho. Bancos acima de 1TB começam a ficar impraticáveis. Se você está nessa escala, precisa de outra solução.

Como começar com rqlite hoje

Se bateu a curiosidade e você quer testar, é ridiculamente fácil:


# Instalar o rqlite (Linux)
curl -L https://github.com/rqlite/rqlite/releases/download/v8.36.8/rqlite-v8.36.8-linux-amd64.tar.gz \
  -o rqlite.tar.gz
tar xvfz rqlite.tar.gz
cd rqlite-v8.36.8-linux-amd64

# Subir um nó standalone pra testar
./rqlited ~/node.1

# Em outro terminal, usar o CLI
./rqlite
> CREATE TABLE teste (id INTEGER PRIMARY KEY, msg TEXT);
> INSERT INTO teste(msg) VALUES("funciona!");
> SELECT * FROM teste;

Cinco minutos pra ter um banco distribuído rodando. Sem Docker, sem Kubernetes, sem YAML. Só um binário.

Pra produção, você vai querer pelo menos 3 nós (pra ter quórum) e configurar TLS:


# Nó 1 (líder inicial)
./rqlited -node-id 1 \
  -http-addr 0.0.0.0:4001 \
  -raft-addr 0.0.0.0:4002 \
  -http-cert server.crt \
  -http-key server.key \
  ~/node.1

# Nó 2 (junta ao cluster)
./rqlited -node-id 2 \
  -http-addr 0.0.0.0:4003 \
  -raft-addr 0.0.0.0:4004 \
  -join https://node1:4001 \
  ~/node.2

12 anos depois, o que aprendemos?

A trajetória do SQLite distribuído prova algo que muitos engenheiros esquecem: a melhor infraestrutura é a que você entende completamente. O rqlite tem um codebase que um desenvolvedor solo consegue ler em um fim de semana. Compara isso com o CockroachDB ou o TiDB.

Philip O’Toole mantém o rqlite como projeto pessoal há 12 anos. Sem VC money, sem empresa por trás, sem marketing. E o projeto continua sendo usado em produção por empresas que preferem rodar seus próprios bancos a depender de SaaS.

Enquanto isso, o ecossistema ao redor explodiu. Turso levantou dezenas de milhões em venture capital, foi adquirida pela Supabase, e o conceito de “SQLite na edge” virou uma categoria de produto. O Cloudflare D1 processou bilhões de queries. O Litestream é usado em milhares de deploys.

E tudo começou com um cara que pensou: “e se eu colocasse um Raft na frente do SQLite?”. Doze anos e a ideia original continua intacta. Às vezes, a solução mais simples é a que sobrevive.

“rqlite é um banco de dados relacional tolerante a falhas que você pode rodar por conta própria, entender completamente, e não pagar ninguém pra usar.” (Philip O’Toole)

Se você está construindo algo que precisa de banco de dados relacional com alta disponibilidade e não quer (ou não pode) rodar PostgreSQL, dá uma chance pro SQLite distribuído. Depois de 12 anos, acho que ele já provou que funciona.

Fonte de inspiração: Twelve years of distributed SQLite

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts