
Replikacija ni varnostna kopija. Ali pa je? Tukaj je, kako smo uporabili odloženo replikacijo za obnovo po naključnem brisanju bližnjic.
na GitLabu so odgovorni za delovanje — največjega primerka GitLaba na svetu. Tukaj je 3 milijone uporabnikov in skoraj 7 milijonov projektov, kar ga uvršča med največje odprtokodne SaaS strani z namensko arhitekturo. Brez sistema baz podatkov PostgreSQL bi infrastruktura GitLab.com težko delovala, in kar koli že počnemo za zagotavljanje odpornosti v primeru okvar, ki bi lahko povzročile izgubo podatkov. Malo verjetno je, da bi se takšna katastrofa zgodila, a smo se dobro pripravili in se opremili z različnimi mehanizmi varnostnega kopiranja in replikacije.
Replikacija ni sredstvo za varnostno kopiranje baz podatkov (). A zdaj bomo videli, kako hitro lahko obnovimo po naključnem brisanju podatke s pomočjo odložene replikacije: na uporabnik za projekt in izgubil povezave z združitvenimi zahtevki in nalogami.
S pomočjo odložene replikacije smo obnovili podatke v samo 1,5 uri. Poglejte, kako je potekalo.
Obnova na točno časovno točko s PostgreSQL
PostgreSQL ima vgrajeno funkcijo, ki obnavlja stanje baze podatkov na določen trenutek. Imenuje se (PITR) in uporablja enake mehanizme, ki podpirajo posodobljeno replikacijo: začenjamo z zanesljivim posnetkom celotnega klasterja baz podatkov (osnovna varnostna kopija) in števimo vrsto sprememb stanja do določenega trenutka.
Da bi to funkcijo uporabili za hladno varnostno kopijo, redno izdelujemo osnovno varnostno kopijo baze podatkov in jo shranjujemo v arhiv (arhivi GitLaba živijo v ). Prav tako spremljamo spremembe v stanju baze podatkov z arhiviranjem dnevnika predhodnih zapisov (, WAL). In s tem lahko izvedemo PITR za nujno obnovo: začnemo s posnetkom, ustvarjenim pred napako, in uporabljamo spremembe iz arhiva WAL do napake.
Kaj je odložena replikacija?
Odložena replikacija je uporaba sprememb iz WAL z zamudo. To pomeni, da se je transakcija zgodila v uri X, toda v replikaciji se bo pojavila z zamudo d v eni uri X + d.
V PostgreSQL sta dva načina za nastavitev fizične replikacije baze podatkov: obnovitev iz arhiva in tokovna replikacija. , v bistvu deluje kot PITR, vendar neprekinjeno: nenehno pridobivamo spremembe iz arhiva WAL in jih uporabljamo na replikaciji. A pridobiva tok WAL neposredno iz nadrejene baze podatkov. Raje imamo obnovitev iz arhiva — lažje je upravljati in ima normalno zmogljivost, ki ne zaostaja za delovnim zvezdnim oblikovnim sistemom.
Kako nastaviti odloženo obnovitev iz arhiva
so opisane v datoteki recovery.conf. Primer:
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 temi parametri smo nastavili odloženo replikacijo z obnovitvijo iz arhiva. Uporablja se za pridobivanje segmentov WAL (restore_command) iz arhiva, spremembe pa bodo uporabljene po osmih urah (recovery_min_apply_delay). Replikacija bo spremljala spremembe časovne osi v arhivu, na primer zaradi obdelave odpovedi v zvezdnem oblaku (recovery_target_timeline).
Z recovery_min_apply_delay lahko nastavite tokovno replikacijo z odložitvijo, a tu obstaja nekaj pasti, povezanih s prostori replikacije, povratnimi informacijami aktivnega rezervnega in podobno. Arhiv WAL omogoča, da se temu izognemo.
Parametri recovery_min_apply_delay se je pojavil šele v PostgreSQL 9.3. V prejšnjih različicah je bilo za odloženo replikacijo treba nastaviti kombinacijo (pg_xlog_replay_pause(), pg_xlog_replay_resume()) ali obdržati segmentne WAL v arhivu za čas odložitve.
Kako to počne PostgreSQL?
Zanimivo je videti, kako PostgreSQL implementira odloženo obnovitev. Poglejmo na . Kliče se iz za vsak zapis iz WAL.
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;
}Суть в том, что задержка основана на физическом времени, записанном в метке времени коммита транзакции (xtime). Как видно, задержка применяется только к коммитам и не затрагивает другие записи — все изменения применяются напрямую, а коммит откладывается, так что мы увидим изменения только после настроенной задержки.
Как использовать отложенную реплику для восстановления данных
Допустим, у нас в продакшене есть кластер базы данных и реплика с восьмичасовой задержкой. Посмотрим, как восстановить данные на примере .
Когда мы узнали о проблеме, мы для отложенной реплики:
SELECT pg_xlog_replay_pause();С паузой у нас не было риска, что реплика повторит запрос DELETE. Полезная штука, если нужно время во всем разобраться.
Суть в том, что отложенная реплика должна дойти до момента перед запросом DELETE. Мы примерно знали физическое время удаления. Мы удалили recovery_min_apply_delay и добавили recovery_target_time u recovery.conf. Так реплика доходит до нужного момента без задержек:
recovery_target_time = '2018-10-12 09:25:00+00'С метками времени лучше убавить лишнего, чтобы не промахнуться. Правда, чем больше убавка, тем больше данных теряем. Опять же, если проскочим запрос DELETE, все опять удалится и придется начинать заново (или вообще брать холодный бэкап для PITR).
Ponovno smo pokrenuli odloženi primjerak Postgresa, a WAL segmenti su se ponavljali do zadanog vremena. Napredak u ovoj fazi može se pratiti upitom:
SELECT
-- trenutna lokacija u WAL
pg_last_xlog_replay_location(),
-- trenutni vremenski žig transakcije (stanje replikata)
pg_last_xact_replay_timestamp(),
-- trenutna fizička vremena
now(),
-- količina vremena koja se još treba primijeniti do postizanja recovery_target_time
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;Ako se vremenski žig više ne mijenja, obnova je završena. Može se postaviti akcija , kako bi se zatvorio, unaprijedio ili obustavio primjerak nakon ponavljanja (zadano se obustavlja).
Baza podataka je došla u stanje prije tog nesretnog upita. Sada možemo, na primjer, izvesti podatke. Izveli smo izbrisane podatke o oznakama i sve veze s zadacima i mjeri zahtjevima te ih prenijeli u radnu bazu. Ako su gubici veliki, možemo jednostavno unaprijediti replikat i koristiti ga kao glavni. No tada će se izgubiti sve promjene nakon trenutka do kojeg smo se obnovili.
Umjesto vremenskih oznaka bolje je koristiti ID transakcija. Korisno je zabilježiti te ID-ove, na primjer, za DDL operatore (poput DROP TABLE), pomoću log_statements = 'ddl'. Da smo imali ID transakcije, uzeli bismo recovery_target_xid i pokrenuli sve do transakcije prije upita DELETE.
Vrati se na posao vrlo lako: ukloni sve promjene iz recovery.conf i ponovo pokreni Postgres. Ubrzo će se u replici ponovo pojaviti osmosatna kašnjenja i spremni smo za buduće nevolje.
Prednosti za obnovu
S odloženom replikom umjesto hladnog backupa ne treba satima obnavljati cijeli snimak iz arhive. Na primjer, treba nam pet sati da dobijemo cijeli osnovni backup od 2 TB. A onda će još trebati primijeniti cijeli dnevni WAL kako bismo se obnovili do potrebnog stanja (u najgorem slučaju).
Odložena replika je bolja od hladnog backupa iz dva razloga:
- Nema potrebe izvlačiti cijeli osnovni backup iz arhive.
- Postoji fiksno osmosatno okno WAL segmenata koje treba ponoviti.
Osim toga, stalno provjeravamo može li se PITR napraviti iz WAL-a, i brzo bismo primijetili oštećenja ili druge probleme s arhivom WAL, prateći kašnjenje odložene replikacije.
U ovom primjeru potrošeno je 50 minuta na obnovu, što znači da je brzina bila 110 GB podataka WAL po satu (arhiv je tada još uvijek bio na ). Z uspehom smo rešili težavo in obnovili podatke v 1,5 uri.
Zaključki: kje je uporabna odložena replikacija (in kje ne)
Uporabite odloženo replikacijo kot sredstvo prve pomoči, če slučajno izgubite podatke in opazite to težavo v okviru nastavljene zamude.
Vendar upoštevajte: replikacija ni varnostna kopija.
Varnostne kopije in replikacije imata različne cilje. Hladna varnostna kopija bo koristna, če slučajno naredite DELETE ili DROP TABLE. Opravljamo varnostno kopijo iz hladnega shranjevanja in obnavljamo prejšnje stanje tabele ali celotne baze podatkov. Ampak ob tem se poizvedba DROP TABLE skoraj takoj reproducira na vseh replikah v delovnem klasterju, zato običajna replikacija v tem primeru ne bo pomagala. Sama replikacija ohranja bazo podatkov dostopno, ko se oddajajo posamezni strežniki, in porazdeli obremenitev.
Tudi z odloženo replikacijo potrebujemo hladno varnostno kopijo na varnem mestu, če pride do okvare podatkovnega centra, skritega poškodb ali drugih dogodkov, ki jih takoj ne opazite. Tukaj od same replikacije ni koristi.
Napomena. Na trenutno ščitimo pred izgubo podatkov le na ravni sistema in ne obnavljamo podatkov na ravni uporabnika.
Izvor: habr.com
