PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Czy podczas wykonywania PITR byłoby możliwe wstrzymanie/wznowienie w PostgreSQL?

Tak, naprawdę możliwe i inteligentnie obsługiwane przez PostgreSQL. Aby to zademonstrować, najpierw muszę zastosować standardową technikę odzyskiwania punktu w czasie w PostgreSQL. Różne książki/artykuły/blogi są bardzo dobrze demonstrowane przez niezwykłych autorów, dlatego nie będę wdawać się w szczegóły, jak to zrobić, jednak przechodzę bezpośrednio do tematu, tj. Jak zrobić pauzę podczas odzyskiwania przy użyciu tej samej techniki. Prawdopodobnie przedstawiłem wyrażenie matematyczne z PITR jako „PITR =(Ostatnia kopia zapasowa systemu plików (LFB) + archiwa WAL wygenerowane po LFB + niezarchiwizowane WAL w bieżących $ PGDATA / pg_xlogs)”. Aby lepiej zrozumieć, umieściłem to na wykresie, ponieważ bardziej wyjaśnia to myśl:(Przepraszam, ten blog jest trochę długi, nieświadomie stało się to podczas wchodzenia w szczegóły koncepcji)

Kroki PITR, które nastąpią z niewielkimi zmianami, o których niedługo opowiem:

Krok 1. Przywróć najnowszą kopię zapasową na poziomie systemu plików (FSB) do dowolnej lokalizacji, w której planowane jest odzyskiwanie.
Krok 2. Jeśli FSB to tar, rozpakuj ją i wyczyść katalog pg_xlog, pozostawiając archive_status. Jeśli kopia zapasowa wykluczyła ten katalog, utwórz pusty katalog pg_xlog w FSB.
Krok 3. Skopiuj niezarchiwizowane pliki WAL z uszkodzonego klastra $PGDATA/pg_xlog do $FSB/pg_xlog (krok 2)
Krok 4. Usuń postmaster.pid z katalogu FSB.
Krok 5. Utwórz plik recovery.conf w katalogu FSB.
Krok 6. Uruchom klaster (FSB).

Powinniśmy zadać pytanie, kiedy wstrzymuje wymagane odzyskiwanie?. Być może, aby zapobiec wielokrotnemu przywracaniu bazy lub przywracaniu do przodu, ale sprawdzaj lub wycofuj dane lub zainteresowania konkretne tabele, aby zobaczyć, jak daleko zostały odzyskane :). Pamiętaj, pauza w odzyskiwaniu oznacza, że ​​pozwala na połączenie podczas odzyskiwania. Aby to nakreślić, odtworzyłem sytuację na wykresie ulepszeń poszczególnych wierszy tabeli, aż do nieszczęśliwego wypadku.

Z powyższego diagramu, jego zadowalające wiersze tabeli DEMO wynosiły 10 000 000, gdy wykonano kopię zapasową na poziomie systemu plików ($PGDATA) i 40 000 000 wierszy przed awarią. W mojej lokalnej maszynie wirtualnej stworzyłem sytuację na podstawie CZASU zamiast daty.

Wymaganie wstępne:
1. Kopia zapasowa na poziomie systemu plików, gdy tabele DEMO mają 10 000 000 wierszy.
2. Od tego momentu archiwa WAL przed awarią, w których tabela DEMO ma 40 000 000 wierszy.
3. Lokalizacja archiwów WAL:/opt/PostgreSQL/9.3/archives.
4. Katalog danych:/opt/PostgreSQL/9.3/data (PGDATA)
5. Lokalizacja kopii zapasowej:/opt/PostgreSQL/9.3/backups

Należy pamiętać, że praca z wstrzymaniem odzyskiwania wymaga obowiązkowych zmian w głównym klastrze ($PGDATA) „wal_level” ustawionym na „hot_standby” oraz w klastrze odzyskiwania (kopia zapasowa na poziomie systemu plików) „hot_standby” ustawionym na „ON”. Wprowadziłem te zmiany w głównym klastrze, zrestartowałem klaster, aby odniosły skutek i zainicjowałem tworzenie kopii zapasowej. Jeśli nie masz nic przeciwko, zrób notatkę, to po prostu demo, więc moje archiwa WAL mogą nie być gigantyczną liczbą, ponieważ są w kilku liczbach. Wymieniłem tutaj również archiwa WAL, które zostały wygenerowane od czasu wykonania kopii zapasowej do awarii.

-bash-4.1$ psql -c "select count(*), now() from demo;"
count | now
---------+-------------------------------
1000000 | 2014-04-04 15:06:04.036928-07
(1 row)

-bash-4.1$ pg_basebackup -D /opt/PostgreSQL/9.3/backup/data_pitr -- I have my $PGDATA, $PGUSER, $PGPORT set, so its a straight command in my case
NOTICE: pg_stop_backup complete, all required WAL segments have been archived

Aktualny stan archiwów WAL i $PGDATA/pg_xlog

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001C
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001D
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/data/pg_xlog | tail -4
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
drwx------ 2 postgres postgres 4.0K Apr 4 16:13 archive_status

W porządku, mamy kopię zapasową, wstawiamy kilka rekordów w trzech częściach, notując czas, co pomoże wstrzymać odzyskiwanie i dodatkowo zobaczyć WAL utworzone od czasu FSB.

-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
2000000 | 2014-04-04 16:06:34.941615-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
3000000 | 2014-04-04 16:10:31.136725-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
4000000 | 2014-04-04 16:13:00.136725-07
(1 row)

Sprawdź liczbę WAL-ów wyprodukowanych podczas WSTAWIANIA.

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000020
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000021
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000022
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000023
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000024
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000025
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000026
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000027
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000028
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000029
-rw------- 1 postgres postgres 16M Apr 4 16:10 00000001000000000000002A
-rw------- 1 postgres postgres 16M Apr 4 16:13 00000001000000000000002B

Załóżmy, że w tym momencie wydarzyło się nieszczęście i musisz wykonać odzyskiwanie za pomocą archiwów FSB + WAL + niezarchiwizowanych WAL (jeśli istnieją). Podczas odzyskiwania chcę zatrzymać się trzy razy, aby zobaczyć każde odzyskiwanie 20 000 000, 30 000 i 40 000 000 wierszy tabeli DEMO, łącząc się z bazą danych w trybie TYLKO DO ODCZYTU. Dla każdego wznowienia odzyskiwania konieczne jest ponowne uruchomienie klastra odzyskiwania przez przejście do nowej osi czasu w pliku recovery.conf/recovery_target_time. Ponadto w $FSB/postgresql.conf musimy ustawić hot_standby=on. Oto mój plik recovery.conf:

-bash-4.1$ more recovery.conf
pause_at_recovery_target = true
#recovery_target_time = '2014-04-04 16:06:34' # For 2 lakh records
#recovery_target_time = '2014-04-04 16:10:31' # For 3 lakh records
#recovery_target_time = '2014-04-04 16:13:00' # For 4 lakh records
restore_command = 'cp /opt/PostgreSQL/9.3/archives/%f %p'

Zacznijmy odzyskiwanie 20 000 000 rekordów:

-bash-4.1$ /opt/PostgreSQL/9.3/bin/pg_ctl -D /opt/PostgreSQL/9.3/data_pitr/ start
server starting

Now in logs:

-bash-4.1$ more postgresql-2014-04-04_162524.log
2014-04-04 16:25:24 PDT-24187---[] LOG: starting point-in-time recovery to 2014-02-06 18:48:56-08
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001E" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: redo starts at 0/1E0000C8
2014-04-04 16:25:24 PDT-24187---[] LOG: consistent recovery state reached at 0/1E000190
2014-04-04 16:25:24 PDT-24185---[] LOG: database system is ready to accept read only connections
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001F" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "000000010000000000000020" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000021" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000022" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery stopping before commit of transaction 1833, time 2014-04-04 16:06:23.893487-07
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery has paused
2014-04-04 16:25:25 PDT-24187---[] HINT: Execute pg_xlog_replay_resume() to continue

Fajnie, zobacz w dziennikach, że zostało wstrzymane, i inteligentną WSKAZÓWKĘ z prośbą o wznowienie. Tutaj, jeśli odzyskiwanie było zadowalające, możesz je wznowić, wywołując „select pg_xlog_replay_resume();” (możesz to sprawdzić). Nie wznawiajmy teraz, jednak sprawdź liczbę odzyskanych wierszy, łącząc się z serwerem.

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
2000000 | t
(1 row)

Dobrze, dotarło do punktu i zatrzymało się tam, gdzie prosiłem. Przejdźmy jeszcze o krok do przodu, aby odzyskać 30 000 000 wierszy. Teraz ustaw kolejną oś czasu w recovery.conf/recovery_target_time i zrestartuj klaster.

2014-04-04 16:28:40 PDT-24409---[] LOG:  restored log file "00000001000000000000002A" from archive
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery stopping before commit of transaction 1836, time 2014-04-04 16:10:40.141175-07
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery has paused
2014-04-04 16:28:40 PDT-24409---[] HINT: Execute pg_xlog_replay_resume() to continue.

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
3000000 | t
(1 row)

Fajnie… spróbujmy zrobić ostatnią pauzę przy 40 000 000 rzędów.

2014-04-04 20:09:07 PDT-4723---[] LOG:  restored log file "00000001000000000000002B" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001000000000000002C': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: redo done at 0/2B0059A0
2014-04-04 20:09:07 PDT-4723---[] LOG: last completed transaction was at log time 2014-04-04 16:11:12.264512-07
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000001000000000000002B" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000002.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000003.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000004.history" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000005.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: selected new timeline ID: 5
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: archive recovery complete
2014-04-04 20:09:08 PDT-4721---[] LOG: database system is ready to accept connections
2014-04-04 20:09:08 PDT-4764---[] LOG: autovacuum launcher started

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
4000000 | f
(1 row)

Ups, co się stało, dlaczego nie zostało wstrzymane i na co narzeka?. Należy pamiętać, że jeśli w czasie recovery_target_time nie ma archiwów WAL, nie zatrzyma się ono i nie będzie oczekiwać, że dotarło do ostatniego punktu i otworzy bazę danych do ODCZYTU/ZAPISU. W logach bez większego naciągania widać, że szukał pliku „000000010000000000000002C”, który nie jest dostępny, ponieważ w tym czasie klaster się zawiesił. Niektórzy mogą nie uznawać tego zachowania, ale jest to fakt i ma sens, gdy nie ma archiwów WAL, wtedy nie ma powodu, aby wstrzymywać odzyskiwanie. Jeśli w ogóle wymagane jest wstrzymanie, nawet po braku archiwów WAL, skorzystaj z trybu gotowości =„włączony” (HOT_STANDBY), w tej metodzie nie wyjdzie z odzyskiwania, ale poczeka na archiwa WAL.

Mam nadzieję, że to było przydatne.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Co dokładnie robi pg_escape_string?

  2. Chcę przywrócić bazę danych z innym schematem

  3. Jaki jest format ciągu połączenia / adresu URL PostgreSQL?

  4. Jak efektywnie wybrać poprzednią wartość inną niż null?

  5. Używanie logicznej replikacji PostgreSQL do utrzymywania zawsze aktualnego serwera TEST do odczytu/zapisu