Si e përdorëm replikimin e vonuar për rikuperimin e emergjencës me PostgreSQL

Si e përdorëm replikimin e vonuar për rikuperimin e emergjencës me PostgreSQL
Replikimi nuk është backup. Apo ndoshta po? Kështu e përdorëm replikimin e vonshëm për të rikuperuar, duke fshirë rastësisht lidhjet.

Specialistët e Infrastrukturës në GitLab janë përgjegjës për funksionimin GitLab.com — instanca më e madhe e GitLab në botë. Këtu ka 3 milion përdorues dhe pothuajse 7 milion projekte, dhe ky është një nga sajtet më të mëdha open-source SaaS me një arkitekturë të dedikuar. Pa sistemin e bazës së të dhënave PostgreSQL, infrastruktura e GitLab.com nuk do të shkojë larg, dhe ne kemi bërë çdo gjë për të siguruar që të jemi të gatshëm për çdo dështim që mund të çojë në humbjen e të dhënave. Është e pamundshme që një katastrofë e tillë të ndodhë, por ne jemi shumë të përgatitur dhe kemi siguruar mekanizma të ndryshëm për backup dhe replikim.

Replikimi nuk është një mjet backup për bazat e të dhënave (shih më poshtë). Por tani do të shohim se si të rikuperojmë shpejt të dhënat e fshirë rastësisht me anë të replikimit të vonshëm: në GitLab.com përdorues fshiva lidhjen për projektin gitlab-ce dhe humba lidhjet me kërkesat për bashkim dhe detyrat.

Me replikën e vonshme, ne e rikuperuam të dhënat vetëm brenda 1.5 orëve. Shihni si ndodhi.

Rikuperimi në një moment të caktuar me PostgreSQL

PostgreSQL ka një funksion të ndërtuar, i cili rikthen gjendjen e bazës së të dhënave në një moment të caktuar. E quajtur Rikuperimi në Momentin e Caktuar (PITR) dhe përdor mekanizmat e njëjtë që mbështesin aktualitetin e replikës: duke filluar nga një snapshot i besueshëm i gjithë klasterit të bazës së të dhënave (backup bazik), ne aplikojmë një sërë ndryshimesh deri në një moment të caktuar.

Për të përdorur këtë funksion për backup të ftohtë, ne rregullisht bëjmë backup bazik të bazës së të dhënave dhe e ruajmë atë në arkivë (arkivat e GitLab jetojnë në ruajtjen e cloud Google). Po ashtu, monitorojmë ndryshimet e gjendjes së bazës së të dhënave, duke arkivuar log-un e shënimeve të parashikuara (logs të shënimeve të parashikueshme, WAL). Dhe me gjithë këtë ne mund të realizojmë PITR për rikuperim në rast fatkeqësie: fillojmë me snapshot-in e bërë para gabimit dhe aplikojmë ndryshimet nga arkiva WAL deri në dështim.

Çfarë është replikimi i vonshëm?

Replikimi i vonshëm është aplikimi i ndryshimeve nga WAL me një vonesë. Domethënë transaksioni ndodhi në orën X, por në replikë do të shfaqet me një vonesë d në orën X + d.

Në PostgreSQL ka 2 mënyra për të konfiguruar një replikë fizike të bazës së të dhënave: rikuperimi nga arkiva dhe replikimi me transmetim. Rikuperimi nga arkiva, në thelb, funksionon si PITR, por në vazhdimësi: ne vazhdimisht nxjerrim ndryshimet nga arkivi WAL dhe i aplikojmë ato në kopjen e dytë. A replikimi në rrjedhë nxjerr drejtpërdrejt rrjedhën e WAL nga hosti më i lartë të databazës. Ne preferojmë rikthimin nga arkivi — është më e lehtë të menaxhohet dhe ka performancë të ndershme, e cila nuk mbetet pas klasit të punës.

Si të konfiguroni rikthimin e vonuar nga arkivi

Opcioni i rikthimit është përshkruar në skedarin recovery.conf. Shembull:

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'

Me këto parametra, ne kemi konfiguruar një kopje të vonuar me rikthim nga arkivi. Këtu përdoret wal-e për të nxjerrë segmente WAL (restore_command) nga arkivi, dhe ndryshimet do të aplikohen pas tetë orësh (recovery_min_apply_delay). Kopja do të ndjekë ndryshimet në linjën e kohës në arkiv, për shembull, për shkak të ndodhisë së dështimit në klasë (recovery_target_timeline).

D recovery_min_apply_delay mund të konfiguroni replikimin në rrjedhë me vonesë, por këtu ka disa mashtrime që lidhen me slotet e replikimit, feedback-un e rezervës aktive etj. Arkiva WAL lejon të shmangen ato.

Parametri recovery_min_apply_delay u prezantua vetëm në PostgreSQL 9.3. Në versionet e mëparshme, për replikimin e vonuar duhej të konfiguroni një kombinim të funksioneve për menaxhimin e rikthimit (pg_xlog_replay_pause(), pg_xlog_replay_resume()) ose të mbani segmentet WAL në arkiv gjatë kohës së vonesës.

Si e bën PostgreSQL këtë?

Është interesante të shikoni si PostgreSQL implementon rikthimin e vonuar. Le të shohim në recoveryApplyDelay(XlogReaderState). Ai thirret nga cikli kryesor i përsëritjes për çdo shënim nga 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;
}

Kjo është e vërteta, se vonesa bazohet në kohën fizike të regjistruar në etiketën e kohës së angazhimit të transaksionit (xtime). Siç shihet, vonesa aplikohet vetëm për angajimet dhe nuk prek regjistrimet e tjera — të gjitha ndryshimet aplikohen drejtpërdrejt, dhe angazhimi vonohet, kështu që ne do t'i shohim ndryshimet vetëm pas vonesës së caktuar.

Si të përdorim replikimin e vonuar për rikuperimin e të dhënave

Supozoni se kemi një grup të dhënash në prodhim dhe një replikë me një vonesë prej tetë orësh. Le të shohim si të rikuperojmë të dhënat duke marrë si shembull fshirjen e rastësishme të etiketave.

Kur mësuam për problemin, ne pamë rikuperimin nga arkiva për replikën e vonuar:

SELECT pg_xlog_replay_pause();

Me pauzën nuk kishim asnjë rrezik që replika të përsërisë kërkesën FSHI. Një gjë e dobishme, nëse nevojitet kohë për të sqaruar gjithçka.

E vërteta është, se replika e vonuar duhet të arrijë momentin para kërkesës FSHI. Ne e dinim pak a shumë kohën fizike të fshirjes. Ne fshim recovery_min_apply_delay dhe shtojmë recovery_target_timerecovery.conf. Kështu replika arrin në momentin e nevojshëm pa vonesa:

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

Me etiketat e kohës është më mirë të tregoni më pak, për të mos humbur drejtimin. Megjithatë, sa më shumë të heqim, aq më shumë të dhëna humbasim. Përsëri, nëse kalojmë kërkesën FSHI, gjithçka do të fshihet përsëri dhe do të duhet të fillojmë nga e para (ose në fakt të marrim një kopje më të ftohtë për PITR).

Ne shfuqizëm instancën e vonuar të Postgres dhe segmentet WAL u përsëritën deri në kohën e caktuar. Mund të ndiqni progresin në këtë hap përmes pyetjes:

SELECT
  -- vendndodhja aktuelle në WAL
  pg_last_xlog_replay_location(),
  -- marka e kohës së aktualizimit të transaksionit (gjendja e kopjes së dhënash)
  pg_last_xact_replay_timestamp(),
  -- koha aktuale fizike
  now(),
  -- sasia e kohës që duhet të aplikohet deri në arritjen e kohës së objektivit të rikuperimit
  '2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() si vonesë;

Nëse marka e kohës nuk ndryshon më, rikuperimi është përfunduar. Mund të konfiguroni veprimin recovery_target_action, për të mbyllur, avancuar ose pezulluar instancën pas përsëritjes (në mënyrë default ajo pezullohet).

Baza e të dhënave arriti në gjendjen para atij kërkese fatkeqe. Tani mund të, për shembull, eksportoni të dhënat. Ne eksportuam të dhënat e fshira për etiketën dhe të gjitha lidhjet me detyrat dhe merge-request-at dhe i transferuam ato në bazën e të dhënave aktive. Nëse humbjet janë të mëdha, mund thjesht të avancojmë kopjen dhe ta përdorim si bazën kryesore. Por atëherë do të humbasim të gjitha ndryshimet pas momentit deri në të cilin u rikuperuam.

Më mirë se sa markat e kohës është të përdorim ID-të e transaksioneve. Është e dobishme të regjistroni këto ID, për shembull, për operatorët DDL (siç është DROP TABLE) me anë të log_statements = 'ddl'. Sikur të kishim ID-në e transaksionit, do të merrnim recovery_target_xid dhe do të kalonim të gjitha deri në transaksionin para kërkesës. FSHI.

Të kthehesh në punë është shumë e thjeshtë: hiqni të gjitha ndryshimet nga recovery.conf dhe riu aktivizoni Postgres. Së shpejti do të rikthehet vonesa e tetë orëve në kopjen e dhënave, dhe ne jemi gati për ndodhitë e ardhshme.

Përfitimet për rikuperim

Me një kopje të vonuar në vend të një kopje të ftohtë, nuk është e nevojshme të rikuperoni gjithë snapshot-in nga arkiva për orë të tëra. Për ne, për shembull, na duhen pesë orë për të nxjerrë të gjithë kopjen e bazës mbi 2 TB. Dhe pastaj do të duhej të aplikonim të gjithë WAL-in ditor për t'u rikuperuar në gjendjen e nevojshme (në rastin më të keq).

Kopja e vonuar është më e mirë se një kopje e ftohtë për dy arsye:

  1. Nuk është e nevojshme të nxirrni të gjithë kopjen bazë nga arkiva.
  2. Ka një dritare të fiksuar të tetë orëve të segmenteve WAL që duhet të përsëriten.

Po ashtu, ne vazhdojmë të kontrollojmë nëse mund të bëjmë PITR nga WAL, dhe do ta kishim vërejtur shpejt çdo dëmtim ose probleme të tjera me arkivën WAL, duke ndjekur vonesën e kopjes së vonuar.

Në këtë shembull, na duhej 50 minuta për rikuperimin, që do të thotë një shpejtësi prej 110 GB të dhënash WAL në orë (arkiva ndodhej ende në AWS S3). Në total, ne zgjodhëm problemin dhe rikthyem të dhënat brenda 1.5 orëve.

Përfundimet: ku do të nevojitet replikimi i vonuar (dhe ku jo)

Përdorni replikimin e vonuar si një vegël ndihmës nëse keni humbur aksidentalisht të dhëna dhe e keni vërejtur këtë problem brenda periudhës së caktuar.

Por mbani parasysh: replikimi nuk është backup.

Backup-i dhe replikimi kanë qëllime të ndryshme. Backup-i i ftohtë është i dobishëm nëse keni bërë aksidentalisht FSHI или DROP TABLE. Ne bëjmë backup nga depoja e ftohtë dhe rikthejmë gjendjen e mëparshme të tabelës ose të gjithë bazës së të dhënave. Por në këtë rast, kërkesa DROP TABLE palmost momentalisht riprodhohet në të gjitha replikat në klastri aktiv, kështu që replikimi normal këtu nuk do të ndihmojë. Vetë replikimi mbështet bazën e të dhënave në dispozicion kur disa serverë dalin jashtë funksionit dhe shpërndan ngarkesën.

Edhe me replikimin e vonuar, ndonjëherë na nevojitet shumë një backup i ftohtë në një vend të sigurt, nëse ndodh ndonjë dështim në qendrën e të dhënave, dëmtim të fshehur ose ngjarje të tjera që nuk i vëren menjëherë. Këtu një replikim i vetëm nuk është i mjaftueshëm.

Shënim. Në GitLab.com Ne aktualisht mbrojmë humbjen e të dhënave vetëm në nivelin e sistemit dhe nuk rikthejmë të dhënat në nivelin e përdoruesit.

Burimi: habr.com

Blini hostim të besueshëm për faqe interneti me mbrojtje DDoS, serverë VPS VDS 🔥 Blini hostim të besueshëm për faqe interneti me mbrojtje DDoS, serverë VPS VDS - ProHoster