Die Replikation ist kein Backup. Oder nicht? So haben wir die verzögerte Replikation zur Wiederherstellung genutzt, indem wir versehentlich Verknüpfungen gelöscht haben.
Die Replikation ist nicht Ihr Datenbank-Backup-Tool (gitlab-ce
Mit der verzögerten Replik konnten wir Daten in nur 1,5 Stunden wiederherstellen. Sehen Sie, wie es war.
Point-in-Time-Wiederherstellung mit PostgreSQL
PostgreSQL verfügt über eine integrierte Funktion, die den Zustand einer Datenbank zu einem bestimmten Zeitpunkt wiederherstellt. Es wird genannt
Um diese Funktion für ein Cold-Backup zu nutzen, erstellen wir regelmäßig ein Basis-Datenbank-Backup und speichern es in einem Archiv (in dem sich die GitLab-Archive befinden).
Was ist verzögerte Replikation?
Unter verzögerter Replikation versteht man die verzögerte Anwendung von Änderungen aus WAL. Das heißt, die Transaktion erfolgte zur vollen Stunde X
, aber es wird mit einer Verzögerung in der Replik angezeigt d
rechtzeitig X + d
.
Es gibt zwei Möglichkeiten, eine physische Datenbankreplik in PostgreSQL einzurichten: Archivwiederherstellung und Streaming-Replikation.
So richten Sie eine verzögerte Backup-Wiederherstellung ein
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 Einstellungen haben wir eine verzögerte Replik mit Archivwiederherstellung konfiguriert. Wird hier verwendet restore_command
) aus dem Archiv, und die Änderungen werden nach acht Stunden übernommen (recovery_min_apply_delay
). Das Replikat überwacht das Archiv auf Zeitachsenänderungen, beispielsweise aufgrund eines Cluster-Failovers (recovery_target_timeline
).
С recovery_min_apply_delay
Sie können die Latenz-Streaming-Replikation einrichten, es gibt jedoch einige Fallstricke im Zusammenhang mit Replikationsslots, Hot-Spare-Feedback usw. Das WAL-Archiv vermeidet sie.
Parameter recovery_min_apply_delay
erschien nur in PostgreSQL 9.3. In früheren Versionen erforderte die verzögerte Replikation eine Kombination aus pg_xlog_replay_pause(), pg_xlog_replay_resume()
) oder halten Sie die WAL-Segmente für die Dauer der Verzögerung im Archiv.
Wie macht PostgreSQL das?
Es ist interessant zu sehen, wie PostgreSQL Lazy Restore implementiert. Schauen wir uns an 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;
}
Die Quintessenz ist, dass die Verzögerung auf der physischen Zeit basiert, die im Zeitstempel des Transaktions-Commits aufgezeichnet ist (xtime
). Wie Sie sehen, gilt die Verzögerung nur für Commits und wirkt sich nicht auf andere Datensätze aus – alle Änderungen werden direkt angewendet und der Commit ist verzögert, sodass wir die Änderungen erst nach der konfigurierten Verzögerung sehen.
So verwenden Sie Lazy Replica für die Datenwiederherstellung
Nehmen wir an, wir haben einen Datenbankcluster in Produktion und ein Replikat mit einer Verzögerung von acht Stunden. Sehen wir uns anhand eines Beispiels an, wie man Daten wiederherstellt
Als uns das Problem bewusst wurde, haben wir
SELECT pg_xlog_replay_pause();
Bei einer Pause bestand für uns kein Risiko, dass die Replik die Anfrage wiederholt DELETE
. Nützliche Sache, wenn Sie Zeit brauchen, um alles herauszufinden.
Die Quintessenz ist, dass die verzögerte Replik den Moment vor der Anfrage erreichen muss DELETE
. Wir kannten ungefähr den physischen Zeitpunkt der Entfernung. Wurden bewegt recovery_min_apply_delay
und hinzugefügt recovery_target_time
в recovery.conf
. So kommt die Replik ohne Verzögerung zum richtigen Zeitpunkt:
recovery_target_time = '2018-10-12 09:25:00+00'
Bei Zeitstempeln ist es besser, den Überschuss zu reduzieren, um nichts zu verpassen. Es stimmt, je größer der Rückgang, desto mehr Daten gehen uns verloren. Nochmals, wenn wir die Anfrage überspringen DELETE
, wird alles wieder gelöscht und Sie müssen von vorne beginnen (oder sogar ein Kalt-Backup für PITR erstellen).
Wir haben die verzögerte Postgres-Instanz neu gestartet und die WAL-Segmente wurden bis zum angegebenen Zeitpunkt wiederholt. Sie können den Fortschritt in dieser Phase verfolgen, indem Sie Folgendes abfragen:
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;
Wenn sich der Zeitstempel nicht mehr ändert, ist die Wiederherstellung abgeschlossen. Sie können die Aktion anpassen recovery_target_action
Die Datenbank gelangte bereits vor dieser unglückseligen Anfrage in den Zustand. Jetzt können Sie beispielsweise Daten exportieren. Wir haben die Remote-Label-Daten und alle Links zu Issues und Merge Requests exportiert und in die Produktionsdatenbank übertragen. Wenn die Verluste groß sind, können Sie die Replik einfach bewerben und als Hauptversion verwenden. Aber dann werden alle Änderungen nach dem Moment, zu dem wir uns erholt haben, verloren gehen.
Es ist besser, Transaktions-IDs anstelle von Zeitstempeln zu verwenden. Es ist sinnvoll, diese IDs beispielsweise für DDL-Anweisungen aufzuzeichnen (z. B DROP TABLE
), mit Hilfe log_statements = 'ddl'
. Wenn wir eine Transaktions-ID hätten, würden wir sie nehmen recovery_target_xid
und habe vor der Anfrage alles bis zur Transaktion ausgeführt DELETE
.
Die Rückkehr zur Arbeit ist ganz einfach: Entfernen Sie alle Änderungen aus recovery.conf
und starten Sie Postgres neu. Bald wird der Hinweis erneut eine Verzögerung von acht Stunden haben, und wir sind auf künftige Probleme vorbereitet.
Erholungsvorteile
Mit einem verzögerten Replikat müssen Sie anstelle eines Cold-Backups nicht stundenlang den gesamten Snapshot aus dem Archiv wiederherstellen. Beispielsweise benötigen wir fünf Stunden, um das gesamte 2-TB-Basis-Backup zu erhalten. Und dann müssen Sie (im schlimmsten Fall) immer noch die gesamte tägliche WAL anwenden, um den gewünschten Zustand wiederherzustellen.
Ein verzögertes Replikat ist in zweierlei Hinsicht besser als ein Kalt-Backup:
- Sie müssen nicht das gesamte Basis-Backup aus dem Archiv abrufen.
- Es gibt ein festes Acht-Stunden-Fenster für WAL-Segmente, die wiederholt werden müssen.
Außerdem prüfen wir ständig, ob WAL PITRed sein kann, und wir würden Beschädigungen oder andere Probleme mit dem WAL-Archiv schnell bemerken, indem wir den Rückstand des verzögerten Replikats überwachen.
In diesem Beispiel dauerte die Wiederherstellung 50 Minuten, d. h. die Geschwindigkeit betrug 110 GB WAL-Daten pro Stunde (das Archiv war noch aktiv).
Zusammenfassung: Wo ist eine verzögerte Replik sinnvoll (und wo nicht)
Nutzen Sie die verzögerte Replikation als erste Hilfe, wenn Sie versehentlich Daten verlieren und diese Katastrophe innerhalb der konfigurierten Verzögerung bemerken.
Aber bedenken Sie: Replikation ist kein Backup.
Backup und Replikation dienen unterschiedlichen Zwecken. Ein Kalt-Backup ist praktisch, wenn Sie es versehentlich erstellt haben DELETE
oder DROP TABLE
. Wir erstellen ein Backup aus dem Cold Storage und stellen den vorherigen Zustand einer Tabelle oder einer gesamten Datenbank wieder her. Aber gleichzeitig die Bitte DROP TABLE
fast sofort in allen Replikaten im Arbeitscluster reproduziert, sodass die reguläre Replikation hier nicht gespeichert wird. Die Replikation selbst hält die Datenbank bei der Vermietung einzelner Server verfügbar und verteilt die Last.
Selbst bei einer verzögerten Replik benötigen wir manchmal unbedingt ein Cold-Backup an einem sicheren Ort, wenn plötzlich ein Rechenzentrumsausfall, versteckte Schäden oder andere Ereignisse auftreten, die Sie nicht sofort bemerken. Hier macht eine Replikation keinen Sinn.
Beachten. Auf
Source: habr.com