Hajutatud rakenduste ehitusplokid. Teine lähendus

Kuulutus

Kolleegid, plaanin suve keskel välja anda veel ühe artiklite seeria järjekorrasüsteemide kujundamise kohta: “The VTrade Experiment” - katse kirjutada kauplemissüsteemide raamistik. Sarjas uuritakse börsi, oksjoni ja poe ehitamise teooriat ja praktikat. Artikli lõpus kutsun teid hääletama nende teemade poolt, mis teid enim huvitavad.

Hajutatud rakenduste ehitusplokid. Teine lähendus

See on Erlangi/Elixiri hajutatud reaktiivrakenduste sarja viimane artikkel. IN esimene artikkel leiate reaktiivarhitektuuri teoreetilised alused. Teine artikkel illustreerib selliste süsteemide ehitamise põhimustreid ja mehhanisme.

Täna tõstatame koodibaasi arendamise ja üldiselt projektide küsimused.

Teenuste korraldamine

Reaalses elus tuleb teenust arendades sageli ühes kontrolleris kombineerida mitu interaktsioonimustrit. Näiteks kasutajateenus, mis lahendab projekti kasutajaprofiilide haldamise probleemi, peab vastama req-resp päringutele ja teavitama profiili uuendustest pub-sub kaudu. See juhtum on üsna lihtne: sõnumite saatmise taga on üks kontroller, mis rakendab teenindusloogikat ja avaldab värskendusi.

Olukord muutub keerulisemaks, kui meil on vaja rakendada tõrketaluvusega hajutatud teenust. Kujutagem ette, et nõuded kasutajatele on muutunud:

  1. nüüd peaks teenus töötlema taotlusi 5 klastri sõlmes,
  2. oskama taustatöötlusülesandeid täita,
  3. ja samuti saab dünaamiliselt hallata profiilivärskenduste tellimuste loendeid.

Märkus: Me ei käsitle järjepideva salvestamise ja andmete replikatsiooni küsimust. Oletame, et need probleemid on varem lahendatud ja süsteemil on juba usaldusväärne ja skaleeritav salvestuskiht ning töötlejatel on mehhanismid sellega suhtlemiseks.

Kasutajateenuse formaalne kirjeldamine on muutunud keerulisemaks. Programmeerija seisukohast on sõnumivahetuse kasutamise tõttu muudatused minimaalsed. Esimese nõude täitmiseks peame konfigureerima tasakaalustamise req-resp vahetuspunktis.

Taustaülesannete töötlemise nõue esineb sageli. Kasutajate puhul võib see olla kasutaja dokumentide kontrollimine, allalaaditud multimeediumi töötlemine või andmete sünkroonimine sotsiaalmeediaga. võrgud. Need ülesanded tuleb klastris kuidagi jaotada ja täitmise edenemist jälgida. Seetõttu on meil kaks lahendusvõimalust: kas kasutada eelmise artikli ülesannete jaotamise malli või kui see ei sobi, siis kirjutada kohandatud ülesannete ajakava, mis haldab protsessorite kogumit meile vajalikul viisil.

Punkt 3 nõuab pub-alammalli laiendit. Ja rakendamiseks peame pärast pubi-alamvahetuspunkti loomist täiendavalt käivitama selle punkti kontrolleri meie teenuses. Seega justkui viime tellimuste ja tellimuste töötlemise loogika sõnumikihist kasutajate juurutusse.

Selle tulemusena näitas probleemi dekomponeerimine, et nõuete täitmiseks peame käivitama 5 teenuse eksemplari erinevates sõlmedes ja looma lisaüksuse - abonemendi eest vastutava pubi-alamkontrolleri.
5 töötleja käitamiseks ei pea te teenusekoodi muutma. Ainus lisategevus on tasakaalustusreeglite seadistamine vahetuspunktis, millest räägime veidi hiljem.
Samuti on täiendav keerukus: pub-alamkontroller ja kohandatud ülesannete ajakava peavad töötama ühes eksemplaris. Jällegi, sõnumiteenus kui põhiline teenus peab pakkuma juhi valimise mehhanismi.

Juhi valik

Hajussüsteemides on juhi valimine protseduur ühe protsessi määramiseks, mis vastutab mõne koormuse hajutatud töötlemise ajastamise eest.

Süsteemides, mis ei ole tsentraliseerimisele kalduvad, kasutatakse universaalseid ja konsensusepõhiseid algoritme, nagu paxos või raft.
Kuna sõnumside on vahendaja ja keskne element, siis teab see kõiki teenusekontrollereid – kandidaate. Sõnumside saab määrata juhi ilma hääletamiseta.

Pärast vahetuspunkti käivitamist ja sellega ühenduse loomist saavad kõik teenused süsteemiteate #'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers}. Kui LeaderPid langeb kokku pid praegust protsessi, määratakse see juhiks ja nimekirja Servers sisaldab kõiki sõlme ja nende parameetreid.
Hetkel ilmub uus ja töötav klastri sõlm on lahti ühendatud, saavad kõik teenusekontrollerid #'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} и #'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} võrra.

Nii on kõik komponendid kõikidest muudatustest teadlikud ja klastris on igal ajahetkel garanteeritud üks juht.

Vahendajad

Keeruliste hajutatud töötlemisprotsesside rakendamiseks, aga ka olemasoleva arhitektuuri optimeerimise probleemide korral on mugav kasutada vahendajaid.
Teenuse koodi mitte muutmiseks ja näiteks sõnumite täiendava töötlemise, marsruutimise või logimise probleemide lahendamiseks saate enne teenust lubada puhverserveri töötleja, mis teeb kõik lisatööd.

Pub-sub optimeerimise klassikaline näide on hajutatud rakendus, millel on ärituum, mis genereerib värskendussündmusi, nagu hinnamuutused turul, ja juurdepääsukiht – N serverit, mis pakuvad veebiklientidele veebisoketi API-d.
Kui otsustate otsekohe, näeb klienditeenindus välja järgmine:

  • klient loob platvormiga ühendused. Liiklust lõpetava serveri poolel käivitatakse selle ühenduse teenindamiseks protsess.
  • Teenindusprotsessi kontekstis toimub autoriseerimine ja värskenduste tellimine. Protsess kutsub välja teemade tellimismeetodi.
  • Kui sündmus on kernelis genereeritud, edastatakse see ühendusi teenindavatele protsessidele.

Kujutagem ette, et meil on "uudiste" teemal 50000 5 tellijat. Abonendid on jaotatud ühtlaselt 50000 serveri vahel. Selle tulemusel kopeeritakse iga vahetuspunkti saabuvat värskendust 10000 XNUMX korda: XNUMX XNUMX korda igas serveris, vastavalt sellel olevate abonentide arvule. Pole eriti tõhus skeem, eks?
Olukorra parandamiseks tutvustame puhverserverit, mis kannab vahetuspunktiga sama nime. Globaalne nimeregistripidaja peab suutma lähima protsessi nime järgi tagastada, see on oluline.

Käivitame selle puhverserveri juurdepääsukihi serverites ja kõik meie veebipesa api teenindavad protsessid tellivad selle, mitte kerneli algse pub-sub vahetuspunkti. Puhverserver tellib tuuma ainult kordumatu tellimuse korral ja kordab sissetulevat sõnumit kõigile oma abonentidele.
Selle tulemusena saadetakse kerneli ja juurdepääsuserverite vahel 5 50000 sõnumi asemel XNUMX sõnumit.

Marsruutimine ja tasakaalustamine

Req-Resp

Praeguses sõnumsiderakenduses on 7 päringute levitamise strateegiat:

  • default. Taotlus saadetakse kõigile kontrolleritele.
  • round-robin. Taotlused loetletakse ja jaotatakse tsükliliselt kontrollerite vahel.
  • consensus. Teenust teenindavad kontrollerid jagunevad juhtideks ja orjadeks. Taotlused saadetakse ainult juhile.
  • consensus & round-robin. Rühmal on juht, kuid taotlused jaotatakse kõigi liikmete vahel.
  • sticky. Räsifunktsioon arvutatakse ja määratakse konkreetsele töötlejale. Selle allkirjaga edasised päringud lähevad samale töötlejale.
  • sticky-fun. Vahetuspunkti lähtestamisel kasutatakse räsi arvutamise funktsiooni jaoks sticky tasakaalustamine.
  • fun. Sarnaselt kleepuva lõbuga saate selle täiendavalt ümber suunata, tagasi lükata või eeltöödelda ainult teie.

Jaotusstrateegia määratakse vahetuspunkti initsialiseerimisel.

Lisaks tasakaalustamisele võimaldab sõnumside teil olemeid sildistada. Vaatame süsteemis olevate siltide tüüpe:

  • Ühenduse silt. Võimaldab mõista, mis seose kaudu sündmused tulid. Kasutatakse siis, kui kontrolleri protsess loob ühenduse sama vahetuspunktiga, kuid erinevate marsruutimisvõtmetega.
  • Hooldusmärgis. Võimaldab ühendada töötlejad rühmadesse ühe teenuse jaoks ning laiendada marsruutimise ja tasakaalustamise võimalusi. Req-resp mustri puhul on marsruutimine lineaarne. Saadame päringu vahetuspunkti, seejärel edastatakse see teenindusele. Aga kui peame jagama töötlejad loogilisteks rühmadeks, siis jagamine toimub siltide abil. Sildi määramisel saadetakse päring kindlale kontrollerite rühmale.
  • Taotle märgendit. Võimaldab vastuseid eristada. Kuna meie süsteem on asünkroonne, peame teenuse vastuste töötlemiseks suutma päringu saatmisel määrata RequestTagi. Sellest saame aru vastusest, millisele päringule meieni jõudis.

Pub-sub

Pubide jaoks on kõik veidi lihtsam. Meil on vahetuspunkt, kuhu sõnumeid avaldatakse. Vahetuspunkt jagab teated nende abonentide vahel, kes on tellinud neile vajalikud marsruutimisvõtmed (võime öelda, et see on analoogne teemadega).

Skaleeritavus ja veataluvus

Süsteemi kui terviku skaleeritavus sõltub süsteemi kihtide ja komponentide skaleeritavuse astmest:

  • Teenused skaleeritakse, lisades selle teenuse käitlejatega klastrisse täiendavaid sõlme. Proovitöö ajal saate valida optimaalse tasakaalustuspoliitika.
  • Sõnumiteenust ennast eraldi klastris skaleeritakse üldiselt kas eriti koormatud vahetuspunktide teisaldamisega eraldi klastri sõlmedesse või puhverserveri protsesside lisamisega klastri eriti koormatud aladele.
  • Kogu süsteemi kui tunnuse skaleeritavus sõltub arhitektuuri paindlikkusest ja võimalusest ühendada üksikud klastrid ühiseks loogiliseks üksuseks.

Projekti edukus sõltub sageli skaleerimise lihtsusest ja kiirusest. Sõnumid selle praeguses versioonis kasvavad koos rakendusega. Isegi kui meil puudub 50–60 masinast koosnev klaster, võime pöörduda föderatsiooni poole. Kahjuks jääb föderatsiooni teema sellest artiklist välja.

Reserveerimine

Koormuse tasakaalustamise analüüsimisel käsitlesime juba teeninduskontrollerite koondamist. Kuid ka sõnumid tuleb reserveerida. Sõlme või masina krahhi korral peaks sõnumivahetus automaatselt taastuma ja võimalikult lühikese aja jooksul.

Oma projektides kasutan lisasõlmesid, mis kukkumise korral koormuse üles võtavad. Erlangil on OTP-rakenduste jaoks standardne hajutatud režiimi rakendamine. Hajutatud režiim teostab tõrke korral taastamise, käivitades ebaõnnestunud rakenduse mõnes teises varem käivitatud sõlmes. Protsess on läbipaistev, pärast riket liigub rakendus automaatselt tõrkesiirdesõlme. Lisateavet selle funktsiooni kohta saate lugeda siin.

Производительность

Proovime vähemalt ligikaudselt võrrelda rabbitmq ja meie kohandatud sõnumite toimivust.
ma leidsin ametlikud tulemused rabbitmq testimine openstacki meeskonnalt.

Punktis 6.14.1.2.1.2.2. Algdokument näitab RPC CASTi tulemust:
Hajutatud rakenduste ehitusplokid. Teine lähendus

Me ei tee OS-i kernelile ega erlangi VM-ile eelnevalt mingeid lisaseadeid. Testimise tingimused:

  • erl valib: +A1 +sbtu.
  • Test ühes erlangi sõlmes käivitatakse sülearvutis, mille mobiiliversioon on vana i7.
  • Klastritestid viiakse läbi 10G võrguga serverites.
  • Kood töötab dokkimiskonteinerites. Võrk NAT-režiimis.

Testi kood:

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.

1. stsenaarium: Testi tehakse vana i7 mobiiliversiooniga sülearvutiga. Test, sõnumivahetus ja teenus teostatakse ühes Dockeri konteineri ühes sõlmes:

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)

2. stsenaarium: 3 sõlme, mis töötavad erinevatel masinatel dockeri (NAT) all.

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)

Kõigil juhtudel ei ületanud protsessori kasutamine 250%

Tulemused

Loodan, et see tsükkel ei näe välja nagu mõttetuisk ja minu kogemusest on tõeliselt kasu nii hajutatud süsteemide uurijatele kui ka praktikutele, kes on oma ärisüsteemidele hajutatud arhitektuuri loomise alguses ja vaatavad huviga Erlangi/Elixiri. , kuid kahtle, kas see on seda väärt...

Photo Shoot @chuttersnap

Küsitluses saavad osaleda ainult registreerunud kasutajad. Logi sissepalun.

Milliseid teemasid peaksin VTrade Experiment sarja raames üksikasjalikumalt käsitlema?

  • Teooria: Turud, tellimused ja nende ajastus: DAY, GTD, GTC, IOC, FOK, MOO, MOC, LOO, LOC

  • Tellimuste raamat. Rühmitustega raamatu rakendamise teooria ja praktika

  • Kauplemise visualiseerimine: puugid, ribad, resolutsioonid. Kuidas säilitada ja kuidas liimida

  • Backoffice. Planeerimine ja arendus. Töötajate jälgimine ja juhtumite uurimine

  • API. Mõelgem välja, milliseid liideseid on vaja ja kuidas neid rakendada

  • Teabe salvestamine: PostgreSQL, Timescale, Tarantool kauplemissüsteemides

  • Reaktiivsus kauplemissüsteemides

  • muud. Kirjutan kommentaaridesse

6 kasutajat hääletas. 4 kasutajat jäi erapooletuks.

Allikas: www.habr.com

Lisa kommentaar