Pracując z bazami danych zawsze mamy do czynienia z replikacjami. Nie ma teraz chyba systemu, w którym replikacji by nie było. Może ona służyć jako kopia zapasowa (backup), maszyna dla celów raportowych (przy replikacji master-slave) lub dodatkowy master serwer aby odciążyć innego mastera (replikacja master-master).
Podstawowy schemat przepływu plików replikacji master-slave (master-master będzie lustrzany) będzie następujący:
- Slave łączy się z masterem
- Wątek I/O pyta o dane
- Wątek Binlog dump na masterze wysyła zawartość do wątku I/O
- Wątek SQL zatwierdza dane (zmiany)
Poniżej krótko opiszę jak zestawić replikację master-master dla MySQL v.5.5 w następujących krokach:
- Konfiguracja serwerów - plik my5.5.cnf
- Instalacja serwera MySQL v5.5
- Ustawienie replikacji
Na tych maszynach zainstalowano już inne wersje serwerów MySQL dlatego opis obejmuję instalacji wersji binarnych na niestandardowych ścieżkach i porcie 3309.
Serwery bazodanowe będą stać pod adresami:
- 192.168.100.167 - server ID = 1
- 192.168.100.166 - server ID = 2
Konfiguracja MySQL'a (my5.5.cnf)
Chce aby klient łączył się na porcie 3309 przy kodowaniu utf8. Wskazałam także ścieżkę do socket-u:
[client]
port = 3309
socket = /tmp/mysql5.5.sock
default-character-set = utf8
Ustawienia serwera:
[mysqld]
user = mysql
skip-name-resolve
innodb_file_per_table
skip-external-locking
report-port = 3309
tmpdir = /home/mysql/mysql5.5/mysqltmp
event_scheduler = 0
pid-file = /home/mysql/mysql5.5/mysql.pid
socket = /tmp/mysql5.5.sock
datadir = /home/mysql/mysql5.5/myisam
port = 3309
server-id = 1
character-set-server = utf8
auto_increment_offset = 1
auto_increment_increment = 2
log-output = file
general_log = 1
general_log_file = /home/mysql/mysql5.5/log/mysql.log
log_error = /home/mysql/mysql5.5/log/mysql.err
log-warnings = 1
long_query_time = 1
slow_query_log = 1
slow_query_log_file = /home/mysql/mysql5.5/slow.log
log_queries_not_using_indexes = 1
log-bin = /home/mysql/mysql5.5/replication/binlog
binlog-format = ROW
relay-log = /home/mysql/mysql5.5/replication/relay-bin
#default-table-type = InnoDB
innodb_data_home_dir = /home/mysql/mysql5.5/innodb/
innodb_data_file_path = ibdata/ibdata1:50M:autoextend
innodb_log_group_home_dir = /home/mysql/mysql5.5/innodb/iblogs
innodb_flush_log_at_trx_commit = 2
innodb_fast_shutdown
Z ustawień serwera przeczytamy, że:
- nasłuchuję na porcie 3309, jest to także port dla połączenia ze slavem
- logi bazodanowe możemy znaleźć w katalogu: /home/mysql/mysql5.5/log
- slow logi są pod ścieżką: /home/mysql/mysql5.5/slow.log
- katalog dla tabel tymczasowych jest pod ścieżką: /home/mysql/mysql5.5/mysqltmp
- każdy z serwerów podpiętych do replikacji musi mieć unikalną wartość dla server-id, w tym przypadku jest ustawione na 1
- dla replikacji master-master musimy dobrze ustawić zmienne odpowiadające za kontrolowanie auto incrementów kluczy głównych. Zmienna auto_increment_increment mówi jak mają być zmieniane wartość, a auto_increment_offset od jakiej wartości zaczynamy. Dla dwóch serwerów w replikacji master-master ustawimy, że wartości mają się zmieniać co 2 zaczynając od 1 dla serwera ID 1 i zaczynając od 2 dla serwera ID 2
- dla enginu InnoDB będziemy przechowywać dane w katalogu: /home/mysql/mysql5.5/innodb. Przed uruchomieniem serwera stworzymy podkatalogi:
- ibdata -pod zmienną innodb_data_file_path znajdziecie ścieżkę do plików danych związanych z tym enginem odraz ich rozmiar. Pełna ścieżka do tego katalogu jest zapisana pod zmienną innodb_data_home_dir.
- iblogs -katalog, do którego ścieżka została zdefiniowana przez zmienną innodb_log_group_home_dir. Przechowane są tam redo log-i, czyli struktury danych na dysku używane w czasie odzyskiwania danych po niespodziewanym zamknięciu serwera aby odzyskać poprawnie zapisane dane przy niedokończonych transakcjach.
- pliki dla replikacji, które można znaleźć w katalogu /home/mysql/mysql5.5/replication/ pod nazwami zaczynającymi się od:
- binlog - pliki binlogów, które zawierają informację o numerze pliku, zdarzenia o zmianach w bazie danych i plik indexu z listą wszystkich używanych plików
- relay-bin - składa się ze zdarzeń odczytywanych z binary logów z mastera i zapisanych przez wątek I/O slav-a. Zdarzenia w tych plikach są wykonywane na slave jako część wątku SQL.
- typ replikacji (w tym przypadku ROW):
- ROW - master wysyła zdarzenia, które identyfikują indywidualne zmiany wierszy które zostały dokonane
- STATEMENT - replikowane są zapytania SQL (dla naszej wersji serwera jest to domyślna opcja)
- MIXED - połączenie dwóch poprzednich typów replikacji.
- zmienna innodb_file_per_table - jest włączona aby dla każdej tabeli, dane i index-y były w oddzielnych plikach.
Instalacja serwera MySQL 5.5
Przed rozpoczęciem instalacji, pobrałam wybraną przeze mnie wersję serwera ze storny
http://downloads.mysql.com/archives/community/. Po rozpakowaniu pliku tar.gz znajdziecie plik INSTALL-BINARY, w których opisany jest proces instalacji, dlatego tylko krótko przedstawię swoje kroki instalacji.
W pierwszej kolejności dodaję grupy i użytkownika mysql (jeśli jeszcze nie istnieje). W lokalizacji /usr/local rozpakowuje plik z serwerem, a następnie stworzony katalog podlinkuje pod symlinka mysql5.5.
sudo groupadd mysql
sudo useradd -g mysql mysql
cd /usr/local
sudo gunzip < /home/ela/mysql/mysql-5.5.23-linux2.6-x86_64.tar.gz | sudo tar xvf -
sudo ln -s /usr/local/mysql-5.5.23-linux2.6-x86_64.tar.gz mysql5.5
Domyślnie mysql szuka pliku konfiguracyjnego w katalogu /etc. Na tej maszynie istnieje już działający serwer MySQL, dlatego nasz plik konfiguracyjny będzie można znaleźć pod /etc/my5.5.cnf
cd mysql5.5
sudo chown -R mysql .
sudo chgrp -R mysql .
sudo cp /home/ela/mysql/my.cnf /etc/my5.5.cnf
Po zainstalowaniu plików serwera, musimy zainicjować katalog z danymi i stworzyć system tabel. Ponieważ mamy niestandardowe ścieżki, musimy je podać:
sudo scripts/mysql_install_db --defaults-file=/etc/my5.5.cnf --user=mysql --builddir=/usr/local/mysql5.5/bin --pid-file=/home/mysql/mysql5.5/mysql.pid
sudo chown -R root .
Uruchamiamy zainstalowany serwer i jeśli wszystko zakończy się dobrze, musimy stworzyć super użytkownika, któremu nadamy hasło:
bin/mysqld_safe --defaults-file=/etc/my5.5.cnf --user=mysql --ledir=/usr/local/mysql5.5/bin --pid-file=/home/mysql/mysql5.5/mysql.pid &
./bin/mysqladmin -u root password 'root' --host=127.0.0.1 --port=3309
Ustawienie replikacji
Ponieważ dopiero co zainstalowaliśmy nasze serwery, nie ma potrzeby ich wyrównywać. W przeciwnym przypadku musieli byśmy zrobić dump serwera i zrestować dane na drugim serwerze.
Aby replikacja mogła działać, na każdym z serwerów stworzymy użytkownika z prawami do replikacji:
CREATE USER 'replication'@'%' IDENTIFIED BY 'replication';
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%';
Jeśli na masterze mamy dane, które chcemy synchronizować przed uruchomieniem replikacji, musimy zatrzymać działające zapytania na masterze aby otrzymać aktualne binary logi, zdumpować je, zrestartować na slave i pozwolić na kontynuowanie działania przerwanych zapytań (Polecenie na masterze: UNLOCK TABLES).
Aktualne binlogi otrzymamy przez zapytanie:
FLUSH TABLES WITH READ LOCK;
Sprawdzamy jaki jest status binary logów (nazwa i pozycja) dla serwerów (poniżej przykład wyniku dla serwera ID 1) aby sprawdzić od którego pliku i jakiej pozycji ma się rozpocząć replikacja:
mysql (root@(none))> show master status;
+---------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| binlog.000003 | 502 | | |
+---------------+----------+--------------+------------------+
1 row in set (0.00 sec)
Ustawiamy parametry replikacji na każdym masterze (Szczegóły w dokumentacji:
http://dev.mysql.com/doc/refman/5.5/en/change-master-to.html lub
http://dev.mysql.com/doc/refman/5.5/en/replication-howto-slaveinit.html).
Dla serwera ID 1 (192.168.100.167):
mysql (root@(none))>CHANGE MASTER TO
MASTER_HOST='192.168.100.166',
MASTER_PORT=3309,
MASTER_USER='replication',
MASTER_PASSWORD='replication',
MASTER_LOG_FILE='binlog.000005',
MASTER_LOG_POS=107;
Dla serwera ID 2 (192.168.100.166):
mysql (root@(none))>CHANGE MASTER TO
MASTER_HOST='192.168.100.167',
MASTER_PORT=3309,
MASTER_USER='replication',
MASTER_PASSWORD='replication',
MASTER_LOG_FILE='binlog.000003',
MASTER_LOG_POS=502;
Uruchamiany replikację na każdym serwerze:
mysql (root@(none))> SLAVE START;
Status slave z servera id 1 (192.168.100.167) weryfikuję:
mysql (root@(none))> SHOW slave STATUS \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.100.166
Master_User: replication
Master_Port: 3309
Connect_Retry: 60
Master_Log_File: binlog.000005
Read_Master_Log_Pos: 107
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 250
Relay_Master_Log_File: binlog.000005
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 107
Relay_Log_Space: 400
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 2
1 row in set (0.00 sec)
Status slave z servera id 2 (192.168.100.166) weryfikuję:
mysql (root@(none))> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.100.167
Master_User: replication
Master_Port: 3309
Connect_Retry: 60
Master_Log_File: binlog.000003
Read_Master_Log_Pos: 502
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 250
Relay_Master_Log_File: binlog.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 502
Relay_Log_Space: 400
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
1 row in set (0.00 sec)
Mam nadzieję, że Wam także się udało. Przy pomocy stworzonej replikacji będę chciała sprawdzać kilka rzeczy, które mogą się przyda wiedzieć dla programisty. Ale to do następnego posta.