Kaip mes panaudojome tingų replikaciją atkūrimui po nelaimės naudodami PostgreSQL

Kaip mes panaudojome tingų replikaciją atkūrimui po nelaimės naudodami PostgreSQL
Replikacija nėra atsarginė kopija. Arba ne? Štai kaip mes panaudojome atidėtą replikaciją, kad atsikurtume po netyčinių sparčiųjų klavišų ištrynimo.

Infrastruktūros specialistai GitLab yra atsakinga už darbą GitLab.com - didžiausias „GitLab“ egzempliorius gamtoje. Su 3 milijonais vartotojų ir beveik 7 milijonais projektų, tai yra viena didžiausių atvirojo kodo SaaS svetainių su specialia architektūra. Be PostgreSQL duomenų bazių sistemos GitLab.com infrastruktūra toli nenueis, o ką darome, kad užtikrintume atsparumą gedimams kilus gedimams, kai gali būti prarasti duomenys. Mažai tikėtina, kad tokia nelaimė įvyks, tačiau esame gerai pasiruošę ir apsirūpinę įvairiais atsarginių kopijų kūrimo ir replikacijos mechanizmais.

Replikacija nėra priemonė kurti atsargines duomenų bazių kopijas (žiūrėti žemiau). Bet dabar pamatysime, kaip greitai atkurti netyčia ištrintus duomenis naudojant tingų replikaciją: įjungta GitLab.com vartotojas ištrynė nuorodą projektui gitlab-ce ir prarado ryšius su sujungimo užklausomis ir užduotimis.

Naudodami atidėtą kopiją, duomenis atkūrėme vos per 1,5 valandos. Pažiūrėk, kaip tai atsitiko.

Laiko atkūrimas naudojant PostgreSQL

PostgreSQL turi integruotą funkciją, kuri atkuria duomenų bazės būseną tam tikru momentu. Tai vadinama Atkūrimo taškas (PITR) ir naudoja tuos pačius mechanizmus, kurie nuolat atnaujina kopiją: pradedant nuo patikimos visos duomenų bazės klasterio momentinės nuotraukos (bazinės atsarginės kopijos), taikome eilę būsenos pakeitimų iki tam tikro momento.

Norėdami naudoti šią funkciją šaltajam atsarginiam kopijavimui, reguliariai sukuriame bazinę duomenų bazės atsarginę kopiją ir saugome ją archyve („GitLab“ archyvai veikia „Google“ debesies saugykla). Taip pat stebime duomenų bazės būsenos pokyčius archyvuodami įrašymo į priekį žurnalą (į priekį įrašomas žurnalas, WAL). Ir visa tai atlikę, galime atlikti PITR atkūrimui po nelaimės: pradedant momentine nuotrauka, daryta prieš gedimą, ir pritaikyti pakeitimus nuo WAL archyvo iki gedimo.

Kas yra atidėtas replikavimas?

Tingus replikavimas – tai WAL pakeitimų taikymas su uždelsimu. Tai yra, sandoris įvyko per valandą X, bet jis bus rodomas kopijoje su vėlavimu d per valandą X + d.

„PostgreSQL“ turi 2 būdus, kaip nustatyti fizinę duomenų bazės kopiją: atsarginės kopijos atkūrimą ir srautinio perdavimo replikaciją. Atkuriama iš archyvo, iš esmės veikia kaip PITR, bet nuolat: nuolat gauname pakeitimus iš WAL archyvo ir pritaikome juos kopijai. A transliacijos replikacija tiesiogiai nuskaito WAL srautą iš ankstesnės duomenų bazės pagrindinio kompiuterio. Mes teikiame pirmenybę archyvo atkūrimui – jį lengviau valdyti, o našumas yra normalus, neatsilikdamas nuo gamybos grupės.

Kaip nustatyti atidėtą atkūrimą iš archyvo

Atkūrimo parinktys aprašyta byloje recovery.conf. Pavyzdys:

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'

Naudodami šiuos parametrus sukonfigūravome atidėtą kopiją su atsarginės kopijos atkūrimu. Čia jis naudojamas wal-e išgauti WAL segmentus (restore_command) iš archyvo, o pakeitimai bus pritaikyti po aštuonių valandų (recovery_min_apply_delay). Replika stebės laiko juostos pakeitimus archyve, pvz., dėl klasterio gedimo (recovery_target_timeline).

С recovery_min_apply_delay Galite nustatyti srautinio perdavimo replikaciją su uždelsimu, tačiau čia yra keletas spąstų, susijusių su replikacijos lizdais, karštojo budėjimo režimo atsiliepimais ir pan. WAL archyvas leidžia jų išvengti.

Parametras recovery_min_apply_delay pasirodė tik PostgreSQL 9.3. Ankstesnėse versijose, norint atidėti replikaciją, reikia sukonfigūruoti derinį atkūrimo valdymo funkcijos (pg_xlog_replay_pause(), pg_xlog_replay_resume()) arba laikykite WAL segmentus archyve visą delsos laiką.

Kaip PostgreSQL tai daro?

Įdomu pamatyti, kaip PostgreSQL įgyvendina tingų atkūrimą. Pažiūrėkime recoveryApplyDelay(XlogReaderState). Jis vadinamas iš pagrindinė kartojimo kilpa už kiekvieną įrašą iš 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;
}

Esmė ta, kad delsa pagrįsta fiziniu laiku, įrašytu operacijos įvykdymo laiko žymoje (xtime). Kaip matote, delsimas taikomas tik commitams ir neturi įtakos kitiems įrašams – visi pakeitimai taikomi tiesiogiai, o commit vėluoja, todėl pakeitimus matysime tik po sukonfigūruoto uždelsimo.

Kaip naudoti uždelstą kopiją duomenims atkurti

Tarkime, kad turime duomenų bazės klasterį ir kopiją su aštuonių valandų gamybos vėlavimu. Pažiūrėkime, kaip atkurti duomenis naudojant pavyzdį netyčia ištrynę sparčiuosius klavišus.

Kai sužinojome apie problemą, mes archyvo atkūrimas pristabdytas atidėtai kopijai:

SELECT pg_xlog_replay_pause();

Su pauze neturėjome rizikos, kad kopija pakartos užklausą DELETE. Naudingas dalykas, jei reikia laiko viską išsiaiškinti.

Esmė ta, kad atidėta kopija turi pasiekti momentą prieš užklausą DELETE. Mes maždaug žinojome fizinį pašalinimo laiką. Mes ištrynėme recovery_min_apply_delay ir pridėjo recovery_target_time в recovery.conf. Taip replika nedelsdama pasiekia reikiamą momentą:

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

Naudojant laiko žymas, geriau sumažinti perteklių, kad nepraleistumėte. Tiesa, kuo didesnis sumažėjimas, tuo daugiau duomenų prarandame. Vėlgi, jei praleisime prašymą DELETE, viskas vėl bus ištrinta ir teks pradėti iš naujo (ar net pasidaryti šaltą atsarginę PITR).

Iš naujo paleidome atidėtą Postgres egzempliorių ir WAL segmentai buvo kartojami iki nurodyto laiko. Šiame etape galite stebėti pažangą klausdami:

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;

Jei laiko žyma nebekeičiama, atkūrimas baigtas. Veiksmą galima pritaikyti recovery_target_actionuždaryti, reklamuoti arba pristabdyti egzempliorių po pakartotinio bandymo (pagal numatytuosius nustatymus jis sustabdytas).

Duomenų bazė grįžo į savo būseną prieš šį apgailėtiną prašymą. Dabar galite, pavyzdžiui, eksportuoti duomenis. Eksportavome ištrintus etiketės duomenis ir visas nuorodas į problemas bei sujungimo užklausas ir perkėlėme į gamybos duomenų bazę. Jei nuostoliai yra didelio masto, galite tiesiog reklamuoti kopiją ir naudoti ją kaip pagrindinę. Bet tada visi pokyčiai po taško, iki kurio atsigavome, bus prarasti.

Vietoj laiko žymų geriau naudoti operacijų ID. Naudinga įrašyti šiuos ID, pavyzdžiui, DDL teiginiams (pvz., DROP TABLE), naudojant log_statements = 'ddl'. Jei turėtume operacijos ID, imtume recovery_target_xid ir paleido viską iki sandorio prieš užklausą DELETE.

Grįžti į darbą labai paprasta: pašalinkite visus pakeitimus iš recovery.conf ir iš naujo paleiskite Postgres. Netrukus replika vėl vėluos aštuonias valandas, ir mes esame pasiruošę būsimoms bėdoms.

Atkūrimo privalumai

Turėdami atidėtą kopiją, o ne šaltą atsarginę kopiją, jums nereikės valandų valandų atkurti viso vaizdo iš archyvo. Pavyzdžiui, mums reikia penkių valandų, kad gautume visą pagrindinę 2 TB atsarginę kopiją. Ir tada vis tiek turite pritaikyti visą dienos WAL, kad atsigautumėte į norimą būseną (blogiausiu atveju).

Atidėta kopija yra geriau nei šaltoji atsarginė kopija dviem būdais:

  1. Nereikia pašalinti visos pagrindinės atsarginės kopijos iš archyvo.
  2. Yra nustatytas aštuonių valandų WAL segmentų langas, kuris turi būti kartojamas.

Taip pat nuolat tikriname, ar galima padaryti PITR iš WAL, ir greitai pastebėtume korupciją ar kitas WAL archyvo problemas, stebėdami atidėtos replikos atsilikimą.

Šiame pavyzdyje atkūrimas užtruko 50 minučių, o tai reiškia, kad greitis buvo 110 GB WAL duomenų per valandą (archyvas vis dar buvo įjungtas AWS S3). Iš viso problemą išsprendėme ir duomenis atkūrėme per 1,5 val.

Rezultatai: kur atidėta kopija yra naudinga (o kur ne)

Naudokite atidėtą replikaciją kaip pirmąją pagalbą, jei netyčia praradote duomenis ir pastebėjote šią problemą per sukonfigūruotą delsą.

Tačiau atminkite: replikacija nėra atsarginė kopija.

Atsarginė kopija ir replikacija turi skirtingus tikslus. Šalta atsarginė kopija bus naudinga, jei netyčia padarėte DELETE arba DROP TABLE. Padarome atsarginę kopiją iš šaltosios saugyklos ir atkuriame ankstesnę lentelės arba visos duomenų bazės būseną. Bet kartu ir prašymas DROP TABLE beveik akimirksniu atkuriamas visose darbo klasterio kopijose, todėl įprasta replikacija čia nepadės. Pati replikacija palaiko duomenų bazę prieinamą, kai atskiri serveriai išnuomojami ir paskirsto apkrovą.

Net ir naudojant atidėtą kopiją, kartais mums tikrai reikia šaltos atsarginės kopijos saugioje vietoje, jei įvyksta duomenų centro gedimas, paslėpta žala ar kiti įvykiai, kurie nėra iš karto pastebimi. Vien replikacija čia nenaudinga.

Atkreipti dėmesį. Apie GitLab.com Šiuo metu saugome tik nuo duomenų praradimo sistemos lygiu ir neatkuriame duomenų vartotojo lygmeniu.

Šaltinis: www.habr.com

Добавить комментарий