
La replica non è un backup. O forse sì? Ecco come abbiamo usato la replica ritardata per il ripristino dopo aver eliminato accidentalmente i collegamenti.
su GitLab sono responsabili del funzionamento — del più grande esempio di GitLab esistente. Qui ci sono 3 milioni di utenti e quasi 7 milioni di progetti, e questo è uno dei più grandi siti SaaS open-source con architettura dedicata. Senza il sistema di database PostgreSQL, l'infrastruttura di GitLab.com non andrebbe lontano, e qualsiasi cosa facciamo per la tolleranza ai guasti in caso di eventuali crash in cui si possono perdere dati. È improbabile che si verifichi una tale catastrofe, ma ci siamo preparati bene e abbiamo accumulato vari meccanismi di backup e replica.
La replica non è un metodo di backup per database (). Ma ora vedremo come ripristinare rapidamente i dati eliminati accidentalmente con la replica ritardata: nella utente per il progetto e ho perso il collegamento con le merge request e i task.
Con la replica ritardata abbiamo ripristinato i dati in sole 1,5 ore. Guarda come è stato.
Ripristino a un momento specifico con PostgreSQL
PostgreSQL ha una funzione integrata che ripristina lo stato del database a un momento specifico. Si chiama (PITR) e utilizza gli stessi meccanismi che mantengono l'attualità della replica: partendo da un'istantanea affidabile dell'intero cluster del database (backup di base), applichiamo una serie di modifiche fino a un momento specifico.
Per utilizzare questa funzione per il backup a freddo, eseguiamo regolarmente un backup di base del database e lo conserviamo in archivio (gli archivi di GitLab risiedono in ). Inoltre, monitoriamo le modifiche allo stato del database, archiviando il log delle scritture anticipate (, WAL). E con tutto ciò possiamo eseguire PITR per il ripristino di emergenza: iniziamo con l'istantanea creata prima dell'errore e applichiamo le modifiche dall'archivio WAL fino al guasto.
Che cos'è la replica ritardata?
La replica ritardata è l'applicazione delle modifiche dal WAL con un ritardo. Cioè, la transazione è avvenuta un'ora X, ma nella replica apparirà con un ritardo d di un'ora X + d.
In PostgreSQL ci sono 2 modi per configurare una replica fisica del database: ripristino dall'archivio e replica in streaming. , in sostanza, funziona come PITR, ma in modo continuo: estraiamo costantemente le modifiche dall'archivio WAL e le applichiamo alla replica. A estrae direttamente il flusso WAL dall'host del database di livello superiore. Preferiamo il ripristino dall'archivio: è più semplice da gestire e ha prestazioni normali che non sono inferiori a quelle del cluster di lavoro.
Come configurare il ripristino ritardato dall'archivio
sono descritte nel file recovery.conf. Esempio:
standby_mode = 'on'
restore_command = ' /usr/bin/envdir /etc/wal-e.d/env /opt/wal-e/bin/wal-e wal-fetch -p 4 "%f" "%p"'
recovery_min_apply_delay = '8h'
recovery_target_timeline = 'latest'Con queste impostazioni abbiamo configurato una replica ritardata con ripristino dall'archivio. Qui si utilizza per estrarre i segmenti WAL (restore_command) dall'archivio, e le modifiche verranno applicate dopo otto ore (recovery_min_apply_delay). La replica seguirà le modifiche della timeline nell'archivio, come ad esempio a causa della gestione dei guasti nel cluster (recovery_target_timeline).
C recovery_min_apply_delay è possibile configurare la replica streaming con ritardo, ma ci sono un paio di insidie relative agli slot di replica, al feedback del backup caldo, ecc. L'archivio WAL consente di evitarle.
Parametro recovery_min_apply_delay è apparso solo in PostgreSQL 9.3. Nelle versioni precedenti, per la replica ritardata era necessario configurare una combinazione di (pg_xlog_replay_pause(), pg_xlog_replay_resume()) o mantenere i segmenti WAL nell'archivio durante il tempo di ritardo.
Come lo fa PostgreSQL?
È interessante vedere come PostgreSQL implementa il ripristino ritardato. Guardiamo a . Viene chiamato dal per ciascun record del WAL.
static bool
recoveryApplyDelay(XLogReaderState *record)
{
uint8 xact_info;
TimestampTz xtime;
long secs;
int microsecs;
/* niente da fare se non è configurato alcun ritardo */
if (recovery_min_apply_delay <= 0)
return false;
/* nessun ritardo viene applicato a un database non ancora consistente */
if (!reachedConsistency)
return false;
/*
* È un record di COMMIT?
*
* Abbiamo deliberatamente scelto di non ritardare gli aborti poiché non hanno effetto su
* MVCC. Già consentiamo la riproduzione di record che non hanno un timestamp,
* quindi c'è già opportunità di problemi causati da conflitti anticipati su
* standby.
* /
if (XLogRecGetRmid(record) != RM_XACT_ID)
return false;
xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
if (xact_info != XLOG_XACT_COMMIT &&
xact_info != XLOG_XACT_COMMIT_PREPARED)
return false;
if (!getRecordTimestamp(record, &xtime))
return false;
recoveryDelayUntilTime =
TimestampTzPlusMilliseconds(xtime, recovery_min_apply_delay);
/*
* Esci senza armare il latch se è già passato il tempo per applicare questo
* record
* /
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// Accorciato:
// Usa WaitLatch fino a raggiungere recoveryDelayUntilTime
// e poi
break;
}
return true;
}Il punto è che il ritardo è basato sul tempo fisico, registrato nel timestamp del commit della transazione (xtime). Come si può vedere, il ritardo si applica solo ai commit e non tocca altri record: tutte le modifiche vengono applicate direttamente, mentre il commit viene rinviato, quindi vedremo le modifiche solo dopo il ritardo configurato.
Come utilizzare una replica ritardata per il recupero dei dati
Supponiamo di avere in produzione un cluster di database e una replica con un ritardo di otto ore. Vediamo come recuperare i dati usando come esempio .
Quando abbiamo saputo del problema, abbiamo per la replica ritardata:
SELECT pg_xlog_replay_pause();Con la pausa non c'era il rischio che la replica ripetesse la richiesta DELETE. Utile se serve tempo per capire tutto.
Il punto è che la replica ritardata deve arrivare al momento prima della richiesta DELETE. Sapevamo più o meno il tempo fisico della cancellazione. Abbiamo rimosso recovery_min_apply_delay e aggiunto recovery_target_time in recovery.conf. Così la replica raggiunge il momento desiderato senza ritardi:
recovery_target_time = '2018-10-12 09:25:00+00'Con i timestamp è meglio ridurre il superfluo per non sbagliare. Tuttavia, quanto maggiore è la riduzione, più dati perdiamo. In ogni caso, se saltiamo la richiesta DELETE, tutto verrà di nuovo eliminato e dovremo ricominciare daccapo (o prendere un backup a freddo per il PITR).
Abbiamo riavviato l'istanza Postgres in attesa e i segmenti WAL sono stati ripetuti fino all'orario indicato. È possibile monitorare i progressi a questo stadio con la seguente query:
SELECT
-- posizione attuale nel WAL
pg_last_xlog_replay_location(),
-- timestamp della transazione corrente (stato della replica)
pg_last_xact_replay_timestamp(),
-- tempo fisico attuale
now(),
-- quantità di tempo ancora da applicare fino al raggiungimento del recovery_target_time
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;Se il timestamp non cambia più, il ripristino è completato. Puoi configurare l'azione , per chiudere, promuovere o sospendere l'istanza dopo il ripristino (di default viene sospesa).
Il database è tornato a uno stato precedente a quella famigerata richiesta. Ora puoi, ad esempio, esportare i dati. Abbiamo esportato i dati rimossi sul collegamento e tutte le associazioni con il lavoro e le merge request e li abbiamo trasferiti nel database di lavoro. Se la perdita è ampia, puoi semplicemente promuovere la replica e usarla come principale. Ma in tal caso perderai tutte le modifiche dopo il momento fino a cui siamo tornati.
È meglio usare gli ID delle transazioni invece dei timestamp. È utile registrare questi ID, ad esempio, per gli operatori DDL (tipo , ma la situazione con), tramite log_statements = 'ddl'. Se avessimo l'ID della transazione, avremmo preso recovery_target_xid e avremmo eseguito tutte fino alla transazione prima della richiesta. DELETE.
Tornare al lavoro è molto semplice: rimuovi tutte le modifiche da recovery.conf e riavvia Postgres. Presto nella replica apparirà di nuovo un ritardo di otto ore e saremo pronti per future sgradevolezze.
Vantaggi del ripristino
Con una replica in attesa, non è necessario ripristinare per ore l'intero snapshot dall'archivio. Ci vogliono, ad esempio, cinque ore per estrarre l'intero backup base da 2 TB. E poi dovremo applicare tutto il WAL giornaliero per ripristinare lo stato desiderato (nel peggiore dei casi).
Una replica in attesa è migliore di un backup a freddo per due motivi:
- Non è necessario estrarre l'intero backup base dall'archivio.
- C'è una finestra fissa di otto ore di segmenti WAL da ripetere.
Inoltre, controlliamo costantemente se è possibile effettuare un PITR dal WAL e noteremmo rapidamente eventuali danni o altri problemi con l'archivio WAL, monitorando il ritardo della replica in attesa.
In questo esempio, abbiamo impiegato 50 minuti per il ripristino, quindi la velocità era di 110 GB di dati WAL all'ora (l'archivio all'epoca era ancora su ). Abbiamo risolto il problema e ripristinato i dati in 1,5 ore.
Risultati: dove è utile la replica differita (e dove no)
Utilizza la replica differita come mezzo di pronto soccorso, se hai perso accidentalmente dei dati e ti sei accorto di questo problema entro il ritardo impostato.
Ma ricorda: la replica non è un backup.
Il backup e la replica hanno obiettivi diversi. Un backup freddo è utile se hai fatto accidentalmente DELETE o , ma la situazione con. Effettuamo un backup da un archivio freddo e ripristiniamo lo stato precedente della tabella o dell'intera base di dati. Ma in questo caso la richiesta , ma la situazione con viene quasi istantaneamente replicata in tutte le repliche nel cluster operativo, quindi la replica normale non aiuterà. La replica stessa mantiene il database accessibile quando vengono disattivati server singoli e distribuisce il carico.
Anche con la replica differita, a volte abbiamo davvero bisogno di un backup freddo in un luogo sicuro, nel caso in cui si verifichi un guasto del data center, un danno nascosto o altri eventi che non noti immediatamente. Qui una semplice replica non è sufficiente.
Nota. Su Attualmente proteggiamo solo a livello di sistema contro la perdita di dati e non ripristiniamo i dati a livello utente.
Fonte: habr.com
