Backup i odtwarzanie w PostgreSQL

Istnieją trzy sposoby wykonywania kopi zapasowych w PostgreSQL.

  • Z użyciem pg_dump lub pg_dumpall – jest to zrzut aktualnego stanu danych do pliku SQL, nie zawiera informacji o strukturze fizycznej. Są to tylko struktury danych (tabele, indeksy etc), bez informacji o np. przestrzeniach tabel czy strukturze plików i katalogów. Ewentualne przywrócenie bazy będzie możliwe tylko do momentu z którego będzie pochodził zrzut. Bardzo przydatne narzędzie do wykonywania kopii danych np. z serwera produkcyjnego na testowy.

  • Backup na poziomie fizycznym. W zasadzie sprowadza się to do skopiowania niezbędnych plików przy wyłączonej bazie. Tutaj również odtworzenie będzie możliwe tylko do punktu w czasie z którego pochodzi backup.

  • Archiwizacja ciągła. Jest to najbardziej złożony sposób, ale daje też najwięcej możliwości. Umożliwia między innymi przywrócenie bazy do punktu przed awarią, lub wskazanego przez administratora punktu w czasie.

Zajmiemy się tymi trzema metodami po kolei i zastanowimy się nad plusami i minusami wykorzystania poszczególnych.

Na początek stworzyłem sobie tabelkę zawierającą dwie proste kolumny i wrzucam do niej dane, aby w ogóle było co backupować :)



Wrzucam do tej tabeli 161 MB bzdurnych danych. Jeśli masz ochotę iść za mną krok w krok, to wrzuciłem plik który importuję pod adres : http://www.jsystems.pl/storage/postgres/dane.csv

Importuję dane z poziomu PgAdmina. Klikamy prawym przyciskiem na nazwę tabeli, wybieramy „importuj”. W okienku które wyskoczy podajemy położenie naszego pliku, format ustawiamy na CSV, a w zakładce „różne opcje” jako rozdzielacz wybieramy średnik.



Upewniam się jeszcze że dane zostały wrzucone:



I zawartość tabeli:



i tak w naszej tabelce znalazło się 10 milionów ponumerowanych mapetów ;)

Backup lokalny i zdalny z użyciem narzędzia PG_DUMP


Korzystając z tego narzędzia utworzymy skrypt który będzie zawierał zwyczajne polecenia SQL tworzące tabele i ładujące dane. To jest kopia na poziomie logicznym!

Aby wykonać backup wybranej bazy podajemy jako parametry dla pg_dump'a nazwę bazy której kopię chcemy wykonać, oraz ścieżkę do pliku do którego ma zostać zrzucona.


pg_dump postgres > /home/mapet/exporty/postgres.sql



Jeśli otworzysz teraz ten plik z użyciem jakiegoś edytora tekstu ( ale lepiej przygotuj się na to, że otwieranie tego pliku może chwilę potrwać ) powinieneś zobaczyć mniej więcej taką zawartość:


Jak widzisz są to komendy tworzące struktury danych i ładujące dane. Zapewne już się domyślasz w jaki sposób odtwarzamy bazę z takiego pliku ;)

Zanim jednak do tego dojdziemy chciałbym omówić jeszcze kilka ważnych elementów związanych z wykonywaniem tego typu zrzutów. Eksportować możesz również bazy znajdujące się na innym hoście – wystarczy dodać przełącznik -h i adres IP albo nazwę domenową hosta z którego chcemy eksportować:



Analogicznie możemy też wykorzystać przełącznik -p by ustawić port po którym chcemy się łączyć ze zdalną bazą.

Pytanie które samo się nasuwa: co jeśli dane zmienią się podczas wykonywania backupu? Jest tak jakbyśmy sobie tego życzyli – zawartość zrzutu będzie spójna. To znaczy że stan wszystkich danych będzie pochodził z momentu rozpoczęcia backupu. Nic więc nam się nie „rozjedzie”. Wykonywanie takiego zrzutu nie blokuje też bazy – wszystkie procesy nadal działają i dane można zmieniać w trakcie wykonywania backupu.


Odtwarzanie lokalne i zdalne bazy danych


Skoro już wyrzuciliśmy sobie dane do pliku, to teraz go załadujmy. Oczywiście możemy dane wrzucić do tej samej bazy danych, ale nic nie stoi też na przeszkodzie by stworzyć nową bazę danych i załadować do niej zrzut danych z innej (tak właśnie zrobię). Bazę będziemy musieli jednak stworzyć sami, nie zostanie ona utworzona automatycznie:



Sam plik zrzutu wciągamy z użyciem dobrze znanego nam już narzędzia psql (wszak plik zrzutu zawiera po prostu instrukcje SQL):

psql -U postgres -d druga -h localhost < /home/mapet/exporty/postgres.sql



Sprawdźmy więc czy w nowej bazie danych pojawiła się nasza tabela:


 


Jeśli wrócimy pamięcią do pierwszych rozdziałów tych materiałów, to przypomnimy sobie że z użyciem narzędzia psql możemy też podpinać się do zdalnej bazy danych. Czemu więc nie odtworzyć bazy na zdalnym hoście?


psql -U postgres -d druga -h jsystems.pl < /home/mapet/exporty/postgres.sql


Żaden problem, wystarczy po przełączniku -h podać adres IP albo nazwę domenową zdalnego hosta.




Sprawdzamy :



Szybkie kopiowanie baz między dwoma klastrami


No to teraz „z grubej rury” :). Szybkie kopiowanie baz danych między dwoma klastrami z czego jeden jest zdalny. Nic nie stoi oczywiście na przeszkodzie by obie bazy były zdalne.


pg_dump -h localhost druga | psql -h jsystems.pl inna


Zasadniczo sprowadza się to do eksportu z jednej bazy i jednoczesnego wciągnięcia do innej – bez wytwarzania pliku eksportu. Strumień wytwarzany przez pg_dump'a tym razem nie ląduje w pliku tylko jest od razu przekierowany do PSQL którego podpinamy do zdalnej bazy ;) Wcześniej utworzyłem sobie nową bazę o nazwie „inna” na serwerze zdalnym:


pg_dump -h localhost druga | psql -h jsystems.pl inna



Błędy podczas odtwarzania


Domyślnie kiedy używamy pg_dump'a wciąganie danych nie zostaje przerwane w wyniku błędów takich jak np. brak jakiegoś użytkownika który jest właścicielem obiektu wciąganego. PG_DUMP będzie kontynuował ładowanie, z ewentualnym pominięciem części danych. To nie zawsze jest to czego byśmy sobie życzyli. Gdybyśmy w takiej sytuacji chcieli przerwać ładowanie, należy dodać przełącznik -1

psql -h localhost -d druga -U postgres -1 < /home/mapet/exporty/postgres.sql



Ten przełącznik sprawi, że całość skryptu jest wykonywana jako jedna transakcja i jako taka zostanie w całości zatwierdzona albo wycofana.


Bardziej uważni czytelnicy z pewnością wpadną na pomysł, że ponieważ plik zrzutu jest zwykłym edytowalnym plikiem możemy wykomentować to co nie jest nam potrzebne i wciągnąć całą resztę :)


Backup i odtwarzanie całego klastra


Dotychczas wykonywaliśmy kopie zapasowe pojedynczych baz danych. Średnio to wygodne jeśli tych baz mamy dużo, a chcielibyśmy wykonywać regularne kopie zapasowe wszystkich. Ponadto użycie pg_dump powoduje że nie są zrzucane informacje dotyczące całego klastra – jak przestrzenie tabel czy użyszkodnicy. Jeśli chcielibyśmy takie informacje zawrzeć w kopii zapasowej, albo skopiować między dwoma serwerami cały klaster musimy skorzystać z narzędzia pg_dumpall. PG_DUMPALL w pliku zrzutu zawrze też informacje na temat przestrzeni tabel i użytkowników.

Wyrzucenie całego klastra do pliku:

pg_dumpall > /home/mapet/exporty/full.exp

Taki wytworzony plik również (podobnie jak przy pg_dump) wciągamy przy użyciu narzędzia psql:



Jak widzimy, podczas importu podejmowana jest też próba tworzenia baz danych i przestrzeni tabel. Jeśli takowe już istnieją w docelowej bazie danych, to psql zgłosi tylko błąd i przejdzie dalej, tak jak widzimy na powyższej ilustracji.


Idąc za ciosem, a pamiętając różne wariacje z eksportem i importem plików pg_dump'a i tutaj mamy rząd możliwości. Gdybyśmy zechcieli zrzucić zdalny klaster do lokalnego pliku:

pg_dumpall -h jsystems.pl -U postgres > /home/mapet/exporty/full2.exp

albo gdybyśmy zechcieli skopiować cały klaster „w locie”:

pg_dumpall -h localhost | psql -h jsystems.pl



Nieco irytująca rzecz związana z pg_dumpall – będzie eksportował bazy liniowo, a przy każdej kolejnej zapyta o hasło...


Backup plików danych na poziomie fizycznym


Możemy też wykonać kopię plików danych. Sprowadza się to do skopiowania plików, ja użyłem akurat narzędzia tar aby sobie je jednocześnie skompresować. Ważne by te pliki były konsystentne. Podczas takiego sposobu wykonywania backupu, nic nie przeszkadza klastrowi PostgreSQL w normalnym działaniu, co jednocześnie oznacza że pliki te mogą podlegać zmianom w trakcie kopiowania. Taki backup byłby bezużyteczny. Dlatego też przed wykonaniem backupu należy klaster wyłączyć!

/usr/pgsql-9.4/bin/pg_ctl -D /var/lib/pgsql/9.4/data stop

tar -czf /home/mapet/exporty/backup_plikow.tar /var/lib/pgsql/9.4/data

/usr/pgsql-9.4/bin/pg_ctl -D /var/lib/pgsql/9.4/data start



Na powyższym screenie widzimy też utworzony plik backupu we wskazanym miejscu. Taki sposób wykonywania backupu będzie z reguły szybszy niż z użyciem pg_dumpall, ale też jednocześnie będzie zajmował więcej miejsca.


Dla pewności sprawdźmy też jak przebiega odtwarzanie takiego backupu. Najpierw położyłem klaster, a następnie usunąłem katalog z plikami jednej z baz. Podniosłem klaster. Jak widzimy PostgreSQL nie zgłosił sprzeciwu. Problemy zaczną się dopiero pojawiać przy próbie dostępu do danych z tej bazy.



Przy próbie dobrania się do bazy:



KATASTROFALNY nawet błąd :) Ok, brakuje mu katalogu. Stworzę więc go ręcznie i ponowię próbę:



Tym razem będzie zgłaszał problem przy dostępie do poszczególnych plików – tutaj akurat nic ważnego – plik zawierający informacje o wersji oprogramowania naszego klastra. Ponieważ jestem czepliwy i mam obyczaj sprawdzać poprawność dokumentacji (a to wynika akurat z bardzo poważnego błędu w dokumentacji baz Oracle przez który kiedyś najadłem się sporo nerwów i pewnie straciłem nieco włosów), to postanowiłem nieco utrudnić zadanie. Zanim przystąpiłem do odtwarzania, wykonałem wprawdzie na innej bazie spore operacje zmieniające dane. Chodziło mi o to, żeby przewinęło się kilka dzienników WAL, oraz żeby powstało też kilka checkpointów – tak żeby zweryfikować czy PostgreSQL później nie będzie na mnie krzyczał że np. pliki WAL zawierają zatwierdzone wpisy z punktu w czasie przed stworzeniem plików danych czy coś takiego. Dzienniki WAL dotyczą wszak całego klastra, a nie pojedynczych baz danych. Wiecie, przezorny zawsze ubezpieczony. A i jeszcze jedno – odtarowałem i umieściłem przywracane pliki danych podczas gdy cały klaster zadziałał. Słowem – postarałem się o to by całość przebiegała w zbliżonych warunkach co gdyby wystąpiła jakaś normalna awaria – z reguły minełoby trochę czasu zanim zorientowalibyśmy się że w ogóle coś się dzieje. Ku mojemu zaskoczeniu po wykonaniu tych czynności i ponownej próbie dostępu do danych nie było problemów:



  

Ten artykuł jest elementem poniższych kursów: