Kā mēs izmantojām aizkavētu replikāciju avārijas atkopÅ”anai, izmantojot PostgreSQL

Kā mēs izmantojām aizkavētu replikāciju avārijas atkopÅ”anai, izmantojot PostgreSQL
Replikācija nav dublējums. Vai nē? LÅ«k, kā mēs izmantojām atlikto replikāciju, lai atgÅ«tu no nejauÅ”as Ä«sceļu dzÄ“Å”anas.

InfrastruktÅ«ras speciālisti GitLab ir atbildÄ«gs par darbu GitLab.com - lielākā GitLab eksemplārs dabā. Ar 3 miljoniem lietotāju un gandrÄ«z 7 miljoniem projektu tā ir viena no lielākajām atvērtā pirmkoda SaaS vietnēm ar Ä«paÅ”u arhitektÅ«ru. Bez PostgreSQL datu bāzes sistēmas GitLab.com infrastruktÅ«ra netiks tālu, un ko mēs darām, lai nodroÅ”inātu kļūdu toleranci jebkādu kļūmju gadÄ«jumā, kad dati var tikt zaudēti. Maz ticams, ka Ŕāda nelaime notiks, taču esam labi sagatavojuÅ”ies un uzkrājuÅ”i dažādus rezerves un replikācijas mehānismus.

Replikācija nav lÄ«dzeklis datu bāzu dublÄ“Å”anai (SkatÄ«t zemāk). Bet tagad mēs redzēsim, kā ātri atgÅ«t nejauÅ”i izdzēstos datus, izmantojot slinku replikāciju: ieslēgts GitLab.com lietotājs izdzēsa saÄ«sni projektam gitlab-ce un zaudēti savienojumi ar sapludināŔanas pieprasÄ«jumiem un uzdevumiem.

Izmantojot atlikto kopiju, mēs atkopām datus tikai 1,5 stundu laikā. Paskaties, kā tas notika.

AtgūŔana noteiktā laikā, izmantojot PostgreSQL

PostgreSQL ir iebÅ«vēta funkcija, kas atjauno datu bāzes stāvokli noteiktā brÄ«dÄ«. Tas tiek saukts AtgÅ«Å”ana noteiktā laikā (PITR) un izmanto tos paÅ”us mehānismus, kas nodroÅ”ina reprodukcijas atjaunināŔanu: sākot ar uzticamu visa datu bāzes klastera momentuzņēmumu (bāzes dublējums), mēs piemērojam virkni stāvokļa izmaiņu lÄ«dz noteiktam brÄ«dim.

Lai izmantotu Å”o funkciju aukstai dublÄ“Å”anai, mēs regulāri izveidojam pamata datu bāzes dublējumu un glabājam to arhÄ«vā (GitLab arhÄ«vi ir pieejami Google mākoņkrātuve). Mēs arÄ« uzraugām izmaiņas datubāzes stāvoklÄ«, arhivējot ierakstÄ«Å”anas žurnālu (priekÅ”rakstÄ«Å”anas žurnāls, WAL). Un, ja tas viss ir izveidots, mēs varam veikt PITR avārijas atkopÅ”anai: sākot ar momentuzņēmumu, kas uzņemts pirms kļūmes, un piemērojot izmaiņas no WAL arhÄ«va lÄ«dz kļūmei.

Kas ir atliktā replikācija?

Slinka replikācija ir izmaiņu pielietoÅ”ana no WAL ar aizkavi. Tas ir, darÄ«jums notika stundas laikā X, bet tas tiks parādÄ«ts replikā ar kavÄ“Å”anos d pēc stundas X + d.

PostgreSQL ir divi veidi, kā iestatÄ«t fizisku datu bāzes kopiju: dublējuma atkopÅ”ana un straumÄ“Å”anas replikācija. Atjauno no arhÄ«va, bÅ«tÄ«bā darbojas kā PITR, bet nepārtraukti: mēs pastāvÄ«gi izgÅ«stam izmaiņas no WAL arhÄ«va un lietojam tās replikā. A straumÄ“Å”anas replikācija tieÅ”i izgÅ«st WAL straumi no augÅ”pus datu bāzes resursdatora. Mēs dodam priekÅ”roku arhÄ«va atkopÅ”anai ā€” to ir vieglāk pārvaldÄ«t, un tam ir normāla veiktspēja, kas neatpaliek no ražoÅ”anas klastera.

Kā iestatÄ«t aizkavētu atkopÅ”anu no arhÄ«va

AtkopÅ”anas iespējas aprakstÄ«ts failā recovery.conf. Piemērs:

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'

Izmantojot Å”os parametrus, mēs konfigurējām atlikto repliku ar dublējuma atkopÅ”anu. Å eit tas tiek izmantots Wal-e lai izvilktu WAL segmentus (restore_command) no arhÄ«va, un izmaiņas tiks piemērotas pēc astoņām stundām (recovery_min_apply_delay). Reprodukcija vēros laika skalas izmaiņas arhÄ«vā, piemēram, klastera kļūmjpārlēces (recovery_target_timeline).

Š” recovery_min_apply_delay Varat iestatÄ«t straumÄ“Å”anas replikāciju ar aizkavi, taču Å”eit ir dažas nepilnÄ«bas, kas saistÄ«tas ar replikācijas slotiem, karstās gaidstāves atgriezenisko saiti un tā tālāk. WAL arhÄ«vs ļauj no tiem izvairÄ«ties.

Parametrs recovery_min_apply_delay parādÄ«jās tikai PostgreSQL 9.3. IepriekŔējās versijās, lai veiktu atlikto replikāciju, jums ir jākonfigurē kombinācija atkopÅ”anas vadÄ«bas funkcijas (pg_xlog_replay_pause(), pg_xlog_replay_resume()) vai turiet WAL segmentus arhÄ«vā uz aizkaves laiku.

Kā PostgreSQL to dara?

Interesanti redzēt, kā PostgreSQL Ä«steno slinko atkopÅ”anu. ApskatÄ«sim recoveryApplyDelay(XlogReaderState). To sauc no galvenā atkārtojuma cilpa par katru ierakstu no 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;
}

Galvenais ir tas, ka aizkave ir balstÄ«ta uz fizisko laiku, kas reÄ£istrēts darÄ«juma izpildes laikspiedolā (xtime). Kā redzat, aizkave attiecas tikai uz commitiem un neietekmē citus ierakstus ā€“ visas izmaiņas tiek lietotas tieÅ”i, un commit tiek aizkavēta, tāpēc izmaiņas redzēsim tikai pēc konfigurētās aizkaves.

Kā izmantot aizkavētu repliku datu atjaunoÅ”anai

Pieņemsim, ka mums ir datu bāzes klasteris un kopija ar astoņu stundu ražoÅ”anas aizkavi. ApskatÄ«sim, kā atgÅ«t datus, izmantojot piemēru nejauÅ”i izdzÄ“Å”ot Ä«sceļus.

Kad uzzinājām par problēmu, mēs arhÄ«va atjaunoÅ”ana ir apturēta atliktajai kopijai:

SELECT pg_xlog_replay_pause();

Ar pauzi mums nebija riska, ka kopija atkārtos pieprasījumu DELETE. Noderīga lieta, ja nepiecieŔams laiks, lai visu izdomātu.

Lieta ir tāda, ka atliktajai kopijai ir jāsasniedz brÄ«dis pirms pieprasÄ«juma DELETE. Mēs aptuveni zinājām fizisko izņemÅ”anas laiku. Mēs esam izdzēsuÅ”i recovery_min_apply_delay un pievienoja recovery_target_time Š² recovery.conf. LÅ«k, kā replika bez kavÄ“Å”anās sasniedz pareizo brÄ«di:

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

Izmantojot laika zīmogus, labāk ir samazināt pārpalikumu, lai nepalaistu garām. Tiesa, jo lielāks samazinājums, jo vairāk datu mēs zaudējam. Atkal, ja mēs palaidām garām pieprasījumu DELETE, viss tiks dzēsts vēlreiz, un jums būs jāsāk no jauna (vai pat jāuzņem aukstā dublējums PITR).

Mēs restartējām atlikto Postgres gadījumu, un WAL segmenti tika atkārtoti līdz norādītajam laikam. Šajā posmā varat izsekot progresam, jautājot:

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;

Ja laikspiedols vairs nemainās, atkopÅ”ana ir pabeigta. DarbÄ«bu var pielāgot recovery_target_actionlai pēc atkārtota mēģinājuma aizvērtu, paaugstinātu vai apturētu instanci (pēc noklusējuma tas ir apturēts).

Datubāze atgriezās savā stāvoklÄ« pirms Ŕī nelaimÄ«gā pieprasÄ«juma. Tagad varat, piemēram, eksportēt datus. Mēs eksportējām dzēstos etiÄ·eÅ”u datus un visas saites uz problēmām un sapludināŔanas pieprasÄ«jumiem un pārvietojām tos uz ražoÅ”anas datu bāzi. Ja zaudējumi ir liela mēroga, varat vienkārÅ”i reklamēt kopiju un izmantot to kā galveno. Bet tad visas izmaiņas pēc punkta, lÄ«dz kuram esam atguvuÅ”ies, tiks zaudētas.

Laikspiedolu vietā labāk izmantot darÄ«jumu ID. Ir lietderÄ«gi ierakstÄ«t Å”os ID, piemēram, DDL paziņojumiem (piemēram, DROP TABLE), izmantojot log_statements = 'ddl'. Ja mums bÅ«tu darÄ«juma ID, mēs ņemtu recovery_target_xid un palaida visu lÄ«dz darÄ«jumam pirms pieprasÄ«juma DELETE.

AtgrieÅ”anās darbā ir ļoti vienkārÅ”a: noņemiet visas izmaiņas no recovery.conf un restartējiet programmu Postgre. DrÄ«zumā replika atkal aizkavēsies par astoņām stundām, un mēs esam gatavi turpmākām nepatikÅ”anām.

AtgūŔanas priekŔrocības

Izmantojot atlikto kopiju, nevis aukstu dublējumu, jums nav jātērē stundas, lai atjaunotu visu attēlu no arhÄ«va. Piemēram, mums ir nepiecieÅ”amas piecas stundas, lai iegÅ«tu visu pamata 2 TB dublējumu. Un tad vēl jāpieliek visa ikdienas WAL, lai atgÅ«tos vēlamajā stāvoklÄ« (sliktākajā gadÄ«jumā).

Atliktā kopija ir labāka par aukstu dublējumu divos veidos:

  1. Nav nepiecieÅ”ams noņemt visu pamata dublējumu no arhÄ«va.
  2. Ir fiksēts astoņu stundu WAL segmentu logs, kas ir jāatkārto.

Mēs arī pastāvīgi pārbaudām, vai ir iespējams izveidot PITR no WAL, un mēs ātri pamanām WAL arhīva bojājumus vai citas problēmas, uzraugot atliktās kopijas nobīdi.

Å ajā piemērā atjaunoÅ”ana aizņēma 50 minÅ«tes, kas nozÄ«mē, ka ātrums bija 110 GB WAL datu stundā (arhÄ«vs joprojām bija ieslēgts AWS S3). Kopumā problēmu atrisinājām un datus atkopām 1,5 stundu laikā.

Rezultāti: kur atliktā kopija ir noderīga (un kur tā nav)

Izmantojiet aizkavēto replikāciju kā pirmo palÄ«dzÄ«bu, ja nejauÅ”i pazaudējāt datus un pamanÄ«jāt Å”o problēmu konfigurētās aizkaves laikā.

Bet paturiet prātā: replikācija nav dublējums.

DublÄ“Å”anai un replikācijai ir dažādi mērÄ·i. Aukstā dublējums noderēs, ja nejauÅ”i izveidojāt DELETE vai DROP TABLE. Mēs izveidojam dublējumu no saldētavas un atjaunojam tabulas vai visas datu bāzes iepriekŔējo stāvokli. Bet tajā paŔā laikā lÅ«gums DROP TABLE gandrÄ«z uzreiz tiek reproducēts visās darba klastera replikās, tāpēc parastā replikācija Å”eit nepalÄ«dzēs. Pati replikācija nodroÅ”ina datubāzes pieejamÄ«bu, kad atseviŔķi serveri tiek iznomāti un sadala slodzi.

Pat ar atliktu reprodukciju mums dažreiz patieŔām ir nepiecieÅ”ama auksta dublÄ“Å”ana droŔā vietā, ja rodas datu centra kļūme, slēpti bojājumi vai citi notikumi, kas nav uzreiz pamanāmi. Tikai replikācija Å”eit nav noderÄ«ga.

PiezÄ«me. Par GitLab.com PaÅ”laik mēs aizsargājam tikai pret datu zudumu sistēmas lÄ«menÄ« un neatgÅ«stam datus lietotāja lÄ«menÄ«.

Avots: www.habr.com

Pievieno komentāru