DEV Community

Andrzej Klusiewicz
Andrzej Klusiewicz

Posted on

Konfiguracja pgBouncer krok po kroku - pooler polaczen dla PostgreSQL

Zle skonfigurowany pgBouncer potrafi zamienic zalete poolingu polaczen w zrodlo dziwnych bledow aplikacji - pokazujemy jak ustawic go poprawnie od zera.

pgBouncer, w skrócie

Przykładowy pgbouncer.ini:

[databases]
sklep = host=127.0.0.1 port=5432 dbname=sklep

[pgbouncer]
listen_port = 6432
pool_mode = transaction
max_client_conn = 1000
Enter fullscreen mode Exit fullscreen mode

Z tego artykułu dowiesz się:

  • w jaki sposób konfigurować liczbę połączeń do PostgreSQL wykorzystywaną przez pgBouncer,- w jaki sposób konfigurować rodzaj autoryzacji pgBouncera do serwera PostgreSQL,- w jaki sposób podpiąć pgBouncer do instancji PostgreSQL,- w jaki sposób porównać wydajność połączeń bezpośrednich do PostgreSQL i za pośrednictwem pgBouncera.

PgBouncer umożliwia stworzenie puli połączeń określonej "min_pool_size", które zostaną nawiązane do klastra postgresa "na stałe", z możliwością powiększenia kontrolowanego do "default_pool_size" / "pool_size" jeżeli zajdzie taka potrzeba i zamykania połączeń nieaktywnych przez "server_idle_timeout" do limitu "min_pool_size". A w sytuacjach awaryjnych, jeżeli w kolejce będą znajdowały się połączenia, które nie zostały obsłużone przez "reserve_pool_timeout", otworzy zapasowe połączenia, do maksymalnie "reserve_pool_size". Dzięki temu, że w pgBouncer połączenia nawiązane są tylko raz, a następnie mogą być wielokrotnie ponownie wykorzystane przez różnych klientów. Unikamy potrzeby ciągłego nawiązywania nowych połączeń, co jest dość kosztowną operacją.

Ponadto, pozwala na stworzenie kolejki dla połączeń przychodzących do pgbouncera "max_client_conn", które będą obsługiwane po kolei przez połączenia z puli.

Mamy dostępne trzy tryby pracy, "pool_mode":

  • session - ustawienie domyślne, połączenie jest zwracane do puli po zakończeniu sesji. W tym trybie możemy uniknąć kosztu nawiązania nowego połączenia do klastra, ponieważ pgBouncer stale je utrzymuje i przekazuje kolejnym połączeniom w kolejce,
  • transaction - połączenie wraca do puli po zakończeniu transakcji commitem lub rollbackiem. Najbardziej użyteczny tryb, dzięki niemu jedno połączenie z puli może obsłużyć wiele różnych klientów, dzięki czemu postgres jest w stanie obsłużyć znacznie większą liczbę klientów niż limit w max_connections,
  • statement - połączenie obsługuje pojedyncze zapytania SQL, po czym zwraca sesję do puli. Najwydajniejsza opcja pozwalająca osiągnąć najlepsze wyniki, jeżeli chodzi o wydajność, ale kosztem ograniczenia zapytań w transakcji do jednego.

pgbouncer wymaga uwierzytelniania podczas ustanawiania połączenia. - Sposób uwierzytelniania ustawiamy parametrem "auth_type", obsługiwane opcje to:

  • cert - połączenie musi być nawiązane z wykorzystaniem TLS, a klient musi okazać ważny certyfikat. Nazwa użytkownika jest pobierana z wartości CommonName z certyfikatu.,
  • md5 - hash md5 dla użytkowników korzystających z tego algorytmu,
  • scram-sha-256 - analogicznie dla algorytmu kryptującego scram-sha-256,
  • plain - zapisanie hasła "czystym" tekstem, bez żadnych dodatkowych zabezpieczeń,
  • trust - bez uwierzytelniania, każdy użytkownik wypisany w pliku "userlist.txt" może się połączyć,
  • any - również bez uwierzytelniania, zadana nazwa użytkownika jest ignorowana, a pgbouncer korzysta z użytkownika podanego w definicji połączenia w pgbouncer.ini,
  • hba - podobnie jak w przypadku pg_hba.conf, pgbouncer sprawdza w pliku auth_hba_file, który użytkownik może się zalogować oraz z jakim typem uwierzytelniania, metoda ta pozwala na zdefiniowanie różnych typów uwierzytelniania,
  • pam - uwierzytelnianie po stronie linuxa, auth_file jest ignorowany w tej metodzie oraz nie można jej ustawić w trybie hba.

[Host 4: pgbouncer]

Przykład prostej konfiguracji. W miejsce host=pg1 podajmy naszego aktualnego lidera patroni. W tym pliku będą już sekcje "[databases]" i "[pgbouncer]". Trzeba je wykomentować przed wklejeniem poniższego lub stworzyć ten plik na nowo.

# /etc/pgbouncer/pgbouncer.ini

[databases]

postgres = host=pg1 port=5432 dbname=postgres min_pool_size=10 pool_size=20

* = host=pg1 port=5432 pool_size=20

[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 = 1000

reserve_pool_size = 5

reserve_pool_timeout = 5

server_idle_timeout = 60

max_db_connections = 100

auth_type = md5

auth_file = /etc/pgbouncer/userlist.txt

admin_users = postgres
Enter fullscreen mode Exit fullscreen mode

Do pliku userlist.txt kopiujemy hash md5 hasła dla użytkownika, który powinien móc się połączyć z postgresem. Możemy go znaleźć w widoku pg_shadow na dowolnym z hostów Patroni:

postgres=# \x

Expanded display is on.

postgres=# select * from pg_shadow ;

-[ RECORD 1 ]+------------------------------------

usename        | postgres

usesysid      | 10

usecreatedb - | t

usesuper      | t

userepl        | t

usebypassrls | t

passwd        | md5a9f68b14e99c2c1fc6b28e1291488e53

valuntil      |

useconfig     |
Enter fullscreen mode Exit fullscreen mode

Wartości z kolumn usename oraz passwd przenosimy do pliku /etc/pgbouncer/userlist.txt na hoście 4 - czyli tam, gdzie pgbouncer. Jeżeli plik nie istnieje, należy go stworzyć:

sudo vi /etc/pgbouncer/userlist.txt

"postgres" "md5a9f68b14e99c2c1fc6b28e1291488e53"
Enter fullscreen mode Exit fullscreen mode

Uruchamiamy pgbouncer za pomocą usługi pgbouncer.service:

sudo systemctl start pgbouncer
Enter fullscreen mode Exit fullscreen mode

Przetestujmy teraz, jaką wydajność możemy osiągnąć dla tego samego klastra za pomocą pgbench.

[Host 1,2,3,4: wszystkie serwery patroni i pgbouncer]

Przed testem wykonajmy inicjalizację danych pgbench na serwerze lidera patroni.

Dla poprawnego działania pgbench musimy zainstalować jako użytkownik systemowy z uprawnieniami do sudo na wszystkich serwerach patroni i hoscie pgbouncer:

sudo apt install postgresql-client-15 postgresql-15
Enter fullscreen mode Exit fullscreen mode

[Host 1,2 lub 3: aktualny lider klastra patroni]

Następnie inicjalizujemy bazę z przykładowymi danymi (z poziomu użytkownika systemowego postgres):

pgbench -i -s 10
Enter fullscreen mode Exit fullscreen mode

[Host 4: pgbouncer]

Gdyby podczas poniższych testów Postgresql pytał nas o hasło, podajemy to, które skonfigurowaliśmy w sekcji "authentication" w pliku - /etc/patroni/config.yml - dowolnego z serwerów klastra Patroni, a najlepiej z serwera, który uruchomiliśmy jako pierwszy i który zainicjował klaster. Jeśli mamy za sobą nasz rozdział o Patroni, to tam ustawialiśmy hasło na "haslo_postgres".

  1. Test za pomocą pgbench łącząc się bezpośrednio do postgresa. Wykorzystane parametry to:
    • h - adres serwera,
    • p - port, na którym działa postgres,
    • S - test za pomocą samych zapytań SELECT,
    • c - liczba nawiązanych połączeń,
    • P - interwał, w jakim będzie wyświetlany "progress", informacje o liczbie transakcji na sekundę oraz średnie opóźnienie,
    • T - czas trwania testu,
    • C - każda transakcja będzie otwierała nowe połączenie.
   postgres@ubuntu:~$ pgbench -h <nazwa_hosta_lidera_patroni> -p 5432 -S -c 80 -P 5 -T 30 -C

   pgbench (15.3 (Ubuntu 15.3-1.pgdg22.04+1))

   starting vacuum...end.

   progress: 5.0 s, 257.0 tps, lat 288.754 ms stddev 174.237

   progress: 10.0 s, 255.8 tps, lat 308.288 ms stddev 183.066

   progress: 15.0 s, 252.1 tps, lat 307.900 ms stddev 212.583

   progress: 20.0 s, 306.1 tps, lat 255.459 ms stddev 148.380

   progress: 25.0 s, 259.8 tps, lat 300.960 ms stddev 179.012

   progress: 30.0 s, 257.8 tps, lat 307.302 ms stddev 159.319

   transaction type: <builtin: select only>

   scaling factor: 1000

   query mode: simple

   number of clients: 80

   number of threads: 1

   duration: 30 s

   number of transactions actually processed: 8023

   latency average = 293.352 ms

   latency stddev = 176.923 ms

   average connection time = 3.650 ms

   tps = 265.967665 (including reconnection times)
Enter fullscreen mode Exit fullscreen mode
  1. Połączenia przez pgbouncera, tutaj pomijamy parametr "-h" dlatego, że łączymy się lokalnie. Jako hasło podajemy hasło użytkownika postgres w bazie danych (to z configa Patroni). Nie przejmujemy się, że łączymy się w tym przypadku lokalnie, nie działa to na korzyść Pgbouncera, ponieważ ten i tak dystrybuuje połączenia do serwerów po sieci.
   postgres@ubuntu:~$ pgbench -p 6432 -S -c 80 -P 5 -T 30 -C

   pgbench (15.3 (Ubuntu 15.3-1.pgdg22.04+1))

   starting vacuum...end.

   progress: 5.0 s, 3692.3 tps, lat 10.438 ms stddev 12.292

   progress: 10.0 s, 3609.6 tps, lat 10.520 ms stddev 6.427

   progress: 15.0 s, 4323.0 tps, lat 9.355 ms stddev 5.307

   progress: 20.0 s, 3041.1 tps, lat 12.704 ms stddev 8.346

   progress: 25.0 s, 2347.5 tps, lat 16.138 ms stddev 9.176

   progress: 30.0 s, 3262.3 tps, lat 11.846 ms stddev 6.609

   transaction type: <builtin: select only>

   scaling factor: 1000

   query mode: simple

   number of clients: 80

   number of threads: 1

   duration: 30 s

   number of transactions actually processed: 101414

   latency average = 11.446 ms

   latency stddev = 8.498 ms

   average connection time = 0.280 ms

   tps = 3379.950548 (including reconnection times)
Enter fullscreen mode Exit fullscreen mode

Łącząc się przez pgbouncera, otrzymaliśmy dwunastokrotnie większą liczbę transakcji na sekundę, pomimo wykorzystania puli tylko 20 połączeń, które obsługiwały 80 połączeń przychodzących z pgbench.

Top comments (0)