
Replikation ist kein Backup. Oder doch? So haben wir verzögerte Replikation zur Wiederherstellung genutzt, nachdem wir versehentlich Shortcuts gelöscht haben.
bei GitLab sind verantwortlich fĂŒr den Betrieb â die gröĂte Instanz von GitLab weltweit. Hier gibt es 3 Millionen Nutzer und fast 7 Millionen Projekte, und es ist eine der gröĂten Open-Source-SaaS-Seiten mit dedizierter Architektur. Ohne das PostgreSQL-Datenbanksystem wĂŒrde die Infrastruktur von GitLab.com nicht weit kommen, und wir tun alles, um die Ausfallsicherheit fĂŒr den Fall von Datenverlusten zu gewĂ€hrleisten. Eine solche Katastrophe ist zwar unwahrscheinlich, aber wir sind gut vorbereitet und haben verschiedene Backup- und Replikationsmechanismen eingeplant.
Replikation ist nicht das gleiche wie ein Datenbank-Backup (). Aber jetzt werden wir sehen, wie man versehentlich gelöschte Daten schnell mit verzögerter Replikation wiederherstellt: Ich Benutzer fĂŒr das Projekt und habe die Verbindungen zu Merge-Requests und Aufgaben verloren.
Mit der verzögerten Replikation haben wir die Daten in nur 1,5 Stunden wiederhergestellt. Sehen Sie, wie es gemacht wurde.
Wiederherstellung zu einem bestimmten Zeitpunkt mit PostgreSQL
PostgreSQL verfĂŒgt ĂŒber eine integrierte Funktion, die den Zustand der Datenbank zu einem bestimmten Zeitpunkt wiederherstellt. Diese Funktion nennt sich (PITR) und nutzt die gleichen Mechanismen, die die AktualitĂ€t der Replica unterstĂŒtzen: Ausgehend von einem zuverlĂ€ssigen Snapshot des gesamten Datenbankclusters (Basis-Backup) wenden wir eine Reihe von ZustandsĂ€nderungen bis zu einem bestimmten Zeitpunkt an.
Um diese Funktion fĂŒr ein kaltes Backup zu nutzen, fĂŒhren wir regelmĂ€Ăig ein Basis-Backup der Datenbank durch und speichern es im Archiv (GitLab-Archive befinden sich in ). AuĂerdem verfolgen wir die Ănderungen am Datenbankzustand, indem wir das Write-Ahead-Log (, WAL) archivieren. Mit all dem können wir PITR fĂŒr die Notfallwiederherstellung durchfĂŒhren: Wir beginnen mit einem Snapshot, der vor dem Fehler gemacht wurde, und wenden die Ănderungen aus dem WAL-Archiv bis zum Ausfall an.
Was ist verzögerte Replikation?
Verzögerte Replikation ist das Anwenden von Ănderungen aus dem WAL mit Verzögerung. Das heiĂt, die Transaktion fand um Uhr Xstatt, wird aber in der Replik mit Verzögerung angezeigt d um Stunde X + d.
In PostgreSQL gibt es zwei Möglichkeiten, eine physische Datenbankreplikation einzurichten: die Wiederherstellung aus dem Archiv und die Streaming-Replikation. , funktioniert im Grunde wie PITR, jedoch kontinuierlich: Wir extrahieren stĂ€ndig die Ănderungen aus dem WAL-Archiv und wenden diese auf die Replik an. Die extrahiert direkt den WAL-Stream vom ĂŒbergeordneten Datenbankhost. Wir bevorzugen die Wiederherstellung aus dem Archiv â sie ist einfacher zu verwalten und bietet eine normale Leistung, die der des aktiven Clusters nicht nachsteht.
So richten Sie die verzögerte Wiederherstellung aus dem Archiv ein
sind in der Datei recovery.conf. Beispiel:
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'Mit diesen Parametern haben wir eine verzögerte Replikation mit Wiederherstellung aus dem Archiv eingerichtet. Hierbei verwenden wir zum Extrahieren der WAL-Segmente (restore_command) aus dem Archiv, und die Ănderungen werden nach acht Stunden angewendet (recovery_min_apply_delay). Die Replik wird die Ănderungen in der Zeitleiste im Archiv verfolgen, zum Beispiel aufgrund eines Ausfalls im Cluster (recovery_target_timeline).
E recovery_min_apply_delay Es ist möglich, eine Streaming-Replikation mit Verzögerung einzurichten, jedoch gibt es hier ein paar Fallstricke, die mit den Replikationsslots, dem Hot-Standby-Feedback und Àhnlichem zu tun haben. Das WAL-Archiv hilft, diese zu umgehen.
Parameter recovery_min_apply_delay dies wurde erst in PostgreSQL 9.3 eingefĂŒhrt. In frĂŒheren Versionen musste eine Kombination fĂŒr die verzögerte Replikation eingerichtet werden. (pg_xlog_replay_pause(), pg_xlog_replay_resume()) oder die WAL-Segmente wĂ€hrend der Verzögerungszeit im Archiv halten.
Wie macht PostgreSQL das?
Es ist interessant zu sehen, wie PostgreSQL die verzögerte Wiederherstellung umsetzt. Schauen wir uns an, . Dies wird aus dem fĂŒr jeden Eintrag im WAL aufgerufen.
static bool
recoveryApplyDelay(XLogReaderState *record)
{
uint8 xact_info;
TimestampTz xtime;
long secs;
int microsecs;
/* nichts zu tun, wenn keine Verzögerung konfiguriert ist */
if (recovery_min_apply_delay <= 0)
return false;
/* Keine Verzögerung bei einer Datenbank, die noch nicht konsistent ist */
if (!reachedConsistency)
return false;
/*
* Ist es ein COMMIT-Datensatz?
*
* Wir wĂ€hlen absichtlich, keine Verzögerung fĂŒr AbbrĂŒche anzuwenden, da sie keine
* Auswirkungen auf MVCC haben. Wir erlauben bereits die Wiedergabe von DatensÀtzen,
* die keinen Zeitstempel haben,
* daher gibt es bereits Gelegenheiten fĂŒr Probleme, die durch frĂŒhe Konflikte
* auf Standby-Systemen verursacht werden.
*/
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);
/*
* Beenden, ohne den Latch zu aktivieren, falls es bereits an der Zeit
* ist, diesen Datensatz anzuwenden
*/
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// AbgekĂŒrzt:
// Verwenden Sie WaitLatch, bis wir die recoveryDelayUntilTime erreicht haben
// und dann
break;
}
return true;
}Der Kernpunkt ist, dass die Verzögerung auf der physikalischen Zeit basiert, die in dem Zeitstempel der TransaktionsbestĂ€tigung aufgezeichnet ist (xtime). Wie zu sehen ist, wird die Verzögerung nur auf die Commits angewendet und betrifft keine anderen EintrĂ€ge â alle Ănderungen werden direkt angewendet, wĂ€hrend der Commit verzögert wird, sodass wir die Ănderungen erst nach der festgelegten Verzögerung sehen.
Wie man eine verzögerte Replikat zur Datenwiederherstellung verwendet
Angenommen, wir haben in der Produktion einen Datenbankcluster und eine Replikat mit einer achtstĂŒndigen Verzögerung. Schauen wir uns an, wie wir Daten anhand des Beispiels .
als wir von dem Problem erfuhren, haben wir fĂŒr die verzögerte Replikat:
SELECT pg_xlog_replay_pause();Mit der Pause hatten wir kein Risiko, dass die Replikat die Anfrage wiederholt DELETE. NĂŒtzlich, wenn man Zeit benötigt, um alles zu klĂ€ren.
Die Idee ist, dass die verzögerte Replikat bis zum Moment vor der Anfrage gelangen sollte DELETE. Wir wussten ungefĂ€hr, wann die Löschung stattgefunden hat. Wir haben gelöscht recovery_min_apply_delay und hinzugefĂŒgt recovery_target_time in recovery.conf. So erreicht die Replikat den gewĂŒnschten Zeitpunkt ohne Verzögerungen:
recovery_target_time = '2018-10-12 09:25:00+00'Bei Zeitstempeln sollte man lieber nicht zu viel abziehen, um nichts zu verpassen. Allerdings bedeutet eine gröĂere Abziehmenge, dass mehr Daten verloren gehen. Wiederum, wenn wir die Anfrage ĂŒberspringen. DELETE, alles wird wieder gelöscht und Sie mĂŒssen von vorne beginnen (oder ein kaltes Backup fĂŒr PITR ĂŒbernehmen).
Wir haben die verzögerte Postgres-Instanz neu gestartet, und die WAL-Segmente wiederholten sich bis zu dem angegebenen Zeitpunkt. Den Fortschritt in dieser Phase können Sie mit der Abfrage verfolgen:
SELECT
-- aktuelle Position in WAL
pg_last_xlog_replay_location(),
-- aktueller Transaktionszeitstempel (Status des Replikats)
pg_last_xact_replay_timestamp(),
-- aktuelle physische Zeit
now(),
-- die Menge an Zeit, die noch angewendet werden muss, bis die recovery_target_time erreicht ist
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;Wenn der Zeitstempel nicht mehr verĂ€ndert wird, ist die Wiederherstellung abgeschlossen. Sie können die Aktion , um die Instanz nach der Wiederholung zu schlieĂen, voranzutreiben oder anzuhalten (standardmĂ€Ăig wird sie angehalten).
Die Datenbank ist in den Zustand vor der fehlerhaften Anfrage zurĂŒckgekehrt. Jetzt können Sie beispielsweise Daten exportieren. Wir haben die gelöschten Daten zu den Labels und alle Verbindungen zu Aufgaben und Merge-Requests exportiert und in die Produktionsdatenbank ĂŒbertragen. Wenn die Verluste erheblich sind, können Sie einfach das Replikat voranbringen und als Hauptdatenbank verwenden. Aber dann gehen alle Ănderungen nach dem Zeitpunkt verloren, zu dem wir wiederhergestellt haben.
Statt Zeitstempel sollten Transaktions-IDs verwendet werden. Es ist nĂŒtzlich, diese IDs aufzuzeichnen, zum Beispiel fĂŒr DDL-Operatoren (wie DROP TABLE), mithilfe von log_statements = 'ddl'. HĂ€tten wir die Transaktions-ID, wĂŒrden wir recovery_target_xid nehmen und alles bis zur Transaktion vor der Anfrage ausfĂŒhren. DELETE.
Es ist sehr einfach, zur Arbeit zurĂŒckzukehren: Entfernen Sie alle Ănderungen aus recovery.conf und starten Sie Postgres neu. Bald wird die Replikation wieder eine achtstĂŒndige Verzögerung aufweisen, und wir sind bereit fĂŒr zukĂŒnftige Probleme.
Vorteile der Wiederherstellung
Mit einer verzögerten Replikation mĂŒssen wir nicht stundenlang ein vollstĂ€ndiges Snapshot aus dem Archiv wiederherstellen. Es dauert bei uns beispielsweise fĂŒnf Stunden, um das gesamte Basis-Backup von 2 TB abzurufen. Und dann mĂŒssen wir auch noch das gesamte tĂ€gliche WAL anwenden, um den gewĂŒnschten Zustand wiederherzustellen (im schlimmsten Fall).
Eine verzögerte Replikation ist in zwei Punkten besser als ein kaltes Backup:
- Das gesamte Basis-Backup muss nicht aus dem Archiv entnommen werden.
- Es gibt ein festgelegtes achtstĂŒndiges Fenster fĂŒr die WAL-Segmente, die wiederholt werden mĂŒssen.
AuĂerdem ĂŒberprĂŒfen wir stĂ€ndig, ob ein PITR aus dem WAL möglich ist, und wĂŒrden schnell SchĂ€den oder andere Probleme mit dem WAL-Archiv bemerken, wĂ€hrend wir die Verzögerung der verzögerten Replikation im Auge behalten.
In diesem Beispiel benötigten wir 50 Minuten fĂŒr die Wiederherstellung, was einer Geschwindigkeit von 110 GB WAL-Daten pro Stunde entspricht (Archiv war zu diesem Zeitpunkt noch auf ). Insgesamt haben wir das Problem gelöst und die Daten in 1,5 Stunden wiederhergestellt.
Zusammenfassung: Wo ist verzögerte Replikation sinnvoll (und wo nicht)
Nutzen Sie verzögerte Replikation als Erste-Hilfe-MaĂnahme, wenn Sie versehentlich Daten verloren haben und dieses Problem innerhalb der konfigurierten Verzögerung bemerken.
Aber beachten Sie: Replikation ist kein Backup.
Backup und Replikation haben unterschiedliche Ziele. Ein Kalt-Backup ist nĂŒtzlich, wenn Sie versehentlich gemacht haben DELETE oder DROP TABLE. Wir fĂŒhren ein Backup aus einem kalten Speicher durch und stellen den vorherigen Zustand einer Tabelle oder der gesamten Datenbank wieder her. Aber gleichzeitig wird die Anfrage DROP TABLE fast sofort in allen Replikaten des Arbeitsclusters reproduziert, sodass die gewöhnliche Replikation hier nicht hilft. An sich sorgt Replikation dafĂŒr, dass die Datenbank verfĂŒgbar bleibt, wenn einzelne Server ausfallen, und verteilt die Last.
Selbst mit einer verzögerten Replikation benötigen wir manchmal dringend ein Kalt-Backup an einem sicheren Ort, falls es zu einem Ausfall des Rechenzentrums, einem verdeckten Schaden oder anderen Ereignissen kommt, die man nicht sofort bemerkt. Hier nĂŒtzt eine reine Replikation nichts.
Hinweis. In Wir schĂŒtzen derzeit Datenverlust nur auf Systemebene und stellen die Daten nicht auf Benutzerebene wieder her.
Quelle: habr.com
