Kako smo uporabili leno replikacijo za obnovitev po katastrofi s PostgreSQL

Kako smo uporabili leno replikacijo za obnovitev po katastrofi s PostgreSQL
Replikacija ni varnostna kopija. ali ne? Tukaj je opisano, kako smo uporabili odloženo podvajanje za obnovitev po nenamernem brisanju bližnjic.

Strokovnjaki za infrastrukturo Za delo je odgovoren GitLab GitLab.com - največja instanca GitLab v naravi. S 3 milijoni uporabnikov in skoraj 7 milijoni projektov je eno največjih odprtokodnih spletnih mest SaaS z namensko arhitekturo. Brez baze podatkov PostgreSQL infrastruktura GitLab.com ne bo šla daleč in kaj počnemo, da zagotovimo toleranco na napake v primeru kakršnih koli okvar, ko lahko pride do izgube podatkov. Malo verjetno je, da se bo takšna katastrofa zgodila, vendar smo dobro pripravljeni in založeni z različnimi mehanizmi za varnostno kopiranje in replikacijo.

Replikacija ni sredstvo za varnostno kopiranje baz podatkov (glej spodaj). Zdaj pa bomo videli, kako hitro obnoviti pomotoma izbrisane podatke z uporabo lene replikacije: on GitLab.com Uporabnik izbrisal bližnjico za projekt gitlab-ce in izgubljene povezave z zahtevami za spajanje in opravili.

Z odloženo repliko smo obnovili podatke v samo 1,5 ure. Poglej, kako se je zgodilo.

Obnovitev v času s PostgreSQL

PostgreSQL ima vgrajeno funkcijo, ki obnovi stanje baze podatkov na določeno časovno točko. Se imenuje Obnovitev v trenutku (PITR) in uporablja enake mehanizme, ki ohranjajo repliko posodobljeno: začenši z zanesljivim posnetkom celotne gruče baze podatkov (osnovna varnostna kopija), uporabimo niz sprememb stanja do določene točke v času.

Za uporabo te funkcije za hladno varnostno kopiranje redno izdelujemo osnovno varnostno kopijo baze podatkov in jo shranimo v arhiv (arhivi GitLab živijo v Googlova shramba v oblaku). Spremembe stanja baze podatkov spremljamo tudi z arhiviranjem vnaprejšnjega zapisa (dnevnik vnaprejšnjega pisanja, WAL). In ko je vse to na mestu, lahko naredimo PITR za obnovitev po katastrofi: začnemo s posnetkom, narejenim pred napako, in uporabimo spremembe iz arhiva WAL do napake.

Kaj je odložena replikacija?

Leno podvajanje je uporaba sprememb iz WAL z zamikom. To pomeni, da se je transakcija zgodila v eni uri X, vendar se bo v replici pojavil z zamikom d v eni uri X + d.

PostgreSQL ima dva načina za nastavitev fizične replike baze podatkov: obnovitev varnostne kopije in pretočno replikacijo. Obnavljanje iz arhiva, v bistvu deluje kot PITR, vendar neprekinjeno: nenehno pridobivamo spremembe iz arhiva WAL in jih uporabljamo za repliko. A pretočna replikacija neposredno pridobi tok WAL iz gostitelja baze podatkov navzgor. Raje imamo arhivsko obnovitev - lažje jo je upravljati in ima normalno zmogljivost, ki sledi produkcijskemu grozdu.

Kako nastaviti odloženo obnovitev iz arhiva

Možnosti obnovitve opisano v datoteki recovery.conf... Primer:

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'

S temi parametri smo konfigurirali odloženo repliko z obnovitvijo varnostne kopije. Tukaj se uporablja wal-e za ekstrahiranje segmentov WAL (restore_command) iz arhiva, spremembe pa bodo uveljavljene po osmih urah (recovery_min_apply_delay). Replika bo opazovala spremembe časovnice v arhivu, na primer zaradi preklopa gruče (recovery_target_timeline).

С recovery_min_apply_delay Pretočno replikacijo lahko nastavite z zamikom, vendar je tukaj nekaj pasti, ki so povezane z režami za replikacijo, povratnimi informacijami v vročem stanju pripravljenosti itd. Arhiv WAL vam omogoča, da se jim izognete.

Parameter recovery_min_apply_delay pojavil šele v PostgreSQL 9.3. V prejšnjih različicah morate za odloženo podvajanje konfigurirati kombinacijo funkcije upravljanja obnovitve (pg_xlog_replay_pause(), pg_xlog_replay_resume()) ali obdržite segmente WAL v arhivu za čas zakasnitve.

Kako to počne PostgreSQL?

Zanimivo je videti, kako PostgreSQL izvaja leno obnovitev. Poglejmo si recoveryApplyDelay(XlogReaderState). Kliče se iz glavna ponavljajoča se zanka za vsak vnos iz 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;
}

Bistvo je, da zakasnitev temelji na fizičnem času, zabeleženem v časovnem žigu izvršitve transakcije (xtime). Kot lahko vidite, zakasnitev velja samo za objave in ne vpliva na druge vnose - vse spremembe se uporabijo neposredno, potrditev pa je zakasnjena, zato bomo spremembe videli šele po konfigurirani zakasnitvi.

Kako uporabiti odloženo repliko za obnovitev podatkov

Recimo, da imamo gručo baze podatkov in repliko z osemurno zamudo v proizvodnji. Poglejmo, kako obnoviti podatke na primeru nenamerno brisanje bližnjic.

Ko smo izvedeli za težavo, smo obnovitev arhiva je bila zaustavljena za odloženo repliko:

SELECT pg_xlog_replay_pause();

S premorom nismo imeli nobenega tveganja, da bi replika ponovila zahtevo DELETE. Uporabna stvar, če potrebujete čas, da vse ugotovite.

Bistvo je, da mora odložena replika doseči trenutek pred zahtevo DELETE. Fizični čas odstranitve smo približno poznali. Izbrisali smo recovery_min_apply_delay in dodal recovery_target_time в recovery.conf. Tako replika pride v pravi trenutek brez zamude:

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

Pri časovnih žigih je bolje zmanjšati presežek, da ne zamudite. Res je, večje kot je zmanjšanje, več podatkov izgubimo. Še enkrat, če zamudimo zahtevo DELETE, bo vse znova izbrisano in morali boste začeti znova (ali celo narediti hladno varnostno kopijo za PITR).

Znova smo zagnali odloženi primerek Postgres in segmenti WAL so se ponavljali do določenega časa. Na tej stopnji lahko spremljate napredek tako, da vprašate:

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;

Če se časovni žig ne spremeni več, je obnovitev končana. Ukrep je mogoče prilagoditi recovery_target_actionda zaprete, povišate ali začasno ustavite primerek po ponovnem poskusu (privzeto je začasno ustavljen).

Baza podatkov se je vrnila v stanje pred to nesrečno zahtevo. Zdaj lahko na primer izvozite podatke. Izvozili smo podatke o izbrisanih oznakah in vse povezave do težav in zahtev za združitev ter jih premaknili v produkcijsko bazo podatkov. Če so izgube velikega obsega, lahko preprosto promovirate repliko in jo uporabite kot glavno. Toda potem bodo vse spremembe po točki, do katere smo si opomogli, izgubljene.

Namesto časovnih žigov je bolje uporabiti ID-je transakcij. Te ID-je je koristno zabeležiti na primer za stavke DDL (kot npr DROP TABLE), z uporabo log_statements = 'ddl'. Če bi imeli ID transakcije, bi vzeli recovery_target_xid in opravil vse do transakcije pred zahtevo DELETE.

Vrnitev na delo je zelo preprosta: odstranite vse spremembe iz recovery.conf in znova zaženite Postgres. Replika bo kmalu spet imela osemurno zamudo in pripravljeni smo na prihodnje težave.

Prednosti okrevanja

Z odloženo repliko namesto hladne varnostne kopije vam ni treba porabiti ur za obnavljanje celotne slike iz arhiva. Na primer, potrebujemo pet ur, da pridobimo celotno osnovno varnostno kopijo 2 TB. In potem morate še vedno uporabiti celoten dnevni WAL, da se vrnete v želeno stanje (v najslabšem primeru).

Odložena replika je boljša od hladne varnostne kopije na dva načina:

  1. Iz arhiva ni treba odstraniti celotne osnovne varnostne kopije.
  2. Obstaja fiksno osemurno okno segmentov WAL, ki jih je treba ponoviti.

Prav tako nenehno preverjamo, ali je mogoče narediti PITR iz WAL, in hitro bi opazili poškodbe ali druge težave z arhivom WAL, če bi spremljali zaostajanje odložene replike.

V tem primeru smo za obnovitev potrebovali 50 minut, kar pomeni, da je bila hitrost 110 GB podatkov WAL na uro (arhiv je bil še vedno vklopljen AWS S3). Skupno smo rešili težavo in obnovili podatke v 1,5 ure.

Rezultati: kje je odložena replika uporabna (in kje ne)

Uporabite zakasnjeno podvajanje kot prvo pomoč, če ste pomotoma izgubili podatke in opazili to težavo znotraj konfigurirane zakasnitve.

Vendar ne pozabite: replikacija ni varnostna kopija.

Varnostno kopiranje in podvajanje imata različne namene. Hladna varnostna kopija vam bo prav prišla, če ste jo pomotoma naredili DELETE ali DROP TABLE. Naredimo varnostno kopijo iz hladilnice in povrnemo prejšnje stanje tabele ali celotne baze podatkov. A hkrati zahteva DROP TABLE se skoraj takoj reproducira v vseh replikah v delujoči gruči, zato navadna replikacija tukaj ne bo pomagala. Replikacija sama ob oddaji posameznih strežnikov ohranja na voljo bazo podatkov in porazdeli obremenitev.

Tudi z odloženo repliko včasih resnično potrebujemo hladno varnostno kopijo na varnem mestu, če pride do okvare podatkovnega centra, skrite poškodbe ali drugih dogodkov, ki niso takoj opazni. Replikacija sama po sebi tukaj ni uporabna.

Obvestilo. Na GitLab.com Trenutno ščitimo pred izgubo podatkov samo na sistemski ravni in ne obnavljamo podatkov na uporabniški ravni.

Vir: www.habr.com

Dodaj komentar