niedziela, 26 stycznia 2014

Instalacja servera i replikacji master-master w MySQL v5.5

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:

  1. Slave łączy się z masterem
  2. Wątek I/O pyta o dane
  3. Wątek Binlog dump na masterze wysyła zawartość do wątku I/O
  4. 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:
  1. Konfiguracja serwerów - plik my5.5.cnf
  2. Instalacja serwera MySQL v5.5
  3. 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.

2 komentarze:

  1. " pozwolić na kontynuowanie działania przerwanych zapytań (Polecenie na masterze: UNLOCK TABLES)."

    Po zatrzymaniu na master binlogów wykonaniu dumpa i zaimportowaniu na slavie dodaniu danych odnośnie binloga i pozycj nie musimy wykonywać unlock tables; na master. Po uruchomieniu start slave; na slavie, pozycja na master zacznie się zmieniać sama.

    OdpowiedzUsuń
    Odpowiedzi
    1. Dodatkowo polecany jest jednak dump master z master-data= ponieważ to daje gwarancje aktualnych zmian w binlogu.

      Usuń