Indice del diarioDockup / nota dal campo
Note / database-backups-you-have-restored

Un backup che non hai mai ripristinato non è un backup

I backup di database non testati falliscono in modi prevedibili: dump vuoti, ruoli mancanti, flag errati, chiavi di cifratura assenti. Scopri come verificare un ripristino, per assicurarti che il file che conservi sia davvero utilizzabile.

Il momento peggiore per scoprire che un backup non funziona è proprio quando ne hai bisogno. Eppure, il modello più comune è esattamente questo: backup configurati una volta, un segno di spunta verde nella dashboard per diciotto mesi e poi un ripristino che produce un database vuoto.

Testare il ripristino di un backup del database non è una best practice nel senso in cui lo sono la maggior parte delle best practice, cioè una pratica facoltativa. Un backup è un'affermazione e, finché non ne hai ripristinato uno, rimane un'affermazione non verificata.

Ecco come si verificano i problemi e che cosa deve controllare una vera verifica.

I quattro modi in cui un backup può essere inutilizzabile senza che nessuno se ne accorga

1. È vuoto e nessuno lo ha controllato

Un pg_dump che fallisce a metà può comunque produrre un file. Un dump eseguito sul database sbagliato produce un file valido, corretto e vuoto. Entrambi sembrano riusciti a qualsiasi controllo che verifichi solo un exit code diverso da zero o l'esistenza del file.

Il controllo più economico del mondo: guarda la dimensione e confrontala con quella di ieri. Un backup da 400 byte quando quello di ieri era di 40 MB ti ha già detto tutto. Un backup che è di 400 byte da sei mesi te lo sta dicendo da sempre.

2. Contiene i dati, ma non ciò che li circonda

Il pg_dump di un singolo database non include i ruoli e non include gli altri database. Ripristinalo su un server nuovo: le tabelle arriveranno, ma ogni GRANT farà riferimento a un ruolo inesistente. La tua app si connetterà, ricevendo permission denied su qualsiasi operazione.

Lo stesso vale per le estensioni. Se il tuo schema dipende da pgcrypto o uuid-ossp e il target non le contiene, il ripristino fallirà a metà, lasciandoti con alcune tabelle.

3. I flag erano sbagliati per il ripristino necessario

pg_dump produce risultati diversi a seconda del formato e l'errore viene solitamente scoperto nel momento peggiore:

  • Plain SQL viene ripristinato con psql ed è leggibile. Non può essere ripristinato in modo selettivo ed è lento per i database di grandi dimensioni.
  • Custom format (-Fc) viene ripristinato con pg_restore, supporta il parallelismo e il ripristino selettivo ed è il formato da preferire per qualsiasi database di dimensioni significative.

Creare backup in formato plain perché lo faceva il tutorial e scoprire poi, durante un incidente, che non puoi ripristinare una singola tabella è un tipo di brutta giornata molto specifico e facilmente evitabile.

4. Non puoi decrittografarlo

Se i backup sono cifrati — e dovrebbero esserlo — la chiave fa parte del backup. Una chiave che risiede solo sulla macchina andata persa o soltanto in una variabile d'ambiente del servizio non disponibile è una chiave che non avrai quando sarà importante.

Come si presenta una vera verifica

Il test non consiste nel chiedersi «il file esiste?». Consiste nel ripristinarlo da un'altra parte e fargli una domanda.

# 1. Restore into a scratch database, not the live one
createdb verify_$(date +%Y%m%d)
pg_restore -d verify_$(date +%Y%m%d) --no-owner --no-privileges latest.dump

# 2. Ask it something only real data can answer
psql -d verify_$(date +%Y%m%d) -c "
  select
    (select count(*) from users)            as users,
    (select count(*) from orders)           as orders,
    (select max(created_at) from orders)    as newest_order;
"

# 3. Drop it
dropdb verify_$(date +%Y%m%d)

Il passaggio 2 è l'intero punto della procedura. Un ripristino completato senza errori non ti dice comunque nulla sulla presenza effettiva dei dati. I conteggi delle righe e un controllo sulla data più recente, invece, sì.

Tre aspetti che vale la pena verificare:

  • I conteggi delle righe sono dello stesso ordine di grandezza. Non devono essere identici — i dati cambiano — ma una tabella che conteneva 200.000 righe e ora ne contiene 12 indica un errore.
  • Il record più recente è recente. Se l'ordine più recente nel tuo backup «notturno» risale a marzo, il processo di backup si è fermato a marzo.
  • L'app riesce davvero a connettersi. Punta un'istanza di staging al database ripristinato e carica una pagina.

Fallo secondo una pianificazione, non quando hai tempo

Una cadenza realistica è mensile e automatizzata, con il risultato in un punto in cui noterai eventuali problemi. Un promemoria sul calendario con scritto «testare i backup» è un promemoria che rimanderai.

Per fare in modo che la procedura venga rispettata, devi rendere il fallimento impossibile da ignorare: se la query di verifica restituisce meno righe di una determinata soglia, dovrebbe generare una notifica per qualcuno, proprio come farebbe un errore in produzione. Un sistema di backup che fallisce senza avvisare non è distinguibile dall'assenza di un sistema di backup, almeno finché non serve davvero.

Come gestisce questo aspetto Dockup

Tre decisioni, ognuna pensata per affrontare uno dei problemi descritti sopra.

I backup vengono salvati altrove. Un backup sullo stesso disco del database non è un backup: è una copia che scompare insieme al disco. Dockup invia i backup del database direttamente allo storage a oggetti mentre vengono creati, così il file non dipende mai dall'host che lo ha generato.

Sono cifrati e la chiave non si trova sulla macchina. I backup vengono cifrati con AES-256-GCM durante l'invio. L'aspetto rilevante per il recovery è che la chiave è gestita dalla piattaforma, invece di trovarsi nell'ambiente del servizio di cui stai eseguendo il backup.

Un backup che non ha prodotto nulla non viene registrato come backup. Questa decisione affronta direttamente il problema dei file vuoti: se il dump termina con un exit code diverso da zero o produce zero byte, l'upload viene eliminato e il backup viene registrato come fallito. Non ti ritroverai con un elenco di voci verdi, una delle quali corrisponde a un file da 400 byte.

dockup db backup my-project/main-db --json     # take one now
dockup db backups my-project/main-db --json    # list them with sizes

Le dimensioni riportate in quell'elenco sono il controllo dello stato di salute più economico che hai a disposizione. Osservane l'andamento.

La domanda scomoda

Se il tuo database di produzione venisse distrutto nei prossimi dieci minuti, quanto tempo ti servirebbe per ripristinarlo e quanti dati perderesti?

Se non sai rispondere a entrambe le domande, non hai una strategia di backup: hai dei file di backup. La differenza dipende interamente dal fatto che qualcuno abbia mai eseguito il ripristino.

Domande frequenti

Con quale frequenza dovrei testare un ripristino? Una volta al mese è una cadenza ragionevole come impostazione predefinita, automatizzata anziché manuale. L'aspetto importante è che un errore generi un avviso evidente, non che la cadenza sia particolarmente ravvicinata.

Perché il mio ripristino è stato completato, ma non ha prodotto dati? Di solito il dump è stato eseguito sul database sbagliato oppure è fallito a metà mentre il file veniva ancora scritto. Confronta le dimensioni dei backup nel tempo: un dump vuoto è evidente osservando l'andamento delle dimensioni, ma invisibile in una colonna di stato.

I backup devono essere cifrati? Sì, e la chiave deve trovarsi in un luogo che sopravviva alla perdita della macchina. Un backup cifrato la cui chiave si trovava sul server perduto non è recuperabile.

Uno snapshot equivale a un backup? No. Uno snapshot del volume cattura il disco, incluso lo stato in cui si trovava il database in quell'istante. Un dump logico è coerente per costruzione. La maggior parte dei team vuole entrambi, perché proteggono da problemi diversi.