Gdy czytasz pierwsze kroki z PostgreSQL, zobaczysz wiersz:„Serwer PostgreSQL może obsługiwać wiele jednoczesnych połączeń od klientów. Aby to osiągnąć, rozpoczyna („forks”) nowy proces dla każdego połączenia. Od tego momentu klient i nowy proces serwera komunikują się bez interwencji oryginalnego procesu postgres. W ten sposób proces serwera głównego zawsze działa, czekając na połączenia klienta, podczas gdy procesy klienta i powiązanego serwera przychodzą i odchodzą. ”
Genialny pomysł. A jednak oznacza to, że każde nowe połączenie uruchamia nowy proces, rezerwując pamięć RAM i prawdopodobnie stając się zbyt obciążone wieloma sesjami. Aby uniknąć problemów, postgres ma ustawienie max_connections z domyślnymi 100 połączeniami. Oczywiście możesz go zwiększyć, ale takie działanie wymagałoby ponownego uruchomienia (pg_settings.context to „postmaster”):
t=# select name,setting,short_desc,context from pg_settings where name = 'max_connections';
-[ RECORD 1 ]--------------------------------------------------
name | max_connections
setting | 100
short_desc | Sets the maximum number of concurrent connections.
context | postmaster
Kilka ekscytujących lektur Wykorzystanie PgBouncera Jaki jest sens odbijania? PgBouncer Changelog Posty zawierające „pgbouncer” w Stack Overflow Posty oznaczone jako „pgbouncer” w 2. kwadrancie A nawet po zwiększeniu - w pewnym momencie możesz potrzebować więcej połączeń (oczywiście pilnie jak zawsze na uruchomionym prod). Dlaczego zwiększanie go jest tak niewygodne? Ponieważ gdyby było to wygodne, prawdopodobnie skończyłoby się niekontrolowanym spontanicznym zwiększaniem liczby, dopóki klaster nie zacznie się opóźniać. Oznacza to, że stare połączenia są wolniejsze - więc zajmują więcej czasu, więc potrzebujesz jeszcze więcej i więcej nowych. Aby uniknąć takiej możliwej lawiny i dodać trochę elastyczności, mamy superuser_reserved_connections - aby móc połączyć się i naprawić problemy z SU, gdy wyczerpie się max_connections. I oczywiście widzimy potrzebę jakiegoś poolera połączeń. Ponieważ chcemy, aby nowi kandydaci na połączenie czekali w kolejce zamiast przegrywać, z wyjątkiem KRYTYCZNY:przepraszam, za dużo klientów już i nie ryzykując postmastera.
Pula połączeń jest na pewnym poziomie oferowana przez wielu popularnych „klientów”. Przez jakiś czas można go używać z jdbc. Ostatnio node-postgres zaoferował swoją własną pulę node-pg-pool. Implementacja jest mniej więcej prosta (jak w założeniu):pooler uruchamia połączenia do bazy danych i utrzymuje je. Klient łączący się z db otrzymuje tylko „współdzielone” istniejące połączenie i po jego zamknięciu połączenie wraca do puli. Mamy też dużo bardziej wyrafinowane oprogramowanie, takie jak pgPool. A jednak pgbouncer jest niezwykle popularnym wyborem do tego zadania. Czemu? Ponieważ wykonuje tylko część związaną z łączeniem, ale robi to dobrze. Jest wolne. Konfiguracja jest dość prosta. I spotykasz go u większości największych dostawców usług, zgodnie z zaleceniami lub używanymi, np. citusdata, aws, heroku i inne bardzo szanowane zasoby.
Przyjrzyjmy się więc bliżej, co może i jak z niego korzystasz. W mojej konfiguracji używam domyślnego pool_mode =transaction (sekcja [pgbouncer]), co jest bardzo popularnym wyborem. W ten sposób nie tylko kolejkujemy połączenia przekraczające max_connections, ale raczej ponownie wykorzystujemy sesje bez czekania na zamknięcie poprzedniego połączenia:
[databases]
mon = host=1.1.1.1 port=5432 dbname=mon
mons = host=1.1.1.1 port=5432 dbname=mon pool_mode = session pool_size=2 max_db_connections=2
monst = host=1.1.1.1 port=5432 dbname=mon pool_mode = statement
[pgbouncer]
listen_addr = 1.1.1.1
listen_port = 6432
unix_socket_dir = /tmp
auth_file = /pg/pgbouncer/bnc_users.txt
auth_type = hba
auth_hba_file = /pg/pgbouncer/bnc_hba.conf
admin_users = root vao
pool_mode = transaction
server_reset_query = RESET ALL; --DEALLOCATE ALL; /* custom */
ignore_startup_parameters = extra_float_digits
application_name_add_host = 1
max_client_conn = 10000
autodb_idle_timeout = 3600
default_pool_size = 100
max_db_connections = 100
max_user_connections = 100
#server_reset_query_always = 1 #uncomment if you want older global behaviour
Krótki przegląd najpopularniejszych ustawień oraz wskazówek i trików:
-
server_reset_query jest bardzo przydatny i ważny. W trybie łączenia sesji „czyści” „artefakty” poprzedniej sesji. W przeciwnym razie miałbyś problemy z takimi samymi nazwami przygotowanych instrukcji, ustawieniami sesji wpływającymi na kolejne sesje i tak dalej. Wartość domyślna to DISCARD ALL, która „resetuje” wszystkie stany sesji. Możesz jednak wybrać bardziej wyrafinowane wartości, np. RESETUJ WSZYSTKO; ZWOLNIJ PRZYDZIELENIE WSZYSTKICH; zapomnieć tylko o SET SESSION i przygotowanych zestawieniach, zachowując „wspólne” tabele i plany TEMP. Lub odwrotnie – możesz chcieć, aby przygotowane wypowiedzi były „globalne” z dowolnej sesji. Taka konfiguracja jest wykonalna, choć ryzykowna. Musisz sprawić, by pgbouncer ponownie wykorzystywał sesję dla wszystkich (co powoduje albo bardzo mały rozmiar puli, albo lawinowanie sesji), co nie jest całkowicie niezawodne. W każdym razie - to przydatna umiejętność. Zwłaszcza w konfiguracjach, w których chcesz, aby sesje klienta ostatecznie (nie natychmiast) zmieniły się na skonfigurowane ustawienia sesji w puli. Bardzo ważnym punktem jest tutaj tryb puli sesji. Przed 1.6 to ustawienie wpływało również na inne tryby puli, więc jeśli na nim polegałeś, musisz użyć nowego ustawienia server_reset_query_always =1. Prawdopodobnie w pewnym momencie ludzie będą chcieli, aby server_reset_query był jeszcze bardziej elastyczny i konfigurowalny dla pary db/użytkownika ( i zamiast tego client_reset_query). Ale w chwili obecnej, w marcu 2018 r., nie ma takiej opcji. Ideą, która spowodowała, że to ustawienie jest domyślnie ważne tylko w trybie sesji, było - jeśli udostępniasz połączenie na poziomie transakcji lub wyciągu - nie możesz w ogóle polegać na ustawieniu sesji.
-
Typ_uwierzytelnienia =hba. Przed wersją 1.7 dużym problemem z pgbouncer był brak uwierzytelniania opartego na hoście – „zapora ogniowa postgres”. Oczywiście nadal miałeś go dla połączenia klastra postgres, ale pgbouncer był „otwarty” dla dowolnego źródła. Teraz możemy użyć tego samego hba.conf, aby ograniczyć połączenia dla hosta/db/użytkownika w oparciu o sieć połączeń.
-
connect_query nie jest wykonywane przy każdym „połączeniu” klienta z pgbouncer, ale raczej, gdy pgbouncer łączy się z instancją Postgres. Dlatego nie można go używać do ustawiania lub zastępowania „domyślnych” ustawień. W trybie sesji inne sesje nie wpływają na siebie nawzajem, a po rozłączeniu zresetowane zapytanie odrzuca wszystkie - więc nie musisz się z tym bawić. W trybie puli transakcji możesz mieć nadzieję, że użyjesz go do ustawienia błędnie ustawionego przez inne sesje, ale niestety nie zadziała. Np. chcesz udostępniać przygotowany wyciąg między „sesjami” w trybie transakcyjnym, więc ustawiasz coś takiego
trns = dbname=mon pool_mode = transaction connect_query = 'do $$ begin raise warning $w$%$w$, $b$new connection$b$; end; $$; prepare s(int) as select $1;'
i rzeczywiście - każdy nowy klient widzi przygotowane instrukcje (chyba że zostawiłeś włączony server_reset_query_always, więc pgbouncer odrzuca go przy zatwierdzeniu). Ale jeśli jakiś klient uruchamia DISCARD s; w swojej sesji wpływa na wszystkich klientów tego połączenia, a nowi klienci łączący się z nim nie będą już widzieć przygotowanych wyciągów. Ale jeśli chcesz mieć jakieś początkowe ustawienie dla połączeń postgres pochodzących z pgbouncer, to jest to miejsce.
-
application_name_add_host został dodany w 1.6, ma podobne ograniczenie. „Umieszcza” adres IP klienta w nazwa_aplikacji, dzięki czemu można łatwo uzyskać złe źródło zapytania, ale łatwo go zastąpić przez proste ustawienie nazwa_aplikacji TO „to nie ja”; Mimo to możesz „wyleczyć” to za pomocą widoków - śledź ten post, aby uzyskać pomysł, a nawet skorzystaj z tych krótkich instrukcji. Zasadniczo pomysł polega na tym, aby pokazać klientom; pokaże adres IP klienta, więc możesz wysłać zapytanie bezpośrednio z bazy danych pgbouncer przy każdym wyborze z pg_stat_activity, aby sprawdzić, czy został zresetowany. Ale oczywiście korzystanie z prostego ustawienia jest znacznie prostsze i przytulniejsze. Chociaż nie gwarantuje to rezultatu...
-
pool_mode może być określony zarówno jako domyślny, dla bazy danych, jak i dla użytkownika - dzięki czemu jest bardzo elastyczny. Tryby miksowania sprawiają, że pgbouncer jest niezwykle skuteczny w tworzeniu puli. Jest to potężna funkcja, ale podczas korzystania z niej trzeba być ostrożnym. Często użytkownicy używają go bez zrozumienia wyników do absolutnie atomowych mieszanek na transakcję/na sesję/na użytkownika/na bazę danych/globalne ustawienia działające inaczej dla tego samego użytkownika lub bazy danych, ze względu na różne tryby puli z pgbouncer. To pudełko zapałek, którego nie dajesz dzieciom bez nadzoru. Również wiele innych opcji jest konfigurowalnych jako domyślne i na db i na użytkownika.
-
Nie bierz tego dosłownie, ale możesz „porównać” różne sekcje ini z SET i ALTER:SET LOCAL wpływa na transakcje i jest dobry do użycia, gdy poll_mode=transaction , SET SESSION wpływa na sesje i jest bezpieczny w użyciu, gdy poll_mode=session , ALTER USER SET wpływa na role i koliduje z częścią pgbouncer.ini sekcji [users], ALTER DATABASE SET wpływa na bazy danych i koliduje z częścią pgbouncer.ini sekcji [databases], ALTER SYSTEM SET lub edytowanie postgres.conf globalnie wpływa na ustawienia domyślne i jest porównywalny pod względem efektu z domyślną sekcją pgbouncer.ini.
-
Jeszcze raz - odpowiedzialnie korzystaj z trybu basenowego. Przygotowane zestawienia lub ustawienia całej sesji będą bałaganem w trybie pulowania transakcji. To samo, co transakcja SQL, nie ma sensu w trybie łączenia instrukcji. Wybierz odpowiedni tryb puli dla odpowiednich połączeń. Dobrą praktyką jest tworzenie ról z myślą, że:
- niektóre będą działać tylko z szybkimi wyborami, dzięki czemu mogą udostępniać jedną sesję bez transakcji dla setek równoczesnych, małych, nieistotnych wyborów.
- Niektórzy członkowie ról są bezpieczni dla współbieżności na poziomie sesji i ZAWSZE używają transakcji. Dzięki temu mogą bezpiecznie udostępniać kilka sesji dla setek jednoczesnych transakcji.
- Niektóre role są zbyt skomplikowane i skomplikowane, aby udostępniać swoją sesję innym. Dlatego używasz trybu łączenia sesji, aby uniknąć błędów podczas połączenia, gdy wszystkie „sloty” są już zajęte.
-
Nie używaj go zamiast HAProxy lub innego load balancera. Pomimo faktu, że pgbouncer ma kilka konfigurowalnych funkcji dotyczących tego, co adresuje load balancer, takich jak dns_max_ttl i możesz ustawić dla niego konfigurację DNS, większość środowisk prod używa HAProxy lub innego load balancera dla HA. Dzieje się tak, ponieważ HAProxy jest naprawdę dobry w równoważeniu obciążenia między serwerami na żywo w sposób okrężny, lepszy niż pgbouncer. Chociaż pgbouncer jest lepszy do puli połączeń postgres, może być lepiej użyć jednego małego demona, który doskonale wykonuje jedno zadanie, zamiast większego, który wykonuje dwa zadania, ale gorzej.
-
Zmiany konfiguracji mogą być trudne. Niektóre zmiany w pgbouncer.ini wymagają ponownego uruchomienia (listen_port itp.), podczas gdy inne, takie jak admin_users, wymagają ponownego załadowania lub SIGHUP. Zmiany w auth_hba_file wymagają ponownego załadowania, podczas gdy zmiany w auth_file nie.
Niezwykle krótki przegląd powyższych ustawień jest ograniczony formatem. Zapraszam do zapoznania się z pełną listą. Pgbouncer to rodzaj oprogramowania z bardzo małą ilością „nudnych ustawień” - wszystkie mają ogromny potencjał i są niezwykle interesujące.
Pobierz oficjalny dokument już dziś Zarządzanie i automatyzacja PostgreSQL za pomocą ClusterControlDowiedz się, co musisz wiedzieć, aby wdrażać, monitorować, zarządzać i skalować PostgreSQLPobierz oficjalny dokumentI wreszcie przejście od krótkiej entuzjastycznej recenzji do czegoś, z czego możesz być mniej zadowolony - instalacji. Proces jest jasno opisany w tej sekcji dokumentacji. Jedyną opisaną opcją jest budowanie ze źródeł git. Ale wszyscy wiedzą, że są paczki! Próbuję obu najbardziej popularnych:
sudo yum install pgbouncer
sudo apt-get install pgbouncer
może pracować. Ale czasami trzeba zrobić dodatkowy krok. Np. jeśli nie jest dostępny żaden pakiet pgbouncer, spróbuj tego.
Lub nawet:
sudo yum install pgbouncer
Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main | 2.1 kB 00:00:00
amzn-updates | 2.5 kB 00:00:00
docker-ce-edge | 2.9 kB 00:00:00
docker-ce-stable | 2.9 kB 00:00:00
docker-ce-test | 2.9 kB 00:00:00
pgdg10 | 4.1 kB 00:00:00
pgdg95 | 4.1 kB 00:00:00
pgdg96 | 4.1 kB 00:00:00
pglogical | 3.0 kB 00:00:00
sensu | 2.5 kB 00:00:00
(1/3): pgdg96/x86_64/primary_db | 183 kB 00:00:00
(2/3): pgdg10/primary_db | 151 kB 00:00:00
(3/3): pgdg95/x86_64/primary_db | 204 kB 00:00:00
50 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package pgbouncer.x86_64 0:1.8.1-1.rhel6 will be installed
--> Processing Dependency: libevent2 >= 2.0 for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Processing Dependency: c-ares for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Processing Dependency: libcares.so.2()(64bit) for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Running transaction check
---> Package c-ares.x86_64 0:1.13.0-1.5.amzn1 will be installed
---> Package pgbouncer.x86_64 0:1.8.1-1.rhel6 will be installed
--> Processing Dependency: libevent2 >= 2.0 for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Finished Dependency Resolution
Error: Package: pgbouncer-1.8.1-1.rhel6.x86_64 (pgdg10)
Requires: libevent2 >= 2.0
You could try using --skip-broken to work around the problem
You could try running: rpm -Va --nofiles --nodigest
Oczywiście dodanie pgdg do /etc/yum.repos.d/ już nie pomoże. Ani --skip-broken ani rpm -Va --nofiles --nodigest. Prosty
sudo yum install libevent2
Loaded plugins: priorities, update-motd, upgrade-helper
50 packages excluded due to repository priority protections
No package libevent2 available.
Error: Nothing to do
byłoby zbyt łatwe. Musisz więc sam zbudować libevent2, sprowadzając cię z powrotem do sytuacji, w której musisz sam kompilować. Albo jest to pgbouncer, albo jedna z jego zależności.
Ponownie - zbyt głębokie kopanie w szczegółach instalacji jest poza zakresem. Powinieneś wiedzieć, że masz dużą szansę na zainstalowanie go jako pakietu.
Wreszcie – w kółko pojawiają się pytania typu „dlaczego postgres nie oferuje natywnego narzędzia do puli sesji”. Pojawiają się nawet bardzo świeże sugestie i przemyślenia na ten temat. Ale jak dotąd najpopularniejszym podejściem jest użycie pgbouncera.