Download: Sysadmin_mysql

Transkrypt

Download: Sysadmin_mysql
Kopia zapasowa MySQL
SYSADMIN
Wykonywanie kopii zapasowej baz danych MySQL – część 1
Bezpieczna przystań
MySQL, popularna baza danych
Open Source, oferuje różne metody wykonania kopii zapasowej.
Każda z nich ma swoje wady i zalety, które w pewnych sytuacjach
są decydujące.
Gerd Waloszek, vispix.com
THOMAS WÖLFER
Opcja 1: Polecenie
select into outfile
Jeżeli baza danych składa się tylko z kilku
tabel i mamy dostęp do serwera MySQL
z poziomu powłoki, polecenie select into
outfile jest najprostszym sposobem wykonania kopii zapasowej danych. Dzięki tej
metodzie możemy szybko zapisać tabelę
lub jej część do pliku tymczasowego. Wykorzystując pełnię możliwości instrukcji select możemy ograniczyć wybór plików, które mają znaleźć się w kopii zapasowej, aby
zapisać całą tabele, wpisujemy po prostu
polecenie select *. Na Listingu 1 przedstawiono możliwości opcji select into outfile.
File oznacza nazwę pliku, która zostanie
zapisana w tabeli. Opcja fields terminated
by określa znak rozdzielający kolumny
w pliku. Znakiem domyślnym jest przecinek. Nasz przykład generuje listę rozdzielaną przecinkami z poszczególnymi wartościami w znakach cudzysłowu. Pamiętajmy,
że plik wynikowy nie może już znajdować
się na dysku. MySQL sprawdza, czy taki
plik istnieje – jest to forma prostego zabezpieczenia się przed przypadkowym nadpisaniem istniejących kopii zapasowych. Ponadto konto użytkownika, z którego uruchomione zostanie polecenie select into
outfile, musi posiadać uprawnienia do
zmiany plików na serwerze MySQL. Największą zaletą tej metody jest niewiarygodna szybkość wykonywania kopii zapasowej
pojedynczej tabeli.
Analogiczna instrukcja load date infile
oferuje podobną wydajność. Przy jej pomocy możemy załadować plik zapisany wcześniej przez select into outfile. Składnia load
data infile oczekuje na parametr w postaci
nazwy pliku:
load data info 'File' [replaceU
| ignore] into table Table
W tej sytuacji następuje załadowanie zawartości pliku do tabeli o określonej nazwie. Jeżeli do wykonywania kopii zapasowych tabel chcemy wykorzystać tandem select into outfile i load data info, zanim wykonamy load data powinniśmy upewnić się,
czy tabela docelowa jest pusta. Możemy
także określić parametr ignore – w ten sposób polecenie pominie linie zawierające podwójne klucze główne, zapobiegając w ten
sposób powstawaniu błędów w przypadku,
gdy tabela zawierałaby już te same dane.
Wadą rozwiązania select into outfile i load data infile jest to, że opcje te posiadają
zbyt wiele ograniczeń, aby znalazły zastosowanie u większej liczby użytkowników. Możemy zapisywać i ładować wyłącznie całe
tabele. Oznacza to konieczność modyfikowania skryptów wykonujących kopie zapasowe za każdym razem, gdy stworzymy nową tabelę. Jednakże, jeżeli chcemy wykonać
AUTOR
B
azy danych MySQL potrafią przechowywać każdy typ danych, począwszy od produktów przeznaczonych do sprzedaży, a na szczegółowych informacjach dotyczących kampanii reklamowej skończywszy. To świetnie – jednak
należy pamiętać o regularnym wykonywaniu kopii zapasowych wszystkich danych –
żeby być przygotowanym w razie katastrofy. MySQL [1] posiada szeroką gamę opcji
dla wykonywania kopii zapasowych w różnych sytuacjach. Użytkownicy mogą skorzystać zarówno z metod szybkich, jak
i tych wyjątkowo bezpiecznych, ale wymagających poświęcenia większej ilości czasu.
Thomas Wölfer jest twórcą oprogramowania od 20 lat. Zajmuje się
serwerami pocztowymi sieci WWW
i baz danych w portalu nickles.de.
www.linux-magazine.pl
Lipiec 2004
69
SYSADMIN
Kopia zapasowa MySQL
kopię pojedynczej tabeli, opisany sposób jest chyba najlepszym rozwiązaniem.
Opcja 2:
Polecenie backup table
Polecenie backup table działa podobnie
do select into outfile, ale jego struktura
jest dużo prostsza. Backup table oczekuje na podanie parametrów, czyli jednej lub
kilku tabel oraz nazwy pliku wynikowego
dla tabel: backup table Tabela1 [więcejtabel] to
„Plik”. Takie polecenie umożliwia użytkownikom równoczesne tworzenie wielu kopii
zapasowych tabel przy wykorzystaniu listy
nazw tabel rozdzielanej przecinkami.
W dokumentacji MySQL można przeczytać, że wykonywanie kopii zapasowej tabeli
jest rozwiązaniem przestarzałym i programiści pracują właśnie nad nowymi rozwiązaniami. Można spokojnie zignorować to
stwierdzenie, gdyż polecenie działa naprawdę bardzo dobrze i nie ma tutaj znaczenia,
czy jest to metoda przestarzała, czy nie. Jej
wielką zaletą, w porównaniu z select into
outfile, jest możliwość zapisu wielu tabel
przy pomocy jednego polecenia. Z drugiej
jednak strony, będziemy tutaj potrzebowali
dostępu do MySQL z poziomu powłoki (podobnie jak przy instrukcji select).
Opcja 3:
Polecenie mysqldump
Dzięki programowi mysqldump zapomnimy, czym są problemy przy tworzeniu kopii
zapasowych. Program zapisuje na dysku
kompletną bazę danych (a nawet wiele baz
danych jednocześnie). Zaleta mysqldump
wynika z faktu, że nie potrzebujemy już
zać programowi mysqldump odzyskanie
danych z serwera zdalnego. Do tego celu
program wymaga parametru -host=RemoteHost. Pamiętajmy, że metoda ta ge01 select * into outfile 'File.txt'
neruje bardzo duży ruch w sieci, szcze02 fields terminated by ','
gólnie jeśli posiadamy dużą bazę da03 enclosed by '''
nych. Tak naprawdę jest to największa
04 lines terminated by 'n' from Table;
przeszkoda do wykonywania kopii zapasowych całych baz danych poprzez sieć.
Jeżeli jednak wykonujemy kopię zapasokonta w MySQL, aby dokonać archiwizacji
wą lokalnie, program jest wprost idealny do
w ten sposób. Wystarczy dostęp do portu,
tego typu zadania. Jak można się spodziena którym pracuje MySQL. Skrócona
wać, mysqldump dysponuje szeroką gamą
składnia programu mysqldump jest nastęopcji (patrz Rysunek 1) umożliwiających
pująca:
przystosowanie programu do indywidualnych potrzeb użytkownika. Pełną listę paramysqldump [parametry] database U
metrów wiersza poleceń, podaną w formie
[tables]
przykładów, umieszczono w dokumentacji
gdzie [tables] oznacza listę tabel w bazie
MySQL, znajdującej się pod adresem [2].
danych, których kopię zapasową chcemy
wykonać. Jeżeli zamierzamy wykonać archiwizację wszystkich tabel znajdujących
Opcja 4: Ręczne
się w bazie danych, po prostu pomijamy ten
wykonywanie kopii
parametr. Polecenie wyświetli na ekranie
zapasowej
ogromną ilość danych. Aby zapisać bazę daJeżeli możemy pozwolić sobie na przerwanych do pliku, kierujemy dane wyjściowe
nie pracy serwera MySQL na czas wykonado pliku. Ponownie musimy pamiętać, aby
nia kopii zapasowej, możliwe jest zastosoplik nie istniał jeszcze na dysku twardym:
wanie wyjątkowo prostej metody archiwizacji. Przede wszystkim przerywamy pracę demona MySQL, następnie kopiujemy pliki
mysqldump database > backup.sql
bazy danych i uruchamiamy ponownie demona. Teraz, korzystając z protokołu SSH,
Kopia zapasowa backup.sql będzie zawiemożemy bezpiecznie przesłać kopię zapasorać zarówno strukturę tabel, jak i zawarte
wą do innego komputera. Aby wszystko
w nich dane. Aby pobrać oba zestawy infordziałało poprawnie, musimy z katalogu bamacji z kopii zapasowej, wpisujemy:
zy danych skopiować wszystkie pliki o rozszerzeniach FRM, MYD i MYI. Aby odzymysql < backup.sql
skać dane z kopii zapasowej, musimy postępować według procedury: przerwać pracę
Jeżeli nie mamy bezpośredniego dostępu do
demona, skopiować z powrotem pliki bazy
serwera MySQL, administrator może naka-
Listing 1: Przekierowanie
polecenia select do pliku
Rysunek 1: Mysqldump posiada ogromną liczbę funkcji, które można do-
Rysunek 2: PHP MyAdmin posiada także funkcje kopii zapasowej dla ta-
pasować do indywidualnych potrzeb użytkownika.
bel MySQL.
70
Lipiec 2004
www.linux-magazine.pl
Kopia zapasowa MySQL
Listing 2: Połączenie
z komputerem lokalnym
01 $cL = mysql_connect(Local_U
Server', 'Write_Username', U
'Password');
02 if( $cL)
03 {
04 print 'no local connection.';
05 return;
06 }
danych, uruchomić ponownie serwer.
Metoda ta jest prosta, nawet dla początkujących użytkowników. Jednak taki sposób tworzenia kopii zapasowych ma swoje
ograniczenia. Przerwanie pracy demona
MySQL jest możliwe w przypadku mniejszych baz danych, albo witryn intranetowych ze zdefiniowanymi okresami konserwacji systemu, ale w odniesieniu do dużych
witryn internetowych, pracujących 7 dni
w tygodniu 24 godziny na dobę, zastosowanie takiego rozwiązania z pewnością nie
wchodzi w grę.
Wadą jest to, że potrzebujemy dostępu
administracyjnego do serwera z poziomu
powłoki, tak więc nie jest to dobre rozwiązanie dla małych sieci. Jeżeli jednak posiadamy już dostęp do powłoki, ręczne wykonywanie kopii zapasowych może być prostym i skutecznym rozwiązaniem. Fakt ten
zauważyli programiści i umieścili w dystrybucji MySQL wygodny skrypt Perl o nazwie mysqlhotcopy [2].
Jeżeli mamy możliwość uruchomienia
skryptów Perl na serwerze, mysqlhotcopy
umożliwi automatyzację procesu tworzenia
kopii zapasowych. Musimy jednak pamiętać o dwóch ograniczeniach – skrypt pracuje tylko w bazach danych ISAM i MyISAM.
Opcja 5: Skrypty PHP
Aby dostosować i nieco zautomatyzować
proces tworzenia kopii zapasowych danych
MySQL, możemy skorzystać z języka
skryptowego typu PHP. Metoda przy pomocy języka PHP jest bardzo prosta i zapewnia podstawową strukturę, na której
możemy zbudować własny skrypt do wykonywania kopii zapasowej. Pełną wersję
skryptu można pobrać z adresu [3]. Oczywiście niewykluczona jest także opcja wykorzystania ogólnodostępnego rozwiązania
do przenoszenia danych pomiędzy bazami
MySQL, jak np. rozszerzenie PHP MyAdmin [4], ale jest to metoda zbyt nieporęcz-
na, aby można ją było stosować bez dokładnych przygotowań.
Do uruchomienia skryptu wymagane są
dwa działające serwery MySQL. Na jednym
z nich trzeba ponadto uruchomić Apache
z obsługą PHP. Poza tym musimy zainstalować obsługę MySQL dla języka PHP (opcja
domyślna przy instalacji PHP). Serwer archiwizacji wymaga także dostępu do portów
MySQL. Baza MySQL zwykle nasłuchuje
na portach 3306 i 6000 dla UDP i TCP. Jeżeli nie mamy dostępu do tych portów,
sprawdźmy ustawienia naszego firewalla.
Dla stworzenia przydatnej kopii zapasowej niezwykle istotna jest odpowiednia organizacja danych na serwerze. Jeżeli nieustannie zmieniamy dane, musimy archiwizować
dane znacznie częściej niż w przypadku, gdy
nowe rekordy są dodawane tylko od czasu do
czasu. W pierwszej sytuacji musimy zapisać
zarówno nowe dane, które pojawiły się od
momentu wykonania ostatniej kopii zapasowej, jak i wszystkie rekordy poddane modyfikacjom w tym czasie. W drugim przypadku
wystarczy wykonać kopię zapasową składającą się wyłącznie z nowych rekordów. Jeżeli
do uruchomienia skryptu zamierzamy wykorzystać przeglądarkę lub WGET, będziemy musieli stworzyć standardową stronę
PHP zawierającą instrukcje dla HTML. Jest
to całkiem proste:
<html><head></head><body>
<?php Update();?>
</body></html>
SYSADMIN
function UpdateNew()
{
print „Begin Update New <br>”;
Funkcja rozpoczyna działanie od wyświetlenia krótkiego komunikatu. Jeżeli do wywołania procesu aktualizacji korzystamy
z przeglądarki, takie rozwiązanie jest bardzo praktyczne – umożliwia użytkownikowi
śledzenie na bieżąco całego procesu:
$cR = mysql_connect('Remote_U
ServerŻ,'Read_Username', U
'Password');
Kolejny krok skryptu to ustanowienie połączenia ze zdalnym serwerem bazy danych
(serwer zdalny to serwer główny przechowujący dane źródłowe naszej kopii zapasowej). W tym celu podajemy nazwę lub adres
IP w Remote_Server. Zwykle urządzenia tego typu, lub też serwery MySQL na takich
urządzeniach, skonfigurowane są w taki
sposób, aby obsługiwać wiele kont użytkowników i haseł dostępu do odczytu i zapisu.
Podany poniżej skrypt wymaga praw dostępu do odczytu na serwerze i dlatego też
podczas ustanawiania połączenia dostarcza
danych uwierzytelniających konto dla dostępu do odczytu oraz podaje odpowiednie
hasło (Read_Username, Password):
if( $cR)
{
print 'No remote connection';
return;
}
Wszystko czego potrzebujemy to najmniejsza strona HTML, w której instrukcja PHP
wywołuje funkcję aktualizacji. Dzięki temu
funkcja uruchomi wszystkie funkcje aktualizacyjne, jedną po drugiej. Obecnie szukamy
funkcji aktualizacji przyrostowej, czyli aktualizacji tworzącej kopię zapasową składającą
się wyłącznie z nowych rekordów:
Jako że problemy z nawiązaniem połączenia są dość częste, skrypt sprawdza najpierw wartość zwrotną dla funkcji connect.
Jeżeli nie udało się nawiązać połączenia,
skrypt przerywa pracę.
Listing 3:
Wybór identyfikatorów
Listing 4: Zapytanie
do serwera zdalnego
01 $qs = 'select id from Table order by id desc limit 1';
02 $rLocal = mysql_db_query(Datebase', $qs, $cL);
03 if( $rLocal)
04 {
05 print 'query error: $qs <br>';
06 return;
07 }
01 $qsr = 'select * from Table U
where id>$num order by id';
02 $rRemote = mysql_db_query(U
Database', $qsr, $cR);
03 if( $rRemote)
04 {
05 print 'query error: $qsr <br>';
06 return;
07 }
www.linux-magazine.pl
Lipiec 2004
71
SYSADMIN
Kopia zapasowa MySQL
Kolejnym krokiem jest ustanowienie połączenia z komputerem lokalnym, ponownie przy pomocy obsługi błędów (Listing
2). Komputer lokalny będzie przechowywać
kopię danych. Ponownie musimy podać
w skrypcie nazwę komputera lub adres IP
wraz z odpowiednimi danymi uwierzytelniającymi użytkownika. Tym razem będziemy potrzebować konta użytkownika z prawem do zapisu.
Wyszukiwanie
nowych rekordów
Po ustanowieniu obu połączeń z serwerami
bazy danych przechodzimy do najtrudniejszej części. Jako że pierwszy przykładowy
skrypt kopiował wyłącznie nowe rekordy,
musimy teraz poinformować go o tym, które z rekordów są faktycznie nowe. Skrypt
wykorzystuje numer seryjny lub też unikalny identyfikator przypisywany każdej linii
w tabeli. Skrypt zakłada, że najwyższy identyfikator jest przypisywany do rekordu
z najwyższym numerem (Listing 3).
W naszym przykładzie zapytanie SQL
sprawdza najpierw najwyższy identyfikator
w tabeli. Użytkownicy muszą tylko dopasować do swojego środowiska miejsca na Table i Database, gdzie Table dotyczy tabeli
wewnątrz bazy danych, a Database określa
nazwę bazy danych, do której będziemy
uzyskiwali dostęp przez serwer MySQL.
Ponownie skorzystamy z obsługi błędów –
dzięki temu upewnimy się, czy zapytanie
wywoła (lub czy może wywołać) jakąś reakcję. Jeżeli nadchodzi odpowiedź, skrypt
przekazuje właściwe zapytanie. Dzięki temu możemy użyć przeglądarki do sprawdzenia, czy określone zapytanie spowodowało jakieś problemy:
$row = mysql_fetch_rowU
(rLocal);
$num = $row[0];
Teraz należy przetworzyć otrzymane wartości. PHP oferuje do tego zadania wiele interesujących funkcji. Jako że nas interesuje
tylko jedna wartość, doskonale poradzi sobie z tym zadaniem polecenie mysql_fetch_row(). Wartość znajduje się
w pierwszym gnieździe uzyskanej tablicy,
indeks [0]. W ten sposób uzyskujemy najwyższą wartość rekordu lokalnego. Następnie możemy przeprowadzić ponowne zapytanie na serwerze zdalnym (patrz Listing 4).
W przypadku drugiego zapytania interesują nas wyłącznie wartości większe niż odszukana poprzednio. W tym celu musimy
nieco zmodyfikować poprzednie zapytanie.
Warunkowość określono za pomocą instrukcji where. Uzyskana wartość przechowywana jest w wynikach zapytania, które
PHP może ponownie przetworzyć:
$count = mysql_num_rowsU
Listing 5: Kopiowanie rekordów
01 for(i=0; $i<$count; $i++)
02 {
03 print 'Updating: $i... <br> ';
04 $row = mysql_fetch_row(rRemote);
05 $qsLocal = 'insert into Table(Fields) values(Values)';
06 $rLocal = mysql_db_query('Database',
$qsLocal, $cL);
07 if( $rLocal)
08 {
09 print 'query error: $qsLocal <br>';
10 return;
11 }
12 }
(rRemote);
Teraz wiemy, ile rekordów musimy skopiować. Kolejnym krokiem będzie skopiowanie danych (Listing 5) – powtarzamy go tak
często, jak to konieczne, aż do momentu
uzyskania pełnej kopii zapasowej nowych
rekordów. Dla każdego nowego rekordu
skrypt wywołuje mysql _fetch_row(). Dane
przechowywane są w tablicy.
Po utworzeniu kopii dane trzeba jeszcze
umieścić w tabeli. Do wykonania tego potrzebujemy miejsca Table, zawierającego
nazwę naszej tabeli. Zamiast Fields wykorzystamy tutaj listy pól oddzielanych przecinkami. Umieszczane w tabeli wartości to:
$row[0], $row[1] itd. Na koniec musimy
jeszcze dostarczyć zapytanie MySQL z żądanym pytaniem, które do tej pory stworzył
proces. Dzięki temu dane zostaną rzeczywiście wstawione w odpowiednie miejsca.
Kompletna
kopia zapasowa
Dla kompletnej kopii zapasowej nie ma
w zasadzie większych zmian i skrypt będzie
miał następującą postać:
$strDel = 'delete from Table';
$r = mysql_db_query('Database',U
$strDel, $cL);
Jednakże musimy pamiętać o kilku rzeczach. Przede wszystkim musimy upewnić
się, że tabela, którą chcemy skopiować, została zresetowana na komputerze docelowym. Będzie to oznaczać, że mamy pustą
tabelę i możemy skorzystać z instrukcji insert into do zapisania nowych danych. Aby
opróżnić tabelę, możemy skorzystać z delete from. Bardzo istotne jest usunięcie właściwej tabeli z właściwej bazy danych jeszcze przed uruchomieniem skryptu. Następnie skrypt wybiera wszystkie dane z tabeli
źródłowej i wstawia je do tabeli docelowej
(Listing 6).
■
INFO
Listing 6: Wstawianie danych do tabeli docelowej
01
02
03
04
72
$qs = 'select * from Table';
$r = mysql_db_query('Database', $qs, $cR);
$num = mysql_num_rows(r);
for(i=0; $i<$num; $i++)
Lipiec 2004
www.linux-magazine.pl
[1] MySQL: http://www.mysql.com
[2] Mysqldump: http://www.mysql.com/
doc/en/mysqldump.html
[3] Skrypt PHP script:
http://www.linux-magazine.com/Magazine/
Downloads/44/MySQL
[4] PHP MyAdmin: http://www.phpmyadmin.net