Hoe ons lui replikasie gebruik het vir rampherstel met PostgreSQL

Hoe ons lui replikasie gebruik het vir rampherstel met PostgreSQL
Replikasie is nie rugsteun nie. Of nie? Hier is hoe ons uitgestelde replikasie gebruik het om te herstel nadat kortpaaie per ongeluk uitgevee is.

Infrastruktuur spesialiste GitLab is verantwoordelik vir die werk GitLab.com - die grootste GitLab-instansie in die natuur. Met 3 miljoen gebruikers en byna 7 miljoen projekte, is dit een van die grootste oopbron SaaS-webwerwe met 'n toegewyde argitektuur. Sonder die PostgreSQL-databasisstelsel sal die GitLab.com-infrastruktuur nie ver gaan nie, en wat doen ons om fouttoleransie te verseker in geval van enige mislukkings wanneer data verlore kan gaan. Dit is onwaarskynlik dat so 'n ramp sal gebeur, maar ons is goed voorbereid en toegerus met verskeie rugsteun- en replikasiemeganismes.

Replikasie is nie 'n manier om databasisse te rugsteun nie (sien onder). Maar nou sal ons sien hoe om vinnig geskrap data per ongeluk te herstel met behulp van lui replikasie: aan GitLab.com gebruiker het die kortpad uitgevee vir die projek gitlab-ce en verloor verbindings met samesmeltingsversoeke en take.

Met 'n uitgestelde replika het ons data in net 1,5 uur herwin. Kyk hoe het dit gebeur.

Punt in tyd herstel met PostgreSQL

PostgreSQL het 'n ingeboude funksie wat die toestand van 'n databasis na 'n spesifieke tydstip herstel. Dit word genoem Punt-in-tyd herstel (PITR) en gebruik dieselfde meganismes wat die replika op datum hou: begin met 'n betroubare momentopname van die hele databasiskluster (basisrugsteun), pas ons 'n reeks toestandsveranderinge toe tot op 'n sekere tydstip.

Om hierdie kenmerk vir koue rugsteun te gebruik, maak ons ​​gereeld 'n basiese databasisrugsteun en stoor dit in 'n argief (GitLab argiewe woon in Google wolkberging). Ons monitor ook veranderinge in die toestand van die databasis deur die voorskryf-log te argiveer (vooruitskryf-logboek, WAL). En met dit alles in plek, kan ons 'n PITR vir rampherstel doen: begin met die momentopname wat voor die mislukking geneem is, en pas die veranderinge vanaf die WAL-argief tot by die mislukking toe.

Wat is uitgestelde replikasie?

Lui replikasie is die toepassing van veranderinge vanaf WAL met 'n vertraging. Dit wil sΓͺ, die transaksie het binne 'n uur plaasgevind X, maar dit sal met 'n vertraging in die replika verskyn d in 'n uur X + d.

PostgreSQL het 2 maniere om 'n fisiese databasis replika op te stel: rugsteunherwinning en stroomreplikasie. Herstel vanaf 'n argief, werk in wese soos PITR, maar deurlopend: ons haal voortdurend veranderinge uit die WAL-argief en pas dit toe op die replika. A stroom replikasie haal die WAL-stroom direk van die stroomop databasisgasheer af. Ons verkies argiefherwinning – dit is makliker om te bestuur en het normale werkverrigting wat tred hou met die produksiekluster.

Hoe om vertraagde herstel uit 'n argief op te stel

Herstel opsies beskryf in die lΓͺer recovery.conf. 'N Voorbeeld:

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'

Met hierdie parameters het ons 'n uitgestelde replika met rugsteunherstel opgestel. Hier word dit gebruik wal-e om WAL-segmente te onttrek (restore_command) uit die argief, en veranderinge sal na agt uur toegepas word (recovery_min_apply_delay). Die replika sal kyk vir tydlynveranderinge in die argief, byvoorbeeld as gevolg van 'n cluster failover (recovery_target_timeline).

Π‘ recovery_min_apply_delay U kan stroomreplikasie met 'n vertraging opstel, maar hier is 'n paar slaggate wat verband hou met replikasiegleuwe, warm bystand-terugvoer, ensovoorts. Die WAL-argief laat jou toe om dit te vermy.

Parameter recovery_min_apply_delay het slegs in PostgreSQL 9.3 verskyn. In vorige weergawes, vir uitgestelde replikasie moet jy die kombinasie konfigureer herstelbestuursfunksies (pg_xlog_replay_pause(), pg_xlog_replay_resume()) of hou WAL-segmente in die argief vir die duur van die vertraging.

Hoe doen PostgreSQL dit?

Dit is interessant om te sien hoe PostgreSQL lui herstel implementeer. Kom ons kyk na recoveryApplyDelay(XlogReaderState). Dit word genoem van hoof herhaling lus vir elke inskrywing van 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;
}

Die slotsom is dat die vertraging gebaseer is op die fisiese tyd wat aangeteken is in die transaksie-toewysingstydstempel (xtime). Soos u kan sien, is die vertraging slegs van toepassing op commits en beΓ―nvloed dit nie ander inskrywings nie - alle veranderinge word direk toegepas, en die commit is vertraag, so ons sal die veranderinge eers na die gekonfigureerde vertraging sien.

Hoe om 'n vertraagde replika te gebruik om data te herstel

Kom ons sΓͺ ons het 'n databasiskluster en 'n replika met 'n vertraging van agt uur in produksie. Kom ons kyk hoe om data te herstel deur 'n voorbeeld te gebruik per ongeluk kortpaaie uitvee.

Toe ons van die probleem geleer het, het ons argiefherstel is onderbreek vir 'n uitgestelde replika:

SELECT pg_xlog_replay_pause();

Met 'n pouse het ons geen risiko gehad dat die replika die versoek sou herhaal nie DELETE. 'n Nuttige ding as jy tyd nodig het om alles uit te vind.

Die punt is dat die uitgestelde replika die oomblik voor die versoek moet bereik DELETE. Ons het omtrent die fisiese tyd van verwydering geweet. Ons het uitgevee recovery_min_apply_delay en bygevoeg recovery_target_time Π² recovery.conf. Dit is hoe die replika sonder versuim die regte oomblik bereik:

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

Met tydstempels is dit beter om die oorskot te verminder om nie te mis nie. Dit is waar, hoe groter die afname, hoe meer data verloor ons. Weereens, as ons die versoek mis DELETE, sal alles weer uitgevee word en jy sal oor moet begin (of selfs 'n koue rugsteun vir PITR neem).

Ons het die uitgestelde Postgres-instansie weer begin en die WAL-segmente is herhaal tot die gespesifiseerde tyd. U kan vordering op hierdie stadium dophou deur te vra:

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;

As die tydstempel nie meer verander nie, is die herstel voltooi. Aksie kan aangepas word recovery_target_actionom die instansie na herprobeer toe te maak, te bevorder of te onderbreek (dit word by verstek opgeskort).

Die databasis het teruggekeer na sy toestand voor daardie ongelukkige versoek. Nou kan jy byvoorbeeld data uitvoer. Ons het die geskrapte etiketdata en alle skakels na kwessies en samesmeltingsversoeke uitgevoer en na die produksiedatabasis geskuif. As die verliese grootskaalse is, kan jy eenvoudig die replika bevorder en dit as die hoof een gebruik. Maar dan sal alle veranderinge nΓ‘ die punt waartoe ons herstel het, verlore gaan.

In plaas van tydstempels, is dit beter om transaksie-ID's te gebruik. Dit is nuttig om hierdie ID's op te teken, byvoorbeeld vir DDL-stellings (soos DROP TABLE), deur die gebruik van log_statements = 'ddl'. As ons 'n transaksie-ID gehad het, sou ons dit neem recovery_target_xid en het alles afgeloop tot die transaksie voor die versoek DELETE.

Om terug te gaan werk toe is baie eenvoudig: verwyder alle veranderinge van recovery.conf en herbegin Postgres. Die replika sal binnekort weer 'n agt uur vertraging hΓͺ, en ons is voorbereid op toekomstige probleme.

Herstelvoordele

Met 'n uitgestelde replika in plaas van 'n koue rugsteun, hoef u nie ure te spandeer om die hele beeld uit die argief te herstel nie. Dit neem ons byvoorbeeld vyf uur om die hele basiese 2 TB-rugsteun te kry. En dan moet jy nog die hele daaglikse WAL aanwend om na die verlangde toestand te herstel (in die ergste geval).

’n Uitgestelde replika is op twee maniere beter as ’n koue rugsteun:

  1. Dit is nie nodig om die hele basiese rugsteun uit die argief te verwyder nie.
  2. Daar is 'n vaste agt-uur-venster van WAL-segmente wat herhaal moet word.

Ons kyk ook voortdurend of dit moontlik is om 'n PITR van WAL te maak, en ons sal vinnig korrupsie of ander probleme met die WAL-argief opmerk deur die vertraging van die uitgestelde replika te monitor.

In hierdie voorbeeld het dit ons 50 minute geneem om te herstel, wat beteken dat die spoed 110 GB WAL-data per uur was (die argief was steeds aan AWS S3). In totaal het ons die probleem opgelos en die data in 1,5 uur herstel.

Resultate: waar 'n uitgestelde replika nuttig is (en waar dit nie is nie)

Gebruik vertraagde replikasie as 'n noodhulp as jy per ongeluk data verloor het en hierdie probleem binne die gekonfigureerde vertraging opgemerk het.

Maar hou in gedagte: replikasie is nie 'n rugsteun nie.

Rugsteun en replikasie het verskillende doeleindes. 'n Koue rugsteun sal handig te pas kom as jy dit per ongeluk gemaak het DELETE of DROP TABLE. Ons maak 'n rugsteun vanaf koelberging en herstel die vorige toestand van die tabel of die hele databasis. Maar terselfdertyd die versoek DROP TABLE word byna onmiddellik in alle replikas op die werkende groep gereproduseer, so gewone replikasie sal nie hier help nie. Replikasie self hou die databasis beskikbaar wanneer individuele bedieners verhuur word en versprei die vrag.

Selfs met 'n uitgestelde replika het ons soms regtig 'n koue rugsteun op 'n veilige plek nodig as 'n datasentrumfout, verborge skade of ander gebeurtenisse wat nie onmiddellik opmerklik is nie, plaasvind. Replikasie alleen is hier van geen nut nie.

Let daarop. Op GitLab.com Ons beskerm tans slegs teen dataverlies op stelselvlak en herstel nie data op gebruikersvlak nie.

Bron: will.com

Voeg 'n opmerking