Come eseguire il backup di SQLite su S3 in tempo reale senza perdere dati
Ti piace SQLite per la sua semplicità? Avvia un nuovo VPS, lancia un piccolo servizio, posiziona un file di database accanto ad esso, e tutto funziona con risposte istantanee. Nessun container Docker extra con PostgreSQL, nessuna gestione di utenti o configurazione dei diritti di accesso. Bellissimo.
I problemi iniziano quando il server si blocca improvvisamente o il provider "accidentalmente" elimina il tuo disco. Se facevi un backup una volta al giorno tramite cron, hai perso un giorno intero di utenti e ordini. Se hai provato a copiare il file del database con un semplice cp mentre erano in corso scritture, ti sei ritrovato con un file corrotto che SQLite non riesce nemmeno ad aprire.
Il creatore del noto database key-value BoltDB, Ben Johnson, ha affrontato questo identico problema e ha costruito Litestream. È un piccolo strumento Go che risolve il problema del backup di SQLite una volta per tutte.
Cosa fa Litestream e perché ti serve
Litestream funziona come processo in background sullo stesso server della tua applicazione. Il suo compito è trasmettere continuamente le modifiche dal tuo database SQLite locale a uno storage remoto. Può essere un cloud compatibile con S3, Yandex Object Storage, MinIO, o semplicemente una cartella su un altro disco montato.
Il risultato è un sistema di disaster recovery pronto all'uso. Se il tuo VPS va in fumo, avvii una nuova istanza, esegui un singolo comando di restore, e il database viene ripristinato fino all'ultima transazione prima del crash.
La caratteristica principale dello strumento è l'affidabilità. Interagisce con il database esclusivamente attraverso l'API C ufficiale di SQLite, non leggendo ciecamente byte raw dal disco. Questo garantisce che le fasi di scrittura non si sovrappongano a compressione o checkpoint del journal, e che il database non si trasformi in un file corrotto.
Come funziona la replica sotto il cofano
Per capire come funziona, ricordiamo la modalità WAL (Write-Ahead Logging) di SQLite.
Di default, SQLite scrive le modifiche direttamente nel file principale .db. In modalità WAL, tutte le nuove transazioni vanno prima in un journal separato con l'estensione -wal. Periodicamente, queste modifiche vengono scaricate nel file principale. Questo approccio accelera le scritture e non blocca le letture.
Litestream utilizza questo meccanismo:
- Attiva la modalità WAL del database.
- Monitora l'apparizione di nuove pagine nel file WAL.
- Copia queste modifiche e le invia in piccoli segmenti a S3.
- Controlla il processo di checkpoint in modo che SQLite non cancelli il WAL prematuramente prima che i dati siano stati caricati nel cloud.
Il ritardo nell'invio dei dati a S3 è di soli pochi secondi. Se il server si rompe, il massimo che perdi sono i dati degli ultimi un paio di secondi.
Configurazione ed esempio d'uso
Puoi avviare la replica in un paio di minuti. Basta scaricare il binario o usare un'immagine Docker già pronta.
Prima di tutto, creiamo il file di configurazione litestream.yml:
dbs:
- path: /var/lib/my-app/production.db
replicas:
- url: s3://my-backup-bucket/production.db
I parametri di connessione a S3 come le chiavi di accesso e l'endpoint vengono solitamente passati tramite variabili d'ambiente standard: AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY.
Il processo viene avviato con un semplice comando:
litestream replicate -config /etc/litestream.yml
Spesso Litestream viene eseguito nello stesso container Docker dell'applicazione principale, usando un leggero orchestratore di processi come entrypoint.sh o supervisord.
Se il server si è bloccato e devi distribuire il database in una nuova posizione, esegui il comando di restore prima di avviare l'applicazione:
litestream restore -o /var/lib/my-app/production.db s3://my-backup-bucket/production.db
L'utility recupererà l'ultimo dump di base dal bucket, scaricherà tutti i segmenti WAL mancanti sopra, assemblerà un file di database completo e lo posizionerà nel percorso specificato.
Limitazioni e inconvenienti
Lo strumento sembra molto interessante, ma Litestream ha un ambito chiaro e le sue limitazioni.
Prima di tutto, l'utility richiede che la modalità WAL sia attivata. Se la tua applicazione o una libreria driver del database specifica è incompatibile con essa, non funzionerà nulla.
In secondo luogo, questo è uno strumento di disaster recovery, non per la scalabilità orizzontale in lettura. Non puoi usare Litestream per avviare cinque copie del servizio su server diversi che leggono tutte dallo stesso database replicato simultaneamente. Per scenari distribuiti con più nodi, è meglio guardare LiteFS dello stesso team o progetti come rqlite.
Terzo, se hai un database enorme di centinaia di gigabyte con scritture pesanti costanti, i costi del traffico S3 e delle richieste API potrebbero essere una sorpresa sgradevole. Lo strumento è progettato per carichi di lavoro da piccoli a medi.
A chi sarà utile questo progetto
Litestream elimina la necessità di configurare database pesanti dove non c'è una reale necessità. È una scelta eccellente per:
- Bot Telegram e API REST in Go, Python o Node.js con una singola istanza dell'applicazione.
- Progetti su framework come PocketBase o Directus che girano su SQLite.
- Servizi self-hosted personali in esecuzione su VPS economici.
- Microservizi con cache locale o isolamento dei dati dei clienti.
Se volevi spostare un progetto personale su SQLite ma il timore di perdere il disco ti tratteneva, prova ad aggiungere Litestream. La configurazione richiede mezz'ora, ma dormirai sonni tranquilli.
Progetti correlati