Boustene van verspreide toepassings. Tweede benadering

aankondiging

Kollegas, in die middel van die somer beplan ek om nog 'n reeks artikels oor die ontwerp van toustelsels vry te stel: "The VTrade Experiment" - 'n poging om 'n raamwerk vir handelstelsels te skryf. Die reeks sal die teorie en praktyk van die bou van 'n uitruil, veiling en winkel ondersoek. Aan die einde van die artikel nooi ek jou uit om te stem vir die onderwerpe wat jou die meeste interesseer.

Boustene van verspreide toepassings. Tweede benadering

Dit is die laaste artikel in die reeks oor verspreide reaktiewe toepassings in Erlang/Elixir. IN eerste artikel jy kan die teoretiese grondslae van reaktiewe argitektuur vind. Tweede artikel illustreer die basiese patrone en meganismes vir die konstruksie van sulke stelsels.

Vandag sal ons kwessies aanroer oor die ontwikkeling van die kodebasis en projekte in die algemeen.

Organisasie van dienste

In die werklike lewe, wanneer jy 'n diens ontwikkel, moet jy dikwels verskeie interaksiepatrone in een beheerder kombineer. Byvoorbeeld, die gebruikersdiens, wat die probleem van die bestuur van projekgebruikerprofiele oplos, moet reageer op versoek-resp-versoeke en profielopdaterings via pub-sub rapporteer. Hierdie geval is redelik eenvoudig: agter boodskappe is daar een kontroleerder wat die dienslogika implementeer en opdaterings publiseer.

Die situasie word meer ingewikkeld wanneer ons 'n foutverdraagsame verspreide diens moet implementeer. Kom ons stel ons voor dat die vereistes vir gebruikers verander het:

  1. nou moet die diens versoeke op 5 cluster nodusse verwerk,
  2. in staat wees om agtergrondverwerkingstake uit te voer,
  3. en ook in staat wees om intekeninglyste vir profielopdaterings dinamies te bestuur.

Opmerking: Ons oorweeg nie die kwessie van konsekwente berging en data-replikasie nie. Kom ons neem aan dat hierdie probleme vroeër opgelos is en die stelsel het reeds 'n betroubare en skaalbare bergingslaag, en hanteerders het meganismes om daarmee in wisselwerking te tree.

Die formele beskrywing van die gebruikersdiens het meer ingewikkeld geword. Vanuit 'n programmeerder se oogpunt is veranderinge minimaal as gevolg van die gebruik van boodskappe. Om aan die eerste vereiste te voldoen, moet ons balansering by die req-resp-uitruilpunt instel.

Die vereiste om agtergrondtake te verwerk kom gereeld voor. By gebruikers kan dit die nagaan van gebruikersdokumente wees, die verwerking van afgelaaide multimedia of die sinchronisering van data met sosiale media. netwerke. Hierdie take moet op een of ander manier binne die groepering versprei word en die vordering van uitvoering moet gemonitor word. Daarom het ons twee oplossingsopsies: gebruik óf die taakverspreidingssjabloon van die vorige artikel, óf, as dit nie pas nie, skryf 'n pasgemaakte taakskeduleerder wat die poel van verwerkers sal bestuur op die manier wat ons nodig het.

Punt 3 vereis die pub-sub sjabloon uitbreiding. En vir implementering, nadat ons 'n pub-sub-uitruilpunt geskep het, moet ons die beheerder van hierdie punt ook binne ons diens bekendstel. Dit is dus asof ons die logika vir die verwerking van intekeninge en uittekens van die boodskaplaag na die implementering van gebruikers verskuif.

As gevolg hiervan het die ontbinding van die probleem getoon dat om aan die vereistes te voldoen, ons 5 gevalle van die diens op verskillende nodusse moet begin en 'n bykomende entiteit moet skep - 'n kroeg-subbeheerder, verantwoordelik vir die intekening.
Om 5 hanteerders te laat loop, hoef jy nie die dienskode te verander nie. Die enigste bykomende aksie is die opstel van balanseringsreëls by die uitruilpunt, waaroor ons 'n bietjie later sal praat.
Daar is ook 'n bykomende kompleksiteit: die pub-sub kontroleerder en pasgemaakte taakskeduleerder moet in 'n enkele kopie werk. Weereens, die boodskapdiens, as 'n fundamentele een, moet 'n meganisme verskaf om 'n leier te kies.

Leier se Keuse

In verspreide stelsels is leierverkiesing die prosedure vir die aanstelling van 'n enkele proses wat verantwoordelik is vir die skedulering van verspreide verwerking van een of ander vrag.

In stelsels wat nie geneig is tot sentralisasie nie, word universele en konsensus-gebaseerde algoritmes, soos paxos of vlot, gebruik.
Aangesien boodskappe 'n makelaar en 'n sentrale element is, weet dit van alle diensbeheerders - kandidaatleiers. Boodskappe kan 'n leier aanstel sonder om te stem.

Nadat die uitruilpunt begin en gekoppel is, ontvang alle dienste 'n stelselboodskap #'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers}. As LeaderPid val saam met pid huidige proses, is dit aangestel as die leier, en die lys Servers sluit alle nodusse en hul parameters in.
Op die oomblik dat 'n nuwe een verskyn en 'n werkende groepknoop ontkoppel word, ontvang alle diensbeheerders #'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} и #'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} onderskeidelik.

Op hierdie manier is alle komponente bewus van alle veranderinge, en die groep is gewaarborg om een ​​leier op enige gegewe tydstip te hê.

tussengangers

Om komplekse verspreide verwerkingsprosesse te implementeer, sowel as in probleme met die optimalisering van 'n bestaande argitektuur, is dit gerieflik om tussengangers te gebruik.
Om nie die dienskode te verander nie en byvoorbeeld probleme van bykomende verwerking, roetering of aanteken van boodskappe op te los, kan u 'n instaanbediener aktiveer voor die diens, wat al die bykomende werk sal verrig.

'n Klassieke voorbeeld van pub-sub-optimering is 'n verspreide toepassing met 'n besigheidskern wat opdateringsgebeurtenisse genereer, soos prysveranderings in die mark, en 'n toegangslaag - N-bedieners wat 'n websocket API vir webkliënte verskaf.
As jy reguit besluit, dan lyk kliëntediens so:

  • die kliënt vestig verbindings met die platform. Aan die kant van die bediener wat die verkeer beëindig, word 'n proses geloods om hierdie verbinding te bedien.
  • In die konteks van die diensproses vind magtiging en intekening op opdaterings plaas. Die proses noem die intekenmetode vir onderwerpe.
  • Sodra 'n gebeurtenis in die kern gegenereer is, word dit gelewer aan die prosesse wat die verbindings bedien.

Kom ons stel ons voor dat ons 50000 5 intekenare op die "nuus"-onderwerp het. Intekenare word eweredig oor 50000 bedieners versprei. Gevolglik sal elke opdatering, wat by die uitruilpunt aankom, 10000 XNUMX keer herhaal word: XNUMX XNUMX keer op elke bediener, volgens die aantal intekenare daarop. Nie 'n baie effektiewe skema nie, reg?
Om die situasie te verbeter, kom ons stel 'n instaanbediener bekend wat dieselfde naam as die uitruilpunt het. Die globale naamregistrateur moet die naaste proses by naam kan terugstuur, dit is belangrik.

Kom ons begin hierdie instaanbediener op die toegangslaagbedieners, en al ons prosesse wat die websocket-api bedien, sal daarop inteken, en nie op die oorspronklike pub-sub-uitruilpunt in die kern nie. Proxy teken slegs op die kern in in die geval van 'n unieke intekening en herhaal die inkomende boodskap aan al sy intekenare.
As gevolg hiervan sal 5 boodskappe tussen die kern en toegangsbedieners gestuur word, in plaas van 50000 XNUMX.

Roetering en balansering

Req-Resp

In die huidige boodskapimplementering is daar 7 versoekverspreidingstrategieë:

  • default. Die versoek word aan alle beheerders gestuur.
  • round-robin. Versoeke word opgesom en siklies tussen beheerders versprei.
  • consensus. Die beheerders wat die diens bedien, is verdeel in leiers en slawe. Versoeke word slegs aan die leier gestuur.
  • consensus & round-robin. Die groep het 'n leier, maar versoeke word onder alle lede versprei.
  • sticky. Die hash-funksie word bereken en aan 'n spesifieke hanteerder toegewys. Daaropvolgende versoeke met hierdie handtekening gaan na dieselfde hanteerder.
  • sticky-fun. Wanneer die uitruilpunt geïnisialiseer word, word die hash-berekeningsfunksie vir sticky balanseer.
  • fun. Soortgelyk aan taai-pret, net jy kan dit addisioneel herlei, verwerp of vooraf verwerk.

Die verspreidingstrategie word gestel wanneer die uitruilpunt geïnisialiseer word.

Benewens balansering, stel boodskappe jou in staat om entiteite te merk. Kom ons kyk na die tipe etikette in die stelsel:

  • Verbinding tag. Laat jou toe om te verstaan ​​deur watter verband die gebeure gekom het. Word gebruik wanneer 'n beheerderproses aan dieselfde uitruilpunt koppel, maar met verskillende roetesleutels.
  • Dienskaartjie. Laat jou toe om hanteerders in groepe te kombineer vir een diens en roeteer- en balanseringsvermoëns uit te brei. Vir die req-resp-patroon is roetering lineêr. Ons stuur 'n versoek na die uitruilpunt, dan gee dit dit aan die diens deur. Maar as ons die hanteerders in logiese groepe moet verdeel, dan word die verdeling gedoen met behulp van etikette. Wanneer 'n merker gespesifiseer word, sal die versoek aan 'n spesifieke groep beheerders gestuur word.
  • Versoek merker. Laat jou toe om tussen antwoorde te onderskei. Aangesien ons stelsel asynchronies is, moet ons 'n RequestTag kan spesifiseer om diensreaksies te verwerk wanneer 'n versoek gestuur word. Daaruit sal ons die antwoord kan verstaan ​​waarop versoek tot ons gekom het.

Pub-sub

Vir pub-sub is alles 'n bietjie eenvoudiger. Ons het 'n uitruilpunt waarheen boodskappe gepubliseer word. Die uitruilpunt versprei boodskappe onder intekenare wat ingeteken het op die roetesleutels wat hulle benodig (ons kan sê dat dit analoog is aan onderwerpe).

Skaalbaarheid en fouttoleransie

Die skaalbaarheid van die stelsel as geheel hang af van die mate van skaalbaarheid van die lae en komponente van die stelsel:

  • Dienste word afgeskaal deur bykomende nodusse by die groepering te voeg met hanteerders vir hierdie diens. Tydens proefwerking kan u die optimale balanseringsbeleid kies.
  • Die boodskapdiens self binne 'n afsonderlike groepering word oor die algemeen afgeskaal, óf deur veral gelaaide uitruilpunte na afsonderlike klusternodusse te skuif, óf deur volmagprosesse by te voeg tot besonder gelaaide areas van die groep.
  • Die skaalbaarheid van die hele stelsel as 'n kenmerk hang af van die buigsaamheid van die argitektuur en die vermoë om individuele groepe te kombineer in 'n gemeenskaplike logiese entiteit.

Die sukses van 'n projek hang dikwels af van die eenvoud en spoed van skaal. Boodskappe in sy huidige weergawe groei saam met die toepassing. Selfs as ons 'n groep van 50-60 masjiene kort, kan ons ons tot federasie wend. Ongelukkig val die onderwerp van federasie buite die bestek van hierdie artikel.

Bespreking

Toe ons lasbalansering ontleed het, het ons reeds oortolligheid van diensbeheerders bespreek. Boodskappe moet egter ook gereserveer word. In die geval van 'n nodus of masjienongeluk, moet boodskappe outomaties herstel, en in die kortste moontlike tyd.

In my projekte gebruik ek bykomende nodusse wat die vrag optel in geval van 'n val. Erlang het 'n standaard verspreide modus implementering vir OTP toepassings. Verspreide modus voer herstel uit in geval van mislukking deur die mislukte toepassing op 'n ander voorheen geloodsde nodus te begin. Die proses is deursigtig; na 'n mislukking skuif die toepassing outomaties na die failover-nodus. Jy kan meer oor hierdie funksionaliteit lees hier.

produktiwiteit

Kom ons probeer om ten minste rofweg die prestasie van rabbitmq en ons persoonlike boodskappe te vergelyk.
ek het gevind amptelike resultate rabbitmq-toets van die oopstapel-span.

In paragraaf 6.14.1.2.1.2.2. Die oorspronklike dokument toon die resultaat van die RPC CAST:
Boustene van verspreide toepassings. Tweede benadering

Ons sal geen bykomende instellings aan die OS-kern of erlang VM vooraf maak nie. Voorwaardes vir toetsing:

  • erl kies: +A1 +sbtu.
  • Die toets binne 'n enkele erlang-nodus word uitgevoer op 'n skootrekenaar met 'n ou i7 in mobiele weergawe.
  • Trostoetse word uitgevoer op bedieners met 'n 10G-netwerk.
  • Die kode loop in docker-houers. Netwerk in NAT-modus.

Toets kode:

req_resp_bench(_) ->
  W = perftest:comprehensive(10000,
    fun() ->
      messaging:request(?EXCHANGE, default, ping, self()),
      receive
        #'$msg'{message = pong} -> ok
      after 5000 ->
        throw(timeout)
      end
    end
  ),
  true = lists:any(fun(E) -> E >= 30000 end, W),
  ok.

Scenario 1: Die toets word op 'n skootrekenaar met 'n ou i7 mobiele weergawe uitgevoer. Die toets, boodskappe en diens word op een nodus in een Docker-houer uitgevoer:

Sequential 10000 cycles in ~0 seconds (26987 cycles/s)
Sequential 20000 cycles in ~1 seconds (26915 cycles/s)
Sequential 100000 cycles in ~4 seconds (26957 cycles/s)
Parallel 2 100000 cycles in ~2 seconds (44240 cycles/s)
Parallel 4 100000 cycles in ~2 seconds (53459 cycles/s)
Parallel 10 100000 cycles in ~2 seconds (52283 cycles/s)
Parallel 100 100000 cycles in ~3 seconds (49317 cycles/s)

Scenario 2: 3 nodusse loop op verskillende masjiene onder docker (NAT).

Sequential 10000 cycles in ~1 seconds (8684 cycles/s)
Sequential 20000 cycles in ~2 seconds (8424 cycles/s)
Sequential 100000 cycles in ~12 seconds (8655 cycles/s)
Parallel 2 100000 cycles in ~7 seconds (15160 cycles/s)
Parallel 4 100000 cycles in ~5 seconds (19133 cycles/s)
Parallel 10 100000 cycles in ~4 seconds (24399 cycles/s)
Parallel 100 100000 cycles in ~3 seconds (34517 cycles/s)

In alle gevalle het SVE-gebruik nie 250% oorskry nie

Resultate van

Ek hoop nie hierdie siklus lyk soos 'n "mind dump" nie en my ervaring sal tot groot voordeel wees vir beide navorsers van verspreide stelsels en praktisyns wat heel aan die begin is om verspreide argitekture vir hul besigheidstelsels te bou en met belangstelling na Erlang/Elixir kyk. , maar twyfel of dit die moeite werd is...

Фото @chuttersnap

Slegs geregistreerde gebruikers kan aan die opname deelneem. Meld aan, asseblief.

Watter onderwerpe moet ek in meer besonderhede dek as deel van die VTrade Experiment-reeks?

  • Teorie: Markte, bestellings en hul tydsberekening: DAG, GTD, GTC, IOC, FOK, MOO, MOC, LOO, LOC

  • Boek van bestellings. Teorie en praktyk van die implementering van 'n boek met groeperings

  • Visualisering van handel: regmerkies, stawe, besluite. Hoe om te stoor en hoe om te gom

  • Agter kantoor. Beplanning en ontwikkeling. Werknemermonitering en voorvalondersoek

  • API. Kom ons vind uit watter koppelvlakke benodig word en hoe om dit te implementeer

  • Inligtingberging: PostgreSQL, Tydskaal, Tarantool in handelstelsels

  • Reaktiwiteit in handel stelsels

  • Ander. Ek sal in die kommentaar skryf

6 gebruikers het gestem. 4 gebruikers het buite stemming gebly.

Bron: will.com

Voeg 'n opmerking