Klasztor → proste zarządzanie klastrem OTP

Prawie każda udana aplikacja biznesowa prędzej czy później wchodzi w fazę, w której wymagane jest skalowanie poziome. W wielu przypadkach można po prostu uruchomić nową instancję i zmniejszyć średnie obciążenie. Ale są też mniej trywialne przypadki, w których musimy upewnić się, że różne węzły wiedzą o sobie nawzajem i ostrożnie rozdzielają obciążenie.

Klasztor → proste zarządzanie klastrem OTP

Okazało się, że to takie szczęśliwe Erlang, który wybraliśmy ze względu na przyjemną składnię i szum wokół niego, jest pierwszorzędny wsparcie dla systemów rozproszonych. W teorii brzmi to zupełnie banalnie:

Przekazywanie wiadomości pomiędzy procesami w różnych węzłach, a także pomiędzy łączami i monitorami jest przejrzyste […]

W praktyce wszystko jest nieco bardziej skomplikowane. Rozpowszechniane Erlang został opracowany, gdy „kontener” oznaczał dużą żelazną skrzynię do transportu, a „doker” był po prostu synonimem dokera. W IP4 było wiele wolnych adresów, przerwy w sieci były zwykle spowodowane przez szczury przeżuwające kabel, a średni czas sprawności systemu produkcyjnego mierzono w dziesięcioleciach.

Teraz wszyscy jesteśmy niewiarygodnie samowystarczalni, spakowani i działamy w formie rozproszonej Erlang w środowisku, w którym dynamiczne adresy IP są przydzielane na zasadzie dużej losowości, a węzły mogą pojawiać się i znikać w zależności od kaprysu lewego pięty programu planującego. Aby uniknąć stosów szablonowego kodu w każdym projekcie, w którym działa rozproszony Erlang, aby walczyć z wrogim środowiskiem, potrzebna jest pomoc.

Operacja: Wiem, że istnieje libcluster. Jest naprawdę super, ma ponad tysiąc gwiazdek, autor jest znany w środowisku i tak dalej. Jeżeli oferowane przez ten pakiet metody tworzenia i utrzymywania klastra są dla Ciebie wystarczające, to cieszę się razem z Tobą. Niestety potrzebuję dużo więcej. Chcę szczegółowo kontrolować konfigurację, a nie być zewnętrznym widzem w teatrze reorganizacji klastra.

Wymagania

Mnie osobiście potrzebna była biblioteka, która przejęłaby zarządzanie klastrem i miałaby następujące właściwości:

  • przejrzysta praca zarówno z zakodowaną na stałe listą węzłów, jak i dynamicznym odkrywaniem poprzez usługi Erlang;
  • w pełni funkcjonalne wywołanie zwrotne dla każdej zmiany topologii (węzeł tam, węzeł tutaj, niestabilność sieci, podziały);
  • przejrzysty interfejs do uruchamiania klastra z długimi i krótkimi nazwami, np :nonode@nohost;
  • Gotowa do użycia obsługa Dockera, bez konieczności pisania kodu infrastruktury.

To drugie oznacza, że ​​po tym jak przetestowałem aplikację lokalnie w :nonode@nohostlub w sztucznie rozproszonym środowisku przy użyciu test_cluster_task, Chcę po prostu biegać docker-compose up --scale my_app=3 i zobacz, jak wykonuje trzy instancje w oknie dokowanym bez żadnych zmian w kodzie. Chcę także aplikacji zależnych, takich jak mnesia - gdy zmienia się topologia, za kulisami odbudowują klaster na żywo, bez dodatkowego kopnięcia ze strony aplikacji.

Klasztor nie miała być biblioteką zdolną do wszystkiego, od obsługi klastra po parzenie kawy. Nie jest to złoty środek, który ma na celu uwzględnienie wszystkich możliwych przypadków, ani nie jest rozwiązaniem kompletnym pod względem akademickim w tym sensie, w jakim teoretycy z różnych krajów CS umieścić w tym określeniu. Biblioteka ta została zaprojektowana tak, aby służyć bardzo jasnemu celowi, ale doskonale wykonywać swoje niezbyt duże zadanie. Celem tym będzie zapewnienie całkowitej przejrzystości pomiędzy lokalnym środowiskiem programistycznym a rozproszonym, elastycznym środowiskiem pełnym wrogich kontenerów.

Wybrane podejście

Klasztor jest przeznaczony do uruchamiania jako aplikacja, chociaż zaawansowani użytkownicy mogą ręcznie montować i konserwować klaster, uruchamiając go bezpośrednio Cloister.Manager w drzewie nadzorców aplikacji docelowej.

Biblioteka uruchamiana jako aplikacja opiera się na config, z którego odczytuje następujące podstawowe wartości:

config :cloister,
  otp_app: :my_app,
  sentry: :"cloister.local", # or ~w|n1@foo n2@bar|a
  consensus: 3,              # number of nodes to consider
                             #    the cluster is up
  listener: MyApp.Listener   # listener to be called when
                             #    the ring has changed

Powyższe parametry oznaczają dosłownie: Klasztor używany do aplikacji OTP :my_app, używa wykrywanie usług Erlang aby połączyć węzły, co najmniej trzy, i MyApp.Listener moduł (implementujący @behaviour Cloister.Listener) jest skonfigurowany do otrzymywania powiadomień o zmianach topologii. Szczegółowy opis pełnej konfiguracji można znaleźć w dokumentacja.

W tej konfiguracji aplikacja Klasztor wola uruchamiać etapami, opóźniając proces uruchamiania głównej aplikacji do czasu osiągnięcia konsensusu (trzy węzły są połączone i połączone, jak w powyższym przykładzie). Daje to głównej aplikacji możliwość założenia, że ​​w momencie uruchomienia klaster jest już dostępny. Ilekroć zmieni się topologia (będzie ich wiele, ponieważ węzły nie uruchamiają się całkowicie synchronicznie), zostanie wywołana procedura obsługi MyApp.Listener.on_state_change/2. W większości przypadków wykonujemy akcję po otrzymaniu komunikatu o stanie %Cloister.Monitor{status: :up}, co oznacza: „Witajcie, klaster jest złożony”.

W większości przypadków instalacja consensus: 3 jest optymalne, ponieważ nawet jeśli spodziewamy się połączenia większej liczby węzłów, wywołanie zwrotne zostanie zrealizowane status: :rehashingstatus: :up w każdym nowo dodanym lub usuniętym węźle.

Rozpoczynając pracę w trybie programistycznym, wystarczy ustawić consensus: 1 и Klasztor z radością pominie oczekiwanie na montaż klastra, gdy to zobaczy :nonode@nohostLub :node@hostLub :[email protected] - w zależności od konfiguracji węzła (:none | :shortnames | :longnames).

Zarządzanie aplikacjami rozproszonymi

Aplikacje rozproszone, które nie działają w próżni, zwykle zawierają rozproszone zależności, takie jak mnesia. Z łatwością poradzimy sobie z ich rekonfiguracją za pomocą tego samego wywołania zwrotnego on_state_change/2. Tutaj znajduje się na przykład szczegółowy opis sposobu rekonfiguracji mnesia w locie dokumentacja Klasztor.

Główną zaletą korzystania Klasztor polega na tym, że wykonuje wszystkie niezbędne operacje w celu odbudowania klastra po zmianie topologii pod maską. Aplikacja po prostu działa w przygotowanym już środowisku rozproszonym, z podłączonymi wszystkimi węzłami, niezależnie od tego, czy znamy z góry adresy IP, a co za tym idzie nazwy węzłów, czy też zostały one dynamicznie przypisane/zmienione. Nie wymaga to absolutnie żadnych specjalnych ustawień konfiguracyjnych dokera i z punktu widzenia twórcy aplikacji nie ma różnicy pomiędzy działaniem w środowisku rozproszonym a działaniem w środowisku lokalnym. :nonode@nohost. Więcej na ten temat można przeczytać w dokumentacja.

Chociaż kompleksowa obsługa zmian topologii jest możliwa dzięki niestandardowej implementacji MyApp.Listener, zawsze mogą zaistnieć przypadki brzegowe, w których ograniczenia bibliotek i błędy konfiguracyjne okażą się kamieniami węgielnymi implementacji. W porządku, po prostu weź powyższe libcluster, który jest bardziej ogólnego przeznaczenia, lub nawet samodzielnie obsługuj klaster niskiego poziomu. Celem tej biblioteki kodów nie jest uwzględnienie każdego możliwego scenariusza, ale użycie najpopularniejszego scenariusza bez niepotrzebnego bólu i uciążliwego kopiowania i wklejania.

Uwaga: w tym miejscu w oryginale było sformułowanie „Szczęśliwe grupowanie!”, a Yandex, za pomocą którego tłumaczę (sam nie muszę przeglądać słowników), zaproponował mi opcję „Szczęśliwego grupowania!” Lepszego tłumaczenia chyba nie można sobie wyobrazić, zwłaszcza w świetle obecnej sytuacji geopolitycznej.

Źródło: www.habr.com

Dodaj komentarz