W tym artykule porównano architekturę trzech puli: język, tryby puli, model z jedną lub wieloma dzierżawcami, funkcje wykraczające poza czystą pulę. Tembo i PkgPulse opublikowały porównania numeryczne tych trzech narzędzi, ale sami nie odtworzyliśmy żadnego z ich pomiarów. Nasze stanowisko redakcyjne dotyczące wskaźników referencyjnych, szczegółowo opisane w naszej metodologii testów porównawczych , polega na tym, aby nigdy nie publikować ponownie danych, których sami nie zweryfikowaliśmy. Co zamiast tego znajdziesz tutaj: rzeczywistą architekturę każdego narzędzia i sposób, w jaki Aurabase faktycznie kieruje ruchem Postgres, zweryfikowane sekcja po sekcji w kodzie źródłowym.
- PgBouncer (C) pozostaje najbardziej sprawdzonym narzędziem typu Pooler i najlepiej zintegrowanym z Kubernetesem: CloudNativePG bezpośrednio na nim polega w zakresie swoich zasobów
Pooler. - Supavisor (Elixir, projekt Supabase) ma na celu inny problem: obsługę tysięcy baz danych z tej samej usługi, a nie jednego Poolera na bazę danych.
- PgCat (Rust) dodaje sharding aplikacji, równoważenie obciążenia pomiędzy replikami i automatyczne przełączanie awaryjne do surowego łączenia zasobów.
- Repozytorium Aurabase pokazuje, że PgBouncer jest używany na dwóch poziomach: współdzielone wdrożenie dla współdzielonej floty oraz zasób
Poolerzarządzany przez CloudNativePG dla każdego dedykowanego dzierżawcy. Obydwa działają w trybie transakcyjnym. - PostgREST i pula administracyjna
aura-dbdobrowolnie pozostają w bezpośrednim połączeniu z Postgres, bez przechodzenia przez moduł puli: gromadzenie transakcji zerwałoby przeładowanie ich schematu i blokady sesji.
Trzej bilardziści, trzy filozofie
PgBouncer minimalizuje, Supavisor pule w skali wielu dzierżawców, PgCat dodaje funkcje sieciowe do surowego puli. Żaden z trzech nie zastępuje bezpośrednio pozostałych dwóch, chociaż często porównuje się je termin po terminie na tych samych stronach.
| Język | C | Eliksir (BEAM) | Rdza |
|---|---|---|---|
| Tryby łączenia | Sesja, transakcja, wyciąg | Sesja, transakcja | Sesja, transakcja, wyciąg |
| Model najmu | Jeden klaster docelowy na instancję, zaprojektowany z myślą o pojedynczej dzierżawie | Natywny multi-tenant: usługa dla wielu baz danych | Klaster docelowy, fragmentowanie według klucza partycji |
| Poza łączeniem | Żadnych dodatkowych funkcji, celowo minimalne | Admin HTTP API, dynamiczna rejestracja najemcy | Sharding, równoważenie obciążenia i przełączanie awaryjne pomiędzy replikami |
| Natywna integracja Kubernetes | Tak: Pula zasobów CloudNativePG | Do tej pory nie zostało to natywnie udokumentowane | Do tej pory nie zostało to natywnie udokumentowane |
| Pochodzenie | Historyczny standard łączenia Postgres | Zbudowany przez Supabase dla własnej chmury dla wielu dzierżawców | Urodzony w Instacart, prowadzony dziś przez PostgresML |
Kolumny w kolejności: PgBouncer, Supavisor, PgCat. Charakterystyka architektury zgodna z oficjalnymi zgłoszeniami każdego projektu, którą należy potwierdzić w wdrażanej wersji, ekosystem szybko ewoluuje pod tym względem.
Historyczny standard, lekki i zintegrowany z Kubernetesem
PgBouncer robi tylko jedno: łączy połączenia Postgres, bez żadnych dodatkowych funkcji. Ten celowo wąski zakres w dużej mierze wyjaśnia jego długowieczność i przyjęcie go jako podstawowego elementu składowego większości produkcyjnych stosów Postgres.
Dostępne są trzy tryby łączenia. Tryb sesji otwiera jedno połączenie serwera na każde połączenie klienta, najbardziej liberalne. Tryb transakcyjny ponownie wykorzystuje połączenie serwerowe pomiędzy kilkoma klientami, zwalniane na każdym końcu transakcji. Tryb instrukcji idzie jeszcze dalej i jest rzadko używany w produkcji. To właśnie tryb transakcyjny przynosi realny zysk z puli, ale narzuca rygorystyczne zasady. Dowolny stan sesji (zmienneSET, blokady doradcze, LISTEN/NOTIFY) nie przetrwa transakcji. Szczegółowo opisujemy te zasady i związane z nimi pułapki w naszym dedykowanym artykule na temat trybu łączenia transakcji w PgBouncer.
Historycznie jednoprocesowa instancja PgBouncer domyślnie używa jednego rdzenia procesora. Uruchamianie wielu instancji za tym samym portem (za pośrednictwem SO_REUSEPORT) jest nowszą ewolucją projektu, a nie początkową funkcją projektową. Po stronie uwierzytelniania PgBouncer obsługuje konfigurowalną auth_query, funkcję SQL wykonywaną przy każdym połączeniu w celu dynamicznego rozpoznawania hasła roli. Mechanizm ten pozwala uniknąć uzależnienia od statycznego pliku zawierającego listę każdego użytkownika z wyprzedzeniem. To właśnie ten mechanizm wykorzystuje Aurabase do swoich ról w projekcie (sekcja 05).
PgBouncer to moduł puli, który CloudNativePG natywnie wdraża za swoim zasobem Pooler. Na klastrze Postgres zarządzanym przez operatora CloudNativePG aktywacja zarządzanego Poolera sprowadza się w praktyce do aktywacji PgBouncera bez jego ręcznej konfiguracji.
Natywny w chmurze moduł pulowy dla wielu dzierżawców Supabase
Supavisor rozwiązuje problem, do rozwiązania którego PgBouncer nigdy nie został zaprojektowany na taką skalę. Wiąże się to z obsługą bardzo dużej liczby odrębnych baz danych dzierżawców w ramach pojedynczej usługi, a nie jednej instancji puli na bazę danych. Napisany w Elixir i wykonany na wirtualnej maszynie Erlang (BEAM), projekt jest rozwijany i utrzymywany przez Supabase, w otwartym kodzie źródłowym, we własnym repozytorium GitHub.
Natywny model z wieloma najemcami stanowi prawdziwą różnicę strukturalną. Tam, gdzie klasyczna flota PgBouncera wymaga jednego procesu (lub zestawu dedykowanych połączeń) na bazę docelową, Supavisor działa inaczej. Dynamicznie rejestruje najemców za pośrednictwem interfejsu administracyjnego HTTP i kieruje każde połączenie przychodzące do właściwej bazy danych bez ponownego uruchamiania usługi. Właśnie z tego powodu Supabase przeprowadziła migrację własnych projektów chmurowych z PgBouncer do Supavisor. Klasyczny klaster puli, po jednym na bazę danych, nie jest skalowalny do chmury z wieloma dzierżawcami, w której znajdują się setki tysięcy projektów.
Ten wybór architektoniczny ma udokumentowaną wadę. Stabilizacja funkcji z PgBouncerem w zaawansowanych przypadkach wymagała czasu po uruchomieniu projektu. Dwa przykłady: pewne zachowania LISTEN/NOTIFYi dokładne zarządzanie przygotowanymi wyciągami w trybie transakcyjnym. Sprawdź swoją wersję przed migracją, jeśli Twoja aplikacja zależy od tych konkretnych zachowań.
Outsider Rusta: natywny sharding i równoważenie obciążenia
PgCat jest wyraźnie pozycjonowany jako alternatywa dla PgBouncera, napisanego w Rust. Dodaje funkcje sieciowe do klasycznego łączenia zasobów, których natywnie nie osadza ani PgBouncer, ani Supavisor. W szczególności trzy: dzielenie aplikacji według klucza partycji, równoważenie obciążenia między replikami odczytu i automatyczne przełączanie awaryjne w przypadku uszkodzonej repliki. Projekt narodził się w Instacart, a dziś został przejęty i utrzymywany przez PostgresML.
Konkretnie, PgCat może odgrywać rolę, jaką normalnie pełniłyby dwie odrębne warstwy: moduł puli połączeń i serwer proxy aplikacji do routingu pomiędzy kilkoma instancjami Postgres. Zespół, który już ręcznie shardował swoje dane, może uprościć swój kod za pomocą PgCat. To samo dotyczy logiki dystrybucji odczytów pomiędzy opracowanymi wewnętrznie replikami: dedykowana warstwa sieciowa bezpośrednio ją zastępuje.
Istnieje również odwrotny kompromis: PgCat jest młodszym projektem, ze znacznie mniejszym ekosystemem dokumentacji i informacji zwrotnych z produkcji niż PgBouncer. Przyjęcie funkcji fragmentowania i przełączania awaryjnego oznacza także zgodę na uzależnienie od dojrzałości tego konkretnego komponentu, a nie tylko od jego możliwości łączenia.
Co pokazuje kod Aurabase: PgBouncer wszędzie, z wyjątkiem sytuacji, gdy łączenie transakcji psuje wszystko
Repozytorium Aurabase wdraża PgBouncer na dwóch oddzielnych poziomach, oba w trybie transakcyjnym. W przypadku współdzielonej floty wykres Helm definiuje dedykowane wdrożenie PgBouncera przed współdzieloną płaszczyzną danych (deploy/helm/aurabase/templates/infra/pgbouncer.yaml, obraz edoburu/pgbouncer). Dla dzierżawy w dedykowanej instancji dostawca generuje zasób Pooler zarządzany natywnie przez CloudNativePG (deploy/cnpg/tenant-pooler.yaml, renderowany przez k8s_tenant.rs). Ani nie używa Supavisora, ani PgCata. Kod nie dokumentuje wyraźnego porównania poprzedzającego ten wybór. Z drugiej strony wykazuje głęboką i już operacyjną integrację z ekosystemem CloudNativePG, co jest spójne z faktem, że PgBouncer jest natywną cegiełką do Poolingu.
Jednak nie wszystko przechodzi przez Pooler i jest to celowy wybór udokumentowany w samym kodzie. PostgREST pozostaje połączony na żywo z Postgres, nigdy za pośrednictwem PgBouncer. Komentarz do wykresu Helma jasno określa przyczynę: gromadzenie transakcji przerwałoby przeładowanie schematu, które zależy od LISTEN na kanale pgrst. Ten mechanizm jest niezgodny z odzyskanymi połączeniami serwera między klientami. Pula administracyjnaaura-db (schemat, DDL, blokady doradcze sesji) również pozostaje w bezpośrednim połączeniu z tego samego podstawowego powodu. SET search_path i blokady sesji niemające zakresu transakcji nie przetrwają puli w trybie transakcji.
Uwierzytelnianie odbywa się według wzorca auth_query opisanego w sekcji 02: AUTH_QUERY: SELECT * FROM pgbouncer.user_lookup($1), bez statycznego pliku userlist.txt. To właśnie umożliwia rolom tworzonym dynamicznie dla każdego projektu (project_<uuid>_authenticator) uwierzytelnianie za pośrednictwem PgBouncer bez ponownego wdrażania modułu puli dla każdego nowego projektu.
Komentarz kontroli stanu PgBouncer w lokalnym manifestie Kubernetes dokumentuje prawdziwy błąd, już naprawiony. Uruchomienie pg_isready przeciwko PgBouncer sprawdza jedynie uzgadnianie proxy, a nie rzeczywiste połączenie z backendem Postgres, które przekazuje. PgBouncer odpowiada „akceptując połączenia” nawet wtedy, gdy backend jest zatrzymany, kolejkując żądania. Wynik zaobserwowany podczas testu niszczącego: usługa pozostawała healthy przez 5 kolejnych cykli, podczas gdy Postgres był nieosiągalny. Poprawka zastępuje sprawdzenie prawdziwym, kompleksowym żądaniem psql za pośrednictwem modułu puli, aż do zaplecza. Wynik po korekcie, odtworzony w tym samym teście: unhealthy wykryty w 7 cyklach, około 35 sekund.
Ostatni szczegół, drobny, ale odkrywczy: wykres Helma domyślnie przypina edoburu/pgbouncer:v1.24.1-p1, podczas gdy lokalna ława k3d używa v1.25.2-p0. Nie jest to wybór architektoniczny, po prostu niewielki brak synchronizacji wersji między dwoma środowiskami, rodzaj szczegółów, które recenzja kodu wyłapuje szybciej niż post na blogu. Dokumentujemy go takim, jaki jest, zamiast go upiększać. Aby uzyskać szczegółowe informacje na temat partycjonowania schematu obsługiwanego przez tę pulę, zobacz nasz artykuł na tematizolacji RLS dla wielu dzierżawców.
Jak wybrać pomiędzy tymi trzema
Wybierz PgBouncer, jeśli…
- Klaster Postgres zarządzany ogólnie przez CloudNativePG lub Kubernetes
- Chcesz najbardziej sprawdzonego i dobrze udokumentowanego gracza bilardowego
- Docelowa baza na instancję Poolera Ci odpowiada
Wybierz Supavisor, jeśli…
- Setki lub tysiące baz za tą samą usługą
- Należy dynamicznie rejestrować najemców za pośrednictwem interfejsu API, bez konieczności ponownego wdrażania
- Już w ekosystemie Supabase lub chcąc na nim polegać
Wybierz PgCat, jeśli…
- Udostępnianie aplikacji już istnieje lub jest planowane na poziomie Poolera
- Równoważenie obciążenia i replika awaryjna bez oddzielnej warstwy aplikacji
- Wygodny z młodszym projektem, mniej udokumentowanym niż PgBouncer
Niezależnie od tego, jaki basen zostanie wybrany, nie zastępuje on rozmiaru samego Postgres. Rozmiar puli i serwer max_connections należy rozpatrywać łącznie, a nie jeden po drugim. Obfita pula przed zbyt niskim max_connections po prostu przesuwa nasycenie z jednego poziomu na drugi. Nasz przewodnik na temat tuningu max_connections szczegółowo opisuje wzór doboru, który należy zastosować przed ustawieniem rozmiaru basenu.
O co jesteśmy pytani najczęściej
Nie ma uniwersalnego basenu, jest tylko odpowiedni do Twojego najmu
PgBouncer, Supavisor i PgCat rozwiązują trzy odmiany tego samego problemu, a nie trzy wersje tego samego narzędzia. PgBouncer pozostaje najbezpieczniejszym wyborem, gdy Twoja platforma opiera się już na Kubernetes i CloudNativePG lub gdy po prostu potrzebujesz najbardziej udokumentowanego Poolera. Supavisor staje się istotny poza określoną liczbą baz obsługujących tę samą usługę. PgCat jest warty obejścia, jeśli brakuje Ci fragmentowania i przełączania awaryjnego replik na poziomie sieci, pod warunkiem, że zaakceptujesz dojrzałość młodszego projektu.
Kod Aurabase pokazuje spójny, a nie neutralny wybór: PgBouncer w trybie transakcyjnym, na dwóch poziomach, współdzielona flota i CNPG Pooler na dedykowanego najemcę. Pozostają dwa udokumentowane wyjątki dla PostgREST i administrowania schematem. Jeśli chcesz zobaczyć, jak ten projekt wygląda w praktyce, a nie na papierze, nasza strona Performance dokumentuje powiązaną metodologię pomiaru.