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_time në recovery.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 ose 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 hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster