Zwykle zaczyna się od jednego serwera bazy. Działa latami i nikt o nim nie myśli. Aż pewnego dnia pada dysk albo zawiesza się kernel i okazuje się, ile kosztuje godzina, w której sklep czy aplikacja nie działa. Albo backup niby jest, tylko nikt nigdy nie próbował z niego wstać.
Bywa też odwrotnie: baza żyje, ale nie nadąża. Raporty, wyszukiwarka i analityka czytają te same tabele, do których pisze aplikacja, i wszystko zwalnia naraz.
Na oba problemy pomaga replikacja, czyli druga (i trzecia) kopia bazy, która na bieżąco dogania główną. Pod warunkiem, że wiadomo, co ona daje, a czego nie.
Co robimy
Do każdego projektu dobieramy najprostszy układ, który pokrywa realne ryzyko. Najczęściej jest to jeden z trzech.
PostgreSQL z automatycznym failoverem:
- trzy węzły PostgreSQL ze streaming replication: jeden primary przyjmuje zapis, dwie repliki odtwarzają jego WAL;
- Patroni na każdym węźle pilnuje lokalnego PostgreSQL i decyduje, kto jest liderem;
- etcd na tych samych trzech węzłach przechowuje jedną informację – „kto jest liderem” – i zapewnia kworum;
- HAProxy daje aplikacji dwa stałe adresy: do zapisu (zawsze na primary) i do odczytu (rozkłada ruch na repliki). W razie potrzeby dokładamy PgBouncer jako pulę połączeń.
MariaDB Galera:
- trzy węzły z replikacją synchroniczną, każdy technicznie przyjmuje zapis;
- zewnętrzny arbiter nie jest potrzebny – kworum jest wbudowane w Galerę;
- przed klastrem stoi ProxySQL. Rozumie SQL, więc sam wysyła
SELECTdo węzłów czytających, a zapis do jednego węzła piszącego. Aplikacja widzi jeden adres i nie musi nic wiedzieć o topologii.
Wariant prosty: jeden primary, jedna asynchroniczna replika i porządne backupy. Przełączenie robi się ręcznie według instrukcji. W wielu projektach to w zupełności wystarcza.
Węzły rozkładamy na różne serwery fizyczne, a całą konfigurację opisujemy w Ansible.
Jak to działa i gdzie są pułapki
Dlaczego trzy węzły, a nie dwa. Kworum to większość. Przy dwóch węzłach, gdy jeden padnie, większości nie ma i nikt nie może podjąć decyzji. Dwa węzły do automatycznego failoveru są gorsze niż jeden: więcej złożoności, zero korzyści. Trzy przeżyją awarię jednego, pięć – dwóch. Stąd zawsze liczba nieparzysta. Kworum chroni przed split-brain, czyli sytuacją, w której sieć się rozpadła i obie połowy uznały się za główne. Połowa bez większości po prostu odmawia przyjmowania zapisu.
Jak przełącza się PostgreSQL. Lider cały czas odświeża w etcd klucz „żyję”. Gdy padnie, klucz wygasa, a replika z najświeższymi danymi go przejmuje i staje się primary. HAProxy pyta Patroni, kto jest liderem, i przenosi ruch:
listen pg_write
bind *:5000
option httpchk GET /primary
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server db1 db1:5432 check port 8008
server db2 db2:5432 check port 8008
server db3 db3:5432 check port 8008
Od awarii do działania mija około 20–30 sekund, bez udziału człowieka. Stary primary po powrocie sam staje się repliką.
Cena synchroniczności. Replikacja asynchroniczna jest szybka, ale przy awarii można stracić ostatnie milisekundy transakcji. Galera ich nie traci, bo każdy COMMIT czeka na potwierdzenie klastra. Za to zapis jest wolniejszy, klaster pisze w tempie najwolniejszego węzła, a przez WAN Galery się nie rozciąga. Są też wymagania wobec schematu: tylko InnoDB i klucz główny w każdej tabeli. Tabela w MyISAM po cichu rozjeżdża węzły, bez żadnego błędu. Dlatego przed migracją sprawdzamy schemat.
Multi-master nie przyspiesza zapisu. Każdy węzeł Galery stosuje wszystkie zmiany klastra, więc trzy węzły nie piszą trzy razy szybciej. Lepiej pisać do jednego węzła – równoległe zmiany tych samych wierszy na różnych węzłach kończą się deadlockiem dopiero przy COMMIT.
Odczyt z replik ma haczyk. Zapis poszedł na węzeł piszący, a kolejny odczyt na replikę, która jeszcze nie zdążyła. W Galerze bez obciążenia tego nie widać, pod obciążeniem część odczytów po cichu zwraca stare dane. Dlatego wsrep_sync_wait włączamy, zanim włączymy rozdzielanie odczytu i zapisu. W PostgreSQL odczyty, które muszą widzieć świeżo zapisane dane, zostawiamy na primary.
Replikacja to nie backup
Trzeba to powiedzieć wprost. Usunięta tabela w ułamku sekundy znika też na wszystkich replikach. Ransomware, błąd w migracji, UPDATE bez WHERE – replikacja wszystko to sumiennie skopiuje.
Dlatego backupy robimy zawsze, niezależnie od klastra:
- PostgreSQL – pgBackRest: kopie pełne i przyrostowe plus archiwum WAL. To daje PITR, czyli odtworzenie bazy na konkretną minutę, np. na 14:32, tuż przed awarią;
- MariaDB – mariabackup plus binlog do takiego samego odtwarzania na punkt w czasie;
- backup robimy z repliki, żeby nie obciążać primary;
- kopie trzymamy na osobnym storage’u, nie na tych samych serwerach;
- regularnie testujemy odtwarzanie: stawiamy kopię na osobnej maszynie i sprawdzamy dane. Backup, z którego nikt nigdy nie odtwarzał, to tylko nadzieja.
Monitoring na Prometheusie i Grafanie śledzi opóźnienie replikacji, stan klastra (ile węzłów w kworum, kto jest liderem) i wiek ostatniego backupu. Alert przychodzi, gdy replika zostaje w tyle, węzeł wypada albo backup nie wykonał się na czas.
Kiedy klaster nie jest potrzebny
Klaster jest bardziej złożony niż jeden serwer: więcej węzłów, więcej ruchomych części, własne pułapki przy aktualizacjach. Jeśli godzina przestoju was nie zabija, uczciwie doradzimy jeden primary, asynchroniczną replikę i dobre backupy z PITR. A jeśli baza nie nadąża z zapisem, najpierw patrzymy na indeksy, zapytania i sprzęt. Replikacja skaluje odczyty, nie zapis.
Co dostajecie
- Działający klaster PostgreSQL lub MariaDB (albo prostszy układ, jeśli wystarczy) z jednym punktem połączenia dla aplikacji.
- Automatyczne przełączanie przy awarii węzła, sprawdzone przez wyłączanie węzłów, a nie tylko na papierze.
- Backupy z PITR na osobnym storage’u i regularne testy odtwarzania.
- Dashboardy i alerty: opóźnienie replikacji, stan kworum, wiek backupu.
- Role Ansible i konfiguracje w waszym repozytorium.
- Dokumentację: schemat, jak sprawdzić stan, jak ręcznie przełączyć primary, jak odtworzyć dane z backupu.
- Pełne dostępy do wszystkiego, co wdrożyliśmy.
Napiszcie, jaką macie bazę, ile danych i co boli: przestoje, wolne zapytania czy niepewność co do backupów. Podpowiemy, jaki układ jest wam naprawdę potrzebny.