
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.
GitLab ir atbildīgs par darbu - 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 (). Bet tagad mēs redzēsim, kā ātri atgūt nejauši izdzēstos datus, izmantojot slinku replikāciju: ieslēgts lietotājs projektam 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 (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 ). Mēs arī uzraugām izmaiņas datubāzes stāvoklī, arhivējot ierakstīšanas žurnālu (, 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. , 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 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
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 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 (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 . To sauc no 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, µsecs);
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 .
Kad uzzinājām par problēmu, mēs 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 lai 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:
- Nav nepieciešams noņemt visu pamata dublējumu no arhīva.
- 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 ). 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 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
