
Replikatsioon ei ole varundamine. Või kuidas? Nii kasutasime edasilükatud replikatsiooni taastamiseks, kui juhuslikult kaotasime otseteed.
GitLabis vastutavad — kõige suurema GitLabi eksemplari eest maailmas. Siin on 3 miljonit kasutajat ja peaaegu 7 miljonit projekti, ja see on üks suurimaid avatud lähtekoodiga SaaS veebisaite, millel on pühendatud arhitektuur. Ilma PostgreSQL andmebaasisüsteemita ei saaks GitLab.com kaugeltki hakkama ning me teeme kõik, et tagada jätkusuutlikkus igasuguste tõrgete korral, millega andmed võivad kaduda. See katastroof tõenäoliselt ei juhtu, kuid oleme hästi ette valmistunud ja varustanud end erinevate varundamis- ja replikatsioonimehhanismidega.
Replikatsioon ei ole andmebaasi varundamise vahend (). Kuid nüüd näeme, kuidas kiiresti taastada juhuslikult kustutatud andmed edasilükatud replikatsiooni abil: kasutaja projekti jaoks ja kaotasin ühenduse liitmisettepanekute ja ülesannetega.
Edasilükatud replikatsiooni abil taastasime andmed vaid 1,5 tunni jooksul. Vaata, kuidas see juhtus.
Ajapunkti taastamine PostgreSQLis
PostgreSQL-il on sisseehitatud funktsioon, mis taastab andmebaasi seisundi teatud ajapunktis. Seda nimetatakse (PITR) ja see kasutab samu mehhanisme, mis toetavad replikatsiooni ajakohasust: alustame usaldusväärsest väljavõttest kogu andmebaasi klastrist (põhivarundus) ning rakendame muudatusi seisundi osas kuni teatud ajapunktini.
Selle funktsiooni kasutamiseks külmavaru, teeme regulaarselt põhivarunduse andmebaasist ja hoiame seda arhiivis (GitLabi arhiivide asukoht on ). Ja jälgime ka andmebaasi seisundi muutusi, arhiivides etteteatava kirjutamise päeviku (, WAL). Ja kõigega selle abil saame teostada PITR-i avarii taastamiseks: alustame väljavõttest, mis tehti enne viga, ja rakendame muudatused WAL arhiivist kuni tõrkeni.
Mis on edasilükatud replikatsioon?
Edasilükatud replikatsioon on muudatuste rakendamine WAL-st viivitusega. See tähendab, et tehing toimus tunni X, kuid replikatsioonis ilmub see viivitusega d tunni X + d.
PostgreSQL-is on kahte tüüpi füüsilise andmebaasi replikatsiooni seadistamise viise: arhiivist taastamine ja voogedastav replikatsioon. , sisuliselt töötab nagu PITR, kuid pidevalt: me ekstrakteerime pidevalt muudatusi WAL arhiivist ja rakendame neid koopiale. A ekstraheerib otse WAL voogu ülemalt andmebaasi hostilt. Eelistame taastamist arhiivist — sellega on lihtsam hallata ja sellel on normaalne jõudlus, mis ei jää järelhaardest maha.
Kuidas seadistada viivitusega taastamine arhiivist
on toodud failis recovery.conf. Näidis:
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'Nende parameetritega oleme seadistanud viivitusega koopia taastamise arhiivist. Siin kasutatakse WAL segmentide (restore_command) ekstraheerimiseks arhiivist, ja muudatused rakendatakse kaheksa tunni pärast (recovery_min_apply_delay). Koopia jälgib arhiivi ajaskaala muudatusi, näiteks klasteri ebaõnnestumise insidente (recovery_target_timeline).
A recovery_min_apply_delay on võimalik seadistada viivitusega voogedastamise replikatsioon, kuid siin on paar peent nüanssi, mis on seotud replikatsiooni slotide, kuumvaru tagasiside ja muu sarnasega. WAL arhiiv võimaldab neid vältida.
Parameeter recovery_min_apply_delay ilmus alles PostgreSQL 9.3. Eelmistes versioonides tuli viivitusega replikatsiooni seadistamiseks kasutada kombinatsiooni (pg_xlog_replay_pause(), pg_xlog_replay_resume()) või hoida WAL segmente arhiivis viivituse aja jooksul.
Kuidas PostgreSQL seda teeb?
On huvitav vaadata, kuidas PostgreSQL rakendab viivitusega taastamist. Vaatame . Seda kutsutakse välja igal WAL kirjal.
static bool
recoveryApplyDelay(XLogReaderState *record)
{
uint8 xact_info;
TimestampTz xtime;
long secs;
int microsecs;
/* ничего не нужно делать, если задержка не настроена */
if (recovery_min_apply_delay <= 0)
return false;
/* задержка не применяется к базе данных, которая еще не согласована */
if (!reachedConsistency)
return false;
/*
* Это запись COMMIT?
*
* Мы намеренно выбираем не задерживать отмены, так как они не влияют на
* MVCC. Мы уже разрешаем воспроизведение записей, у которых нет отметки времени,
* так что уже есть возможность возникновения проблем, вызванных преждевременными конфликтами на
* резервных копиях.
* /
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);
/*
* Выход без активации фиксации, если уже время применять эту
* запись
*/
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// Укорочено:
// Используйте WaitLatch, пока не дойдем до recoveryDelayUntilTime
// и затем
break;
}
return true;
}Küsimus on selles, et viivitus põhineb füüsilisel ajal, mis on salvestatud tehingu commit'i ajatempli (xtime). Nagu näha, kehtib viivitus ainult commit'ide puhul ja ei puutu teistesse salvestustesse — kõik muudatused kehtivad otse ja commit lükatakse edasi, seega näeme muudatusi alles pärast seatud viivitust.
Kuidas kasutada viivitust replikatsiooni andmete taastamiseks
Oletame, et meil on tootmisriigis andmebaasi klaster ja kaheksa tundi viivitusega replikatsioon. Vaadakem, kuidas taastada andmeid näiteks .
Kui me probleemist kuuldes, oleme viivitusega replikatsiooniks:
SELECT pg_xlog_replay_pause();Pauses ei olnud meil ohtu, et replikatsioon korraks sama päringut. DELETE. Kasulik asi, kui on vaja aega kõik ära selgitada.
Küsimus on selles, et viivitusega replikatsioon peab jõudma hetke enne päringut. DELETE. Me teadsime ligikaudu kustutamise füüsilist aega. Me kustutasime recovery_min_apply_delay ja lisasime recovery_target_time ja recovery.conf. Nii jõuab replikatsioon soovitud hetkeni viivitusteta:
recovery_target_time = '2018-10-12 09:25:00+00'Ajatempleid on parem maha võtta, et mitte mööda lasta. Tõsi, mida rohkem maha võtame, seda rohkem andmeid kaotame. Taas, kui jätame päringu vahele, DELETE, kõik kustub taas ja peame uuesti alustama (või võtma külma varukoopia PITR jaoks).
Me taaskäivitame Postgresi viivitustootmise ja WAL-segmendid taastatakse määratud ajani. Selle etapi edenemist saab jälgida päringuga:
SELECT
-- praegune asukoht WAL-s
pg_last_xlog_replay_location(),
-- praegune tehingu ajatemperatuur (repliika olek)
pg_last_xact_replay_timestamp(),
-- praegune füüsiline aeg
now(),
-- ajavahemik, mis tuleb veel rakendada, kuni recovery_target_time on saavutatud
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;Kui ajatemperatuur enam ei muutu, on taastamine lõppenud. Saame seadistada tegevuse , et sulgeda, edastada või peatada eksemplar pärast kordamist (vaikimisi peatatakse).
Andmebaas on jõudnud enne seda õnnetut päringut. Nüüd saame näiteks andmeid eksportida. Me eksportisime kustutatud andmeid sildist ja kõik seosed ülesannete ning ühinemis-ettepanekutega ja kandisime need tootmisandmebaasi. Kui kadumine on ulatuslik, saame lihtsalt edastada repliika ja kasutada seda põhina. Aga siis kaovad kõik muudatused pärast hetke, mil me taastuma jõudsime.
Aja stampide asemel on parem kasutada tehingu ID-sid. On kasulik need ID-d üles kirjutada, näiteks DDL-operatsioonide jaoks (tüüpi DROP TABLE), kasutades log_statements = 'ddl'. Kui meil oleks tehingu ID, saaksime võtta recovery_target_xid ja käivitada kõik kuni tehinguni enne päringut. DELETE.
Töötamiseks naasmine on väga lihtne: eemaldage kõik muutused recovery.conf ja taaskäivitage Postgres. Varsti on repliikas taas kaheksa tunni viivitus ja oleme valmis tulevasteks probleemideks.
Taastamise eelised
Viivitustega repliikaga ei pea kogu varukohta tundideks taastama. Näiteks kulub meil veel viis tundi, et saada kogu 2 TB suurune põhi varukohti arhiivist. Ja siis tuleb veel kogu ööpäeva WAL rakendada, et taastuda soovitud olekusse (halvimal juhul).
Viivitav repliik on parem külmavara varukohta kahes punktis:
- Ei pea kogu põhi varukohta arhiivist välja tõmbama.
- On kindel kaheksa tunni aken WAL-segmentide jaoks, mis tuleb taastada.
Ja me jälgime pidevalt, kas WAL-ist saab PITR-i teha, ning märkaks kiiresti kahjustusi või muid WAL-arhiivi probleeme, jälgides viivitava repliika mahajäämust.
Selles näites kulus meil taastamiseks 50 minutit, mis tähendab, et kiirus oli 110 GB WAL-andmeid tunnis (arhiiv oli siis endiselt peal). ). Kokku lahendasime probleemi ja taastatasime andmed 1,5 tunni jooksul.
Kokkuvõte: kus on kasulik edasi lükatud replikatsioon (ja kus mitte)
Kasutage edasi lükatud replikatsiooni esmaabi vahendina, kui olete kogemata andmed kaotanud ja märkate seda probleemile seadistatud viivituse raames.
Aga pidage meeles: replikatsioon ei ole varundus.
Varundusel ja replikatsioonil on erinevad eesmärgid. Külm varundus on kasulik, kui olete kogemata teinud DELETE või DROP TABLE. Me teeme varunduse külmalt hoidmisest ja taastame tabeli või kogu andmebaasi eelneva oleku. Kuid selles osas päring DROP TABLE peaaegu koheselt replitseeritakse kõikidesse replikatsioonidesse tööklusteris, seega tavapärane replikatsioon siin ei päästa. Isegi replikatsioon hoiab andmebaasi kergesti kättesaadavana, kui eraldi serverid üle antakse ja jaotab koormust.
Isegi edasi lükatud replikatsiooniga on meil mõnikord väga vajalik külm varundus turvalises kohas, kui peaks tekkima andmekeskuse tõrge, varjatud kahjustus või muud olukorrad, mida kohe ei märka. Siin ei ole replikatsioonist abi.
Märkus. Sellel me kaitseme praegu andmete kaotsimineku eest ainult süsteemi tasemel ning ei taasta andmeid kasutaja tasemel.
Allikas: habr.com
