
Replikation ist kein Backup. Oder etwa doch? So haben wir verzögerte Replikation fĂŒr die Wiederherstellung genutzt, nachdem wir versehentlich Labels gelöscht haben.
bei GitLab sind verantwortlich fĂŒr den Betrieb â der gröĂten GitLab-Instanz der Welt. Hier gibt es 3 Millionen Benutzer und fast 7 Millionen Projekte, und es ist eine der gröĂten Open-Source-SaaS-Seiten mit einer dedizierten Architektur. Ohne das Datenbanksystem PostgreSQL wĂŒrde GitLab.com nicht weit kommen, und was wir nicht alles tun, um die Ausfallsicherheit fĂŒr den Fall von Fehlern, die zu Datenverlust fĂŒhren können, zu gewĂ€hrleisten. So eine Katastrophe wird wahrscheinlich nicht eintreten, aber wir sind gut vorbereitet und haben verschiedene Backup- und Replikationsmechanismen vorrĂ€tig.
Replikation ist nicht das gleiche wie ein Datenbank-Backup (). Aber jetzt werden wir sehen, wie man versehentlich gelöschte Daten mithilfe von verzögerter Replikation schnell wiederherstellt: ich Nutzer fĂŒr das Projekt und habe die Verbindung zu Merge-Requests und Aufgaben verloren.
Mit der verzögerten Replikation konnten wir die Daten in nur 1,5 Stunden wiederherstellen. Sehen Sie, wie es war.
Wiederherstellung zu einem bestimmten Zeitpunkt mit PostgreSQL
PostgreSQL verfĂŒgt ĂŒber eine eingebaute Funktion, die den Zustand der Datenbank zu einem bestimmten Zeitpunkt wiederherstellt. Sie wird genannt (PITR) und nutzt die gleichen Mechanismen, die die AktualitĂ€t der Replikation unterstĂŒtzen: Ausgehend von einem verlĂ€sslichen Snapshot des gesamten Datenbank-Clusters (Basis-Backup) wenden wir eine Reihe von ZustandsĂ€nderungen bis zu einem bestimmten Zeitpunkt an.
Um diese Funktion fĂŒr kalte Backups zu nutzen, erstellen wir regelmĂ€Ăig ein Basis-Backup der Datenbank und speichern es in einem Archiv (Archiven von GitLab leben in ). AuĂerdem verfolgen wir die ZustandsĂ€nderungen der Datenbank, indem wir das Write-Ahead-Log (, WAL) archivieren. Mit all dem können wir PITR fĂŒr die Notfallwiederherstellung durchfĂŒhren: Wir beginnen mit dem Snapshot, der vor dem Fehler erstellt wurde, und wenden die Ănderungen aus dem WAL-Archiv bis zum Fehler an.
Was ist verzögerte Replikation?
Verzögerte Replikation bedeutet, dass Ănderungen aus dem WAL mit einer Verzögerung angewendet werden. Das heiĂt, die Transaktion fand um eine Uhr Xstatt, wird aber mit einer Verzögerung d von einer Stunde in der Replikation erscheinen..
In PostgreSQL gibt es zwei Möglichkeiten, eine physische Datenbankreplikation einzurichten: Wiederherstellung aus dem Archiv und Streaming-Replikation. , funktioniert im Wesentlichen wie PITR, aber kontinuierlich: Wir extrahieren stĂ€ndig Ănderungen aus dem WAL-Archiv und wenden sie auf die Replik an. WĂ€hrend direkt einen WAL-Stream vom ĂŒbergeordneten Datenbankhost extrahiert. Wir ziehen die Wiederherstellung aus dem Archiv vor â sie ist einfacher zu verwalten und hat eine normale Leistung, die mit dem Arbeitscluster nicht hinterherhinkt.
Wie man eine verzögerte Wiederherstellung aus dem Archiv einrichtet
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. Dabei wird zur Extraktion von WAL-Segmenten (restore_command) aus dem Archiv verwendet, und Ănderungen werden nach acht Stunden angewendet (recovery_min_apply_delay). Die Replik wird die Ănderungen auf der Zeitachse im Archiv verfolgen, beispielsweise aufgrund von FehlschlĂ€gen im Cluster (recovery_target_timeline).
C recovery_min_apply_delay es ist möglich, eine verzögerte Streaming-Replikation einzurichten, aber es gibt ein paar Fallstricke, die mit Replikationsslots, Hot-Standby-Feedback usw. zusammenhÀngen. Das WAL-Archiv ermöglicht es, diese zu vermeiden.
Parameter recovery_min_apply_delay wurde erst in PostgreSQL 9.3 eingefĂŒhrt. In frĂŒheren Versionen musste man eine Kombination aus (pg_xlog_replay_pause(), pg_xlog_replay_resume()) einrichten oder WAL-Segmente wĂ€hrend der Verzögerungszeit im Archiv halten.
Wie macht PostgreSQL das?
Es ist interessant zu sehen, wie PostgreSQL eine verzögerte Wiederherstellung implementiert. Schauen wir uns . Es wird im fĂŒr jeden Eintrag aus dem 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 gilt fĂŒr eine Datenbank, die noch nicht konsistent ist */
if (!reachedConsistency)
return false;
/*
* Ist es ein COMMIT-Posten?
*
* Wir entscheiden uns bewusst, AbbrĂŒche nicht zu verzögern, da sie keine Auswirkungen auf
* MVCC haben. Wir erlauben bereits die Wiedergabe von Posten, die keinen Zeitstempel haben,
* daher gibt es bereits Möglichkeiten 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);
/*
* Verlasse ohne das Latch zu aktivieren, wenn es bereits Zeit ist, diesen
* Posten anzuwenden
*/
TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime,
&secs, µsecs);
if (secs <= 0 && microsecs <= 0)
return false;
while (true)
{
// VerkĂŒrzt:
// Benutze WaitLatch, bis wir die recoveryDelayUntilTime erreicht haben
// und dann
break;
}
return true;
}Das Wesentliche ist, dass die Verzögerung auf der physischen Zeit basiert, die im Zeitstempel des Transaktions-Commits verzeichnet ist (xtime). Wie zu erkennen ist, wird die Verzögerung nur auf Commits angewendet und betrifft keine anderen Posten â alle Ănderungen werden direkt angewendet, wĂ€hrend der Commit verzögert wird, sodass wir Ănderungen erst nach der eingestellten Verzögerung sehen.
Wie man eine verzögerte Replikation zur Datenwiederherstellung nutzt
Angenommen, wir haben in der Produktion einen Datenbankcluster und eine Replikation mit einer Verzögerung von acht Stunden. Schauen wir uns an, wie wir Daten am Beispiel von .
wiederherstellen können, als wir von dem Problem erfuhren, haben wir fĂŒr die verzögerte Replikation:
SELECT pg_xlog_replay_pause();Mit der Pause hatten wir kein Risiko, dass die Replikation die Anfrage wiederholt DELETE. NĂŒtzlich, wenn man Zeit braucht, um alles zu klĂ€ren.
Das Wesentliche ist, dass die verzögerte Replikation bis zu dem Zeitpunkt vor der Anfrage kommen muss DELETE. Wir wussten ungefĂ€hr die physische Zeit der Löschung. Wir haben gelöscht recovery_min_apply_delay und hinzugefĂŒgt recovery_target_time in recovery.conf. So kommt die Replikation zum gewĂŒnschten Zeitpunkt ohne Verzögerungen:
recovery_target_time = '2018-10-12 09:25:00+00'Beim Zeitstempel sollte man nichts ĂŒbertreiben, um keine Fehler zu machen. Allerdings, je mehr man abzieht, desto mehr Daten verlieren wir. Wiederum, wenn wir die Anfrage ĂŒbersehen DELETE, wird alles erneut gelöscht und wir mĂŒssen von vorne beginnen (oder sogar ein kaltes Backup fĂŒr PITR nehmen).
Wir haben die verschobene Postgres-Instanz neu gestartet, und die WAL-Segmente wiederholten sich bis zur angegebenen Zeit. Den Fortschritt zu diesem Zeitpunkt kann man mit der Abfrage verfolgen:
SELECT
-- aktuelle Position im WAL
pg_last_xlog_replay_location(),
-- aktueller Transaktionszeitstempel (Zustand der Replik)
pg_last_xact_replay_timestamp(),
-- aktuelle physische Zeit
now(),
-- die Zeit, die noch bis zum Erreichen der recovery_target_time angewendet werden muss
'2018-10-12 09:25:00+00'::timestamptz - pg_last_xact_replay_timestamp() as delay;Wenn der Zeitstempel nicht mehr wechselt, ist die Wiederherstellung abgeschlossen. Man kann die Aktion einstellen , um die Instanz nach der Wiederholung (standardmĂ€Ăig wird sie angehalten) zu schlieĂen, voranzutreiben oder anzuhalten.
Die Datenbank hat den Zustand vor der problematischen Abfrage erreicht. Jetzt kann man zum Beispiel Daten exportieren. Wir haben die entfernten Daten ĂŒber das Label sowie alle Verbindungen zu Aufgaben und Merge-Requests exportiert und in die Arbeitsdatenbank ĂŒbertragen. Falls die Verluste erheblich sind, kann man einfach die Replik vorantreiben und sie als Hauptdatenbank verwenden. Aber dabei gehen alle Ănderungen nach dem Zeitpunkt verloren, zu dem wir zurĂŒckgekehrt sind.
Statt Zeitstempeln sollten besser 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 eine Transaktions-ID, könnten wir die recovery_target_xid nehmen und alles bis zur Transaktion vor der Abfrage durchlaufen. DELETE.
ZurĂŒck an die Arbeit ist ganz einfach: Entfernen Sie alle Ănderungen aus recovery.conf und starten Sie Postgres neu. Bald wird wieder eine achtstĂŒndige Verzögerung in der Replik auftreten, und wir sind bereit fĂŒr zukĂŒnftige Probleme.
Vorteile fĂŒr die Wiederherstellung
Mit einer verzögerten Replikation anstelle eines kalten Backups muss man nicht stundenlang ein ganzes Snapshot aus dem Archiv wiederherstellen. Wir benötigen zum Beispiel fĂŒnf Stunden, um das gesamte Basisbackup von 2 TB zu extrahieren. AuĂerdem muss das gesamte tĂ€gliche WAL angewendet werden, um den gewĂŒnschten Zustand zu erreichen (im schlimmsten Fall).
Eine verzögerte Replik ist in zwei Punkten besser als ein kaltes Backup:
- Es ist nicht notwendig, das gesamte Basisbackup aus dem Archiv zu holen.
- Es gibt ein festes achtstĂŒndiges Fenster von WAL-Segmenten, die wiederholt werden mĂŒssen.
AuĂerdem ĂŒberprĂŒfen wir stĂ€ndig, ob PITR aus dem WAL möglich ist, und wir wĂŒrden schnell SchĂ€den oder andere Probleme mit dem WAL-Archiv feststellen, wĂ€hrend wir die Verzögerung der verzögerten Replik beobachten.
In diesem Beispiel dauerte die Wiederherstellung 50 Minuten, was einer Geschwindigkeit von 110 GB WAL-Daten pro Stunde entsprach (das Archiv war damals noch auf ). Insgesamt haben wir das Problem gelöst und die Daten in 1,5 Stunden wiederhergestellt.
Ergebnisse: Wo sich eine verzögerte Replikation bewÀhrt (und wo nicht)
Verwenden Sie verzögerte Replikation als NotfallmaĂnahme, wenn Sie versehentlich Daten verloren haben und diesen Fehler innerhalb der festgelegten Verzögerung bemerken.
Aber denken Sie daran: Replikation ist kein Backup.
Backup und Replikation haben unterschiedliche Ziele. Ein kaltes Backup ist nĂŒtzlich, wenn Sie versehentlich DELETE oder DROP TABLE. Wir erstellen ein Backup aus einem kalten Speicher und stellen den vorherigen Zustand der Tabelle oder der gesamten Datenbank wieder her. Aber in diesem Fall wird die Anfrage DROP TABLE nahezu sofort in allen Replikaten des Arbeitsclusters reproduziert, daher hilft die normale Replikation hier nicht. Die Replikation selbst hĂ€lt die Datenbank verfĂŒgbar, wenn einzelne Server ausfallen, und verteilt die Last.
Selbst mit einer verzögerten Replikation benötigen wir manchmal dringend ein kaltes Backup an einem sicheren Ort, falls es zu einem Ausfall des Rechenzentrums, versteckten BeschĂ€digungen oder anderen Ereignissen kommt, die sofort nicht bemerkt werden. Hier nĂŒtzt eine reine Replikation nichts.
Hinweis. Auf der Wir schĂŒtzen derzeit nur auf Systemebene vor Datenverlust und stellen die Daten nicht auf Benutzerebene wieder her.
Quelle: habr.com
