Kloster → simpel OTP-klyngestyring

Næsten enhver succesfuld forretningsapplikation går før eller siden ind i en fase, hvor horisontal skalering er påkrævet. I mange tilfælde kan du blot starte en ny instans og reducere belastningsgennemsnittet. Men der er også mindre trivielle tilfælde, hvor vi skal sikre, at forskellige noder kender til hinanden og omhyggeligt fordeler arbejdsbyrden.

Kloster → simpel OTP-klyngestyring

Det viste sig så heldigt opnået, som vi valgte for sin behagelige syntaks og hype omkring det, har en førsteklasses understøttelse af distribuerede systemer. I teorien lyder dette fuldstændig trivielt:

Beskeder, der sendes mellem processer på forskellige noder, såvel som mellem links og skærme, er gennemsigtig […]

I praksis er alt lidt mere kompliceret. Uddelt opnået blev udviklet, da "container" betød en stor jernkasse til forsendelse, og "docker" blot var et synonym for longshoreman. I IP4 der var mange ubesatte adresser, netværksbrud var normalt forårsaget af rotter, der tyggede gennem kablet, og produktionssystemets gennemsnitlige oppetid blev målt i årtier.

Nu er vi alle utroligt selvforsynende, pakket ind og kører distribueret opnået i et miljø, hvor dynamiske IP-adresser uddeles ud fra princippet om stor tilfældighed, og noder kan dukke op og forsvinde efter indfald af planlæggerens venstre hæl. For at undgå bunker af boilerplate-kode i hvert projekt, der kører en distribueret opnået, for at bekæmpe det fjendtlige miljø kræves der hjælp.

Bemærk: Jeg er klar over, at der er libcluster. Det er virkelig fedt, det har over tusind stjerner, forfatteren er berømt i samfundet, og alt det der. Hvis de metoder, som denne pakke tilbyder til at oprette og vedligeholde en klynge, er nok for dig, er jeg glad på dine vegne. Jeg har desværre brug for meget mere. Jeg vil kontrollere opsætningen i detaljer og ikke være en udefrakommende tilskuer i teatret for klyngreorganisering.

Krav

Det, jeg personligt havde brug for, var et bibliotek, der ville overtage ledelsen af ​​klyngen og ville have følgende egenskaber:

  • gennemsigtigt arbejde med både en hårdkodet liste over noder og dynamisk opdagelse gennem tjenester opnået;
  • fuldt funktionelt tilbagekald for hver topologiændring (node ​​der, node her, netværksustabilitet, opdelinger);
  • gennemsigtig grænseflade til lancering af en klynge med lange og korte navne, som med :nonode@nohost;
  • Docker-support ud af boksen uden at skulle skrive infrastrukturkode.

Det sidste betyder, at efter at jeg har testet applikationen lokalt i :nonode@nohost, eller i et kunstigt distribueret miljø ved hjælp af test_cluster_task, jeg vil bare løbe docker-compose up --scale my_app=3 og se, hvordan den udfører tre forekomster i docker uden nogen kodeændringer. Jeg ønsker også afhængige applikationer som mnesia - når topologien ændrer sig, bag kulisserne genopbygger de klyngen live uden yderligere kick fra applikationen.

Kloster var ikke beregnet til at være et bibliotek, der kunne alt fra at støtte en klynge til at lave kaffe. Det er ikke en sølvkugle, der har til formål at dække alle mulige sager, eller være en faglig komplet løsning i den forstand, at teoretikere fra CS lagt ind i dette udtryk. Dette bibliotek er designet til at tjene et meget klart formål, men udfører sit ikke alt for store arbejde perfekt. Dette mål vil være at give fuldstændig gennemsigtighed mellem det lokale udviklingsmiljø og et distribueret elastisk miljø fyldt med fjendtlige containere.

Valgt tilgang

Kloster er beregnet til at blive kørt som en applikation, selvom avancerede brugere kan arbejde med montering og vedligeholdelse af klyngen manuelt ved direkte at køre Cloister.Manager i målapplikationens supervisor-træ.

Når det køres som en applikation, er biblioteket afhængigt af config, hvorfra den læser følgende grundlæggende værdier:

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

Ovenstående parametre betyder bogstaveligt talt følgende: Kloster bruges til OTP-applikation :my_app, bruger erlang service discovery at forbinde noder, mindst tre, og MyApp.Listener modul (implementering @behaviour Cloister.Listener) er konfigureret til at modtage meddelelser om topologiændringer. En detaljeret beskrivelse af den komplette konfiguration kan findes i dokumentation.

Med denne konfiguration vil applikationen Kloster vil lancering i etaper, forsinke processen med at starte hovedapplikationen, indtil konsensus er opnået (tre noder er forbundet og forbundet, som i eksemplet ovenfor.) Dette giver hovedapplikationen mulighed for at antage, at når den starter, er klyngen allerede tilgængelig. Når topologien ændres (der vil være mange af dem, fordi noderne ikke starter helt synkront), vil handleren blive kaldt MyApp.Listener.on_state_change/2. Det meste af tiden udfører vi en handling, når vi modtager en statusmeddelelse %Cloister.Monitor{status: :up}, hvilket betyder: "Hej, klyngen er samlet."

I de fleste tilfælde installation consensus: 3 er optimal, fordi selvom vi forventer, at flere noder forbindes, vil tilbagekaldet gå igennem status: :rehashingstatus: :up på enhver ny tilføjet eller fjernet node.

Når du starter i udviklingstilstand, skal du blot indstille consensus: 1 и Kloster vil med glæde springe ventetiden på klyngesamling over, når han ser :nonode@nohostEller :node@hostEller :[email protected] - afhængig af hvordan noden blev konfigureret (:none | :shortnames | :longnames).

Distribueret applikationsstyring

Distribuerede applikationer, der ikke er i et vakuum, omfatter normalt distribuerede afhængigheder, som f.eks mnesia. Det er nemt for os at håndtere deres omkonfiguration fra det samme tilbagekald on_state_change/2. Her er for eksempel en detaljeret beskrivelse af, hvordan du omkonfigurerer mnesia på flugt ind dokumentation Kloster.

Den største fordel ved at bruge Kloster er, at den udfører alle de nødvendige operationer for at genopbygge klyngen efter en topologiændring under kølerhjelmen. Applikationen kører ganske enkelt i et allerede forberedt distribueret miljø, med alle noder tilsluttet, uanset om vi kender IP-adresserne og dermed nodenavnene på forhånd, eller de er blevet dynamisk tildelt/ændret. Dette kræver absolut ingen specielle docker-konfigurationsindstillinger, og fra en applikationsudviklers synspunkt er der ingen forskel mellem at køre i et distribueret miljø eller at køre i et lokalt. :nonode@nohost. Det kan du læse mere om i dokumentation.

Selvom kompleks håndtering af topologiændringer er mulig gennem en tilpasset implementering MyApp.Listener, kan der altid være edge-tilfælde, hvor disse biblioteksbegrænsninger og konfigurationsbias viser sig at være hjørnestenene i implementeringen. Det er ok, tag blot ovenstående libcluster, som er mere generelle, eller endda håndtere lav-niveau klyngen selv. Målet med dette kodebibliotek er ikke at dække alle mulige scenarier, men at bruge det mest almindelige scenarie uden unødvendig smerte og besværlig copy-paste.

Note: på dette tidspunkt i originalen var der sætningen "Happy clustering!", og Yandex, som jeg oversætter med (jeg behøver ikke selv at gå gennem ordbøger), tilbød mig muligheden "Happy clustering!" Det er måske umuligt at forestille sig en bedre oversættelse, især i lyset af den aktuelle geopolitiske situation.

Kilde: www.habr.com

Tilføj en kommentar