Categories
Database Backup

**

Per gli amministratori di database (DBA) e gli ingegneri DevOps che gestiscono PostgreSQL in produzione, ottenere un Recovery Point Objective (RPO) prossimo allo zero è un mandato primario. Al centro delle funzionalità di disaster recovery e Point-in-Time Recovery (PITR) di PostgreSQL c’è il Write-Ahead Logging (WAL). Mentre il WAL garantisce la conformità ACID registrando le transazioni prima che vengano scritte nei file di dati, l’archiviazione WAL è il meccanismo che preserva questi log per il backup a lungo termine e la replica.

Tuttavia, configurare l’archiviazione WAL non è un’operazione da “imposta e dimentica”. Configurazioni errate, errori silenziosi e incomprensioni architetturali possono portare a una perdita di dati catastrofica, scenari di split-brain o interruzioni complete del database.

In questa guida completa, esploreremo l’architettura dell’archiviazione WAL di PostgreSQL, identificheremo le insidie più comuni che portano alla perdita di dati e delineeremo le migliori pratiche di livello produttivo per garantire che il tuo database rimanga resiliente.

Comprendere l’architettura WAL di PostgreSQL

Prima di addentrarci nelle insidie, è fondamentale capire come PostgreSQL gestisce i log delle transazioni.

PostgreSQL scrive tutte le modifiche nei segmenti WAL (di default file da 16MB) situati nella directory pg_wal (precedentemente pg_xlog nelle versioni precedenti alla 10). Ogni transazione viene registrata sequenzialmente, contrassegnata da un Log Sequence Number (LSN).

Quando un segmento WAL si riempie, PostgreSQL passa a uno nuovo. Per evitare che la directory pg_wal cresca all’infinito, PostgreSQL ricicla o rimuove i vecchi segmenti WAL una volta che non sono più necessari per il crash recovery o la replica.

L’archiviazione WAL intercetta questo processo di riciclo. Quando archive_mode è abilitato, PostgreSQL esegue un archive_command definito dall’utente (o utilizza una archive_library in PostgreSQL 15+) per copiare il segmento WAL completato in una posizione secondaria sicura prima che venga eliminato o sovrascritto.

Per eseguire un Point-in-Time Recovery (PITR), sono necessari due componenti:
1. Un base backup valido.
2. Una catena ininterrotta di file WAL archiviati dal momento del base backup fino al tempo di ripristino desiderato.

Se quella catena WAL viene interrotta, il tuo PITR fallirà.

Configurazione dell’archiviazione WAL per la produzione

Per abilitare l’archiviazione WAL, devi modificare il tuo file postgresql.conf. Una configurazione di base richiede l’impostazione di wal_level, l’abilitazione di archive_mode e la definizione di archive_command.

# postgresql.conf
wal_level = replica             # 'replica' o 'logical' è richiesto per l'archiviazione
archive_mode = on               # Abilita il processo di archiviazione
archive_command = 'test ! -f /mnt/nfs/archive/%f && cp %p /mnt/nfs/archive/%f'
archive_timeout = 600           # Forza uno switch WAL ogni 10 minuti

Nel archive_command:
* %p rappresenta il percorso completo del file WAL da archiviare.
* %f rappresenta il nome del file WAL.

Sebbene la configurazione sopra sembri semplice, fare affidamento su semplici comandi shell in ambienti aziendali introduce rischi significativi.

Insidie comuni nell’archiviazione WAL

Insidia 1: Il “successo silenzioso” di archive_command

PostgreSQL si affida interamente al codice di uscita di archive_command. Se il comando restituisce 0, PostgreSQL presume che il file WAL sia archiviato in modo sicuro e procede a riciclare il file originale.

Un errore comune è utilizzare un comando che restituisce 0 anche se i dati non vengono scaricati in modo sicuro su uno storage persistente. Ad esempio, un semplice comando cp potrebbe restituire successo non appena i dati raggiungono la cache della pagina del sistema operativo sul server di destinazione. Se il server di destinazione perde alimentazione prima che la cache venga scaricata su disco, il file WAL va perso, ma PostgreSQL ha già eliminato la sua copia locale.

Il rischio: Una catena WAL interrotta e l’incapacità di eseguire il PITR, scoperta solo durante uno scenario di disaster recovery.

La mitigazione: Assicurati che il tuo script di archiviazione imponga scritture sincrone. Se utilizzi comandi shell standard, utilizza strumenti che garantiscano lo scaricamento dei dati o scrivi uno script wrapper che verifichi la dimensione del file e il checksum dopo il trasferimento.

Insidia 2: Esaurimento della partizione pg_wal (WAL Bloat)

Se archive_command fallisce (restituisce un codice di uscita diverso da zero)—a causa di interruzioni di rete, autorizzazioni errate o un disco di destinazione pieno—PostgreSQL manterrà il file WAL nella directory pg_wal e riproverà il comando indefinitamente.

Sebbene ciò prevenga la perdita di dati non eliminando i WAL non archiviati, introduce un grave rischio per la disponibilità. Se la directory pg_wal risiede su una partizione che si riempie al 100%, PostgreSQL emetterà un PANIC e andrà in crash. Il database non si riavvierà finché non verrà liberato spazio.

Il rischio: Downtime completo del database a causa di una partizione pg_wal piena.

La mitigazione:
1. Posiziona sempre pg_wal su una partizione disco dedicata.
2. Implementa un monitoraggio aggressivo sulla dimensione della directory pg_wal.
3. Monitora la vista pg_stat_archiver per rilevare immediatamente i comandi di archiviazione falliti.

Insidia 3: Base backup incompleti

Un base backup è inutile senza i file WAL generati durante il processo di backup. Se esegui uno snapshot a livello di file system o utilizzi pg_basebackup senza lo streaming dei WAL (-X stream), devi assicurarti che i file WAL generati tra l’inizio e la fine del backup vengano archiviati correttamente.

Se il tuo archiver è in ritardo o fallisce, e quei file WAL specifici vanno persi, il base backup non può essere portato a uno stato coerente.

Il rischio: Base backup corrotti o non recuperabili.

La mitigazione: Usa pg_basebackup -X stream per includere i file WAL necessari all’interno del payload del backup stesso, oppure utilizza soluzioni di backup aziendali che gestiscono automaticamente la dipendenza tra base backup e segmenti WAL.

Insidia 4: Confusione sulla Timeline e scenari di Split-Brain

Quando un server standby viene promosso a primario, PostgreSQL incrementa il “Timeline ID” (la prima parte del nome del file WAL, ad esempio 0000000200000001000000A4). Ciò impedisce al nuovo primario di sovrascrivere la cronologia WAL del vecchio primario.

Tuttavia, se il vecchio primario viene avviato accidentalmente senza essere correttamente isolato (uno scenario di split-brain), potrebbe tentare di inviare file WAL alla stessa posizione di archiviazione utilizzando la vecchia timeline. Se il tuo archive_command sovrascrive ciecamente i file, potresti corrompere il tuo repository di archiviazione.

Il rischio: File WAL sovrascritti, archivi corrotti e database non recuperabili.

La mitigazione: Il tuo archive_command non deve mai sovrascrivere un file esistente. Nota che nella configurazione di base precedente, abbiamo usato test ! -f /mnt/nfs/archive/%f per fallire esplicitamente se il file esiste già.

Mitigare i rischi di perdita di dati: Best practice di produzione

Per rafforzare la tua strategia di archiviazione PostgreSQL, implementa le seguenti best practice.

1. Monitora nativamente il processo di archiviazione

PostgreSQL fornisce una vista integrata, pg_stat_archiver, che tiene traccia del successo e del fallimento del tuo processo di archiviazione. Dovresti integrare questa vista nel tuo stack di osservabilità (ad esempio, Prometheus, Datadog o Zabbix).

SELECT 
    archived_count,
    last_archived_wal,
    last_archived_time,
    failed_count,
    last_failed_wal,
    last_failed_time,
    stats_reset
FROM pg_stat_archiver;

Soglie di avviso da configurare:
* Avvisa se failed_count aumenta.
* Avvisa se la differenza di tempo tra now() e last_archived_time supera la tua soglia RPO (ad esempio, 15 minuti), tenendo presente che i database a basso traffico potrebbero avere ritardi naturali a meno che non sia impostato archive_timeout.

2. Sfrutta archive_timeout

Nei database con basso volume di scrittura, un file WAL da 16MB potrebbe impiegare ore per riempirsi. Finché non si riempie, non viene archiviato. Se il server va in crash e il disco locale viene perso, perdi ore di transazioni.

Impostare archive_timeout = 600 (10 minuti) forza PostgreSQL a passare a un nuovo file WAL e ad archiviare quello corrente, anche se non è pieno. Ciò garantisce che il tuo RPO non superi i 10 minuti, al costo di un utilizzo dello storage leggermente superiore a causa dei file WAL parzialmente riempiti.

3. Passa a archive_library (PostgreSQL 15+)

Storicamente, archive_command generava un nuovo processo shell per ogni singolo file WAL. In ambienti ad alto throughput che generano centinaia di file WAL al minuto, l’overhead della creazione di processi shell diventa un collo di bottiglia per le prestazioni.

PostgreSQL 15 ha introdotto il parametro archive_library, consentendo all’archiviazione WAL di essere gestita da moduli C caricati dinamicamente. Ciò elimina l’overhead della shell e fornisce un meccanismo di archiviazione molto più robusto e ad alte prestazioni. Se utilizzi PostgreSQL 15 o superiore, cerca strumenti di backup che supportino moduli di archiviazione personalizzati.

4. Testa regolarmente il Point-in-Time Recovery

Un backup non testato non è un backup; è un desiderio. L’unico modo per verificare che l’archiviazione WAL funzioni correttamente, che la catena WAL sia ininterrotta e che i base backup siano coerenti, è eseguire test PITR automatizzati e di routine.

Avvia un’istanza temporanea, ripristina il base backup, configura restore_command per prelevare dal tuo archivio e recupera fino a un timestamp specifico. Verifica che il database raggiunga uno stato coerente e si apra per le connessioni.

Backup e ripristino aziendale con CloudSave

Gestire script shell personalizzati per archive_command, gestire la deduplicazione WAL e garantire uno storage sicuro e offsite per i log delle transazioni può diventare rapidamente un onere operativo per i team IT.

È qui che CloudSave offre un valore significativo per gli ambienti PostgreSQL aziendali. CloudSave si integra direttamente con le API di backup e archiviazione WAL native di PostgreSQL per eliminare le insidie manuali discusse sopra.

Invece di scrivere fragili script bash, CloudSave fornisce un’integrazione robusta, basata su agenti o senza agenti, che:
* Garantisce la consegna: Sostituisce i comandi shell standard con trasferimenti verificati e convalidati da checksum verso uno storage offsite o cloud sicuro.
* Previene il WAL Bloat: Monitora attivamente la directory pg_wal e avvisa gli amministratori molto prima che si verifichi l’esaurimento della partizione.
* Automatizza il PITR: Semplifica il Point-in-Time Recovery attraverso un’interfaccia intuitiva. Selezioni il minuto esatto in cui vuoi recuperare e CloudSave recupera automaticamente il base backup corretto e trasmette l’esatta sequenza di file WAL necessaria per raggiungere quello stato.
* Gestisce le Timeline: Gestisce in modo intelligente le cronologie delle timeline di PostgreSQL, assicurando che i failover e gli scenari di split-brain non corrompano il tuo repository di backup.

Delegando il lavoro pesante della gestione WAL a CloudSave, i DBA possono concentrarsi sull’ottimizzazione delle query e sulle prestazioni del database, sapendo che i loro SLA di RPO e RTO sono protetti da una piattaforma di livello aziendale.

Conclusione

L’archiviazione WAL di PostgreSQL è la spina dorsale del disaster recovery del database. Sebbene il concetto di copiare un file da una directory all’altra sembri semplice, i casi limite—errori silenziosi, esaurimento del disco e divergenza della timeline—pongono gravi rischi all’integrità dei dati.

Comprendendo l’architettura di pg_wal, evitando rigorosamente configurazioni distruttive di archive_command, monitorando pg_stat_archiver e sfruttando piattaforme di backup aziendali come CloudSave, puoi costruire un’infrastruttura PostgreSQL resiliente in grado di sopravvivere a guasti hardware, errori umani e interruzioni catastrofiche senza perdere una singola transazione confermata.

Scopri le insidie comuni dell’archiviazione WAL di PostgreSQL che portano alla perdita di dati. Impara le migliori pratiche dei DBA esperti, suggerimenti di configurazione e come garantire un Point-in-Time Recovery (PITR) affidabile per i database aziendali.