Paano Namin Ginamit ang Lazy Replication para sa Disaster Recovery sa PostgreSQL

Paano Namin Ginamit ang Lazy Replication para sa Disaster Recovery sa PostgreSQL
Ang pagtitiklop ay hindi isang backup. O hindi? Narito kung paano namin ginamit ang lazy replication para sa pagbawi sa pamamagitan ng aksidenteng pagtanggal ng mga shortcut.

mga espesyalista sa imprastraktura Ang GitLab ay responsable para sa trabaho GitLab.com - ang pinakamalaking instance ng GitLab sa kalikasan. Sa 3 milyong user at halos 7 milyong proyekto, isa ito sa pinakamalaking open source na mga site ng SaaS na may dedikadong arkitektura. Kung wala ang PostgreSQL database system, hindi lalayo ang imprastraktura ng GitLab.com, at kung ano ang hindi namin ginagawa para sa fault tolerance kung sakaling magkaroon ng anumang mga pagkabigo kapag maaari kang mawalan ng data. Malabong mangyari ang ganitong sakuna, ngunit naghanda kami nang mabuti at nag-stock ng iba't ibang mekanismo ng backup at replikasyon.

Ang pagtitiklop ay hindi ang iyong database backup tool (tingnan sa ibaba). Ngunit ngayon ay makikita natin kung paano mabilis na mabawi ang hindi sinasadyang tinanggal na data gamit ang tamad na pagtitiklop: sa GitLab.com gumagamit inalis na shortcut para sa proyekto gitlab-ce at nawalan ng mga koneksyon sa pagsasama ng mga kahilingan at gawain.

Sa naantalang replica, na-recover namin ang data sa loob lang ng 1,5 oras. Tingnan kung paano ito.

Point-in-time na pagbawi gamit ang PostgreSQL

Ang PostgreSQL ay may built-in na function na nagpapanumbalik ng estado ng isang database sa isang tiyak na punto ng oras. Ito ay tinatawag na Point-in-Time na Pagbawi (PITR) at gumagamit ng parehong mga mekanismo na nagpapanatili ng isang replica na napapanahon: simula sa isang wastong snapshot ng buong cluster ng database (base backup), naglalapat kami ng isang serye ng mga pagbabago sa estado hanggang sa isang tiyak na punto ng oras.

Para magamit ang feature na ito para sa isang malamig na backup, regular kaming gumagawa ng base database backup at iniimbak ito sa isang archive (ang GitLab archive ay nakatira sa Google cloud storage). Sinusubaybayan din namin ang mga pagbabago sa estado ng database sa pamamagitan ng pag-archive ng write-ahead log (sumulat ng maagang tala, WAL). At sa lahat ng ito, magagawa natin ang PITR para sa pagbawi ng kalamidad: magsisimula tayo sa isang snapshot na kinunan bago ang error at ilapat ang mga pagbabago mula sa archive ng WAL hanggang sa pag-crash.

Ano ang delayed replication?

Ang naantalang pagtitiklop ay ang aplikasyon ng mga pagbabago mula sa WAL na may pagkaantala. Ibig sabihin, nangyari ang transaksyon sa oras X, ngunit lalabas ito sa replica na may pagkaantala d sa isang oras X + d.

Mayroong 2 paraan upang mag-set up ng isang pisikal na replika ng database sa PostgreSQL: pagpapanumbalik ng archive at pagtitiklop ng streaming. Pagpapanumbalik mula sa isang archive, mahalagang gumagana tulad ng PITR, ngunit patuloy: patuloy kaming kumukuha ng mga pagbabago mula sa archive ng WAL at inilalapat ang mga ito sa replica. A pagtitiklop ng streaming kinukuha ang WAL stream nang direkta mula sa upstream database host. Mas gusto naming i-restore mula sa isang archive - mas madaling pamahalaan at may normal na performance, na hindi nahuhuli sa isang production cluster.

Paano i-set up ang naantalang backup recovery

Mga Pagpipilian sa Pagbawi inilarawan sa file recovery.conf... Halimbawa:

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'

Sa mga setting na ito, na-configure namin ang isang naantalang replica na may archive restore. Ginamit dito wal-e upang kunin ang mga segment ng WAL (restore_command) mula sa archive, at ang mga pagbabago ay ilalapat pagkatapos ng walong oras (recovery_min_apply_delay). Babantayan ng Replica ang mga pagbabago sa timeline sa archive, gaya ng dahil sa isang cluster failover (recovery_target_timeline).

Π‘ recovery_min_apply_delay maaari kang mag-set up ng latency streaming replication, ngunit may ilang mga pitfalls na nauugnay sa mga replication slot, mainit na ekstrang feedback, at iba pa. Iniiwasan sila ng WAL archive.

Parametro recovery_min_apply_delay lumitaw lamang sa PostgreSQL 9.3. Sa mga nakaraang bersyon, ang naantalang pagtitiklop ay nangangailangan ng kumbinasyon ng mga function ng pamamahala sa pagbawi (pg_xlog_replay_pause(), pg_xlog_replay_resume()) o hawakan ang mga segment ng WAL sa archive para sa tagal ng pagkaantala.

Paano ito ginagawa ng PostgreSQL?

Nakakatuwang makita kung paano ipinapatupad ng PostgreSQL ang lazy restore. Tignan natin recoveryApplyDelay(XlogReaderState). Tinatawag ito mula sa pangunahing loop ulitin para sa bawat entry mula sa 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;
}

Ang ilalim na linya ay ang pagkaantala ay batay sa pisikal na oras na naitala sa timestamp ng transaksyon na ginawa (xtime). Tulad ng nakikita mo, ang pagkaantala ay nalalapat lamang sa mga commit at hindi nakakaapekto sa iba pang mga tala - lahat ng mga pagbabago ay direktang inilalapat, at ang commit ay naantala, kaya makikita lamang namin ang mga pagbabago pagkatapos ng na-configure na pagkaantala.

Paano gamitin ang lazy replica para sa pagbawi ng data

Sabihin nating mayroon tayong database cluster sa produksyon at isang replica na may walong oras na pagkaantala. Tingnan natin kung paano i-recover ang data gamit ang isang halimbawa hindi sinasadyang pagtanggal ng mga shortcut.

Nung namulat tayo sa problema, tayo naka-pause ang backup recovery para sa naantalang replika:

SELECT pg_xlog_replay_pause();

Sa isang pag-pause, wala kaming panganib na ulitin ng replica ang kahilingan DELETE. Kapaki-pakinabang na bagay kung kailangan mo ng oras upang malaman ang lahat.

Ang bottom line ay ang naantalang replica ay dapat umabot sa sandali bago ang kahilingan DELETE. Tinatayang alam namin ang pisikal na oras ng pag-alis. Tinanggal namin recovery_min_apply_delay at karagdagan recovery_target_time Π² recovery.conf. Kaya't ang replika ay umabot sa tamang sandali nang walang pagkaantala:

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

Sa mga timestamp, mas mainam na bawasan ang sobra para hindi makaligtaan. Totoo, mas malaki ang pagbaba, mas maraming data ang nawawala sa amin. Muli, kung laktawan natin ang kahilingan DELETE, ang lahat ay tatanggalin muli at kailangan mong magsimulang muli (o kahit na kumuha ng malamig na backup para sa PITR).

Sinimulan namin muli ang naantalang instance ng Postgres at ang mga segment ng WAL ay naulit hanggang sa tinukoy na oras. Maaari mong subaybayan ang pag-unlad sa yugtong ito sa pamamagitan ng pagtatanong:

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;

Kung hindi na magbabago ang timestamp, kumpleto na ang pag-restore. Maaari mong i-customize ang pagkilos recovery_target_actionupang isara, i-promote, o i-pause ang instance pagkatapos ng muling pagsubok (ito ay naka-pause bilang default).

Ang database ay dumating sa estado bago ang masamang kahilingan na iyon. Ngayon ay maaari ka na, halimbawa, mag-export ng data. Na-export namin ang data ng remote na label at lahat ng mga link sa mga isyu at mga kahilingan sa pagsasanib at inilipat ang mga ito sa database ng produksyon. Kung malaki ang mga pagkalugi, maaari mo lamang i-promote ang replica at gamitin ito bilang pangunahing isa. Ngunit pagkatapos ay mawawala ang lahat ng pagbabago pagkatapos ng sandali kung saan kami nakabawi.

Mas mainam na gumamit ng mga transaction ID sa halip na mga timestamp. Kapaki-pakinabang na itala ang mga ID na ito, halimbawa, para sa mga pahayag ng DDL (tulad ng DROP TABLE), sa pamamagitan ng paggamit log_statements = 'ddl'. Kung mayroon kaming transaction ID, kukunin namin recovery_target_xid at pinatakbo ang lahat hanggang sa transaksyon bago ang kahilingan DELETE.

Ang pagbabalik sa trabaho ay napakasimple: alisin ang lahat ng pagbabago mula sa recovery.conf at i-restart ang mga postgres. Sa lalong madaling panahon ang cue ay magkakaroon muli ng walong oras na pagkaantala, at handa na kami para sa mga problema sa hinaharap.

Mga Benepisyo sa Pagbawi

Sa isang naantalang replica, sa halip na isang malamig na backup, hindi mo kailangang gumastos ng oras sa pagpapanumbalik ng buong snapshot mula sa archive. Halimbawa, kailangan namin ng limang oras para makuha ang buong 2 TB base backup. At pagkatapos ay kailangan mo pa ring ilapat ang buong pang-araw-araw na WAL upang mabawi sa nais na estado (sa pinakamasamang kaso).

Ang isang naantalang replica ay mas mahusay kaysa sa isang malamig na backup sa dalawang paraan:

  1. Hindi mo kailangang kunin ang buong base backup mula sa archive.
  2. May nakapirming walong oras na palugit ng mga segment ng WAL na dapat ulitin.

Gayundin, patuloy naming sinusuri kung ang WAL ay maaaring PITRed, at mabilis naming mapapansin ang katiwalian o iba pang mga problema sa WAL archive sa pamamagitan ng pagsubaybay sa backlog ng naantalang replika.

Sa halimbawang ito, tumagal kami ng 50 minuto upang maibalik, ibig sabihin, ang bilis ay 110 GB ng WAL data kada oras (naka-on pa rin ang archive AWS S3). Sa kabuuan, nalutas namin ang problema at naibalik ang data sa loob ng 1,5 oras.

Buod: kung saan kapaki-pakinabang ang isang naantalang replika (at kung saan hindi)

Gamitin ang naantalang pagtitiklop bilang pangunang lunas kung hindi mo sinasadyang mawalan ng data at mapansin ang sakuna na ito sa loob ng na-configure na pagkaantala.

Ngunit tandaan: ang pagtitiklop ay hindi isang backup.

Ang pag-backup at pagkopya ay may iba't ibang layunin. Magagamit ang isang malamig na backup kung hindi mo sinasadyang ginawa DELETE o DROP TABLE. Gumagawa kami ng backup mula sa malamig na imbakan at ibinabalik ang nakaraang estado ng isang talahanayan o isang buong database. Ngunit sa parehong oras ang kahilingan DROP TABLE halos agad na muling ginawa sa lahat ng mga replika sa gumaganang kumpol, kaya ang regular na pagtitiklop ay hindi magse-save dito. Ang pagkopya mismo ay nagpapanatili ng database na magagamit kapag ang mga indibidwal na server ay naupahan at namamahagi ng load.

Kahit na may naantalang replica, minsan kailangan talaga namin ng malamig na backup sa isang ligtas na lugar, kung biglang may pagkabigo sa data center, nakatagong pinsala, o iba pang mga kaganapan na hindi mo agad napapansin. Dito mula sa isang pagtitiklop ay walang kahulugan.

Nota. Sa GitLab.com kasalukuyan naming pinoprotektahan lamang laban sa pagkawala ng data sa antas ng system at hindi ibinabalik ang data sa antas ng user.

Pinagmulan: www.habr.com

Magdagdag ng komento