Kako smo koristili odgođenu replikaciju za oporavak od katastrofe s PostgreSQL-om

Kako smo koristili odgođenu replikaciju za oporavak od katastrofe s PostgreSQL-om
Replikacija nije sigurnosna kopija. Ili ne? Evo kako smo koristili odgođenu replikaciju za oporavak od slučajnog brisanja prečaca.

Stručnjaci za infrastrukturu Za rad je odgovoran GitLab GitLab.com - najveća GitLab instanca u prirodi. S 3 milijuna korisnika i gotovo 7 milijuna projekata, to je jedno od najvećih SaaS mjesta otvorenog koda s namjenskom arhitekturom. Bez PostgreSQL sustava baza podataka GitLab.com infrastruktura neće daleko dogurati, a što radimo kako bismo osigurali toleranciju na greške u slučaju bilo kakvih kvarova kada se podaci mogu izgubiti. Malo je vjerojatno da će se takva katastrofa dogoditi, ali mi smo dobro pripremljeni i opskrbljeni raznim mehanizmima za sigurnosno kopiranje i replikaciju.

Replikacija nije sredstvo sigurnosne kopije baza podataka (pogledajte dolje). Ali sada ćemo vidjeti kako brzo oporaviti slučajno izbrisane podatke pomoću lijene replikacije: on GitLab.com korisnik izbrisao prečac za projekt gitlab-ce i izgubljene veze sa zahtjevima za spajanje i zadacima.

S odgođenom replikom vratili smo podatke za samo 1,5 sat. Pogledajte kako se to dogodilo.

Oporavak točke u vremenu uz PostgreSQL

PostgreSQL ima ugrađenu funkciju koja vraća stanje baze podataka u određeno vrijeme. To se zove Oporavak u određenom trenutku (PITR) i koristi iste mehanizme koji održavaju repliku ažurnom: počevši od pouzdane snimke cijelog klastera baze podataka (bazna sigurnosna kopija), primjenjujemo niz promjena stanja do određene vremenske točke.

Da bismo koristili ovu značajku za hladno sigurnosno kopiranje, redovito izrađujemo osnovnu sigurnosnu kopiju baze podataka i pohranjujemo je u arhivu (GitLab arhive žive u Google pohrana u oblaku). Promjene u stanju baze podataka pratimo i arhiviranjem zapisnika unaprijed (write-ahead).zapisnik unaprijed, WAL). I sa svim tim na mjestu, možemo napraviti PITR za oporavak od katastrofe: počevši sa snimkom snimljenom prije kvara i primjenom promjena iz WAL arhive do kvara.

Što je odgođena replikacija?

Lijena replikacija je primjena promjena iz WAL-a s odgodom. Odnosno, transakcija se dogodila za sat vremena X, ali će se u replici pojaviti s odgodom d za sat vremena X + d.

PostgreSQL ima 2 načina za postavljanje fizičke replike baze podataka: oporavak sigurnosne kopije i strujanje replikacije. Vraćanje iz arhive, u biti radi kao PITR, ali kontinuirano: stalno dohvaćamo promjene iz WAL arhive i primjenjujemo ih na repliku. A strujanje replikacije izravno dohvaća WAL tok s hosta uzvodne baze podataka. Preferiramo arhivski oporavak - njime je lakše upravljati i ima normalnu izvedbu koja ide u korak s proizvodnim klasterom.

Kako postaviti odgođeni oporavak iz arhive

Mogućnosti oporavka opisano u datoteci recovery.conf, Primjer:

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 ovim smo parametrima konfigurirali odgođenu repliku s oporavkom sigurnosne kopije. Ovdje se koristi wal-e za izdvajanje WAL segmenata (restore_command) iz arhive, a promjene će biti primijenjene nakon osam sati (recovery_min_apply_delay). Replika će paziti na promjene vremenske trake u arhivi, na primjer zbog prestanka rada klastera (recovery_target_timeline).

С recovery_min_apply_delay Možete postaviti strujanje replikacije s odgodom, ali ovdje postoji nekoliko zamki koje se odnose na utore za replikaciju, povratne informacije o vrućem stanju pripravnosti i tako dalje. WAL arhiva omogućuje vam da ih izbjegnete.

Parametar recovery_min_apply_delay pojavio se tek u PostgreSQL 9.3. U prethodnim verzijama, za odgođenu replikaciju trebate konfigurirati kombinaciju funkcije upravljanja oporavkom (pg_xlog_replay_pause(), pg_xlog_replay_resume()) ili držite WAL segmente u arhivi tijekom trajanja odgode.

Kako PostgreSQL to radi?

Zanimljivo je vidjeti kako PostgreSQL implementira lijeni oporavak. Pogledajmo recoveryApplyDelay(XlogReaderState). Poziva se iz glavna ponavljajuća petlja za svaki unos iz WAL-a.

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;
}

Zaključak je da se odgoda temelji na fizičkom vremenu zabilježenom u vremenskoj oznaci izvršenja transakcije (xtime). Kao što vidite, odgoda se odnosi samo na predaje i ne utječe na druge unose - sve se promjene primjenjuju izravno, a predaja je odgođena, tako da ćemo promjene vidjeti tek nakon konfigurirane odgode.

Kako koristiti odgođenu repliku za vraćanje podataka

Recimo da imamo klaster baze podataka i repliku s osmosatnim kašnjenjem u proizvodnji. Pogledajmo kako oporaviti podatke pomoću primjera slučajno brisanje prečaca.

Kada smo saznali za problem, mi restauracija arhive je pauzirana za odgođenu repliku:

SELECT pg_xlog_replay_pause();

Uz pauzu, nismo imali rizika da će replika ponoviti zahtjev DELETE. Korisna stvar ako vam treba vremena da sve shvatite.

Poanta je da odgođena replika mora doći do trenutka prije zahtjeva DELETE. Približno smo znali fizičko vrijeme uklanjanja. Izbrisali smo recovery_min_apply_delay i dodao recovery_target_time в recovery.conf. Ovako replika stiže u pravi trenutak bez odlaganja:

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

S vremenskim oznakama, bolje je smanjiti višak kako ne biste propustili. Istina, što je smanjenje veće, gubimo više podataka. Opet, ako propustimo zahtjev DELETE, sve će se ponovno izbrisati i morat ćete početi ispočetka (ili čak napraviti hladnu sigurnosnu kopiju za PITR).

Ponovno smo pokrenuli odgođenu instancu Postgresa i WAL segmenti su se ponavljali do navedenog vremena. Možete pratiti napredak u ovoj fazi postavljajući pitanje:

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;

Ako se vremenska oznaka više ne mijenja, oporavak je dovršen. Akcija se može prilagoditi recovery_target_actionza zatvaranje, promicanje ili pauziranje instance nakon ponovnog pokušaja (obustavljeno je prema zadanim postavkama).

Baza se vratila u stanje prije tog nesretnog zahtjeva. Sada možete, na primjer, izvesti podatke. Izvezli smo izbrisane podatke o oznaci i sve poveznice na probleme i zahtjeve za spajanje te ih premjestili u proizvodnu bazu podataka. Ako su gubici velikih razmjera, možete jednostavno promovirati repliku i koristiti je kao glavnu. Ali tada će sve promjene nakon točke do koje smo se oporavili biti izgubljene.

Umjesto vremenskih oznaka, bolje je koristiti ID-ove transakcija. Korisno je zabilježiti ove ID-ove, na primjer, za DDL izjave (kao što je DROP TABLE), pomoću log_statements = 'ddl'. Da imamo ID transakcije, uzeli bismo recovery_target_xid i proveo sve do transakcije prije zahtjeva DELETE.

Povratak na posao vrlo je jednostavan: uklonite sve promjene iz recovery.conf i ponovno pokrenite Postgres. Replika će uskoro ponovno imati odgodu od osam sati, a mi smo spremni za buduće probleme.

Prednosti oporavka

Uz odgođenu repliku umjesto hladne sigurnosne kopije, ne morate trošiti sate vraćajući cijelu sliku iz arhive. Na primjer, potrebno nam je pet sati da dobijemo cijelu osnovnu sigurnosnu kopiju od 2 TB. I onda još morate primijeniti cijeli dnevni WAL da se vratite u željeno stanje (u najgorem slučaju).

Odgođena replika bolja je od hladne sigurnosne kopije na dva načina:

  1. Nema potrebe za uklanjanjem cijele osnovne sigurnosne kopije iz arhive.
  2. Postoji fiksni osmosatni prozor WAL segmenata koji se moraju ponavljati.

Također stalno provjeravamo je li moguće napraviti PITR iz WAL-a i brzo bismo primijetili oštećenje ili druge probleme s WAL arhivom praćenjem kašnjenja odgođene replike.

U ovom primjeru, trebalo nam je 50 minuta za vraćanje, što znači da je brzina bila 110 GB WAL podataka na sat (arhiva je još bila uključena AWS S3). Ukupno smo riješili problem i povratili podatke za 1,5 sat.

Rezultati: gdje je odgođena replika korisna (a gdje nije)

Koristite odgođenu replikaciju kao prvu pomoć ako ste slučajno izgubili podatke i primijetili ovaj problem unutar konfigurirane odgode.

Ali imajte na umu: replikacija nije sigurnosna kopija.

Sigurnosno kopiranje i replikacija imaju različite svrhe. Hladna sigurnosna kopija će vam dobro doći ako ste slučajno napravili DELETE ili DROP TABLE. Izrađujemo backup iz hladnjače i vraćamo tablicu ili cijelu bazu u prethodno stanje. Ali u isto vrijeme zahtjev DROP TABLE se gotovo trenutno reproducira u svim replikama na radnom klasteru, tako da obična replikacija ovdje neće pomoći. Sama replikacija održava bazu podataka dostupnom kada se pojedinačni poslužitelji iznajmljuju i raspoređuje opterećenje.

Čak i s odgođenom replikom, ponekad stvarno trebamo hladnu sigurnosnu kopiju na sigurnom mjestu ako dođe do kvara podatkovnog centra, skrivene štete ili drugih događaja koji nisu odmah vidljivi. Sama replikacija ovdje nema nikakve koristi.

Primijetiti, na GitLab.com Trenutno štitimo od gubitka podataka samo na razini sustava i ne vraćamo podatke na razini korisnika.

Izvor: www.habr.com

Dodajte komentar