Pokazywanie postów oznaczonych etykietą relay logs. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą relay logs. Pokaż wszystkie posty

piątek, 23 maja 2014

Naprawianie replikacji master-master w MySQLu

Pamiętacie mój ostatni post na temat podpinania nowego noda do replikacji w MySQL-u? Możecie go przeczytać tutaj, jeśli jeszcze tego nie zrobiliście.

Chciała bym teraz troszkę zmienić scenariusz wydarzeń i zastanowić się co musimy zrobić aby naprawić replikację master-master w MySQLu. Załóżmy, że mamy dwa serwery, których zmiany powinny być wzajemnie replikowane. Niestety zauważyliśmy, że zmiany z II serwera już od jakiegoś czasu nie są zatwierdzane na slavie z powodu błędu. Dodatkowym problemem jest rosnąca liczba plików relay logów na serwerze. Slave nie może ich usunąć bo zmiany w nich nie zostały zatwierdzone ale są cały czas od mastera pobierane nowe zmiany. Musimy zacząć myśleć co z tym zrobić aby się nie okazało, że za jakiś czas zacznie brakować nam miejsca.

Oto przykładowy błąd w tym wypadku:

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 1.1.1.1
                  Master_User: replicate
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: host-mysql-01-bin.002539
          Read_Master_Log_Pos: 902412914
               Relay_Log_File: host-mysql-01-relay-bin.001829
                Relay_Log_Pos: 461330748
        Relay_Master_Log_File: host-mysql-01-bin.002399
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 1452
                   Last_Error: Could not execute Write_rows event on table test.BATCH_STEP_EXECUTION; Cannot add or update a child row: a foreign key constraint fails (`test`.`BATCH_STEP_EXECUTION`, CONSTRAINT `JOB_EXEC_STEP_FK` FOREIGN KEY (`JOB_EXECUTION_ID`) REFERENCES `BATCH_JOB_EXECUTION` (`JOB_EXECUTION_ID`)), Error_code: 1452; handler error HA_ERR_NO_REFERENCED_ROW; the event's master log host-mysql-01-bin.002399, end_log_pos 508490809
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 508490445
              Relay_Log_Space: 145560879727
              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: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 1452
               Last_SQL_Error: Could not execute Write_rows event on table test.BATCH_STEP_EXECUTION; Cannot add or update a child row: a foreign key constraint fails (`test`.`BATCH_STEP_EXECUTION`, CONSTRAINT `JOB_EXEC_STEP_FK` FOREIGN KEY (`JOB_EXECUTION_ID`) REFERENCES `BATCH_JOB_EXECUTION` (`JOB_EXECUTION_ID`)), Error_code: 1452; handler error HA_ERR_NO_REFERENCED_ROW; the event's master log host-mysql-01-bin.002399, end_log_pos 508490809
1 row in set (0.00 sec)

Napisze od razu, że zastosowanie SQL_SLAVE_SKIP_COUNTER=1 (a tu artykuł dlaczego jest to złe) w tym przypadku nie jest rozwiązaniem - według błędu ta zmiana próbuje się odwołać do elementu, który nie istnieje. Co jeśli takich zmian jest cała masa? Chcecie cały czas siedzieć przed komputerem i sprawdzać czy nie trzeba countera pominąć?! Najlepszym rozwiązaniem będzie odtworzenie całej replikacji. Aby to zrobić będziemy początkowo traktować 'zepsuty' slave jako nowy nod (http://db-diary.blogspot.com/2014/05/podpiecie-nowego-noda-do-replikacji-w.html).

No to co robimy:
  1. Przekierowywujemy cały ruch aplikacji na działającego noda - w naszym przypadku jest to II serwer.
  2. Generujemy dump z II serwera:

    mysqldump -uroot -proot --skip-lock-tables --single-transaction --flush-logs --hex-blob --master-data=2 -A > dump.sql


    UWAGA!
    Tutaj musicie założyć, że wszystkie bazy danych mają tabelkę transakcyjne - InnoDB. Jeśli używanie także MyISAM wymagane będzie zatrzymać aplikację, które powodują zamiany na działającym masterze (w naszym przypadku to oczywiście serwer II) lub wymusić lokowanie tabel w czasie robienia dumpa. Jeśli tego nie zrobicie w dumpie mogą pojawić się dane z 'późniejszych' insertów niż pozycja i plik binary logów na to wskazuje.
  3. Zczytujemy pozycję mastera z dumpa

    head dump.sql -n80 | grep "MASTER_LOG_POS"
  4. Kopiujemy dump na I serwer
  5. Stopujemy replikację na oby dwóch serwerach przy pomocy polecenia:

    STOP SLAVE;

    Ponieważ w dumpie mamy wszystkie polecenia do odtworzenia całego klastra, musimy się upewnić, że w czasie importowania jego, żadne zmiany nie przeniosą się na slava.
  6. Resetujemy slava na I serwerze

    RESET SLAVE;

    Przy pomocy tego polecenia wszystkie relay-logi zostaną usunięte i zostanie stworzony całkiem nowy. Informacje o replikacji także zostaną 'zapomniane' - pliki master.info i relay-log.info zostaną usunięte. Zawierają one informację o połączeniu i pozycjach w plikach. Warto je przekopiować na wypadek jak byśmy nie pamiętali nazwy użytkownika i jego hasła lub IP hosta potrzebnego do połączenia w replikacji.
  7. Zaimportować dump

    mysql -uroot -proot < dump.sql
  8. Zczytujemy nazwę binarylogu i pozycję na serwerze I

    SHOW MASTER STATUS;
  9. Ustawiamy slava dla serwerów

    CHANGE MASTER TO MASTER_HOST='HOST',MASTER_USER='replication',MASTER_PASSWORD='replication', MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=504122;

    Plik i pozycję dla serwera I zaczytaliśmy z dumpa (punkt 3), a dla serwera II z poprzedniego kroku (punkt 8).
  10. Uruchamiany replikację

    START SLAVE;
  11. Potwierdzamy działanie replikacji

    SHOW SLAVE STATUS \G

Może się zdarzyć, że mimo to replikacja i tak nie działa. Musicie się przyjrzeć dokładnie jakie zmiany mają być przenoszone - może to wynikać ze złego sposobu wykonania dumpa (popatrz na komentarz w punkcie 2). Załóżmy, że miało to miejsce i pojawił się następujący błąd:

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 1.1.1.1
                  Master_User: replicate
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: host-03-bin.002549
          Read_Master_Log_Pos: 130312481
               Relay_Log_File: host-03-relay-bin.000002
                Relay_Log_Pos: 33108
        Relay_Master_Log_File: host-03-bin.002549
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 1032
                   Last_Error: Could not execute Update_rows event on table test.BATCH_JOB_SEQ; Can't find record in 'BATCH_JOB_SEQ', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log host-03-bin.002549, end_log_pos 33132
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 32951
              Relay_Log_Space: 130313453
              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: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 1032
               Last_SQL_Error: Could not execute Update_rows event on table test.BATCH_JOB_SEQ; Can't find record in 'BATCH_JOB_SEQ', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log host-03-bin.002549, end_log_pos 33132
1 row in set (0.00 sec)

Istnieje prawdopodobieństwo, że tych złych danych jest tak mało, że możemy ręcznie wyrównać zmiany, aż slave przestanie sypać błędami (wykonanie dumpa trwało na tyle krótko, że tych 'nadmiernych' zmian było mało). Ale jak to zrobić? Posłużymy się narzędziem masterbinlog. Ja postanowiłam przejżeć wszystkie zmiany w relay logach:

mysqlbinlog --start-position=0 --verbose --base64-output=DECODE-ROWS host-03-relay-bin.000002 > /tmp/binary.logs

Przeglądałam plik i szukałam wystąpienia znaków 'end_log_pos 33132'. W ten sposób znalazłam:

#140522  1:12:00 server id 173  end_log_pos 33108     Table_map: `test`.`BATCH_JOB_SEQ` mapped to number 5085
#140522  1:12:00 server id 173  end_log_pos 33132     Update_rows: table id 5085 flags: STMT_END_F
### UPDATE test.BATCH_JOB_SEQ
### WHERE
###   @1=354422
### SET
###   @1=354423
# at 4309887

Sprawdziłam, że ten wiersz dla tego ID w tej tabeli nie istnieje, a właściwie istnieje ale ma inną wartość - dlatego slave nie jest w stanie zatwierdzić zmian. Co teraz zrobić?

  1. Zatrzymujemy slave

    STOP SLAVE;
  2. Wykonujemy taką zmiane na bazie danych aby dane do tego momentu były zgodne do zatwierdzenia przez slave:

    UPDATE test.BATCH_JOB_SEQ SET ID = 354422 WHERE ID = X;
  3. Wznawiamy slava

    START SLAVE;
Może się okazać, że tych zmian jest troszkę. Ale czasie warto przejść przez to kilka razy. Jeśli jednak zmian jest za dużo, warto się zastanowić nad wykonaniem dumpa ponownie z lokowaniem zapisy do tabel.

sobota, 1 lutego 2014

Status replikacji w MySQL v5.5

Nie wiem czy czytaliście mój niedawny post na temat stawiania replikacji master-master w MySQL-u. Możecie go znaleźć tutaj. Postanowiłam sprawdzić co się stanie, gdy jedna z maszyn, na których stoi serwer padnie, a przy okazji opisać, co możemy się dowiedzieć na temat wyniku zwracanego przez polecenie SHOW SLAVE STATUS lub SHOW MASTER STATUS.

Zaczniemy od momentu gdy serwer ID 1 (192.168.100.166) nie działa, a na serwerze ID 2 (192.168.100.167) zaimportowałam dane z dump-a. Zobaczymy co się stanie gdy serwer ID 1 ponownie zacznie działać.

Przy pomocy polecenia SHOW SLAVE STATUS widzimy, że połączenie do jego mastera nie może zostać nawiązane:

mysql (root@ela_db)> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Connecting to master
                  Master_Host: 192.168.100.166
                  Master_User: replication
                  Master_Port: 3309
                Connect_Retry: 60
              Master_Log_File: binlog.000005
          Read_Master_Log_Pos: 1171
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 1314
        Relay_Master_Log_File: binlog.000005
             Slave_IO_Running: Connecting
            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: 1171
              Relay_Log_Space: 1464
              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: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 2003
                Last_IO_Error: error connecting to master 'replication@192.168.100.166:3309' - retry-time: 60  retries: 86400
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2
1 row in set (0.02 sec)

Po podniesieniu serwera, replikacja sama zaczęła nawiązywać połączenie:

140124 05:49:02 mysqld_safe Starting mysqld daemon with databases from /home/mysql/mysql5.5/myisam
140124  5:49:02 [Note] Plugin 'FEDERATED' is disabled.
140124  5:49:02 InnoDB: The InnoDB memory heap is disabled
140124  5:49:02 InnoDB: Mutexes and rw_locks use GCC atomic builtins
140124  5:49:02 InnoDB: Compressed tables use zlib 1.2.3
140124  5:49:02 InnoDB: Using Linux native AIO
140124  5:49:02 InnoDB: Initializing buffer pool, size = 128.0M
140124  5:49:02 InnoDB: Completed initialization of buffer pool
140124  5:49:02 InnoDB: highest supported file format is Barracuda.
InnoDB: The log sequence number in ibdata files does not match
InnoDB: the log sequence number in the ib_logfiles!
140124  5:49:02  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages from the doublewrite
InnoDB: buffer...
140124  5:49:02  InnoDB: Waiting for the background threads to start
140124  5:49:03 InnoDB: 1.1.8 started; log sequence number 1601052
140124  5:49:03 [Note] Recovering after a crash using /home/mysql/mysql5.5/replication/binlog
140124  5:49:03 [Note] Starting crash recovery...
140124  5:49:03 [Note] Crash recovery finished.
140124  5:49:04 [Note] Slave SQL thread initialized, starting replication in log 'binlog.000003' at position 502, relay log '/home/mysql/mysql5.5/replication/relay-bin.000002' position: 250
140124  5:49:04 [Note] Event Scheduler: Loaded 0 events
140124  5:49:04 [Note] /usr/local/mysql5.5/bin/mysqld: ready for connections.
Version: '5.5.23-log'  socket: '/tmp/mysql5.5.sock'  port: 3309  MySQL Community Server (GPL)
140124  5:49:04 [Note] Slave I/O thread: connected to master 'replication@192.168.100.167:3309',replication started in log 'binlog.000003' at position 502
140124  5:49:07 [Note] Start binlog_dump to slave_server(1), pos(binlog.000005, 1171)


Na serwerze, który został podniesiony, zaczęły napływać dane:

Gdzie:
  • Master_Log_File - nazwa binlog-u mastera, która jest aktualnie czytana przez slave
  • Read_Master_Log_Pos - pozycja z binlog-u mastera, która jest aktualnie czytana
  • Relay_Log_File - nazwa aktualnego  relay log-u
  • Relay_Log_Pos - aktualna pozycja z relay log-u (wszystkie zamiany sprzed tej pozycji, zostały już wykonane w bazach slave)
  • Relay_Master_Log_File - nazwa binlog-u mastera, gdzie zmiana z relay logu była czytana
  • Exec_Master_Log_Pos - pozycja z binlog-u mastera, która właśnie została wykonana
  • Seconds_Behind_Master - ile sekund slave jest do tyłu w stosunku do mastera


Gdy już wszystkie dane zostały wyrównane, chcieli byśmy usunąć zbędne binlog-i. Może nam w tym pomóc polecenia: PURGE BINARY LOGS, SHOW BINARY LOGS oraz zmienne serwerowe.

Zmienne expire_logs_days, mówi po ilu dniach binary log będzie usuwany. Jeśli wartość zmiennej ustawiona jest na 0, mechanizm usuwania jest wyłączony i wymagane jest usuwanie binary logów ręcznie.

mysql (root@ela_db)> show variables like 'expire_logs_days';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| expire_logs_days | 0     |
+------------------+-------+
1 row in set (0.00 sec)

Polecenie SHOW BINARY LOGS zwraca listę binary logów z ich rozmiarem (maksymalny rozmiar jest ustawiany przez zmienną max_binlog_size), a przy pomocy PURGE BINARY LOGS (dokumentacja: http://dev.mysql.com/doc/refman/5.5/en/purge-binary-logs.html) możemy usunąć stare pliki:

mysql (root@ela_db)> show binary logs;
+---------------+------------+
| Log_name      | File_size  |
+---------------+------------+
| binlog.000001 |      26372 |
| binlog.000002 |     938077 |
| binlog.000003 | 1073879253 |
| binlog.000004 | 1074045928 |
| binlog.000005 | 1073749134 |
| binlog.000006 |  725494868 |
+---------------+------------+
6 rows in set (0.00 sec)

mysql (root@ela_db)> PURGE BINARY LOGS to 'binlog.000006';
Query OK, 0 rows affected (0.44 sec)

mysql (root@ela_db)> show binary logs;
+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000006 | 725494868 |
+---------------+-----------+
1 row in set (0.00 sec)

Jeśli chodzi o relay logi w zależności od ustawień serwera, mogą one być np automatycznie usuwane gdy są już nie używane:

mysql (root@(none))> show variables like '%relay%';
+-----------------------+--------------------------------------------+
| Variable_name         | Value                                      |
+-----------------------+--------------------------------------------+
| max_relay_log_size    | 0                                          |
| relay_log             | /home/mysql/mysql5.5/replication/relay-bin |
| relay_log_index       |                                            |
| relay_log_info_file   | relay-log.info                             |
| relay_log_purge       | ON                                         |
| relay_log_recovery    | OFF                                        |
| relay_log_space_limit | 0                                          |
| sync_relay_log        | 0                                          |
| sync_relay_log_info   | 0                                          |
+-----------------------+--------------------------------------------+
9 rows in set (0.82 sec)

  • relay_log_purge - włączone lub wyłączone automatyczne usuwanie relay logu gdy już będzie niepotrzebny
  • relay_log_recovery - gdy włączony, przy starcie serwera relay log jest automatycznie 'pobierany' z serwera mastera dla plików jeszcze niesprocesowanych
  • max_relay_log_size - maksymalny rozmiar relay log plików. Jeśli jest on ustawiony na 0, rozmiar jest definiowany przez zmienną max_binlog_size
  • relay_log - ścieżka pod którą możemy znaleźć pliki
  • relay_log_index - nazwa używana dla pliku indexu relay logów
  • relay_log_info_file - nazwa pliku w którym slave zapisyje informacje o relay logach. 
  • relay_log_space_limit - całkowity limit rozmiaru w bajtach wszystkich relay logów na slave. Jeśli jest ustawione na 0 - oznacza, że nie ma limitu. Dobrze jest ustawić na dostępną powierzchnię dyskową, bo gdy limit zostanie przekroczony, wątek I/O przestanie czytać zdarzenia z binary logi z mastera, dopóki SQL wątek nie dogoni i nie usunie jeszcze niesprocesowanych relay logów. 


I jeszcze kilka poleceń

Aby zobaczyć listę slave-ów możemy użyć polecenia:
mysql (root@ela_db)> show slave hosts;
+-----------+------+------+-----------+
| Server_id | Host | Port | Master_id |
+-----------+------+------+-----------+
|         1 |      | 3309 |         2 |
+-----------+------+------+-----------+
1 row in set (0.00 sec)

Podglądanie zmian w binlogach (polecenie show binlog events):
mysql (root@ela_db)> show binlog events in 'binlog.000008' from 257826769;
+---------------+-----------+-------------+-----------+-------------+--------------------------------+
| Log_name      | Pos       | Event_type  | Server_id | End_log_pos | Info                           |
+---------------+-----------+-------------+-----------+-------------+--------------------------------+
| binlog.000008 | 257826769 | Query       |         2 |   257826852 | BEGIN                          |
| binlog.000008 | 257826852 | Table_map   |         2 |   257826934 | table_id: 52 (ela_db.test)     |
| binlog.000008 | 257826934 | Update_rows |         2 |   257827880 | table_id: 52                   |
| binlog.000008 | 257827880 | Update_rows |         2 |   257828522 | table_id: 52 flags: STMT_END_F |
| binlog.000008 | 257828522 | Xid         |         2 |   257828549 | COMMIT /* xid=5097300 */       |
+---------------+-----------+-------------+-----------+-------------+--------------------------------+
5 rows in set (0.00 sec)

Podgląd relay logów:
mysql (root@ela_db)> SHOW RELAYLOG EVENTS IN 'relay-bin.000034' from 250 limit 10;
+------------------+------+-------------+-----------+-------------+----------------------------+
| Log_name         | Pos  | Event_type  | Server_id | End_log_pos | Info                       |
+------------------+------+-------------+-----------+-------------+----------------------------+
| relay-bin.000034 |  250 | Query       |         1 |   163761726 | BEGIN                      |
| relay-bin.000034 |  333 | Table_map   |         1 |   163761808 | table_id: 93 (ela_db.test) |
| relay-bin.000034 |  415 | Update_rows |         1 |   163762754 | table_id: 93               |
| relay-bin.000034 | 1361 | Update_rows |         1 |   163763700 | table_id: 93               |
| relay-bin.000034 | 2307 | Update_rows |         1 |   163764646 | table_id: 93               |
| relay-bin.000034 | 3253 | Update_rows |         1 |   163765592 | table_id: 93               |
| relay-bin.000034 | 4199 | Update_rows |         1 |   163766538 | table_id: 93               |
| relay-bin.000034 | 5145 | Update_rows |         1 |   163767484 | table_id: 93               |
| relay-bin.000034 | 6091 | Update_rows |         1 |   163768430 | table_id: 93               |
| relay-bin.000034 | 7037 | Update_rows |         1 |   163769376 | table_id: 93               |
+------------------+------+-------------+-----------+-------------+----------------------------+
10 rows in set (0.00 sec)


To tak szybko o replikacji. Jeśli pewne rzeczy były nie jasne, odsyłam do posta wprowadzającego: Instalacja servera i replikacji master-master w MySQL v5.5. Jeśli macie jakieś pytania to komentujcie.

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.