Replikacija nėra atsarginė kopija. Arba ne? Štai kaip mes panaudojome atidėtą replikaciją, kad atsikurtume po netyčinių sparčiųjų klavišų ištrynimo.
Replikacija nėra priemonė kurti atsargines duomenų bazių kopijas (gitlab-ce
Naudodami atidėtą kopiją, duomenis atkūrėme vos per 1,5 valandos. Pažiūrėk, kaip tai atsitiko.
Laiko atkūrimas naudojant PostgreSQL
PostgreSQL turi integruotą funkciją, kuri atkuria duomenų bazės būseną tam tikru momentu. Tai vadinama
Norėdami naudoti šią funkciją šaltajam atsarginiam kopijavimui, reguliariai sukuriame bazinę duomenų bazės atsarginę kopiją ir saugome ją archyve („GitLab“ archyvai veikia
Kas yra atidėtas replikavimas?
Tingus replikavimas – tai WAL pakeitimų taikymas su uždelsimu. Tai yra, sandoris įvyko per valandą X
, bet jis bus rodomas kopijoje su vėlavimu d
per valandą X + d
.
„PostgreSQL“ turi 2 būdus, kaip nustatyti fizinę duomenų bazės kopiją: atsarginės kopijos atkūrimą ir srautinio perdavimo replikaciją.
Kaip nustatyti atidėtą atkūrimą iš archyvo
recovery.conf
. Pavyzdys:
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'
Naudodami šiuos parametrus sukonfigūravome atidėtą kopiją su atsarginės kopijos atkūrimu. Čia jis naudojamas restore_command
) iš archyvo, o pakeitimai bus pritaikyti po aštuonių valandų (recovery_min_apply_delay
). Replika stebės laiko juostos pakeitimus archyve, pvz., dėl klasterio gedimo (recovery_target_timeline
).
С recovery_min_apply_delay
Galite nustatyti srautinio perdavimo replikaciją su uždelsimu, tačiau čia yra keletas spąstų, susijusių su replikacijos lizdais, karštojo budėjimo režimo atsiliepimais ir pan. WAL archyvas leidžia jų išvengti.
Parametras recovery_min_apply_delay
pasirodė tik PostgreSQL 9.3. Ankstesnėse versijose, norint atidėti replikaciją, reikia sukonfigūruoti derinį pg_xlog_replay_pause(), pg_xlog_replay_resume()
) arba laikykite WAL segmentus archyve visą delsos laiką.
Kaip PostgreSQL tai daro?
Įdomu pamatyti, kaip PostgreSQL įgyvendina tingų atkūrimą. Pažiūrėkime recoveryApplyDelay(XlogReaderState)
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, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// Shortened:
// Use WaitLatch until we reached recoveryDelayUntilTime
// and then
break;
}
return true;
}
Esmė ta, kad delsa pagrįsta fiziniu laiku, įrašytu operacijos įvykdymo laiko žymoje (xtime
). Kaip matote, delsimas taikomas tik commitams ir neturi įtakos kitiems įrašams – visi pakeitimai taikomi tiesiogiai, o commit vėluoja, todėl pakeitimus matysime tik po sukonfigūruoto uždelsimo.
Kaip naudoti uždelstą kopiją duomenims atkurti
Tarkime, kad turime duomenų bazės klasterį ir kopiją su aštuonių valandų gamybos vėlavimu. Pažiūrėkime, kaip atkurti duomenis naudojant pavyzdį
Kai sužinojome apie problemą, mes
SELECT pg_xlog_replay_pause();
Su pauze neturėjome rizikos, kad kopija pakartos užklausą DELETE
. Naudingas dalykas, jei reikia laiko viską išsiaiškinti.
Esmė ta, kad atidėta kopija turi pasiekti momentą prieš užklausą DELETE
. Mes maždaug žinojome fizinį pašalinimo laiką. Mes ištrynėme recovery_min_apply_delay
ir pridėjo recovery_target_time
в recovery.conf
. Taip replika nedelsdama pasiekia reikiamą momentą:
recovery_target_time = '2018-10-12 09:25:00+00'
Naudojant laiko žymas, geriau sumažinti perteklių, kad nepraleistumėte. Tiesa, kuo didesnis sumažėjimas, tuo daugiau duomenų prarandame. Vėlgi, jei praleisime prašymą DELETE
, viskas vėl bus ištrinta ir teks pradėti iš naujo (ar net pasidaryti šaltą atsarginę PITR).
Iš naujo paleidome atidėtą Postgres egzempliorių ir WAL segmentai buvo kartojami iki nurodyto laiko. Šiame etape galite stebėti pažangą klausdami:
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;
Jei laiko žyma nebekeičiama, atkūrimas baigtas. Veiksmą galima pritaikyti recovery_target_action
Duomenų bazė grįžo į savo būseną prieš šį apgailėtiną prašymą. Dabar galite, pavyzdžiui, eksportuoti duomenis. Eksportavome ištrintus etiketės duomenis ir visas nuorodas į problemas bei sujungimo užklausas ir perkėlėme į gamybos duomenų bazę. Jei nuostoliai yra didelio masto, galite tiesiog reklamuoti kopiją ir naudoti ją kaip pagrindinę. Bet tada visi pokyčiai po taško, iki kurio atsigavome, bus prarasti.
Vietoj laiko žymų geriau naudoti operacijų ID. Naudinga įrašyti šiuos ID, pavyzdžiui, DDL teiginiams (pvz., DROP TABLE
), naudojant log_statements = 'ddl'
. Jei turėtume operacijos ID, imtume recovery_target_xid
ir paleido viską iki sandorio prieš užklausą DELETE
.
Grįžti į darbą labai paprasta: pašalinkite visus pakeitimus iš recovery.conf
ir iš naujo paleiskite Postgres. Netrukus replika vėl vėluos aštuonias valandas, ir mes esame pasiruošę būsimoms bėdoms.
Atkūrimo privalumai
Turėdami atidėtą kopiją, o ne šaltą atsarginę kopiją, jums nereikės valandų valandų atkurti viso vaizdo iš archyvo. Pavyzdžiui, mums reikia penkių valandų, kad gautume visą pagrindinę 2 TB atsarginę kopiją. Ir tada vis tiek turite pritaikyti visą dienos WAL, kad atsigautumėte į norimą būseną (blogiausiu atveju).
Atidėta kopija yra geriau nei šaltoji atsarginė kopija dviem būdais:
- Nereikia pašalinti visos pagrindinės atsarginės kopijos iš archyvo.
- Yra nustatytas aštuonių valandų WAL segmentų langas, kuris turi būti kartojamas.
Taip pat nuolat tikriname, ar galima padaryti PITR iš WAL, ir greitai pastebėtume korupciją ar kitas WAL archyvo problemas, stebėdami atidėtos replikos atsilikimą.
Šiame pavyzdyje atkūrimas užtruko 50 minučių, o tai reiškia, kad greitis buvo 110 GB WAL duomenų per valandą (archyvas vis dar buvo įjungtas
Rezultatai: kur atidėta kopija yra naudinga (o kur ne)
Naudokite atidėtą replikaciją kaip pirmąją pagalbą, jei netyčia praradote duomenis ir pastebėjote šią problemą per sukonfigūruotą delsą.
Tačiau atminkite: replikacija nėra atsarginė kopija.
Atsarginė kopija ir replikacija turi skirtingus tikslus. Šalta atsarginė kopija bus naudinga, jei netyčia padarėte DELETE
arba DROP TABLE
. Padarome atsarginę kopiją iš šaltosios saugyklos ir atkuriame ankstesnę lentelės arba visos duomenų bazės būseną. Bet kartu ir prašymas DROP TABLE
beveik akimirksniu atkuriamas visose darbo klasterio kopijose, todėl įprasta replikacija čia nepadės. Pati replikacija palaiko duomenų bazę prieinamą, kai atskiri serveriai išnuomojami ir paskirsto apkrovą.
Net ir naudojant atidėtą kopiją, kartais mums tikrai reikia šaltos atsarginės kopijos saugioje vietoje, jei įvyksta duomenų centro gedimas, paslėpta žala ar kiti įvykiai, kurie nėra iš karto pastebimi. Vien replikacija čia nenaudinga.
Atkreipti dėmesį. Apie
Šaltinis: www.habr.com