
Replikácia nie je záloha. Alebo áno? Takto sme použili oneskorenú replikáciu na obnovenie po náhodnom odstránení skratiek.
na GitLab sa starajú o prevádzku — najväčšej inštancie GitLab na svete. Tu je 3 milióny používateľov a takmer 7 miliónov projektov, a to je jedna z najväčších open-source SaaS stránok s dedikovanou architektúrou. Bez systému databáz PostgreSQL sa GitLab.com ďaleko nedostane, a čo len nerobíme preto, aby sme zabezpečili odolnosť v prípade akýchkoľvek porúch, pri ktorých môžeme stratiť dáta. Je nepravdepodobné, že by sa taká katastrofa stala, ale dobre sme sa pripravili a zásobili rôznymi mechanizmami zálohovania a replikácie.
Replikácia nie je spôsob zálohovania databáz (). Ale teraz uvidíme, ako rýchlo obnoviť náhodne odstránené dáta pomocou oneskorenej replikácie: na používateľ pre projekt a stratil spojenia s merge-requestmi a úlohami.
S oneskorenou replikou sme obnovili dáta za iba 1,5 hodiny. Pozrite, ako to bolo.
Obnovenie k určitému času s PostgreSQL
PostgreSQL má zabudovanú funkciu, ktorá obnovuje stav databázy na určitý čas. Nazýva sa (PITR) a využíva rovnaké mechanizmy, ktoré udržujú aktuálnosť repliky: začneme spoľahlivým snímkom celého klasteru databázy (základná záloha) a aplikujeme sériu zmien stavu až do určitého času.
Aby sme mohli túto funkciu použiť pre studenú zálohu, pravidelne robíme základnú zálohu databázy a uchovávame ju v archíve (archívy GitLab žijú v ). A sledujeme aj zmeny stavu databázy archivovaním žurnálu predchádzajúceho zápisu (, WAL). A s tým všetkým môžeme vykonať PITR pre havarijné obnovenie: začíname so snímkom, vykonaným pred chybou, a aplikujeme zmeny z archívu WAL až do poruchy.
Čo je to oneskorená replikácia?
Oneskorená replikácia je aplikácia zmien z WAL so oneskorením. To znamená, že transakcia sa uskutočnila o hodinu X, ale v replikácii sa objaví so oneskorením d o hodinu X + d.
V PostgreSQL sú 2 spôsoby, ako nastaviť fyzickú replikáciu databázy: obnova z archívu a streamová replikácia. , v podstate funguje ako PITR, ale nepretržite: neustále extrahujeme zmeny z archívu WAL a aplikujeme ich na replikáciu. A priamo extrahuje tok WAL z nadradeného hostiteľa databázy. Uprednostňujeme obnovenie z archívu – je to jednoduchšie na správu a má normálny výkon, ktorý sa neliši od pracovného klasteru.
Ako nastaviť oneskorené obnovenie z archívu
sú opísané v súbore recovery.conf. Príklad:
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'S týmito parametrami sme nastavili oneskorenú replikáciu s obnovením z archívu. Tu sa používa na extrakciu segmentov WAL (restore_command) z archívu, a zmeny sa aplikujú za osem hodín (recovery_min_apply_delay). Replika bude sledovať zmeny časovej osi v archíve, napríklad v prípade zlyhania v klastri (recovery_target_timeline).
S recovery_min_apply_delay je možné nastaviť streamovaciu replikáciu s oneskorením, ale existuje niekoľko úskalí súvisiacich so slotmi replikácie, spätnou väzbou horúcej rezervy atď. Archív WAL umožňuje ich obísť.
Parameter recovery_min_apply_delay sa objavil len v PostgreSQL 9.3. V predchádzajúcich verziách bolo na nastavenie oneskorenej replikácie potrebné nastaviť kombináciu (pg_xlog_replay_pause(), pg_xlog_replay_resume()) alebo uchovávať segmenty WAL v archíve počas doby oneskorenia.
Ako to robí PostgreSQL?
Je zaujímavé vidieť, ako PostgreSQL implementuje oneskorené obnovenie. Pozrime sa na . Je volaný z pre každý záznam z WAL.
static bool
recoveryApplyDelay(XLogReaderState *record)
{
uint8 xact_info;
TimestampTz xtime;
long secs;
int microsecs;
/* nič nerobíme, ak nie je nakonfigurované oneskorenie */
if (recovery_min_apply_delay <= 0)
return false;
/* žiadne oneskorenie sa neuplatňuje na databázu, ktorá ešte nie je konzistentná */
if (!reachedConsistency)
return false;
/*
* Je to záznam COMMIT?
*
* Zámerne sa rozhodujeme neodkladať aborty, pretože nemajú žiadny vplyv na
* MVCC. Už umožňujeme prehrávanie záznamov, ktoré nemajú časovú pečať,
* takže už existuje možnosť problémov spôsobených skorými konfliktami na
* stand-by.
* /
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);
/*
* Ukončiť bez zbrojenia spúšťacieho, ak už uplynul čas na uplatnenie tohto
* záznamu
* /
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// Skrátil:
// Použití WaitLatch, kým nedosiahne recoveryDelayUntilTime
// a potom
break;
}
return true;
}Podstatné je, že oneskorenie je založené na fyzickom čase zapísanom v časovej pečati komitnej transakcie (xtime). Ako je vidno, oneskorenie sa uplatňuje iba na komitmy a netýka sa ostatných záznamov — všetky zmeny sa uplatňujú priamo, zatiaľ čo komit sa odkladá, takže uvidíme zmeny až po nastavenom oneskorení.
Ako použiť oneskorenú replikáciu na obnovu dát
Predpokladajme, že v produkcii máme databázový klaster a replikáciu s osemhodinovým oneskorením. Pozrime sa, ako obnoviť dáta na príklade .
Keď sme sa dozvedeli o probléme, my pre oneskorenú replikáciu:
SELECT pg_xlog_replay_pause();S pozastavením sme nemali riziko, že replikácia zopakuje požiadavok DELETE. Užitečná vec, ak potrebujeme čas na všetko pochopiť.
Podstatné je, že oneskorená replikácia by mala dosiahnuť čas pred požiadavkou DELETE. Približne sme vedeli fyzický čas odstránenia. Odstránili sme recovery_min_apply_delay a pridali recovery_target_time v recovery.conf. Takto replikácia dosiahne potrebný čas bez oneskorení:
recovery_target_time = '2018-10-12 09:25:00+00'S časovými pečaťami je dobré znížiť zbytočné, aby sme sa netrafili. Pravda, čím viac zníženia, tým viac dát strácame. Opäť, ak prejdeme požiadavku DELETE, všetko sa opäť vymaže a bude potrebné začať odznova (alebo si vziať studenú zálohu na PITR).
Znovu sme spustili odloženú inštanciu Postgres a segmenty WAL sa opakovali do určeného času. Pokrok v tejto fáze je možné sledovať pomocou dotazu:
SELECT
-- aktuálna poloha v WAL
pg_last_xlog_replay_location(),
-- aktuálny časový pečiatok transakcie (stav repliky)
pg_last_xact_replay_timestamp(),
-- aktuálny fyzický čas
now(),
-- množstvo času, ktoré sa ešte musí aplikovať, kým sa dosiahne recovery_target_time
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;Ak sa časová pečiatka už nezmení, obnovenie je dokončené. Môžeme nastaviť akciu , aby sme uzavreli, posunuli alebo pozastavili inštanciu po opakovaní (prednastavené je pozastavenie).
Databáza sa dostala do stavu pred tým nešťastným dotazom. Teraz môžeme napríklad exportovať údaje. Exportovali sme vymazané údaje o štítku a všetky spojenia s úlohami a merge-requestmi a preniesli ich do pracovnej databázy. Ak sú straty rozsiahle, môžeme jednoducho posunúť replikáciu a použiť ju ako hlavnú. Ale potom prídeme o všetky zmeny po momente, do ktorého sme sa obnovili.
Namiesto časových pečiatok je lepšie používať ID transakcií. Je užitočné tieto ID zapisovať, napríklad pre operátory DDL (ako je DROP TABLE), pomocou log_statements = 'ddl'. Keby sme mali ID transakcie, vzali by sme recovery_target_xid a prešli všetko až po transakciu pred dopytom. DELETE.
Je veľmi jednoduché vrátiť sa k práci: vymažete všetky zmeny z recovery.conf a znovu spustíte Postgres. Čoskoro sa v replikácii opäť objaví osemhodinové oneskorenie a sme pripravení na budúce problémy.
Výhody obnovenia
S odloženou replikou nemusíme hodiny obnovovať celý snímok z archívu ako pri studenom zálohovaní. Napríklad potrebujeme päť hodín, aby sme dostali celú základnú zálohu na 2 TB. A potom musíme ešte aplikovať celý denný WAL, aby sme sa dostali do požadovaného stavu (v najhoršom prípade).
Odložená replikácia je lepšia ako studené zálohovanie z dvoch bodov:
- Nie je potrebné vyťahovať celú základnú zálohu z archívu.
- Existuje fixné osemhodinové okno segmentov WAL, ktoré treba zopakovať.
A navyše neustále kontrolujeme, či je možné vykonať PITR z WAL, a rýchlo by sme si všimli poškodenia alebo iné problémy s archívom WAL, sledujúc odstup odloženej repliky.
V tomto príklade sme potrebovali 50 minút na obnovenie, čo znamená, že rýchlosť bola 110 GB dát WAL za hodinu (archív bol stále na ). Celkovo sme problém vyriešili a obnovili dáta za 1,5 hodiny.
Zhrnutie: kde je užitočná oneskorená replikácia (a kde nie)
Použite oneskorenú replikáciu ako prostriedok prvej pomoci, ak ste náhodne stratili dáta a uvedomili si tento problém v rámci nastaveného zdržania.
Ale majte na pamäti: replikácia nie je záloha.
Záloha a replikácia majú rôzne ciele. Studená záloha bude užitočná, ak ste náhodou vykonali DELETE alebo DROP TABLE. Robíme zálohu zo studeného úložiska a obnovujeme predchádzajúci stav tabulky alebo celej databázy. Ale v tomto prípade sa dopyt DROP TABLE takmer okamžite reprodukuje vo všetkých replikách na pracovnom klastri, takže bežná replikácia tu nepomôže. Samotná replikácia udržiava databázu dostupnú, keď sa odovzdajú jednotlivé servery, a rozdeľuje záťaž.
Aj s oneskorenou replikáciou potrebujeme niekedy veľmi studenú zálohu na bezpečnom mieste, ak sa náhodou vyskytne výpadok dátového centra, skryté poškodenie alebo iné udalosti, ktoré si hneď nevšimnete. Tu od jednej replikácie nie je žiadny úžitok.
Poznámka. Na teraz chránime pred stratou dát iba na úrovni systému a neobnovujeme dáta na úrovni používateľa.
Zdroj: habr.com
