Il point-in-time recovery è un metodo di restore che riproduce un log delle modifiche sopra un backup di base per ricostruire il database a un secondo scelto. Lo scenario per cui esiste non è il guasto hardware – di quello si occupa la replica – ma quello umano: una migrazione che ha corrotto delle righe alle 14:32, uno script che ha eliminato il tenant sbagliato. Il PITR (ripristino a un istante nel tempo) risponde con l’unica cosa che aiuta: il database esattamente com’era alle 14:31:59.
Punti chiave
| Domanda | Risposta |
|---|---|
| Snapshot | Una fotografia – il restore atterra sull’istante in cui è stato scattato |
| PITR | Backup di base + log delle modifiche riprodotto – il restore atterra su qualsiasi secondo |
| RPO | Quanti dati recenti si possono perdere – fissato dalla frequenza di cattura |
| RTO | Quanto può durare il restore – fissato da volume e meccanica |
| La divisione | Un BaaS gestisce la meccanica; obiettivi ed esercitazioni restano a chi sviluppa |
Il meccanismo, in una sola sessione di lavoro
-- Il log delle modifiche è la materia prima: ogni scrittura confermata, in ordine.
-- Prima di un'operazione rischiosa, si può lasciarci un marcatore con un nome:
SELECT pg_create_restore_point('before_pricing_migration');
-- Ripristino = backup di base + replay, fermato nel punto indicato:
-- ripristinare il backup di base preso alle 02:00
-- riprodurre il log in avanti…
-- …e fermarsi appena prima del danno:
-- recovery_target_time = '2026-08-05 14:31:59+00'
-- (oppure recovery_target_name = 'before_pricing_migration')
-- Tutto ciò che è stato confermato prima dell'obiettivo esiste; nulla di posteriore esiste.
È il write-ahead log che fa doppio lavoro: lo stesso registro ordinato che dà alle transazioni la loro durabilità diventa, se archiviato in continuo, una macchina del tempo. I database documentali giocano la stessa partita con l’oplog – catturare il flusso di operazioni, riprodurlo sopra uno snapshot, fermarsi a comando (PostgreSQL lo chiama continuous archiving; MongoDB documenta la stessa architettura sopra snapshot del file system).
Dopo qualsiasi restore, il passo di verifica dell’esercitazione è a livello applicativo – confermare che la linea temporale sia atterrata dove previsto:
// JavaScript / Node.js — Back4app JS SDK
// Restore drill: verify the restored data lines up with the incident timeline
const incident = new Date('2026-08-05T14:32:00Z'); // when the bad deploy hit
const latest = new Parse.Query('Order');
latest.lessThan('createdAt', incident);
latest.descending('createdAt');
const lastGood = await latest.first(); // newest order before the incident
const after = new Parse.Query('Order');
after.greaterThanOrEqualTo('createdAt', incident);
const leaked = await after.count(); // must be 0 on a clean PITR restore
console.log(`last good write: ${lastGood?.get('createdAt')}`);
console.log(`rows past the recovery target: ${leaked}`); // Flutter / Dart — Back4app Flutter SDK
// Restore drill: verify the restored data lines up with the incident timeline
final incident = DateTime.parse('2026-08-05T14:32:00Z'); // the bad deploy
final latest = QueryBuilder<ParseObject>(ParseObject('Order'))
..whereLessThan('createdAt', incident)
..orderByDescending('createdAt')
..setLimit(1);
final lastGood = await latest.query(); // newest order before the incident
final after = QueryBuilder<ParseObject>(ParseObject('Order'))
..whereGreaterThanOrEqualsTo('createdAt', incident);
final leaked = await after.count(); // must be 0 on a clean PITR restore
print('last good write: '
'${(lastGood.results?.first as ParseObject?)?.createdAt}');
print('rows past the recovery target: ${leaked.count}'); // iOS / Swift — Back4app Swift SDK
// Restore drill: verify the restored data lines up with the incident timeline
let incident = ISO8601DateFormatter()
.date(from: "2026-08-05T14:32:00Z")! // when the bad deploy hit
let latest = Order.query("createdAt" < incident)
.order([.descending("createdAt")])
.limit(1)
latest.first { result in // newest order before the incident
if case .success(let lastGood) = result {
print("last good write: \(String(describing: lastGood.createdAt))")
}
}
let after = Order.query("createdAt" >= incident)
after.count { result in // must be 0 on a clean PITR restore
if case .success(let leaked) = result {
print("rows past the recovery target: \(leaked)")
}
} // Android / Kotlin — Back4app Android SDK
// Restore drill: verify the restored data lines up with the incident timeline
val incident = Date(1754404320000L) // 2026-08-05T14:32:00Z, the bad deploy
val latest = ParseQuery.getQuery<ParseObject>("Order")
latest.whereLessThan("createdAt", incident)
latest.orderByDescending("createdAt")
latest.limit = 1
latest.findInBackground { lastGood, _ -> // newest order before the incident
println("last good write: ${lastGood?.firstOrNull()?.createdAt}")
}
val after = ParseQuery.getQuery<ParseObject>("Order")
after.whereGreaterThanOrEqualTo("createdAt", incident)
after.countInBackground { leaked, e -> // must be 0 on a clean PITR restore
if (e == null) println("rows past the recovery target: $leaked")
} Come un restore arriva alle 14:31:59
Dal meccanismo discendono due proprietà. Primo, l’RPO è fissato dalla frequenza di cattura: log spediti ogni pochi secondi significano pochi secondi di perdita massima, a prescindere da quando è girato l’ultimo snapshot. Secondo, l’RTO è fissato dalla distanza di replay: ripristinare alle 23:00 da una base delle 02:00 significa riprodurre 21 ore di scritture – ed è per questo che i sistemi PITR continuano a fare snapshot frequenti, non per la granularità ma per accorciare la rincorsa.
Snapshot vs. PITR
| Dimensione | Solo snapshot | PITR (base + replay del log) |
|---|---|---|
| Granularità del restore | Gli istanti in cui sono girati gli snapshot | Qualsiasi secondo nella finestra |
| RPO tipico | Ore (il vuoto fra due esecuzioni) | Da secondi a minuti |
| Costo di archiviazione | Basso – n copie | Più alto – copie + archivio continuo del log |
| Velocità di restore | Rapida – si ricopia | Più lenta – copia + replay |
| Rispetto all’errore umano | Si perde tutto dall’ultimo snapshot | Non si perde quasi nulla di ciò che precede l’errore |
| Complessità | Minima | Reale – archiviazione, ordinamento, obiettivi |
Quale garanzia di ripristino serve davvero?
| Se perdere… è sopportabile | Allora serve | Da sorvegliare |
|---|---|---|
| Un giorno di scritture | Snapshot notturni | La durata della conservazione |
| Un’ora | Snapshot + incrementi frequenti | Che il calendario scatti davvero |
| Minuti o meno | Cattura continua del log (PITR) | Il ritardo di archiviazione – è l’RPO effettivo |
| Niente, mai | PITR + replica sincrona | Costo e latenza di scrittura, prezzati onestamente |
Casi d’uso comuni
- Il deployment sbagliato. Una migrazione o un hotfix corrompe i dati a metà pomeriggio – si ripristina al secondo prima del rilascio.
- Cancellazioni per errore di battitura. Il tenant, la collection o la clausola WHERE sbagliati – si torna ad appena prima dell’istruzione, spesso in un database usa e getta per estrarre solo ciò che è andato perso.
- Ransomware e compromissione dell’account. Si riavvolge a prima che l’intrusione toccasse i dati – con la crittografia a riposo a proteggere le stesse copie archiviate.
- Conservazione per conformità. I prodotti regolamentati devono dimostrare la ripristinabilità – finestre documentate, restore testati, esercitazioni verificabili.
- Prova generale prima del lancio. L’esercitazione di restore come barriera di rilascio: i team che hanno già ripristinato a un timestamp una volta lo rifanno con calma la notte in cui conta.
Conviene affidarsi ai backup predefiniti? Matrice decisionale
| I predefiniti bastano quando… | Conviene investire oltre quando… |
|---|---|
| Perdere un giorno di dati è fastidioso, non fatale | Le scritture sono denaro – ordini, registri contabili, prenotazioni |
| Il prodotto è pre-lancio o interno | Un’ora di perdita è una catastrofe per il supporto |
| I dati si possono ricostruire da un’altra fonte | Il database è l’unica fonte di verità |
| Nessuno ha chiesto garanzie di ripristino | Un contratto o un regolatore indica cifre di RPO/RTO |
| Non è mai servito un restore | Ne è servito uno – ed è stato un momento di tensione |
Qualunque cosa fornisca la piattaforma, tre decisioni restano a chi sviluppa: l’RPO a cui il prodotto può sopravvivere, l’RTO che gli utenti tollereranno, e la cadenza delle esercitazioni che tiene onesti entrambi i numeri – la disciplina che la guida del NIST alla pianificazione di contingenza formalizza così: definire gli obiettivi, poi testare rispetto a essi.
Limiti e trade-off
- La replica non è ripristino. Le repliche replicano l’errore nel giro di secondi; solo i backup arrivano a prima. Strumenti diversi, classi di guasto diverse.
- La finestra è finita. Il PITR raggiunge qualsiasi secondo – dentro la conservazione. Un danno scoperto dopo la chiusura della finestra è permanente; la conservazione va dimensionata sul tempo di rilevamento, non solo sul prezzo dell’archiviazione.
- Il replay richiede tempo. I restore pesanti di log possono durare a lungo; l’RTO reale si misura con le esercitazioni, non si legge nelle dashboard.
- I restore ripristinano il database intero. Il PITR classico ricostruisce il database a un timestamp; estrarre le righe perse di una sola tabella significa ripristinare su un’istanza usa e getta e copiare da lì – quel workflow va pianificato.
- Un backup mai testato è una voce di corridoio. Export falliti in silenzio, credenziali scadute, runbook mancanti – ognuno è invisibile finché non lo trova un’esercitazione o un disastro. Le esercitazioni costano meno.
PITR e backup su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. I backup del database gestito girano a calendario senza configurazione, e il restore è un’operazione della dashboard anziché una notte di archeologia nei log – la metà “snapshot e meccanica” di questo articolo, assorbita dalla piattaforma. La metà che resta a chi sviluppa è la decisione: gli obiettivi di RPO e RTO, le esigenze di conservazione, e l’esercitazione trimestrale in cui le schede di codice qui sopra verificano che la linea temporale ripristinata sia esattamente quella richiesta.
Domande frequenti
Che cos'è il point-in-time recovery, in parole semplici?
Un restore che può atterrare su qualsiasi istante, non solo sugli orari dei backup pianificati. Il motore parte da un backup di base e ne riproduce il log delle modifiche – ogni scrittura confermata, in ordine – fermandosi al secondo indicato. Invece di perdere tutto ciò che è successo dallo snapshot della notte precedente, si perde solo ciò che è avvenuto dopo le 14:31:59, il secondo prima dell'incidente.
Qual è la differenza fra uno snapshot e il PITR?
La granularità. Uno snapshot è una fotografia: il restore atterra esattamente sull'istante in cui è stato scattato, e tutto ciò che viene dopo è perso. Il PITR è un film: backup di base più cattura continua del log permettono di fermare la riproduzione in qualsiasi punto della finestra di conservazione. Gli snapshot sono più semplici ed economici da conservare; il PITR trasforma il ripristino da "quale notte?" in "quale secondo?".
Che cosa sono RPO e RTO?
I due numeri di cui parla in segreto ogni discussione sui backup. L'RPO – recovery point objective – è quanta parte dei dati recenti ci si può permettere di perdere, ed è fissato dalla frequenza dei backup o della spedizione dei log. L'RTO – recovery time objective – è quanto può durare il restore, ed è fissato dal volume dei dati e dalla meccanica di ripristino. Snapshot giornalieri danno un RPO di ore; la cattura continua del log lo riduce verso i secondi.
La replica sostituisce i backup?
No – la replica è disponibilità, non ripristino. Una replica copia fedelmente tutto ciò che fa il primario, compreso il DROP TABLE lanciato per errore; nel giro di pochi secondi ogni copia concorda sui danni. Backup e PITR esistono proprio per raggiungere uno stato precedente all'errore, che nessuna replica conserva. Servono entrambi, per classi di guasto diverse.
Con quale frequenza vanno eseguiti i backup?
Si parte dall'RPO e si va a ritroso. Se perdere un giorno di scritture è sopportabile, bastano snapshot notturni; se un'ora fa male, si aggiungono incrementi più frequenti; se contano i minuti, serve la cattura continua del log – e a quel punto la frequenza degli snapshot governa la velocità del restore, non la perdita di dati. Qualunque sia il calendario, la durata della conservazione decide fino a quando gli errori restano riparabili.
Perché le esercitazioni di restore sono importanti?
Perché un backup mai testato è un'ipotesi, non un piano. Le esercitazioni fanno emergere i guasti che compaiono solo nella pratica: export rotti in silenzio, restore che durano nove ore contro un RTO di un'ora, credenziali mancanti, passaggi non documentati. Un'esercitazione trimestrale – restore in un ambiente usa e getta, verifica dei dati, cronometro sul processo – trasforma l'ipotesi in una procedura provata.
Che cosa va controllato dopo il restore di un database?
Prima la linea temporale: i record più recenti devono trovarsi appena prima dell'obiettivo di ripristino, e nulla deve esistere dopo. Poi l'integrità – conteggi di righe rispetto alle attese, invarianti critiche, riferimenti che devono risolversi. Infine l'applicazione: effettuare l'accesso, eseguire i flussi principali, confermare che i job in background riprendano in modo pulito. Un restore "completato" può essere sbagliato in tutti e tre i modi.
Chi gestisce i backup in un BaaS: la piattaforma o chi sviluppa?
La meccanica è della piattaforma: snapshot, cattura del log, archiviazione, strumenti di restore. Gli obiettivi restano a chi sviluppa: scegliere RPO e RTO per il proprio prodotto, conoscere la finestra di conservazione, condurre le esercitazioni di restore e tenere un export indipendente se la policy lo richiede. Un backend gestito elimina la parte impiantistica, non la responsabilità di decidere che aspetto ha una perdita sopportabile.