Proxy w PostgreSQL – czyli load balancing w rozwiązaniach wysokiej dostępności
Czy i jakie korzyści przynosi użycie aplikacji pośredniczącej w połączeniu do bazy danych? W jaki sposób proxy łączy się z tematem rozwiązań wysokiej dostępności? Czy narzędzie udostępniające pulę połączeń może kryć przed DBA nieoczekiwane funkcje? Kontynuując cykl na temat tworzenia niezawodnych klastrów PostgreSQL, postaram się odpowiedzieć na te pytania.
Czy i jakie korzyści przynosi użycie aplikacji pośredniczącej w połączeniu do bazy danych? W jaki sposób proxy łączy się z tematem rozwiązań wysokiej dostępności? Czy narzędzie udostępniające pulę połączeń może kryć przed DBA nieoczekiwane funkcje? Kontynuując cykl na temat tworzenia niezawodnych klastrów PostgreSQL, postaram się odpowiedzieć na te pytania.
W poprzednich artykułach omawialiśmy zagadnienia związane z rodzajami replikacji w PostgreSQL, a także, w jaki sposób można monitorować i zarządzać replikacją wykorzystując rozwiązania Open Source. Dzisiaj na warsztat weźmiemy narzędzia uzupełniające pewną lukę w szerokiej gamie możliwości, jakie daje Postgres, a mianowicie rozwiązania pośredniczące w komunikacji z bazą danych, najczęściej w celu zapewnienia większej ilości połączeń do bazy, potocznie zwanych poolerami lub ogólniej określanych jako proxy.
Menedżer połączeń do bazy
PostgreSQL jako silnik bazodanowy sam nie zarządza połączeniami do bazy. Jest całkiem naturalne, że w celu dostrojenia konfiguracji bazy danych do posiadanego sprzętu możemy zmienić liczbę dostępnych połączeń (parametr max_connections
), lecz wprowadzanie zmian w tym parametrze wymaga restartu usługi. Wiąże się to bezpośrednio z architekturą samego PostgreSQL – dla każdego otwartego połączeni tworzony jest nowy proces (backend) obsługujący to połączenie, dla którego z kolei alokowane zostają skończone zasoby serwera (głównie chodzi tutaj o pamięć alokowaną na wyłączność dla tego połączenia).
Podczas wykonywania testów obciążeniowych w celu ustalenia optymalnej liczby połączeń, często widać, że wraz ze wzrostem liczby połączeń, od pewnego momentu niestety przestajemy zyskiwać na teoretycznie „lepiej dociążonym” serwerze, a zaczynamy tracić wydajność. Wykrycie idealnej liczby połączeń dla danej konfiguracji sprzętowej oraz (co najważniejsze!) rodzaju obciążeń związanych z charakterystyką wykorzystującej nasz serwer aplikacji, jest jednym z ważniejszych zadań DBA w przypadku wdrożeń produkcyjnych. Znając ten parametr, możemy doprowadzić do poprawienia działania aplikacji. Jednak co w przypadku gdy otwiera ona dużą liczbę połączeń, a w logach błędów zaczyna pojawiać się poniższy komunikat?
error: could not connect to server: FATAL: sorry, too many clients already
W przypadku gdy kontrolujemy kod aplikacji, dodanie własnego rozwiązania utrzymującego pulę połączeń do bazy może okazać się najlepszym rozwiązaniem (niektóre frameworki czy serwery aplikacji robią to domyślnie), kiedy mamy na to zasoby oraz zależy nam na idealnym dostrojeniu schematów dostępu do bazy z naszą aplikacją. Nierzadko jednak takie rozwiązanie jest nieopłacalne bądź zwyczajnie niemożliwe (szczególnie w przypadku komercyjnych „aplikacji pudełkowych”, w których zasadniczo nie ma możliwości zmian kodu).
W takim przypadku naturalnym rozwiązaniem tego problemu jest dodanie do architektury naszego rozwiązania proxy bazodanowego, które będzie obsługiwać „nadmiarowe” połączenia do bazy danych bez konieczności zmieniania konfiguracji samego serwera, co miałoby wpływ na jego wydajność.
W zależności od stopnia ich zaawansowania, niektóre z dostępnych rozwiązań typu proxy pozwalają na dużo więcej niż proste rozwiązanie powyższego problemu. Ukrywają, czy raczej wyabstrahowują warstwę bazy danych od warstwy aplikacji, pozwalając na przykład na stworzenie klastrów bazodanowych wysokiej dostępności bądź zwiększają wydajność aplikacji przez rozlokowywanie ruchu na podstawie jego rodzaju – odsyłając zapytania read-only do węzłów standby, co zmniejsza obciążenie serwera głównego. Wymaga to jednak smart proxy, czyli potrafiącego dekodować i interpretować protokół komunikacyjny PostgreSQL w celu podejmowania odpowiednich działań.
PgBouncer w roli proxy dla PostgreSQL
Dobrym przykładem otwartoźródłowego proxy do bazy danych jest narzędzie pgBouncer. Dzięki zdolności do interpretowania pakietów kierowanych do Postgresa pozwala na utrzymywanie puli połączeń na kilku poziomach, w zależności od potrzeb naszej aplikacji. Są nimi:
- poziom sesji – najbardziej przypominają zwykłe połączenia do bazy danych. Połączenie klienta wykorzystuje jedno połączenie do bazy danych przez cały czas do momentu rozłączenia klienta.
- poziom transakcji – w tym przypadku poszczególne transakcje mogą być obsługiwane przez różne połączenia do bazy, potencjalnie pozwalając na lepsze rezultaty. Nie wszystkie aplikacje będą jednak mogły skorzystać z tej metody, jeśli korzystają z funkcji PostgreSQL dostępnych jedynie na poziomie sesji.
- poziom zapytania – najniższy dostępny poziom, gdzie każde zapytanie powinno być osobną transakcją.
W przypadku pgBouncera jedną z najciekawszych możliwości, jakie oferuje, jest możliwość jego rekonfiguracji w locie, co pozwala na tworzenie zaawansowanych architektur dostosowanych nawet do najbardziej wymagających zadań.
Proxy w środowiskach High Availability
Jak już pisaliśmy w poprzednim artykule z serii na temat menedżera replikacji, jednym z problemów napotykanych podczas wykrycia awarii w klastrze wysokiej dostępności jest konieczność poinformowania aplikacji o nowym adresie serwera głównego. Jednak w przypadku kiedy aplikacja komunikuje się z aplikacją typu proxy (szczególnie kiedy nie możemy w niej nic zmienić), możemy przenieść ten problem do warstwy, nad którą mamy kontrolę.
W przypadku pgBouncera możliwość dynamicznej rekonfiguracji jest dodatkowo wspierana przez kolejną funkcjonalność, a mianowicie wstrzymywanie przekazywania połączeń do bazy danych i ich kolejkowanie na poziomie proxy.
W czasie, w którym aplikacja może doświadczyć ze swojej strony zwiększenia opóźnienia w obsłudze zapytań, na przykład może mieć miejsce podmiana aktualnie działającego serwera głównego na jeden z zapasowych w celu przeprowadzenia rutynowych prac konserwatorskich. Po zweryfikowaniu w menadżerze replikacji, że switchover zakończył się powodzeniem, wstrzymywane połączenia do bazy można na powrót do niej dopuścić. Jedyne wymaganie ze strony aplikacji to „odporność” na wolniejsze obsłużenie zapytania.
Podsumowanie
Tym artykułem zakończyliśmy serię na temat budowania rozwiązań wysokiej dostępności z wykorzystaniem bazy danych PostgreSQL. Tym i innymi podobnymi zagadnieniami zajmujemy się, świadcząc usługi professional services dla PostgreSQL i EuroDB dla naszych klientów. Zapraszamy serdecznie do kontaktu i korzystania z naszych usług.