Sama replikacja PostgreSQL nie daje jeszcze wysokiej dostepnosci dla aplikacji - dopiero polaczenie HAProxy i pgBouncera pozwala przelaczac ruch bez zmiany connection stringa.
Z tego artykułu dowiesz się:
- czym jest load balancing i w jakim celu się go stosuje,- czym jest HAProxy i w jakim celu się go stosuje,- jak działa load balancing z użyciem HAProxy,- jak skonfigurować HAProxy do współpracy z wieloma serwerami - w tym z klastrem Patroni,- jak testować działanie HAProxy,- jak podłączyć pgBouncer do HAProxy,- jak zrealizować load balancing i HA z pomocą HAProxy i pgBouncera.
HAProxy to popularne bezpłatne oprogramowanie z otwartym źródłem umożliwiające load balancing, czyli automagiczne dystrybuowanie zapytań w grupie serwerów, - przez co obniżamy obciążenie na pojedynczych serwerach, a często też przyspieszamy obsługę zapytań. Dzięki możliwości monitorowania dostępności oraz roli serwerów PostgreSQL, pozwala automatycznie rozdystrybuować połączenia wykonujące sam odczyt na wiele replik. Potrafi także sprawdzać ich status i natychmiast reagować na sytuacje, kiedy serwer lidera był awaryjnie przełączony, natychmiast przekierowując cały ruch na nowy serwer primary.
HAProxy również bardzo dobrze współpracuje z Patroni, między innymi pozwala na wykluczenie repliki z load balancingu poprzez ustawienie jej tagu "noloadbalance" w konfiguracji patroni oraz automatyczne śledzenie lidera po "failoverze/switchoverze".
W połączeniu z pgBouncerem i Patroni możemy stworzyć wysoce dostępny klaster, który bez problemu spełnia wymagania czterech czwórek w dostępności (SLA czyli dostepnosc serwera przez 99,99% czasu czyli 52 minuty w roku może nie banglać), a możemy osiągnąć ich jeszcze kilka. Po automatycznym failoverze haproxy w sam poszuka , na którym serwerze jest nowy lider Patroni, a dzięki połączeniu z pgbouncerem połączone aplikacje nie stracą połączenia i będą kontynuowały pracę na nowej instancji primary. Jedyne utracone transakcje to te, które były zacommitowane podczas failovera.
Znając możliwości API Patroni, skonfigurujemy HAProxy dla serwera mastera oraz zmienimy konfigurację pgBouncera, aby łączył się do patroni przez haproxy.
Najpierw kopiujemy plik konfiguracyjny z domyślną konfiguracją, a następnie tworzymy nowy plik configa haproxy. Dzięki temu nie musimy wykomentowywać wielu linii.
# serwer pgbouncer
sudo mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg_old
sudo vi /etc/haproxy/haproxy.cfg
global
maxconn 300
defaults
log global
mode tcp
retries 2
timeout client 30m
timeout connect 4s
timeout server 30m
timeout check 5s
listen stats
mode http
bind *:7000
stats enable
stats uri /
listen primary
bind *:5000
option httpchk OPTIONS /master
http-check expect status 200
default-server inter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server pg1 pg1:5432 maxconn 100 check port 8008
server pg2 pg2:5432 maxconn 100 check port 8008
server pg3 pg3:5432 maxconn 100 check port 8008
listen replica
bind *:5001
option httpchk OPTIONS /replica
http-check expect status 200
balance roundrobin
default-server inter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server pg1 pg1:5432 maxconn 100 check port 8008
server pg2 pg2:5432 maxconn 100 check port 8008
server pg3 pg3:5432 maxconn 100 check port 8008
Sekcja GLOBAL parametry ustawiane na poziomie całego HAProxy oddziałujące na całość procesu, wszystkie listenery, itp.
- maxconn - globalny limit połączeń do haproxy, do wszystkich frontendów, backendów i listenerów (połączenie frontend + backend)
Sekcja DEFAULTS zawiera domyślne ustawienia dla wszystkich zdefiniowanych backendów, frontendów czy listenerów.
- mode tcp - tryb pracy http lub tcp, w naszym przypadku wszystkie listenery dla pgbouncera będą korzystały z trybu tcp, dlatego warto go dodać tutaj, żeby później się nie powtarzać
- retries 2 - liczba - powtórnych prób połączenia po błędzie
- timeout client 30m - maksymalny czas bezczynności dla klienta przed automatycznym rozłączeniem, czas w milisekundach, chyba że podamy jednostkę (m - minuty, s - sekundy)
- timeout connect 4s - maksymalny czas na nawiązanie połączenia
- timeout server - maksymalny czas oczekiwania na odpowiedź serwera, po przekroczeniu połączenie zostanie rozłączone
- timeout check - timeout dla healthchecka
Sekcje z definicją listenerów LISTEN
- bind - konfiguracja, na których interfejsach sieciowych i na jakim porcie dany listener ma nasłuchiwać
- stats enable - włączenie zbierania statystyk
- stats uri / - konfiguracja adresu, pod jakim dostępne są statystyki
- option httpchk OPTIONS /master - sprawdzenie odpowiedzi na zapytanie http /master lub /replica na porcie "check port" z definicji serwera, podobnie do "curl -s -o /dev/null -w "%{http_code}" http://pg2:8008/master"
- http-check expect status 200 - spodziewana odpowiedź z serwera na zapytanie http
- default-server - domyślne parametry dla serwerów
- inter 1s - interwał pomiędzy healthcheckiem
- fall 3 - liczba nieudanych healthchecków, po których serwer zostanie uznany za niedostępny
- rise 2 - liczba udanych healthchecków, - po których serwer zostanie uznany za ponownie dostępny
- on-marked-down shutdown-sessions - jeżeli serwer zostanie uznany za niedostępny, zamknie wszystkie aktywne sesje
- server pg1 pg1:5432 maxconn 100 check port 8008 - definicja serwera, wartości kolejno to: nazwa, adres serwera i port, maksymalna liczba połączeń, port dla http checka
- balance roundrobin - rozłożenie połączeń naprzemiennie pomiędzy dostępnymi serwerami
Konfiguracja zawarta w sekcji "listen primary" oraz "listen replica" sprawia, że haproxy odpytuje serwery pg1, pg2 i pg3 na porcie 8008, na którym nasłuchuje RestAPI Patroni. Wywołując zapytania z odpowiednio /master oraz /replica, sprawdza, który z serwerów odpowiada kodem 200, oznacza to, że serwer ten pełni odpytywaną rolę i haproxy połączy się do nich, kiedy otrzyma połączenie na porcie 5000 dla mastera/primary oraz na porcie 5001 dla replik.
Następnym krokiem będzie restart usługi haproxy oraz test połączenia
sudo systemctl restart haproxy
psql -h pgbouncer -p 5000 -U postgres -c "select pg_is_in_recovery()"
pg_is_in_recovery
-------------------
f
(1 row)
psql -h pgbouncer -p 5001 -U postgres -c "select pg_is_in_recovery()"
pg_is_in_recovery
-------------------
t
(1 row)
Spróbujmy jeszcze wykonać switchover i sprawdźmy, czy haproxy połączy nas do nowej instancji primary.
# Na dowolnym serwerze patroni
patronictl -c /etc/patroni/config.yml switchover szkolenie
# Na serwerze z pgbouncerem i haproxy
psql -h pgbouncer -p 5000 -U postgres -c "select pg_is_in_recovery()"
Teraz możemy zmodyfikować konfigurację pgbouncera, aby ten łączył się z postgresem przez haproxy. Najważniejszą zmianą jest przepisanie sekcji [databases], gdzie ustawiamy dwa aliasy, z których będziemy korzystać, łącząc się do bazy:
- master - przekierowujący połączenie z pgbouncera do haproxy na port 5000, który z kolei przekieruje nas na aktualny serwer primary/leadera patroni,
- replica przekierowujący połączenie z pgbouncera na haproxy na port 5001, który dalej połączy nas z jedną z dostępnych replik.
# serwer pgbouncer
sudo vi /etc/pgbouncer/pgbouncer.ini
[databases]
master = host=pgbouncer port=5000 dbname=postgres pool_size=90
replica = host=pgbouncer port=5001 dbname=postgres pool_size=90
[pgbouncer]
logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid
unix_socket_dir = /var/run/postgresql
listen_addr = *
listen_port = 6432
pool_mode = transaction
max_client_conn = 10000
max_db_connections = 250
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
admin_users = postgres
Sprawdźmy teraz połączenie oraz wykonajmy testowo switchover.
# z serwera z pgbouncerem
psql -h pgbouncer -p 6432 -U postgres master
master=# select pg_is_in_recovery(),now(),inet_server_addr();
pg_is_in_recovery | now | inet_server_addr
-------------------+-------------------------------+------------------
f | 2022-11-29 21:28:40.225751+00 | 192.168.56.12
(1 row)
master=# \watch 1
# na serwerze z patroni
patronictl -c /etc/patroni/config.yml switchover szkolenie
Tue Nov 29 21:29:12 2022 (every 1s)
pg_is_in_recovery | now | inet_server_addr
-------------------+-------------------------------+------------------
f | 2022-11-29 21:29:12.452795+00 | 192.168.56.12
(1 row)
Tue Nov 29 21:29:13 2022 (every 1s)
pg_is_in_recovery | now | inet_server_addr
-------------------+-------------------------------+------------------
f | 2022-11-29 21:29:28.536762+00 | 192.168.56.11
Całkowita przerwa w działaniu aplikacji wyniosła ok 16 sekund. Połączenie pozostało aktywne i mogło kontynuować pracę po wykonaniu failovera. Musiało jedynie poczekać, aż haproxy znajdzie nową instancję primary.

Top comments (0)