MySQL replikacja — konfiguracja master-replica
Opublikowano: 9 kwietnia 2026 · Kategoria: Bazy danych
Replikacja MySQL pozwala automatycznie kopiować dane z serwera master na jeden lub więcej serwerów replica (slave). Zastosowania: wysoka dostępność (HA) — replica przejmuje ruch gdy master padnie, skalowanie odczytu — aplikacja czyta z replik, odciążając mastera, a także backupy bez obciążenia produkcji. Ten artykuł przeprowadzi Cię przez konfigurację od zera.
Po co replikacja — trzy główne zastosowania
- Wysoka dostępność (HA) — gdy master padnie, możesz ręcznie lub automatycznie (MHA, Orchestrator) promować replikę na nowego mastera. Czas przestoju: minuty zamiast godzin.
- Skalowanie odczytu (Read Scaling) — zapytania SELECT (raporty, listy, API read-only) kieruj na repliki. Master obsługuje tylko zapisy. Dzięki temu jeden zapis generuje dane dla wielu replik obsługujących ruch odczytowy.
- Backupy bez blokowania produkcji —
mysqldumpna replice nie obciąża mastera. Replika może być tymczasowo zatrzymana (STOP REPLICA SQL_THREAD) dla spójnego dumpa.
Typy replikacji: statement vs row vs mixed
| Typ | Co zapisuje w binlog | Zalety | Wady |
|---|---|---|---|
| Statement (SBR) | Oryginalne zapytanie SQL | Mały rozmiar logów | Niebezpieczny dla NOW(), RAND(), UUID() |
| Row (RBR) | Zmienione wiersze (before/after) | Deterministyczny, bezpieczny | Duże logi przy masowych UPDATE |
| Mixed | SBR gdy bezpieczne, RBR gdy konieczne | Kompromis | Trudniejsza analiza logów |
MySQL 8+ domyślnie używa Row-based replication — jest bezpieczniejszy i zalecany dla nowych instalacji.
Konfiguracja mastera — my.cnf
Na serwerze master edytuj /etc/mysql/mysql.conf.d/mysqld.cnf (lub
/etc/my.cnf):
[mysqld] # Unikalny identyfikator serwera w topologii replikacji (1 = master) server-id = 1 # Włącz binary log — WYMAGANE dla replikacji log_bin = /var/log/mysql/mysql-bin.log # Format replikacji (row jest domyślny i zalecany w MySQL 8+) binlog_format = ROW # Opcjonalnie: replikuj tylko konkretne bazy # binlog_do_db = moja_baza # binlog_ignore_db = information_schema # Czas przechowywania binary logów (sekundy) — 7 dni binlog_expire_logs_seconds = 604800 # Synchronizacja dysku po każdym commicie (bezpieczniej, wolniej) sync_binlog = 1 innodb_flush_log_at_trx_commit = 1
sudo systemctl restart mysql # Sprawdź czy binary log działa mysql -u root -p -e "SHOW MASTER STATUS\G"
Zapamiętaj wartości File i Position z SHOW MASTER STATUS — będą potrzebne
przy konfiguracji repliki.
Tworzenie użytkownika replikacji
-- Na masterze: utwórz dedykowanego użytkownika dla repliki mysql -u root -p CREATE USER 'replika_user'@'10.0.0.11' IDENTIFIED WITH mysql_native_password BY 'BezpieczneHaslo123!'; GRANT REPLICATION SLAVE ON *.* TO 'replika_user'@'10.0.0.11'; FLUSH PRIVILEGES; -- Zrób dump bazy z pozycją binary logu (dla pierwszej synchronizacji) -- Opcja 1: zablokuj zapisy na czas dumpa FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS; -- zanotuj File i Position! -- W osobnej sesji (lub po zanotowaniu pozycji): mysqldump -u root -p --all-databases --master-data=2 > /tmp/dump.sql -- Odblokuj UNLOCK TABLES;
Konfiguracja repliki — my.cnf i CHANGE REPLICATION SOURCE
# /etc/mysql/mysql.conf.d/mysqld.cnf na REPLICE [mysqld] # Unikalny ID — inny niż master server-id = 2 # Replika nie musi mieć binary logu (chyba że to kaskadowa replikacja) # log_bin = ... # Zabezpieczenie — replika nie przyjmuje zapisów bezpośrednio super_read_only = ON # Opcjonalnie: relay log relay_log = /var/log/mysql/mysql-relay-bin.log
sudo systemctl restart mysql # Zaimportuj dump z mastera mysql -u root -p < /tmp/dump.sql # Skonfiguruj połączenie z masterem mysql -u root -p CHANGE REPLICATION SOURCE TO SOURCE_HOST = '10.0.0.10', SOURCE_USER = 'replika_user', SOURCE_PASSWORD = 'BezpieczneHaslo123!', SOURCE_LOG_FILE = 'mysql-bin.000001', -- z SHOW MASTER STATUS SOURCE_LOG_POS = 1234; -- z SHOW MASTER STATUS START REPLICA; -- Sprawdź status replikacji SHOW REPLICA STATUS\G
SHOW REPLICA STATUS — interpretacja kluczowych pól
| Pole | Oczekiwana wartość | Co oznacza problem |
|---|---|---|
Replica_IO_Running | Yes | No — problem z połączeniem do mastera (hasło, firewall, sieć) |
Replica_SQL_Running | Yes | No — błąd SQL przy odtwarzaniu (duplikat klucza, brakująca tabela) |
Seconds_Behind_Source | 0 lub bliskie 0 | Duże wartości = replika nie nadąża za masterem |
Last_SQL_Error | puste | Komunikat błędu SQL — napraw lub pomiń |
Last_IO_Error | puste | Błąd połączenia — sprawdź dostęp sieciowy i credentials |
Replikacja GTID — lepsza alternatywa
GTID (Global Transaction Identifier) eliminuje potrzebę ręcznego podawania pozycji w binary logu. Każda transakcja ma unikalny ID, replika wie skąd kontynuować po restarcie lub failoverze.
# Na masterze I replice (my.cnf): [mysqld] gtid_mode = ON enforce_gtid_consistency = ON log_slave_updates = ON # replikuje GTID do binary logu repliki # Na replice — CHANGE SOURCE bez podawania pozycji: CHANGE REPLICATION SOURCE TO SOURCE_HOST = '10.0.0.10', SOURCE_USER = 'replika_user', SOURCE_PASSWORD = 'BezpieczneHaslo123!', SOURCE_AUTO_POSITION = 1; -- GTID: replika sama znajdzie pozycję START REPLICA; SHOW REPLICA STATUS\G -- sprawdź Executed_Gtid_Set
Przy GTID: super_read_only = ON na replice jest krytyczne — zapobiegnie przypadkowym
zapisom które złamałyby sekwencję GTID i wymagały reiniicjalizacji replikacji.
Typowe błędy i jak je naprawić
# Błąd: Duplicate entry 'X' for key 'PRIMARY' (Error 1062) # Przyczyna: wiersz już istnieje na replice (rozbieżność danych) # Rozwiązanie tymczasowe (pomiń jeden błąd): STOP REPLICA; SET GLOBAL sql_replica_skip_counter = 1; START REPLICA; -- Lepiej: reinicjalizuj replikację lub napraw dane ręcznie # Błąd: Access denied for user 'replika_user'@'10.0.0.11' # Sprawdź na masterze: SELECT user, host FROM mysql.user WHERE user = 'replika_user'; SHOW GRANTS FOR 'replika_user'@'10.0.0.11'; # Błąd: Slave_IO_Running: Connecting (nie Yes) # Sprawdź czy port 3306 jest dostępny z repliki: # mysql -h 10.0.0.10 -u replika_user -p (z serwera repliki) # Sprawdź firewall: ufw allow from 10.0.0.11 to any port 3306