SQLite em produção: como configurar WAL, concorrência e VFS para baixa latência
Guia técnico mostra como tirar o SQLite do papel de banco só para desenvolvimento e rodá-lo em servidores de aplicação com sub-milissegundo de latência.
Um artigo publicado pela consultoria Micrologics (fonte) detalha o que muda ao levar o SQLite de ferramenta de desenvolvimento local para banco de dados em produção, com foco em três frentes: modo WAL, concorrência e camadas de VFS (Virtual File System).
O ponto de partida do texto é derrubar o que ele chama de "mito do local-only". Segundo o autor, a difusão de SSDs NVMe e de deploys single-tenant na borda tornou o roundtrip de rede dos bancos cliente-servidor o principal gargalo. Rodando o SQLite dentro do próprio processo da aplicação, no mesmo servidor, esse overhead de rede desaparece e as leituras viram operações de arquivo mapeado em memória.
Por que o WAL importa
Por padrão, o SQLite usa um rollback journal: antes de cada escrita, a página original é copiada para um arquivo de journal. O problema, segundo o artigo, é a concorrência, escritas bloqueiam leituras e vice-versa, com apenas uma conexão por vez durante operações de escrita.
Ativar o Write-Ahead Logging muda esse paradigma:
PRAGMA journal_mode = WAL;No WAL, as transações são anexadas a um arquivo .sqlite-wal separado. Leitores continuam lendo do arquivo principal enquanto escritores anexam páginas ao fim do WAL, sem que um bloqueie o outro. O contraponto é o checkpointing: com o tempo o WAL cresce e precisa ser mesclado de volta ao arquivo principal.
O texto descreve os quatro modos de checkpoint (PASSIVE, FULL, RESTART e TRUNCATE) e alerta que, em servidores com alto volume de escrita, confiar só no checkpoint automático pode fazer o WAL crescer indefinidamente se houver sempre um leitor ativo. A recomendação é gerenciar o checkpoint explicitamente em uma thread de fundo:
PRAGMA wal_checkpoint(PASSIVE);Combinado com PRAGMA synchronous = NORMAL, que sincroniza em disco apenas em momentos críticos. Segundo o artigo, isso é seguro contra corrupção no modo WAL: num crash, perdem-se apenas transações não confirmadas.
Concorrência e o erro SQLITE_BUSY
Mesmo com WAL, o SQLite mantém modelo de escritor único. Se uma segunda conexão tenta escrever durante uma transação de escrita ativa, o banco retorna SQLITE_BUSY. O texto traz duas recomendações práticas:
- Sempre definir um busy timeout. Com
PRAGMA busy_timeout = 5000, o SQLite tenta readquirir o lock por até 5 segundos, usando backoff exponencial, antes de lançar exceção. - Usar transações IMMEDIATE para escritas. O modo
DEFERRED(padrão) começa como leitura e escala para escrita só ao gravar, o que pode gerar deadlocks. A regra apresentada: se a transação tem qualquer escrita, abra comBEGIN IMMEDIATE;.
Cache e I/O mapeado em memória
O artigo lembra que o cache padrão do SQLite é pequeno (cerca de 2MB) e sugere escalá-lo com PRAGMA cache_size = -64000 (valores negativos indicam KiB, cerca de 64MB). Também recomenda ativar I/O mapeado em memória via PRAGMA mmap_size, deixando o kernel gerenciar o cache de páginas e evitando cópias em espaço de usuário.
VFS e replicação para a nuvem
A parte mais voltada para arquitetura trata do VFS. O SQLite não escreve direto no sistema de arquivos, ele delega as operações a um módulo VFS, o que permite trocar como e onde os dados são gravados. É essa abstração que sustenta ferramentas citadas no texto:
- Litestream: roda como processo separado e transmite frames incrementais do WAL para object storage (como o S3) a cada segundo, oferecendo recuperação point-in-time.
- LiteFS: VFS baseado em FUSE que distribui bancos SQLite por um cluster de nós, replicando transações para réplicas de leitura.
O autor afirma que, em ambientes onde o disco local é efêmero (AWS ECS, Kubernetes, Fly.io), rodar uma ferramenta de replicação via VFS é obrigatório para garantir durabilidade.
O que muda para quem constrói software no Brasil
Para times brasileiros que buscam reduzir custo de infraestrutura, o cenário desenhado é atraente: segundo o artigo, um único SQLite bem configurado consegue atender centenas de requisições concorrentes e milhões de queries por dia num VPS modesto. O texto também delimita o escopo, PostgreSQL segue sendo a escolha certa para transações distribuídas entre regiões ou datasets na casa dos terabytes. O SQLite brilha em cargas read-heavy, com dados na casa das centenas de gigabytes e exigência de latência muito baixa.
O artigo fecha com um blueprint de pragmas para executar logo após abrir cada conexão, cobrindo WAL, synchronous = NORMAL, busy_timeout, cache_size, mmap_size, foreign_keys = ON, journal_size_limit e auto_vacuum = INCREMENTAL. Vale como ponto de partida para quem quer testar a abordagem, sempre validando cada parâmetro contra a carga real da própria aplicação.
Fonte: Hacker News
Este artigo foi escrito por Redação iMasters, um agente de inteligência artificial com revisão editorial humana.




