Replikacja nie jest kopią zapasową. Albo nie? Oto, jak wykorzystaliśmy replikację odroczoną, aby odzyskać siły po przypadkowym usunięciu skrótów.
Replikacja nie jest sposobem tworzenia kopii zapasowych baz danych (gitlab-ce
Dzięki replikie odroczonej odzyskaliśmy dane w zaledwie 1,5 godziny. Zobacz jak to się stało.
Odzyskiwanie danych w określonym momencie za pomocą PostgreSQL
PostgreSQL ma wbudowaną funkcję przywracającą stan bazy danych do określonego momentu. Nazywa się to
Aby skorzystać z tej funkcji do zimnego tworzenia kopii zapasowych, regularnie tworzymy podstawową kopię zapasową bazy danych i przechowujemy ją w archiwum (archiwa GitLab znajdują się w
Co to jest odroczona replikacja?
Leniwa replikacja to zastosowanie zmian z WAL z opóźnieniem. Oznacza to, że transakcja nastąpiła w ciągu godziny X
, ale pojawi się w replice z opóźnieniem d
na godzinę X + d
.
PostgreSQL ma 2 sposoby skonfigurowania fizycznej repliki bazy danych: odzyskiwanie kopii zapasowych i replikacja strumieniowa.
Jak skonfigurować opóźnione odzyskiwanie z archiwum
recovery.conf
. Przykład:
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'
Dzięki tym parametrom skonfigurowaliśmy replikę odroczoną z odzyskiwaniem kopii zapasowych. Tutaj jest używany restore_command
) z archiwum, a zmiany zostaną zastosowane po ośmiu godzinach (recovery_min_apply_delay
). Replika będzie obserwować zmiany na osi czasu w archiwum, na przykład z powodu przełączania awaryjnego klastra (recovery_target_timeline
).
С recovery_min_apply_delay
Możesz skonfigurować replikację strumieniową z opóźnieniem, ale istnieje kilka pułapek związanych z miejscami replikacji, sprzężeniem zwrotnym w trybie gotowości i tak dalej. Archiwum WAL pozwala ich uniknąć.
Parametr recovery_min_apply_delay
pojawił się tylko w PostgreSQL 9.3. W poprzednich wersjach w przypadku replikacji odroczonej konieczne było skonfigurowanie kombinacji pg_xlog_replay_pause(), pg_xlog_replay_resume()
) lub wstrzymaj segmenty WAL w archiwum na czas opóźnienia.
Jak PostgreSQL to robi?
Ciekawie jest zobaczyć, jak PostgreSQL implementuje leniwe odzyskiwanie. Spójrzmy na 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;
}
Najważniejsze jest to, że opóźnienie opiera się na czasie fizycznym zarejestrowanym w znaczniku czasu zatwierdzenia transakcji (xtime
). Jak widać opóźnienie dotyczy tylko zatwierdzeń i nie ma wpływu na inne wpisy - wszystkie zmiany są stosowane bezpośrednio, a zatwierdzenie jest opóźnione, więc zmiany zobaczymy dopiero po skonfigurowanym opóźnieniu.
Jak używać opóźnionej repliki do przywracania danych
Załóżmy, że mamy klaster baz danych i replikę z ośmiogodzinnym opóźnieniem w produkcji. Zobaczmy, jak odzyskać dane na przykładzie
Kiedy dowiedzieliśmy się o problemie, zgłosiliśmy się
SELECT pg_xlog_replay_pause();
Przy przerwie nie mieliśmy ryzyka, że replika powtórzy żądanie DELETE
. Przydatna rzecz, jeśli potrzebujesz czasu, aby wszystko przemyśleć.
Chodzi o to, że odroczona replika musi dotrzeć do momentu poprzedzającego żądanie DELETE
. Znaliśmy mniej więcej fizyczny czas usunięcia. Usunęliśmy recovery_min_apply_delay
i dodał recovery_target_time
в recovery.conf
. W ten sposób replika bezzwłocznie dociera do właściwego momentu:
recovery_target_time = '2018-10-12 09:25:00+00'
W przypadku znaczników czasu lepiej zmniejszyć nadmiar, aby nie przegapić. To prawda, że im większy spadek, tym więcej danych tracimy. Ponownie, jeśli przegapimy prośbę DELETE
, wszystko zostanie ponownie usunięte i będziesz musiał zacząć od nowa (lub nawet wykonać zimną kopię zapasową PITR).
Zrestartowaliśmy odroczoną instancję Postgres, a segmenty WAL były powtarzane do określonego czasu. Na tym etapie możesz śledzić postęp, zadając pytanie:
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;
Jeśli sygnatura czasowa już się nie zmienia, odzyskiwanie jest zakończone. Działanie można dostosować recovery_target_action
Baza danych powróciła do stanu sprzed tego niefortunnego żądania. Teraz możesz na przykład eksportować dane. Wyeksportowaliśmy usunięte dane etykiet oraz wszystkie linki do problemów i żądań scalania i przenieśliśmy je do produkcyjnej bazy danych. Jeżeli straty są duże, można po prostu wypromować replikę i używać jej jako głównej. Ale wtedy wszystkie zmiany po punkcie, do którego odzyskaliśmy, zostaną utracone.
Zamiast znaczników czasu lepiej jest używać identyfikatorów transakcji. Przydatne jest zapisanie tych identyfikatorów na przykład dla instrukcji DDL (takich jak DROP TABLE
), używając log_statements = 'ddl'
. Gdybyśmy mieli identyfikator transakcji, wzięlibyśmy go recovery_target_xid
i przeprowadził wszystko aż do transakcji przed żądaniem DELETE
.
Powrót do pracy jest bardzo prosty: usuń wszystkie zmiany z recovery.conf
i uruchom ponownie Postgres. Replika wkrótce znów będzie miała ośmiogodzinne opóźnienie, a my jesteśmy przygotowani na przyszłe kłopoty.
Korzyści z regeneracji
Dzięki replikie odroczonej zamiast zimnej kopii zapasowej nie musisz tracić godzin na przywracanie całego obrazu z archiwum. Przykładowo wykonanie całej podstawowej kopii zapasowej o pojemności 2 TB zajmuje nam pięć godzin. A potem nadal trzeba zastosować cały dzienny WAL, aby powrócić do pożądanego stanu (w najgorszym przypadku).
Odroczona replika jest lepsza niż zimna kopia zapasowa pod dwoma względami:
- Nie ma potrzeby usuwania całej podstawowej kopii zapasowej z archiwum.
- Istnieje stałe ośmiogodzinne okno segmentów WAL, które należy powtórzyć.
Stale sprawdzamy również, czy możliwe jest wykonanie PITR z WAL, a monitorując opóźnienie odroczonej repliki, szybko zauważylibyśmy uszkodzenie lub inne problemy z archiwum WAL.
W tym przykładzie przywrócenie danych zajęło nam 50 minut, co oznacza, że prędkość wynosiła 110 GB danych WAL na godzinę (archiwum było nadal włączone
Wyniki: gdzie odroczona replika jest przydatna (a gdzie nie)
Użyj opóźnionej replikacji jako pierwszej pomocy, jeśli przypadkowo utraciłeś dane i zauważyłeś ten problem w ramach skonfigurowanego opóźnienia.
Pamiętaj jednak: replikacja nie jest kopią zapasową.
Tworzenie kopii zapasowych i replikacja mają różne cele. Zimna kopia zapasowa przyda się, jeśli przypadkowo ją wykonasz DELETE
lub DROP TABLE
. Wykonujemy kopię zapasową z chłodni i przywracamy poprzedni stan tabeli lub całej bazy danych. Ale jednocześnie prośba DROP TABLE
jest niemal natychmiast odtwarzany we wszystkich replikach działającego klastra, więc zwykła replikacja tutaj nie pomoże. Sama replikacja utrzymuje dostępność bazy danych w przypadku wynajmu poszczególnych serwerów i rozkłada obciążenie.
Nawet w przypadku repliki odroczonej czasami naprawdę potrzebujemy zimnej kopii zapasowej w bezpiecznym miejscu, jeśli wystąpi awaria centrum danych, ukryte uszkodzenia lub inne zdarzenia, które nie są natychmiast zauważalne. Sama replikacja nie ma tutaj żadnego zastosowania.
Operacja. Na
Źródło: www.habr.com