Database

PostgreSQL: Recovery da Corruzione del Database in Produzione (Post-Mortem 2026)

PostgreSQL: Recovery da Corruzione del Database in Produzione (Post-Mortem 2026)

Mercoledì mattina. Ore 09:15. Un’interruzione di corrente inaspettata. Il sistema di alimentazione senza interruzione (UPS) avrebbe dovuto coprire il carico, ma qualcosa è andato storto. Non ha retto. Risultato: spegnimento improvviso dei server. Tutti. Compreso il database PostgreSQL che gestiva gli 8 anni di dati di fatturazione di un’azienda manifatturiera con 200 dipendenti. Il backup più recente era di 48 ore prima. Lo scenario peggiore per qualsiasi sysadmin o DBA: un database critico corrotto in produzione. La pressione era palpabile. La fatturazione bloccata significava problemi di liquidità imminenti. Questo è il racconto di come abbiamo gestito il recovery, dagli errori iniziali alle decisioni che hanno salvato il salvabile, e le lezioni apprese per evitare che la storia si ripeta.

Il crash: PostgreSQL non riparte dopo un’interruzione di corrente

L’interruzione di corrente ha causato uno spegnimento ‘sporco’ del server che ospitava il database PostgreSQL. Al riavvio, il servizio non è partito. I tentativi di avviare PostgreSQL si traducevano in errori nel log, indicando una corruzione dello stato interno. Era chiaro: il cluster non era più consistente e non era in grado di riprendere le normali operazioni. Un momento di panico iniziale, seguito dalla consapevolezza che ogni azione doveva essere misurata, rapida e documentata.

Ore 0-2: diagnosi — errori nel WAL e checkpoint corrotto

La prima mossa è sempre la stessa: consultare i log. La verbosità di PostgreSQL è un’alleata in questi momenti. Abbiamo trovato messaggi che indicavano la corruzione dei file WAL (Write-Ahead Log) e l’impossibilità di ripristinare un checkpoint valido. Questo è un classico sintomo di un crash improvviso che non ha permesso al database di scrivere tutte le transazioni in sospeso sui dischi e di aggiornare correttamente i metadati del checkpoint.

Per diagnosticare lo stato del cluster e verificare i log, ho usato:

# Check stato cluster PostgreSQL
pg_lsclusters
# Verifica log errori
tail -100 /var/log/postgresql/postgresql-*.log

I log confermavano che il problema risiedeva nell’integrità del WAL e nel checkpoint. Questo significava che il database non poteva determinare da quale punto ripartire in modo sicuro per garantire la consistenza dei dati.

La prima scelta sbagliata che ha quasi peggiorato tutto

Sotto pressione, la tentazione di cercare soluzioni rapide è enorme. Uno dei primi comandi che viene in mente a chi ha esperienza con PostgreSQL in situazioni di emergenza è pg_resetwal. Questo comando è progettato per ‘resettare’ lo stato dei WAL, facendo credere al database che non ci siano transazioni in sospeso da recuperare. L’ho quasi eseguito. Fortunatamente, un collega più cauto mi ha fermato. pg_resetwal può permettere al database di ripartire, ma lo fa ignorando lo stato dei WAL, il che può portare a una perdita significativa di dati o a un’inconsistenza silente. È uno strumento potente, ma da usare solo quando si accetta una potenziale perdita di dati o quando si è assolutamente certi che i dati nei WAL non sono recuperabili o importanti. In questo caso, con dati di fatturazione critici, non potevamo permetterci errori.

Recovery con pg_resetwal: quando usarlo e quando NO

pg_resetwal (o pg_resetxlog nelle versioni più vecchie) è un utility di emergenza. Il suo scopo principale è quello di ‘ingannare’ PostgreSQL per farlo ripartire dopo un crash grave che ha corrotto i file di controllo o i WAL in modo irrecuperabile. Funziona riscrivendo i metadati del cluster, come l’ultimo checkpoint e la posizione del WAL, a valori che permettono al database di avviarsi. Tuttavia, non ripara i dati corrotti e può portare a un database inconsistente. Se usato in modo improprio, può trasformare una corruzione parziale in una perdita totale di dati.

Quando usarlo:

  • Come ultima spiaggia, quando tutti gli altri tentativi di recovery sono falliti.
  • Quando si è disposti ad accettare una potenziale perdita di dati o inconsistenze.
  • In ambienti di test o sviluppo dove la perdita di dati non è critica.

Quando NON usarlo:

  • Su un database di produzione critico senza un backup recente e valido.
  • Se esiste la possibilità di recuperare i dati tramite Point-in-Time Recovery (PITR).
  • Senza aver prima fatto una copia completa del cluster corrotto per analisi forense o tentativi di recovery alternativi.

Nel nostro caso, abbiamo deciso di non usare pg_resetwal perché avevamo un backup, seppur datato, e speravamo di poter recuperare le transazioni più recenti tramite i WAL archiviati.

Restore da backup + point-in-time recovery con WAL archiving

La strategia vincente è stata il Point-in-Time Recovery (PITR). Avevamo un backup completo del database risalente a 48 ore prima. Fondamentale, avevamo anche configurato il WAL archiving, che copiava i file WAL in una posizione di storage separata e sicura. Questo ci ha permesso di ripristinare il database allo stato del backup e poi ‘rigiocare’ tutte le transazioni contenute nei file WAL fino a un punto specifico prima del crash.

I passi sono stati i seguenti:

  1. Backup del cluster corrotto: Prima di qualsiasi operazione, abbiamo fatto una copia completa della directory data di PostgreSQL. Questo è un passo critico per avere un punto di ripristino in caso di ulteriori errori.
  2. Restore del backup base: Abbiamo ripristinato il backup completo del database in una nuova directory data.
  3. Configurazione del recovery.conf (o postgresql.conf nelle versioni recenti): Abbiamo modificato il file di configurazione per indicare la posizione dei WAL archiviati e il punto temporale desiderato per il recovery.
# postgresql.conf (o recovery.conf nelle versioni precedenti)
restore_command = 'cp /backup/wal/%f %p'  # Assicurati che il percorso sia corretto
recovery_target_time = '2026-06-10 09:45:00' # L'ora esatta del crash o poco prima
  1. Avvio del database in modalità recovery: Al riavvio, PostgreSQL ha letto il backup, poi ha iniziato ad applicare i WAL archiviati sequenzialmente fino a raggiungere recovery_target_time. Questo processo ha ricostruito lo stato del database fino a pochi minuti prima dell’interruzione di corrente.

Una volta completato il recovery, è fondamentale verificare l’integrità dei dati. Ho usato pg_dumpall | grep -c 'CREATE TABLE' per avere una stima rapida del numero di tabelle e confrontarla con le aspettative. Poi, controlli più approfonditi sui dati critici.

# Verifica consistenza dopo recovery (esempio rapido)
pg_dumpall | grep -c 'CREATE TABLE'

Quanto abbiamo perso e perché poteva essere zero

Il recovery è stato un successo, ma non senza perdita. Abbiamo perso circa 15 minuti di transazioni. Questo perché la frequenza di archiviazione dei WAL era impostata a 15 minuti. Tutte le transazioni avvenute tra l’ultimo WAL archiviato e il momento del crash sono andate perdute. Per un’azienda che emette fatture continuamente, 15 minuti di dati mancanti sono un problema significativo, anche se gestibile manualmente ricostruendo le ultime operazioni.

Questa perdita poteva essere zero se la frequenza di archiviazione dei WAL fosse stata più aggressiva (es. ogni minuto) o, idealmente, se fosse stata configurata una streaming replication con un server standby. Quest’ultima opzione avrebbe garantito un RPO (Recovery Point Objective) quasi a zero, minimizzando la perdita di dati a pochi secondi o addirittura zero in caso di failover automatico.

Setup post-incidente: streaming replication e backup policy

Il post-mortem di un incidente è il momento migliore per implementare miglioramenti. Abbiamo subito messo in atto due cambiamenti critici:

  1. Streaming Replication: Abbiamo configurato una replica sincrona (o asincrona, a seconda dei requisiti di RPO) su un server separato. Questo assicura che ci sia sempre una copia aggiornata del database, pronta a subentrare in caso di fallimento del primario. Ciò riduce drasticamente il RPO e il RTO (Recovery Time Objective).
  2. Revisione della Backup Policy: La policy di backup è stata rivista per includere non solo backup completi giornalieri, ma anche un WAL archiving continuo, con frequenza di archiviazione ridotta a 1 minuto, e test regolari del processo di recovery. Non basta avere un backup; è essenziale sapere che funziona e quanto tempo impiega il recovery.

Un’organizzazione con 2.000 endpoint e un ambiente con 300+ VM non può permettersi un RPO di 48 ore. Le lezioni apprese in questo incidente hanno rafforzato la necessità di una robusta strategia di Disaster Recovery e Business Continuity, non solo a parole, ma con implementazioni concrete e testate. Incidenti come questo, seppur dolorosi, sono opportunità per rafforzare l’infrastruttura.

Errori comuni e troubleshooting

  • Non avere un backup recente: Sembra banale, ma è la causa principale di disastri. Backup regolari e testati sono non negoziabili.
  • Non archiviare i WAL: Senza WAL archiving, il PITR è impossibile, e il RPO è legato solo alla frequenza dei backup completi.
  • Non testare il recovery: Un backup non testato è un backup inesistente. Simulate regolarmente scenari di disastro.
  • Usare pg_resetwal alla cieca: Valutate sempre il rischio di perdita dati. Meglio un recovery più lungo ma sicuro che un recovery rapido ma inconsistente.
  • Ignorare i log: I log di PostgreSQL contengono tutte le informazioni per capire cosa è successo e come procedere.

FAQ — Domande Frequenti

D: Qual è la differenza tra un backup completo e il WAL archiving?

R: Un backup completo è una copia dello stato del database in un momento specifico. Il WAL archiving è il processo di copia continua dei file di log delle transazioni (WAL) in una posizione sicura. Insieme, permettono il Point-in-Time Recovery, dove si ripristina un backup completo e poi si applicano i WAL per portare il database a uno stato desiderato più recente.

D: Quanto spesso dovrei archiviare i WAL?

R: La frequenza dipende dal tuo RPO (Recovery Point Objective). Se puoi tollerare una perdita di pochi minuti, un’archiviazione ogni 5-10 minuti può essere sufficiente. Per un RPO quasi a zero, è necessaria una streaming replication, che invia i WAL in tempo quasi reale a un server standby.

D: pg_resetwal può causare danni permanenti?

R: Sì, se usato in modo inappropriato, pg_resetwal può portare a una perdita irreversibile di dati o a un database inconsistente. Non ripristina i dati, ma forza il database a ripartire ignorando il suo stato precedente. Usalo solo se comprendi appieno le implicazioni e hai esaurito tutte le altre opzioni di recovery.

D: Come posso prevenire la corruzione del database PostgreSQL?

R: Implementa una robusta strategia di backup e recovery (inclusi PITR e streaming replication), usa hardware affidabile (UPS, RAID), monitora costantemente lo stato del database e del sistema operativo, e testa regolarmente i piani di disaster recovery. Leggi anche: Linux Server Hardening: Checklist 15 Punti per la Produzione (2026)

Conclusioni con takeaway operativi

L’incidente di corruzione del database PostgreSQL è stato un promemoria brutale dell’importanza di una strategia di Disaster Recovery ben progettata e regolarmente testata. Non basta avere un backup; è fondamentale che quel backup sia valido e che il processo di recovery sia efficiente. La lezione principale è che il WAL archiving e, idealmente, la streaming replication, sono componenti non negoziabili per qualsiasi database PostgreSQL in produzione con requisiti di alta disponibilità e bassa perdita di dati. Un RPO di 15 minuti è un lusso che poche aziende possono permettersi. Un RPO vicino allo zero è l’obiettivo, raggiungibile con le giuste implementazioni e una cultura della resilienza.

Leggi anche: Zabbix 7 Installazione Ubuntu: Guida Completa e Configurazione (2026)

Leggi anche: Active Directory Hardening: 10 Impostazioni Critiche da Verificare Subito (2026)

Per maggiori dettagli sul Point-in-Time Recovery di PostgreSQL, potete consultare la documentazione ufficiale: https://www.postgresql.org/docs/current/backup-recovery.html

Aggiornato: Giugno 2026

Condividi questo articolo:

Scritto da

Rosario Giordano

Rosario Giordano è System Administrator e consulente IT specializzato in cybersecurity e cloud, con oltre 20 anni di esperienza nella gestione di infrastrutture Linux enterprise. Le sue aree di competenza includono hardening di SSH, piattaforme Kubernetes, database PostgreSQL, ambient i virtualizzati VMware e Proxmox, nonché la conformità ai framework di sicurezza NIS2 e ISO 27001.