La replica non è un backup. O no? Ecco come abbiamo utilizzato la replica differita per ripristinare l'eliminazione accidentale dei collegamenti.
La replica non è un mezzo per eseguire il backup dei database (gitlab-ce
Con una replica differita, abbiamo recuperato i dati in appena 1,5 ore. Guarda come è successo.
Recupero puntuale nel tempo con PostgreSQL
PostgreSQL ha una funzione incorporata che ripristina lo stato di un database a un momento specifico. È chiamato
Per utilizzare questa funzionalità per il backup a freddo, eseguiamo regolarmente un backup di base del database e lo memorizziamo in un archivio (gli archivi GitLab risiedono in
Cos'è la replica differita?
La replica lenta è l'applicazione delle modifiche da WAL con un ritardo. Cioè, la transazione è avvenuta in un'ora X
, ma apparirà nella replica con un ritardo d
nel tempo X + d
.
PostgreSQL ha 2 modi per configurare una replica fisica del database: ripristino del backup e replica in streaming.
Come impostare il ripristino ritardato da un archivio
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 questi parametri abbiamo configurato una replica differita con ripristino del backup. Qui è usato restore_command
) dall'archivio e le modifiche verranno applicate dopo otto ore (recovery_min_apply_delay
). La replica controllerà le modifiche della sequenza temporale nell'archivio, ad esempio a causa di un failover del cluster (recovery_target_timeline
).
С recovery_min_apply_delay
È possibile impostare la replica dello streaming con un ritardo, ma in questo caso sono presenti un paio di insidie correlate agli slot di replica, al feedback hot standby e così via. L'archivio WAL ti consente di evitarli.
Parametro recovery_min_apply_delay
è apparso solo in PostgreSQL 9.3. Nelle versioni precedenti, per la replica differita era necessario configurare la combinazione pg_xlog_replay_pause(), pg_xlog_replay_resume()
) o conservare i segmenti WAL in archivio per tutta la durata del ritardo.
Come fa PostgreSQL a farlo?
È interessante vedere come PostgreSQL implementa il recupero lento. Guardiamo recoveryApplyDelay(XlogReaderState)
static bool
recoveryApplyDelay(XLogReaderState *record)
{
uint8 xact_info;
TimestampTz xtime;
long secs;
int microsecs;
/* nothing to do if no delay configured */
if (recovery_min_apply_delay <= 0)
return false;
/* no delay is applied on a database not yet consistent */
if (!reachedConsistency)
return false;
/*
* Is it a COMMIT record?
*
* We deliberately choose not to delay aborts since they have no effect on
* MVCC. We already allow replay of records that don't have a timestamp,
* so there is already opportunity for issues caused by early conflicts on
* standbys.
*/
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);
/*
* Exit without arming the latch if it's already past time to apply this
* record
*/
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// Shortened:
// Use WaitLatch until we reached recoveryDelayUntilTime
// and then
break;
}
return true;
}
La conclusione è che il ritardo si basa sul tempo fisico registrato nel timestamp di commit della transazione (xtime
). Come puoi vedere, il ritardo si applica solo ai commit e non influisce sulle altre voci: tutte le modifiche vengono applicate direttamente e il commit viene ritardato, quindi vedremo le modifiche solo dopo il ritardo configurato.
Come utilizzare una replica ritardata per ripristinare i dati
Supponiamo di avere un cluster di database e una replica con un ritardo di produzione di otto ore. Vediamo come recuperare i dati utilizzando un esempio
Quando abbiamo appreso del problema, noi
SELECT pg_xlog_replay_pause();
Con una pausa, non c'era rischio che la replica ripetesse la richiesta DELETE
. Una cosa utile se hai bisogno di tempo per capire tutto.
Il punto è che la replica differita deve arrivare al momento precedente alla richiesta DELETE
. Conoscevamo approssimativamente il momento fisico della rimozione. Abbiamo cancellato recovery_min_apply_delay
e aggiunse recovery_target_time
в recovery.conf
. Ecco come la replica raggiunge il momento giusto senza indugio:
recovery_target_time = '2018-10-12 09:25:00+00'
Con i timestamp è meglio ridurre la franchigia per non perderla. È vero, maggiore è la diminuzione, più dati perdiamo. Ancora una volta, se perdiamo la richiesta DELETE
, tutto verrà nuovamente eliminato e dovrai ricominciare da capo (o anche eseguire un backup a freddo per PITR).
Abbiamo riavviato l'istanza Postgres posticipata e i segmenti WAL sono stati ripetuti fino all'ora specificata. Puoi monitorare i progressi in questa fase chiedendo:
SELECT
-- current location in WAL
pg_last_xlog_replay_location(),
-- current transaction timestamp (state of the replica)
pg_last_xact_replay_timestamp(),
-- current physical time
now(),
-- the amount of time still to be applied until recovery_target_time has been reached
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;
Se il timestamp non cambia più, il ripristino è completo. L'azione può essere personalizzata recovery_target_action
Il database è tornato allo stato precedente a quella sfortunata richiesta. Ora puoi, ad esempio, esportare i dati. Abbiamo esportato i dati delle etichette cancellate e tutti i collegamenti ai problemi e alle richieste di unione e li abbiamo spostati nel database di produzione. Se le perdite sono su larga scala, puoi semplicemente promuovere la replica e utilizzarla come principale. Ma poi tutti i cambiamenti successivi al punto in cui ci siamo ripresi andranno perduti.
Invece dei timestamp, è meglio utilizzare gli ID delle transazioni. È utile registrare questi ID, ad esempio, per le istruzioni DDL (come DROP TABLE
), usando log_statements = 'ddl'
. Se avessimo un ID transazione, prenderemmo recovery_target_xid
e ho eseguito tutto fino alla transazione prima della richiesta DELETE
.
Tornare al lavoro è molto semplice: rimuovi tutte le modifiche da recovery.conf
e riavvia Postgres. Presto la replica avrà di nuovo un ritardo di otto ore e siamo preparati per problemi futuri.
Vantaggi del recupero
Con una replica differita invece di un backup a freddo, non devi dedicare ore a ripristinare l'intera immagine dall'archivio. Ad esempio, sono necessarie cinque ore per ottenere l'intero backup di base da 2 TB. E poi devi ancora applicare l'intero WAL giornaliero per ripristinare lo stato desiderato (nel peggiore dei casi).
Una replica differita è migliore di un backup a freddo in due modi:
- Non è necessario rimuovere l'intero backup di base dall'archivio.
- Esiste una finestra fissa di otto ore di segmenti WAL che devono essere ripetuti.
Inoltre controlliamo costantemente se è possibile creare un PITR da WAL e noteremo rapidamente corruzione o altri problemi con l'archivio WAL monitorando il ritardo della replica differita.
In questo esempio, ci sono voluti 50 minuti per il ripristino, il che significa che la velocità era di 110 GB di dati WAL all'ora (l'archivio era ancora attivo
Risultati: dove è utile una replica differita (e dove non lo è)
Utilizzare la replica ritardata come primo soccorso se si perdono accidentalmente dati e si nota questo problema entro il ritardo configurato.
Ma tieni presente: la replica non è un backup.
Il backup e la replica hanno scopi diversi. Un backup a freddo tornerà utile se lo hai fatto accidentalmente DELETE
o DROP TABLE
. Effettuiamo un backup dal cold storage e ripristiniamo lo stato precedente della tabella o dell'intero database. Ma allo stesso tempo la richiesta DROP TABLE
viene riprodotto quasi istantaneamente in tutte le repliche sul cluster di lavoro, quindi la replica ordinaria non sarà d'aiuto in questo caso. La replica stessa mantiene il database disponibile quando i singoli server vengono affittati e distribuisce il carico.
Anche con una replica differita, a volte abbiamo davvero bisogno di un backup a freddo in un luogo sicuro se si verificano un guasto del data center, un danno nascosto o altri eventi non immediatamente evidenti. La sola replica non è di alcuna utilità in questo caso.
Nota. su
Fonte: habr.com