Com hem utilitzat la replicació mandrosa per a la recuperació de desastres amb PostgreSQL

Com hem utilitzat la replicació mandrosa per a la recuperació de desastres amb PostgreSQL
La replicació no és una còpia de seguretat. O no? A continuació s'explica com hem utilitzat la rèplica diferida per recuperar-nos de la supressió accidental de dreceres.

Especialistes en infraestructures GitLab és responsable del treball GitLab.com - la instància de GitLab més gran de la natura. Amb 3 milions d'usuaris i prop de 7 milions de projectes, és un dels llocs SaaS de codi obert més grans amb una arquitectura dedicada. Sense el sistema de bases de dades PostgreSQL, la infraestructura de GitLab.com no anirà lluny, i què estem fent per garantir la tolerància a errors en cas de fallades quan es poden perdre dades. És poc probable que es produeixi un desastre així, però estem ben preparats i proveïts de diversos mecanismes de còpia de seguretat i replicació.

La replicació no és un mitjà per fer una còpia de seguretat de bases de dades (vegeu més avall). Però ara veurem com recuperar ràpidament les dades esborrades accidentalment mitjançant la replicació mandrosa: activat GitLab.com l’usuari esborrat la drecera pel projecte gitlab-ce i s'han perdut connexions amb sol·licituds i tasques de combinació.

Amb una rèplica ajornada, vam recuperar les dades en només 1,5 hores. Mira com va passar.

Recuperació puntual amb PostgreSQL

PostgreSQL té una funció integrada que restaura l'estat d'una base de dades a un moment concret. Es diu Recuperació puntual (PITR) i utilitza els mateixos mecanismes que mantenen la rèplica actualitzada: a partir d'una instantània fiable de tot el clúster de bases de dades (còpia de seguretat base), apliquem una sèrie de canvis d'estat fins a un moment determinat.

Per utilitzar aquesta funció per a una còpia de seguretat en fred, regularment fem una còpia de seguretat bàsica de la base de dades i la desem en un arxiu (els arxius de GitLab viuen a Emmagatzematge al núvol de Google). També supervisem els canvis en l'estat de la base de dades arxivant el registre d'escriptura anticipada (registre d'escriptura anticipada, WAL). I amb tot això al seu lloc, podem fer un PITR per a la recuperació de desastres: començant per la instantània presa abans de la fallada, i aplicant els canvis des de l'arxiu WAL fins a la fallada.

Què és la replicació diferida?

La replicació mandrosa és l'aplicació de canvis de WAL amb un retard. És a dir, la transacció es va produir en una hora X, però apareixerà a la rèplica amb un retard d en una hora X + d.

PostgreSQL té 2 maneres de configurar una rèplica de base de dades física: recuperació de còpies de seguretat i replicació en temps real. Restauració des d'un arxiu, funciona bàsicament com PITR, però contínuament: recuperem constantment els canvis de l'arxiu WAL i els apliquem a la rèplica. A replicació en streaming recupera directament el flux WAL de l'amfitrió de la base de dades amunt. Preferim la recuperació d'arxius: és més fàcil de gestionar i té un rendiment normal que es manté al dia amb el clúster de producció.

Com configurar la recuperació retardada d'un arxiu

Opcions de recuperació descrit a l'arxiu recovery.conf... Exemple:

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'

Amb aquests paràmetres, vam configurar una rèplica diferida amb recuperació de còpia de seguretat. Aquí s'utilitza wal-e per extreure segments WAL (restore_command) de l'arxiu, i els canvis s'aplicaran al cap de vuit hores (recovery_min_apply_delay). La rèplica vigilarà els canvis de la línia de temps a l'arxiu, per exemple a causa d'una migració per error del clúster (recovery_target_timeline).

С recovery_min_apply_delay Podeu configurar la rèplica en streaming amb un retard, però aquí hi ha un parell d'errors relacionats amb les ranures de rèplica, els comentaris en espera activa, etc. L'arxiu WAL permet evitar-los.

Paràmetre recovery_min_apply_delay només apareixia a PostgreSQL 9.3. En versions anteriors, per a la rèplica diferida cal configurar la combinació funcions de gestió de recuperació (pg_xlog_replay_pause(), pg_xlog_replay_resume()) o mantenir els segments WAL a l'arxiu durant la durada del retard.

Com ho fa PostgreSQL?

És interessant veure com PostgreSQL implementa la recuperació mandrosa. Mirem-ho recoveryApplyDelay(XlogReaderState). Es diu des de bucle de repetició principal per a cada entrada de WAL.

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, &microsecs);
    if (secs <= 0 && microsecs <= 0)
        return false;

    while (true)
    {
        // Shortened:
        // Use WaitLatch until we reached recoveryDelayUntilTime
        // and then
        break;
    }
    return true;
}

La conclusió és que el retard es basa en el temps físic registrat a la marca de temps de la transacció (xtime). Com podeu veure, el retard només s'aplica a les confirmacions i no afecta altres entrades: tots els canvis s'apliquen directament i la confirmació es retarda, de manera que només veurem els canvis després del retard configurat.

Com utilitzar una rèplica retardada per restaurar dades

Suposem que tenim un clúster de bases de dades i una rèplica amb un retard de vuit hores en la producció. Vegem com recuperar dades amb un exemple eliminant dreceres accidentalment.

Quan vam conèixer el problema, nosaltres la restauració de l'arxiu s'ha posat en pausa per a una rèplica diferida:

SELECT pg_xlog_replay_pause();

Amb una pausa, no teníem cap risc que la rèplica repeteixi la sol·licitud DELETE. Una cosa útil si necessiteu temps per esbrinar-ho tot.

La qüestió és que la rèplica diferida ha d'arribar al moment anterior a la sol·licitud DELETE. Sabíem aproximadament l'hora física de l'eliminació. Hem esborrat recovery_min_apply_delay i afegit recovery_target_time в recovery.conf. Així és com la rèplica arriba al moment adequat sense demora:

recovery_target_time = '2018-10-12 09:25:00+00'

Amb segells de temps, és millor reduir l'excés per no perdre's. És cert que com més gran sigui la disminució, més dades perdem. De nou, si ens perdem la petició DELETE, tot s'esborrarà de nou i hauràs de començar de nou (o fins i tot fer una còpia de seguretat en fred per a PITR).

Vam reiniciar la instància de Postgres diferit i els segments WAL es van repetir fins a l'hora especificada. Podeu fer un seguiment del progrés en aquesta etapa preguntant:

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;

Si la marca de temps ja no canvia, la recuperació s'ha completat. L'acció es pot personalitzar recovery_target_actionper tancar, promocionar o aturar la instància després de tornar-ho a intentar (està suspès per defecte).

La base de dades va tornar al seu estat abans d'aquella desafortunada sol·licitud. Ara podeu, per exemple, exportar dades. Vam exportar les dades de l'etiqueta suprimides i tots els enllaços a problemes i sol·licituds de combinació i les vam traslladar a la base de dades de producció. Si les pèrdues són a gran escala, simplement podeu promocionar la rèplica i utilitzar-la com a principal. Però aleshores es perdran tots els canvis després del punt al qual ens hem recuperat.

En lloc de segells de temps, és millor utilitzar identificadors de transacció. És útil registrar aquests identificadors, per exemple, per a sentències DDL (com ara DROP TABLE), mitjançant l'ús de log_statements = 'ddl'. Si tinguéssim un identificador de transacció, ho prendríem recovery_target_xid i va executar-ho tot fins a la transacció abans de la sol·licitud DELETE.

Tornar a la feina és molt senzill: elimina tots els canvis de recovery.conf i reinicieu Postgres. La rèplica aviat tornarà a tenir un retard de vuit hores i estem preparats per a problemes futurs.

Beneficis de recuperació

Amb una rèplica diferida en lloc d'una còpia de seguretat en fred, no haureu de passar hores restaurant tota la imatge des de l'arxiu. Per exemple, triguem cinc hores a obtenir tota la còpia de seguretat bàsica de 2 TB. I després encara cal aplicar tot el WAL diari per recuperar l'estat desitjat (en el pitjor dels casos).

Una rèplica diferida és millor que una còpia de seguretat en fred de dues maneres:

  1. No cal eliminar tota la còpia de seguretat bàsica de l'arxiu.
  2. Hi ha una finestra fixa de vuit hores de segments WAL que s'ha de repetir.

També comprovem constantment si és possible fer un PITR des de WAL, i ràpidament detectaríem corrupció o altres problemes amb l'arxiu WAL controlant el retard de la rèplica ajornada.

En aquest exemple, vam trigar 50 minuts a restaurar-nos, és a dir, la velocitat era de 110 GB de dades WAL per hora (l'arxiu encara estava activat AWS S3). En total, vam resoldre el problema i vam recuperar les dades en 1,5 hores.

Resultats: on una rèplica diferida és útil (i on no ho és)

Utilitzeu la replicació retardada com a primers auxilis si heu perdut dades accidentalment i heu detectat aquest problema amb el retard configurat.

Però tingueu en compte: la rèplica no és una còpia de seguretat.

La còpia de seguretat i la replicació tenen finalitats diferents. Una còpia de seguretat en fred serà útil si ho feu per accident DELETE o DROP TABLE. Fem una còpia de seguretat des de l'emmagatzematge en fred i restaurem l'estat anterior de la taula o de tota la base de dades. Però al mateix temps la petició DROP TABLE es reprodueix gairebé a l'instant en totes les rèpliques del clúster de treball, de manera que la rèplica ordinària no ajudarà aquí. La pròpia replicació manté la base de dades disponible quan es lloguen servidors individuals i distribueix la càrrega.

Fins i tot amb una rèplica ajornada, de vegades necessitem una còpia de seguretat en fred en un lloc segur si es produeix una fallada del centre de dades, danys ocults o altres esdeveniments que no es noten immediatament. La replicació sola no serveix aquí.

Nota. Encès GitLab.com Actualment només protegim contra la pèrdua de dades a nivell de sistema i no recuperem dades a nivell d'usuari.

Font: www.habr.com

Afegeix comentari