Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W raporcie Andriej Borodin opowie, jak uwzględnili doświadczenie skalowania PgBouncer podczas projektowania puli połączeń Odyssey, jak wdrażali go w produkcji. Ponadto omówimy, jakie funkcje puli chcielibyśmy zobaczyć w nowych wersjach: ważne jest dla nas nie tylko zaspokojenie naszych potrzeb, ale także rozwijanie społeczności użytkowników Odysseja.

Wideo:

Odtwarzaj wideo

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Cześć wszystkim! Nazywam się Andriej.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W Yandex zajmuję się rozwojem open source baz danych. I dziś naszym tematem jest pula połączeń.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Jeśli wiecie, jak nazwać pulę połączeń po rosyjsku, to mi powiedzcie. Bardzo chcę znaleźć dobry termin techniczny, który powinien się ugruntować w literaturze technicznej.

Temat jest dość skomplikowany, ponieważ w wielu bazach danych pula połączeń jest wbudowana i nawet nie trzeba o niej wiedzieć. Oczywiście w każdym z nich są jakieś ustawienia, ale w Postgresie nie da się tak po prostu. Równocześnie (na HighLoad++ 2019) odbywa się wykład Nikołaja Samochwałowa o konfiguracji zapytań w Postgresie. Rozumiem, że przyszli tu ludzie, którzy już idealnie skonfigurowali zapytania, i to są ludzie, którzy napotykają bardziej rzadkie problemy systemowe związane z siecią, wykorzystaniem zasobów. I miejscami może to być dość skomplikowane, ponieważ problemy nie są oczywiste.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W Yandex mamy Postgres. W Yandex.Cloud mieszka wiele usług Yandexu. I mamy kilka petabajtów danych, które generują nie mniej niż milion zapytań na sekundę w Postgresie.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

I zapewniamy dość standardowy klaster dla wszystkich usług – to główny węzeł primary, zwykle dwie repliki (synchroniczna i asynchroniczna), kopie zapasowe, skalowanie zapytań odczytowych na replikach.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Każdy węzeł klastra to Postgres, w którym oprócz Postgresa i monitorowania systemu jeszcze zainstalowany jest pooler połączeń. Pooler połączeń jest używany do fencing i w swoim podstawowym przeznaczeniu.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Czym jest podstawowe przeznaczenie poolera połączeń?

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W Postgres przyjęto model procesowy podczas pracy z bazą danych. Oznacza to, że jedno połączenie to jeden proces, jeden backend Postgresa. A w tym backendzie jest wiele różnych cache’y, które są dość kosztowne, gdy są zrobione różnie dla różnych połączeń.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Ponadto w kodzie Postgres znajduje się tablica o nazwie procArray. Zawiera ona podstawowe informacje o połączeniach sieciowych. A niemal wszystkie algorytmy przetwarzania procArray mają liniową złożoność, przeszukują całą tablicę połączeń sieciowych. To dość szybka pętla, ale przy dużej liczbie przychodzących połączeń sieciowych staje się to nieco droższe. A gdy wszystko staje się trochę droższe, w rezultacie można zapłacić bardzo wysoką cenę za dużą liczbę połączeń sieciowych.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Istnieją 3 możliwe podejścia:

  • Po stronie aplikacji.
  • Po stronie bazy danych.
  • I pomiędzy nimi, tzn. wszelkie kombinacje.

Niestety, wbudowany pooler jest obecnie w fazie rozwoju. Koledzy z firmy PostgreSQL Professional głównie się tym zajmują. Kiedy się pojawi, ciężko przewidzieć. W rzeczywistości architekt ma do wyboru dwa rozwiązania: pool po stronie aplikacji oraz proxy pool.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Pool po stronie aplikacji to najprostszy sposób. A niemal wszystkie sterowniki klienta oferują sposób na przedstawienie milionów połączeń w kodzie jako kilkudziesięciu połączeń w bazie danych.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Pojawia się problem, gdy w pewnym momencie chcesz skalować backend, chcesz wdrożyć go na wielu maszynach wirtualnych.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Potem zdajesz sobie sprawę, że masz kilka stref dostępności, kilka centrów danych. Podejście z klienta side pooling prowadzi do dużych liczb. Duże to mniej więcej 10 000 połączeń. To jest maksimum, które może działać w miarę normalnie.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Jeśli mówimy o proxy poolerach, to są dwa poolery, które mają wiele do zaoferowania. To nie tylko poolery. To poolery + dodatkowa świetna funkcjonalność. Są to Pgpool i Crunchy-Proxy.

Ale niestety, ta dodatkowa funkcjonalność nie wszystkim jest potrzebna. Prowadzi to do tego, że poolery obsługują tylko pooling sesji, tzn. jeden przychodzący klient, jeden wychodzący klient do bazy danych.

Dla naszych potrzeb to nie jest zbyt dobre, dlatego używamy PgBouncer, który realizuje pooling transakcji, tzn. połączenia serwerowe są dopasowywane do połączeń klienckich tylko na czas transakcji.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

I przy naszym obciążeniu – to prawda. Ale pojawia się kilka problemów..Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Problemy zaczynają się, gdy chcesz zdiagnozować sesję, ponieważ wszystkie przychodzące połączenia są lokalne. Wszystkie pochodzą z loopback i w jakiś sposób śledzenie sesji staje się trudne.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Oczywiście, możesz użyć application_name_add_host. To sposób po stronie Bouncera, aby dodać adres IP do application_name. Jednak application_name jest ustawiane dodatkowym połączeniem.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Na tym wykresie żółta linia reprezentuje rzeczywiste zapytania, a niebieska – zapytania, które trafiają do bazy. A ta różnica to właśnie ustawienie application_name, które jest potrzebne tylko do śledzenia, ale wcale nie jest darmowe.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Ponadto w Bouncerze nie można ograniczyć jednego poola, tzn. liczby połączeń z bazą danych dla konkretnego użytkownika, w konkretnej bazie.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Do czego to prowadzi? Masz obciążoną usługę napisaną w C++, a gdzieś blisko jest mała usługa na nodzie, która nie robi nic szkodliwego z bazą, ale jej sterownik szaleje. Otwiera 20 000 połączeń, a wszystko inne musi poczekać. Twój kod jest nawet poprawny.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Oczywiście napisaliśmy mały patch do Bouncera, który dodał to ustawienie, tzn. ograniczenie klientów w poolu.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Można by to zrobić po stronie Postgresa, tzn. ograniczyć role w bazie danych do liczby połączeń.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Ale wtedy tracisz możliwość zrozumienia, dlaczego nie masz połączeń z serwerem. PgBouncer nie przekazuje błędu połączenia, zawsze zwraca tę samą informację. I nie możesz zrozumieć: może hasło się zmieniło, może baza po prostu leży, może coś jest nie tak. Ale brak jakiejkolwiek diagnostyki. Jeśli sesja nie może być nawiązana, nie dowiesz się, dlaczego to się nie udaje.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W pewnym momencie patrzysz na wykresy aplikacji i widzisz, że aplikacja nie działa.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Patrzysz w top i widzisz, że Bouncer jest jednowątkowy. To przełomowy moment w życiu usługi. Rozumiesz, że przygotowywałeś się do skalowania bazy danych za półtora roku, a musisz skalować poolera.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Doszliśmy do tego, że potrzebujemy więcej PgBouncerów.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

https://lwn.net/Articles/542629/

Trochę zapatchowaliśmy Bouncera.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

I zrobiliśmy tak, że można uruchomić kilka Bouncerów z ponownym wykorzystaniem portu TCP. A system operacyjny automatycznie rozkłada przychodzące połączenia TCP między nimi w sposób round-robin.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

To jest przejrzyste dla klientów, tzn. wszystko wygląda tak, jakbyś miał jednego Bouncera, ale masz fragmentację idle-połączeń między uruchomionymi Bouncerami.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

I w pewnym momencie możesz zauważyć, że te 3 Bouncery wykorzystują każde swoje rdzeń w 100 %. Potrzebujesz sporo Bouncerów. Dlaczego?

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Ponieważ masz TLS. Masz zaszyfrowane połączenie. A jeśli benchmarkujesz Postgres z TLS i bez TLS, odkryjesz, że liczba nawiązanych połączeń spada prawie o dwa rzędy przy włączeniu szyfrowania, ponieważ handshake TLS zużywa zasoby procesora.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Na górze możesz zobaczyć dość dużo funkcji kryptograficznych, które są wykonywane podczas fali przychodzących połączeń. Ponieważ nasz primary może się przełączać między strefami dostępności, fala przychodzących połączeń to dość typowa sytuacja. To znaczy, z jakiegoś powodu stary primary był niedostępny, cała obciążenie zostało wysłane do innego centrum danych. Wszystkie one przybędą jednocześnie, aby przywitać się z TLS.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

A duża liczba handshake TLS może nie przywitać się z Bouncerem, a zatykać mu gardło. Z powodu timeoutu fala przychodzących połączeń może stać się nie wygasającą. Jeśli masz retry w bazie bez exponential backoff, nie będą one przychodzić z powrotem w spójnym strumieniu.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Oto przykład 16 PgBouncerów, które obciążają 16 rdzeni w 100 %

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Doszliśmy do kaskadowego PgBouncer. To najlepsza konfiguracja, jaką można osiągnąć przy naszym obciążeniu z Bouncerem. Zewnętrzne Bouncery służą do handshake TCP, a wewnętrzne Bouncery do rzeczywistego pooling, aby nie fragmentować zbytnio zewnętrznych połączeń.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W takiej konfiguracji możliwy jest płynny restart. Można restartować wszystkie te 18 Bouncerów po jednym. Ale utrzymanie takiej konfiguracji jest dość trudne. Administratorzy systemów, DevOps i ludzie, którzy naprawdę odpowiadają za ten serwer, nie będą zbyt zadowoleni z tego schematu.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Wydaje się, że można wszystkie nasze poprawki wprowadzać do open source, ale Bouncer nie jest zbyt dobrze wspierany. Na przykład możliwość uruchomienia kilku PgBouncerów na tym samym porcie została skomitowana miesiąc temu. A pull request z tą funkcjonalnością był kilka lat temu.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

https://www.postgresql.org/docs/current/libpq-cancel.html

https://github.com/pgbouncer/pgbouncer/pull/79

Albo inny przykład. W Postgres możesz anulować bieżące zapytanie, wysyłając sekretny kod przez inne połączenie bez dodatkowej autoryzacji. Jednak niektórzy klienci po prostu wysyłają TCP-reset, tzn. przerywają połączenie sieciowe. Co wtedy zrobi Bouncer? Nic nie zrobi. Nadal będzie wykonywał zapytanie. Jeśli masz ogromną liczbę połączeń, które małymi zapytaniami obciążają bazę, to samo odłączenie od Bouncera nie wystarczy, trzeba też zakończyć te zapytania, które są wykonywane w bazie.

To zostało załatane, a problem nadal nie został włączony do upstream Bouncera.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

I tak doszliśmy do wniosku, że potrzebujemy własnego connection poolera, który będzie się rozwijał, patchował, w którym będzie można szybko naprawiać problemy i który, oczywiście, musi być wielowątkowy.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Wielowątkowość postawiliśmy jako główne zadanie. Musimy dobrze radzić sobie z falą nadchodzących połączeń TLS.

W tym celu musieliśmy opracować osobną bibliotekę, która nazywa się Machinarium, przeznaczoną do opisywania stanów maszyn połączenia sieciowego jako sekwencji kodu. Jeśli spojrzysz na kod źródłowy libpq, zobaczysz dość skomplikowane wywołania, które mogą zwrócić ci wynik i powiedzieć: „Zadzwoń do mnie później. Teraz mam IO, ale gdy IO zakończy się, mam obciążenie dla procesora”. I to jest wielowarstwowy schemat. Zazwyczaj interakcję sieciową opisuje się jako maszynę stanów. Wiele reguł typu „Jeśli wcześniej odebrałem nagłówek pakietu o rozmiarze N, to teraz oczekuję N bajtów”, „Jeśli wysłałem pakiet SYNC, to teraz oczekuję pakietu z metadanymi wyniku”. Powstaje dość trudny, kontrintuicyjny kod, jakby labirynt został przekształcony w liniową rozwiniętą wersję. Zrobiliśmy tak, że zamiast maszyny stanów programista opisuje główną ścieżkę interakcji w postaci zwykłego kodu imperatywnego. Po prostu w tym kodzie imperatywnym trzeba wstawiać miejsca, w których sekwencję wykonania należy przerwać oczekiwaniem na dane z sieci, przekazując kontekst wykonania innej korutynie (green thread-owi). To podejście jest podobne do tego, że najbardziej oczekiwaną ścieżkę w labiryncie zapisujemy jeden po drugim, a następnie dodajemy do niej odgałęzienia.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W rezultacie mamy jeden wątek, który wykonuje TCP accept i w sposób round-robin przekazuje połączenie TPC do wielu workerów.

Każde połączenie z klientem działa zawsze na jednym procesorze, co czyni je przyjaznym dla pamięci cache.

Dodatkowo, opracowaliśmy drobne poprawki w zbieraniu małych pakietów w jeden duży, aby odciążyć systemowy stos TCP.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Ponadto, poprawiliśmy pulowanie transakcji, w ten sposób, że przy odpowiedniej konfiguracji, Odyssey może wysłać CANCEL i ROLLBACK w przypadku utraty połączenia sieciowego, tj. jeśli żaden proces nie oczekuje na zapytanie, Odyssey poinformuje bazę danych, aby nie próbowała wykonać zapytania, które mogłoby zużywać cenne zasoby.

W miarę możliwości staramy się utrzymywać połączenia z tym samym klientem, co pozwala uniknąć ponownej konfiguracji application_name_add_host. Jeśli to możliwe, nie ma dodatkowej konieczności zmiany parametrów, które są potrzebne do diagnozowania.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Działamy w interesach Yandex.Cloud. Jeśli korzystasz z managed PostgreSQL i masz zainstalowany connection pooler, możesz utworzyć replikację logiczną na zewnątrz, co oznacza, że możesz odejść od nas, jeśli zechcesz, za pomocą replikacji logicznej. Bouncer nie przekaże strumienia replikacji logicznej na zewnątrz.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

To przykład konfiguracji replikacji logicznej.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Ponadto, mamy wsparcie dla replikacji fizycznej na zewnątrz. W chmurze jest to oczywiście niemożliwe, ponieważ klaster przekaże zbyt wiele informacji o sobie. Jednak w twoich instalacjach, jeśli potrzebujesz fizycznej replikacji przez connection pooler w Odyssey, jest to możliwe.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W Odyssey mamy w pełni kompatybilne monitorowanie z PgBouncer. Mamy taką samą konsolę, która wykonuje prawie wszystkie te same polecenia. Jeśli czegoś brakuje, prześlij pull request lub przynajmniej zgłoś problem na GitHubie, a my dodamy potrzebne komendy. Jednak główna funkcjonalność konsoli PgBouncer jest już w pełni dostępna.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Oczywiście, mamy również przekazywanie błędów. Zwrócimy ten błąd, który zgłosiła baza. Otrzymasz informację, dlaczego nie możesz połączyć się z bazą, a nie tylko, że się nie łączysz.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Ta funkcjonalność może być wyłączona, jeśli potrzebujesz 100% zgodności z PgBouncer. Możemy zachowywać się tak samo jak Bouncer, na wszelki wypadek.

Rozwój

Kilka słów o kodzie źródłowym Odyssey.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

https://github.com/yandex/odyssey/pull/66

Na przykład, są komendy „Pause / Resume”. Zwykle są one używane do aktualizacji bazy danych. Jeśli musisz zaktualizować Postgresa, możesz wstrzymać go w połączeniu pooler, wykonać pg_upgrade, a następnie wznowić. I po stronie klienta będzie to wyglądać tak, jakby baza po prostu spowolniła. Tę funkcjonalność dostarczyli nam ludzie ze społeczności. Nie została jeszcze scalona, ale wkrótce wszystko będzie. (Już scalono)

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

https://github.com/yandex/odyssey/pull/73 — już scalono

Ponadto jedną z nowych funkcji w PgBouncer jest wsparcie dla uwierzytelniania SCRAM, które również przyniósł nam ktoś, kto nie pracuje w Yandex.Cloud. Oba są skomplikowaną funkcjonalnością i ważne.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Dlatego chciałbym opowiedzieć, z czego zrobiony jest Odyssey, może także chcecie chwilę napisać kod.

Macie bazę źródłową Odyssey, która opiera się na dwóch głównych bibliotekach. Biblioteka Kiwi to realizacja protokołu komunikacyjnego Postgresa. Tzn. natywny proto 3 w Postgresie to standardowe wiadomości, które frontend i backend mogą wymieniać. Zostały one zaimplementowane w bibliotece Kiwi.

Biblioteka Machinarium to biblioteka realizacji wątków. Mały fragment tego Machinarium został napisany w assemblerze. Ale nie martwcie się, jest tam tylko 15 wierszy.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Architektura Odyssey. Jest główna maszyna, w której uruchomione są coroutines. W tej maszynie realizowane są akceptacje przychodzących połączeń TCP i ich rozdzielanie na workerów.

Wewnątrz jednego workera może pracować handler kilku klientów. A także w głównym wątku działają konsola i przetwarzanie zadań crone do usuwania połączeń, które już nie są potrzebne w pool.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Do testowania Odyssey używa się standardowego zestawu testów Postgresa. Po prostu uruchamiamy install-check przez Bouncera i przez Odyssey, uzyskując zerowy div. Kilka testów związanych z formatowaniem dat nie przechodzi w ogóle w Bouncerze i Odyssey identycznie.

Ponadto istnieje wiele sterowników, które mają własne testy. I używamy ich testów do testowania Odyssey.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Dodatkowo, z powodu naszej kaskadowej konfiguracji, musimy testować różne kombinacje: Postgres + Odyssey, PgBouncer + Odyssey, Odyssey + Odyssey, aby być pewnymi, że jeśli Odyssey znajdzie się w którejkolwiek z części w kaskadzie, również będzie działał tak, jak oczekujemy.

Grapple

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Używamy Odyssey w produkcji. Nie byłoby uczciwie powiedzieć, że wszystko po prostu działa. Tak, to prawda, ale nie zawsze. Na przykład w produkcji wszystko działało, aż nasi przyjaciele z PostgreSQL Professional powiedzieli, że mamy wyciek pamięci. Rzeczywiście tak było, naprawiliśmy to. Ale to było dla nas zaskoczeniem.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Potem odkryliśmy, że w connection pooler są przychodzące i wychodzące połączenia TLS. I w tych połączeniach potrzebne są certyfikaty klienta i certyfikaty serwera.

Certyfikaty serwera Bouncer i Odyssey odczytują swoje pcache, ale certyfikaty klienta nie muszą być odczytywane z pcache, ponieważ nasz skalowalny Odyssey ostatecznie napotyka na wydajność systemu związane z odczytem tych certyfikatów. To było dla nas zaskoczeniem, ponieważ napotkał ten problem dopiero po pewnym czasie. Najpierw skalował się liniowo, a po 20 000 jednoczesnych połączeń przychodzących ten problem się ujawnił.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Metoda uwierzytelniania Pluggable Authentication Method to możliwość uwierzytelnienia przy użyciu wbudowanych środków linuksowych. W PgBouncer zrealizowano to w taki sposób, że jest osobny wątek na oczekiwanie na odpowiedź od PAM oraz główny wątek PgBouncer, który obsługuje bieżące połączenie i może poprosić je o pozostanie w wątku PAM.

Nie zdecydowaliśmy się na to z jednego prostego powodu. Mamy przecież wiele wątków. Po co nam to potrzebne?

W efekcie może to powodować problemy, ponieważ jeżeli masz uwierzytelnianie PAM i nie-PAM, to duża fala uwierzytelnień PAM może znacznie opóźniać uwierzytelnianie nie-PAM. To jedna z rzeczy, których nie naprawiliśmy. Ale jeśli chcesz to naprawić, możesz się tym zająć.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Kolejnym problemem było to, że mamy jeden wątek, który akceptuje wszystkie przychodzące połączenia. A następnie przekazuje je do puli roboczej, gdzie odbywa się zestawienie TLS.

W efekcie, jeśli masz spójną falę 20 000 połączeń sieciowych, wszystkie zostaną zaakceptowane. A po stronie klienta libpq rozpocznie odliczanie limitów czasowych. Domyślnie wydaje się, że jest tam ustawione 3 sekundy.

Jeśli nie mogą jednocześnie wejść do bazy, to nie mogą wejść do bazy, ponieważ wszystko to może być pokryte nieeksponencjalnym ponownym próbą.

Doszliśmy do tego, że skopiowaliśmy tutaj schemat z PgBouncer, w którym mamy throttling liczby połączeń TCP, które akceptujemy.

Jeśli zauważymy, że akceptujemy połączenia, a one ostatecznie nie zdążają się zestawić, umieszczamy je w kolejce, aby nie zużywały zasobów procesora centralnego. To prowadzi do sytuacji, że jednoczesne zestawienie może być realizowane nie dla wszystkich połączeń, które przybyły. Ale przynajmniej ktoś wejdzie do bazy, nawet jeśli obciążenie jest dość duże.

mapę

Czego chcielibyśmy zobaczyć w przyszłości w Odyssey? Co jesteśmy gotowi opracować sami, a czego oczekujemy od społeczności?

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Na sierpień 2019 roku.

Tak wyglądał roadmap Odyssey w sierpniu:

  • Chcieliśmy uwierzytelniania SCRAM i PAM.
  • Chcieliśmy przesyłać zapytania tylko do odczytu na standby.
  • Chcielibyśmy możliwości restartu online.
  • I możliwość wstrzymania serwera.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Połowa tego roadmapu została zrealizowana, i to nie przez nas. I to jest dobre. Dlatego porozmawiajmy o tym, co pozostało i dodajmy więcej.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Jeśli chodzi o przesyłanie zapytań tylko do odczytu do standby.? У нас есть реплики, которые без выполнения запросов будут просто греть воздух. Они нам необходимы для обеспечения failover и switchover. В случае проблем в одном из дата-центре хотелось бы их занять какой-то полезной работой. Потому что те же самые центральные процессоры, ту же самую память мы не можем сконфигурировать по-другому, потому что иначе не будет работать репликация.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W zasadzie w Postgres, począwszy od wersji 10, istnieje możliwość wskazania session_attrs podczas łączenia. Możecie w połączeniu wymienić wszystkie hosty baz danych i określić, dlaczego idziecie do bazy danych: aby zapisać lub tylko przeczytać. I sterownik sam wybierze pierwszy z listy host, który bardziej mu odpowiada i spełnia wymagania session_attrs.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Jednak problem z tym podejściem polega na tym, że nie kontroluje ono opóźnienia replikacji. Możecie mieć jakąś replikę, która jest spóźniona o czas niedopuszczalny dla waszej usługi. Aby umożliwić pełnofunkcyjne wykonanie zapytań do odczytu na replicie, w zasadzie musimy wspierać w Odyssey możliwość niepracy, gdy nie można czytać.

Odyssey powinien czasami wchodzić do bazy i pytać o odległość replikacji od primary. I jeśli osiągnie ona maksymalną wartość, nowe zapytania do bazy nie powinny być akceptowane, a klientowi należy powiedzieć, że musi ponownie zainicjować połączenia i ewentualnie wybrać inny host do wykonania zapytań. To pozwoli bazie szybciej przywrócić opóźnienie replikacji i ponownie wrócić do odpowiedzi na zapytania.

Trudno jest określić terminy realizacji, ponieważ to open source. Ale mam nadzieję, że nie zajmie to 2,5 roku, jak u kolegów z PgBouncer. Chciałbym zobaczyć tę funkcję w Odyssey.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

W społeczności ludzie pytali o wsparcie dla prepared statement.Obecnie możesz utworzyć prepared statement na dwa sposoby. Po pierwsze, możesz wykonać polecenie SQL, a mianowicie „prepared”. Aby zrozumieć to polecenie SQL, musimy nauczyć się rozumieć SQL po stronie Bouncer. Byłoby to overkill, ponieważ potrzebujemy kompletny parser. Nie możemy analizować każdego polecenia SQL.

Jednak istnieje prepared statement na poziomie protokołu wiadomości w proto3. I to jest to miejsce, w którym informacja o tym, że tworzony jest prepared statement, przychodzi w ustrukturyzowanej formie. Moglibyśmy wspierać zrozumienie, że na jakimś połączeniu serwera klient poprosił o utworzenie prepared statements. I nawet jeśli transakcja się zakończyła, nadal musimy zachować spójność serwera i klienta.

Ale tutaj pojawia się rozbieżność w dialogu, ponieważ ktoś mówi o potrzebie zrozumienia, które dokładnie prepared statements utworzył klient i rozdzielenia połączenia serwera między wszystkimi klientami, którzy utworzyli to połączenie serwera, tzn. którzy stworzyli taki prepared statement.

Andres Freund powiedział, że jeśli pojawi się klient, który już tworzył taki prepared statement w innym połączeniu serwera, to stwórz go za niego. Ale wydaje się, że nieco niewłaściwie jest wykonywać zapytania w bazie zamiast klienta, ale z punktu widzenia programisty, który pisze protokół interakcji z bazą, byłoby wygodne, gdyby po prostu dano mu połączenie sieciowe, w którym znajduje się takie przygotowane zapytanie.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

I jeszcze jedna funkcja, którą musimy zaimplementować. Obecnie mamy monitorowanie kompatybilne z PgBouncer. Możemy zwrócić średni czas wykonania zapytania. Ale średni czas to średnia temperatura w szpitalu: ktoś zimny, ktoś ciepły – średnio wszyscy są zdrowi. To nieprawda.

Musimy zaimplementować wsparcie dla percentyli, które wskazywałyby, że istnieją wolne zapytania, które zużywają zasoby, i uczyniłyby monitorowanie bardziej akceptowalnym.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Najważniejsze – chcemy wersję 1.0 (Już wydano wersję 1.1). Faktem jest, że obecnie Odyssey znajduje się w wersji 1.0rc, tzn. release candidate. I wszystkie problemy, które wymieniłem, zostały naprawione w tej wersji, z wyjątkiem wycieku pamięci.

Co dla nas oznacza wersja 1.0? Wdrażamy Odyssey na nasze bazy. Już teraz działa na naszych bazach, ale kiedy osiągnie punkt 1 000 000 zapytań na sekundę, będziemy mogli powiedzieć, że to jest wersja produkcyjna, a ta wersja to 1.0.

Niektórzy w społeczności poprosili o dodanie pauzy i SCRAM w wersji 1.0. Ale to oznacza, że będziemy musieli wdrożyć już następną wersję w produkcji, ponieważ ani SCRAM, ani pauza nie zostały jeszcze połączone. Ale najprawdopodobniej ten problem zostanie dość szybko rozwiązany.

Odyssey roadmap: czego jeszcze oczekujemy od łącznika połączeń. Andriej Borodin (2019)

Czekam na wasze zgłoszenia pull request. I chciałbym również usłyszeć, jakie macie problemy z Bouncer. Porozmawiajmy o tym. Może uda nam się zrealizować jakieś funkcje, które są dla was potrzebne.

Na tym kończę swoją część, chciałbym usłyszeć was. Dziękuję!

Pytania

Jeśli ustawię application_name, będzie poprawnie przekazywane, w tym do transaction pooling w Odyssey?

W Odyssey czy w Bouncer?

W Odyssey. W Bouncer jest przekazywane.

Zestaw zrobimy.

A jeśli moje rzeczywiste połączenie będzie skakać pomiędzy innymi połączeniami, to będzie przekazywane?

Zrobimy zestaw wszystkich parametrów wymienionych na liście. Nie mogę powiedzieć, czy w tej liście znajduje się application_name. Wydaje mi się, że go tam widziałem. Ustawimy wszystkie te same parametry. Jednym zapytaniem przekazuje wszystko to, co zostało ustawione przez klienta przy uruchamianiu.

Dziękuję, Andrieju, za referat! Dobry referat! Cieszę się, że Odyssey rozwija się coraz szybciej z każdą chwilą. Życzę dalszych sukcesów. Już zwracaliśmy się do was z prośbą o posiadanie multi data-source połączenia, aby Odyssey mogło łączyć się jednocześnie z różnymi bazami danych, tzn. master slave, a potem automatycznie po failover łączyć się z nowym masterem.

Tak, zdaje się, że przypominam sobie tę dyskusję. Obecnie istnieje kilka magazynów. Ale nie ma przełączania między nimi. Musimy z naszej strony pytać serwer, czy jeszcze żyje i zrozumieć, że nastąpił failover, kto wywoła pg_recovery. Mam standardowy sposób, żeby sprawdzić, że nie dotarliśmy do mastera. I musimy jakoś zrozumieć z błędów, czy nie? To znaczy, pomysł jest interesujący, jest omawiany. Piszecie więcej komentarzy. Jeśli macie pracowników, którzy znają C, to wspaniale.

Kwestia skalowania replikami również nas interesuje, ponieważ chcemy, aby przyjęcie replikowanych klastrów było jak najprostsze dla programistów aplikacji. Chcielibyśmy jednak usłyszeć więcej komentarzy, tzn. jak dokładnie to zrobić oraz jak to zrobić dobrze.

Kwestia dotycząca replik. Macie więc jeden master i kilka replik. Oczywiście, że do replik zagląda się rzadziej niż do mastera, ponieważ mogą występować różnice. Mówiliście, że różnice w danych mogą być takie, że mogą nie odpowiadać waszym potrzebom biznesowym i nie będziecie do nich zaglądać, dopóki nie zostaną zreplikowane. Jeśli zaś długo ich nie odwiedzaliście, a potem zaczniecie, to te dane, które są potrzebne, nie będą natychmiast dostępne. To znaczy, że jeśli non stop korzystamy z mastera, to tam cache jest nagrzany, a w replice cache jest nieco opóźniony.

Tak, to prawda. W pcache nie będą znajdowały się bloki danych, których chcecie, w real cache nie będzie informacji o tabelach, których chcecie, w planach nie będzie sparsowanych zapytań, w ogóle nic nie będzie.

A kiedy macie jakiś klaster i dodajecie do niego nową replikę, to póki się uruchamia, wszystko jest w niej źle, tzn. nawiązuje swoją pamięć podręczną.

Zrozumiałem ideę. Prawidłowym podejściem byłoby najpierw uruchomić mały procent zapytań na replikę, które by nagrzewały pamięć podręczną. Mówiąc wprost, mamy warunek, że nie możemy być bardziej niż 10 sekund do tyłu za masterem. I ten warunek wprowadzać nie jednorazowo, a płynnie dla niektórych klientów.

Tak, zwiększać ciężar.

To dobry pomysł. Ale najpierw musimy wdrożyć tę możliwość wyłączenia. Najpierw musimy się wyłączyć, a potem pomyślimy, jak się włączyć. To świetna funkcja, aby płynnie się włączać.

W nginx jest taka opcja powolne uruchamianie w klastrze dla serwera. I stopniowo zwiększa obciążenie.

Tak, świetny pomysł, wypróbujemy, kiedy dojdziemy do tego.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster