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