Replikering är inte backup. Eller inte? Så här använde vi uppskjuten replikering för att återställa från oavsiktlig radering av genvägar.
Replikering är inte ett sätt att säkerhetskopiera databaser (gitlab-ce
Med en uppskjuten replik återställde vi data på bara 1,5 timmar. Titta hur det gick till.
Tidpunktsåterställning med PostgreSQL
PostgreSQL har en inbyggd funktion som återställer tillståndet för en databas till en specifik tidpunkt. Det kallas
För att använda den här funktionen för kall säkerhetskopiering gör vi regelbundet en grundläggande databassäkerhetskopiering och lagrar den i ett arkiv (GitLab-arkiv live i
Vad är uppskjuten replikering?
Lazy replikering är tillämpningen av ändringar från WAL med en fördröjning. Det vill säga transaktionen skedde på en timme X
, men det kommer att visas i repliken med en fördröjning d
om en timme X + d
.
PostgreSQL har två sätt att ställa in en fysisk databasreplik: säkerhetskopiering och strömmande replikering.
Hur man ställer in fördröjd återställning från ett arkiv
recovery.conf
. Exempel:
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'
Med dessa parametrar konfigurerade vi en uppskjuten replik med backup-återställning. Här används det restore_command
) från arkivet, och ändringar kommer att tillämpas efter åtta timmar (recovery_min_apply_delay
). Repliken kommer att titta på tidslinjeändringar i arkivet, till exempel på grund av en kluster-failover (recovery_target_timeline
).
С recovery_min_apply_delay
Du kan ställa in strömmande replikering med en fördröjning, men det finns ett par fallgropar här som är relaterade till replikeringsplatser, hot standby-feedback och så vidare. WAL-arkivet låter dig undvika dem.
Parameter recovery_min_apply_delay
dök endast upp i PostgreSQL 9.3. I tidigare versioner måste du konfigurera kombinationen för uppskjuten replikering pg_xlog_replay_pause(), pg_xlog_replay_resume()
) eller håll WAL-segment i arkivet under fördröjningens varaktighet.
Hur gör PostgreSQL detta?
Det är intressant att se hur PostgreSQL implementerar lazy recovery. Låt oss titta på 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;
}
Summan av kardemumman är att fördröjningen är baserad på den fysiska tiden som registrerats i transaktionens tidsstämpel (xtime
). Som du kan se, gäller fördröjningen endast commits och påverkar inte andra poster - alla ändringar tillämpas direkt, och commiten är försenad, så vi kommer bara att se ändringarna efter den konfigurerade fördröjningen.
Hur man använder en fördröjd replik för att återställa data
Låt oss säga att vi har ett databaskluster och en replika med åtta timmars fördröjning i produktionen. Låt oss se hur man återställer data med hjälp av ett exempel
När vi lärde oss om problemet, vi
SELECT pg_xlog_replay_pause();
Med en paus hade vi ingen risk att repliken skulle upprepa begäran DELETE
. En användbar sak om du behöver tid att lista ut allt.
Poängen är att den uppskjutna repliken måste nå ögonblicket före begäran DELETE
. Vi visste ungefär den fysiska tidpunkten för borttagning. Vi har raderat recovery_min_apply_delay
och tillagt recovery_target_time
в recovery.conf
. Så här når repliken rätt ögonblick utan dröjsmål:
recovery_target_time = '2018-10-12 09:25:00+00'
Med tidsstämplar är det bättre att minska överskottet för att inte missa. Det är sant att ju större minskningen är, desto mer data förlorar vi. Återigen, om vi missar begäran DELETE
, kommer allt att raderas igen och du måste börja om (eller till och med ta en kall säkerhetskopia för PITR).
Vi startade om den uppskjutna Postgres-instansen och WAL-segmenten upprepades till den angivna tiden. Du kan följa framstegen i detta skede genom att fråga:
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;
Om tidsstämpeln inte längre ändras är återställningen klar. Åtgärd kan anpassas recovery_target_action
Databasen återgick till sitt tillstånd innan den olyckliga begäran. Nu kan du till exempel exportera data. Vi exporterade den raderade etikettdatan och alla länkar till frågor och sammanslagningsförfrågningar och flyttade dem till produktionsdatabasen. Om förlusterna är storskaliga kan du helt enkelt marknadsföra kopian och använda den som den huvudsakliga. Men då kommer alla förändringar efter den punkt som vi har återhämtat oss till att gå förlorade.
Istället för tidsstämplar är det bättre att använda transaktions-ID:n. Det är användbart att registrera dessa ID:n, till exempel för DDL-satser (som DROP TABLE
), genom att använda log_statements = 'ddl'
. Om vi hade ett transaktions-ID skulle vi ta recovery_target_xid
och körde allt till transaktionen före begäran DELETE
.
Att komma tillbaka till jobbet är väldigt enkelt: ta bort alla ändringar från recovery.conf
och starta om Postgres. Replikan kommer snart att ha åtta timmars försening igen, och vi är förberedda på framtida problem.
Återvinningsfördelar
Med en uppskjuten replik istället för en kall säkerhetskopia behöver du inte spendera timmar på att återställa hela bilden från arkivet. Till exempel tar det oss fem timmar att få hela den grundläggande 2 TB-backupen. Och då måste du fortfarande applicera hela den dagliga WAL för att återhämta dig till önskat tillstånd (i värsta fall).
En uppskjuten replik är bättre än en kall backup på två sätt:
- Det finns ingen anledning att ta bort hela den grundläggande säkerhetskopian från arkivet.
- Det finns ett fast fönster på åtta timmar med WAL-segment som måste upprepas.
Vi kontrollerar också ständigt om det är möjligt att göra en PITR från WAL, och vi skulle snabbt märka korruption eller andra problem med WAL-arkivet genom att övervaka fördröjningen av den uppskjutna repliken.
I det här exemplet tog det oss 50 minuter att återställa, vilket betyder att hastigheten var 110 GB WAL-data per timme (arkivet var fortfarande på
Resultat: där en uppskjuten replik är användbar (och där den inte är det)
Använd fördröjd replikering som första hjälpen om du av misstag tappat data och upptäckte detta problem inom den konfigurerade fördröjningen.
Men kom ihåg: replikering är inte en säkerhetskopia.
Säkerhetskopiering och replikering har olika syften. En kall backup kommer väl till pass om du av misstag gjorde det DELETE
eller DROP TABLE
. Vi gör en säkerhetskopia från kyllagring och återställer det tidigare tillståndet för tabellen eller hela databasen. Men samtidigt begäran DROP TABLE
reproduceras nästan omedelbart i alla repliker på arbetsklustret, så vanlig replikering hjälper inte här. Replikeringen i sig håller databasen tillgänglig när enskilda servrar hyrs ut och fördelar belastningen.
Även med en uppskjuten replik behöver vi ibland verkligen en kall säkerhetskopia på en säker plats om ett datacenterfel, dolda skador eller andra händelser som inte är direkt märkbara inträffar. Enbart replikering är till ingen nytta här.
Notera. på
Källa: will.com