Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Fl-aħħar artikolu Aħna eżaminajna l-pedamenti teoretiċi tal-arkitettura reattiva. Wasal iż-żmien li nitkellmu dwar il-flussi tad-dejta, modi kif jiġu implimentati sistemi reattivi Erlang/Elixir u mudelli ta’ messaġġi fihom:

  • Talba-tweġiba
  • Rispons Talba-Chunked
  • Risposta b'Talba
  • Ippubblika-abbona
  • Inverted Publish-abbona
  • Distribuzzjoni tal-kompitu

SOA, MSA u Messaging

SOA, MSA huma arkitetturi tas-sistema li jiddefinixxu r-regoli għas-sistemi tal-bini, filwaqt li l-messaġġi jipprovdu primittivi għall-implimentazzjoni tagħhom.

Ma rridx nippromwovi din jew dik l-arkitettura tas-sistema. Jien għall-użu tal-prattiki l-aktar effettivi u utli għal proġett u negozju speċifiku. Tkun xi tkun il-paradigma li nagħżlu, huwa aħjar li noħolqu blokki tas-sistema b'għajnejk fuq il-mod Unix: komponenti b'konnettività minima, responsabbli għal entitajiet individwali. Il-metodi API jwettqu l-aktar azzjonijiet sempliċi possibbli ma 'entitajiet.

Il-messaġġi huma, kif jissuġġerixxi l-isem, sensar tal-messaġġi. L-għan ewlieni tiegħu huwa li jirċievi u jibgħat messaġġi. Huwa responsabbli għall-interfaces biex tintbagħat l-informazzjoni, il-formazzjoni ta 'kanali loġiċi għat-trażmissjoni ta' informazzjoni fis-sistema, ir-rotot u l-ibbilanċjar, kif ukoll l-immaniġġjar tal-ħsarat fil-livell tas-sistema.
Il-messagg li qed niżviluppaw mhux qed jipprova jikkompeti jew jissostitwixxi l-fenekmq. Il-karatteristiċi ewlenin tiegħu:

  • Distribuzzjoni.
    Jistgħu jinħolqu punti ta' skambju fuq in-nodi tal-clusters kollha, qrib kemm jista' jkun tal-kodiċi li jużahom.
  • Is-sempliċità
    Iffoka fuq il-minimizzazzjoni tal-kodiċi tal-boilerplate u l-faċilità tal-użu.
  • Prestazzjoni aħjar.
    Aħna mhux qed nippruvaw nirrepetu l-funzjonalità tal-fenekmq, iżda nenfasizzaw biss is-saff arkitettoniku u tat-trasport, li noqogħdu fl-OTP bl-aktar mod sempliċi possibbli, u jimminimizzaw l-ispejjeż.
  • Flessibilità.
    Kull servizz jista 'jgħaqqad ħafna mudelli ta' skambju.
  • Reżiljenza mid-disinn.
  • Skalabbiltà.
    Il-messaġġi jikbru mal-applikazzjoni. Hekk kif it-tagħbija tiżdied, tista 'tmexxi l-punti ta' skambju għal magni individwali.

Kumment. F'termini ta 'organizzazzjoni tal-kodiċi, il-meta-proġetti huma adattati tajjeb għal sistemi Erlang/Elixir kumplessi. Il-kodiċi tal-proġett kollu jinsab f'repożitorju wieħed - proġett umbrella. Fl-istess ħin, il-mikroservizzi huma iżolati b'mod massimu u jwettqu operazzjonijiet sempliċi li huma responsabbli għal entità separata. B'dan l-approċċ, huwa faċli li tinżamm l-API tas-sistema kollha, huwa faċli li tagħmel bidliet, huwa konvenjenti li tikteb testijiet ta 'unità u integrazzjoni.

Il-komponenti tas-sistema jinteraġixxu direttament jew permezz ta 'sensar. Mill-perspettiva tal-messaġġi, kull servizz għandu diversi fażijiet tal-ħajja:

  • Inizjalizzazzjoni tas-servizz.
    F'dan l-istadju, il-proċess u d-dipendenzi li jeżegwixxu s-servizz huma kkonfigurati u mnedija.
  • Ħolqien ta 'punt ta' skambju.
    Is-servizz jista 'juża punt ta' skambju statiku speċifikat fil-konfigurazzjoni tan-nodu, jew joħloq punti ta 'skambju b'mod dinamiku.
  • Reġistrazzjoni tas-servizz.
    Sabiex is-servizz jaqdi t-talbiet, irid ikun irreġistrat fil-punt tal-iskambju.
  • Funzjonament normali.
    Is-servizz jipproduċi xogħol utli.
  • Għalaq.
    Hemm 2 tipi ta 'għeluq possibbli: normali u ta' emerġenza. Waqt it-tħaddim normali, is-servizz jiġi skonnettjat mill-punt tal-iskambju u jieqaf. F'sitwazzjonijiet ta' emerġenza, il-messaġġi jesegwixxi waħda mill-iskripts ta' failover.

Jidher pjuttost ikkumplikat, iżda l-kodiċi mhux dak kollu tal-biża '. Eżempji ta' kodiċi b'kummenti se jingħataw fl-analiżi tal-mudelli ftit aktar tard.

Skambji

Punt ta 'skambju huwa proċess ta' messaġġi li jimplimenta l-loġika ta 'interazzjoni ma' komponenti fi ħdan il-mudell ta 'messaġġi. Fl-eżempji kollha ppreżentati hawn taħt, il-komponenti jinteraġixxu permezz ta 'punti ta' skambju, li l-kombinazzjoni tagħhom tifforma messaġġi.

Mudelli ta' skambju ta' messaġġi (MEPs)

Globalment, mudelli ta 'skambju jistgħu jinqasmu f'żewġ direzzjonijiet u f'direzzjoni waħda. L-ewwel jimplikaw rispons għal messaġġ li jkun dieħel, l-aħħar le. Eżempju klassiku ta 'mudell bidirezzjonali fl-arkitettura klijent-server huwa l-mudell Request-response. Ejja nħarsu lejn il-mudell u l-modifiki tiegħu.

Talba-tweġiba jew RPC

RPC jintuża meta jkollna bżonn nirċievu tweġiba minn proċess ieħor. Dan il-proċess jista' jkun qed jaħdem fuq l-istess node jew jinsab f'kontinent differenti. Hawn taħt hemm dijagramma tal-interazzjoni bejn il-klijent u s-server permezz tal-messaġġi.

Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Peress li l-messaġġi huma kompletament asinkroniċi, għall-klijent l-iskambju huwa maqsum f'2 fażijiet:

  1. Mittenti talba

    messaging:request(Exchange, ResponseMatchingTag, RequestDefinition, HandlerProcess).

    skambju ‒ isem uniku tal-punt tal-iskambju
    ResponseMatchingTag ‒ tikketta lokali għall-ipproċessar tar-rispons. Pereżempju, fil-każ li jintbagħtu diversi talbiet identiċi li jappartjenu għal utenti differenti.
    TalbaDefinizzjoni - korp tat-talba
    HandlerProcess ‒ PID tal-handler. Dan il-proċess se jirċievi tweġiba mis-server.

  2. Ipproċessa r-rispons

    handle_info(#'$msg'{exchange = EXCHANGE, tag = ResponseMatchingTag,message = ResponsePayload}, State)

    RisponsPayload - rispons tas-server.

Għas-server, il-proċess jikkonsisti wkoll f'2 fażijiet:

  1. Inizjalizzazzjoni tal-punt tal-iskambju
  2. Ipproċessar ta' talbiet riċevuti

Ejja nuru dan il-mudell bil-kodiċi. Ejja ngħidu li għandna bżonn nimplimentaw servizz sempliċi li jipprovdi metodu wieħed eżatt tal-ħin.

Kodiċi tas-server

Ejja niddefinixxu l-API tas-servizz f'api.hrl:

%% =====================================================
%%  entities
%% =====================================================
-record(time, {
  unixtime :: non_neg_integer(),
  datetime :: binary()
}).

-record(time_error, {
  code :: non_neg_integer(),
  error :: term()
}).

%% =====================================================
%%  methods
%% =====================================================
-record(time_req, {
  opts :: term()
}).
-record(time_resp, {
  result :: #time{} | #time_error{}
}).

Ejja niddefinixxu l-kontrollur tas-servizz f'time_controller.erl

%% В примере показан только значимый код. Вставив его в шаблон gen_server можно получить рабочий сервис.

%% инициализация gen_server
init(Args) ->
  %% подключение к точке обмена
  messaging:monitor_exchange(req_resp, ?EXCHANGE, default, self())
  {ok, #{}}.

%% обработка события потери связи с точкой обмена. Это же событие приходит, если точка обмена еще не запустилась.
handle_info(#exchange_die{exchange = ?EXCHANGE}, State) ->
  erlang:send(self(), monitor_exchange),
  {noreply, State};

%% обработка API
handle_info(#time_req{opts = _Opts}, State) ->
  messaging:response_once(Client, #time_resp{
result = #time{ unixtime = time_utils:unixtime(now()), datetime = time_utils:iso8601_fmt(now())}
  });
  {noreply, State};

%% завершение работы gen_server
terminate(_Reason, _State) ->
  messaging:demonitor_exchange(req_resp, ?EXCHANGE, default, self()),
  ok.

Kodiċi tal-klijent

Sabiex tibgħat talba lis-servizz, tista' ċċempel lill-API ta' rikjesta għall-messaġġi kullimkien fil-klijent:

case messaging:request(?EXCHANGE, tag, #time_req{opts = #{}}, self()) of
    ok -> ok;
    _ -> %% repeat or fail logic
end

F'sistema mqassma, il-konfigurazzjoni tal-komponenti tista 'tkun differenti ħafna u fil-ħin tat-talba, il-messaġġi jistgħu għadhom ma jibdewx, jew il-kontrollur tas-servizz mhux se jkun lest biex iservi t-talba. Għalhekk, għandna bżonn niċċekkjaw ir-rispons tal-messaġġi u nittrattaw il-każ tal-falliment.
Wara li jintbagħat b'suċċess, il-klijent jirċievi tweġiba jew żball mis-servizz.
Ejja nittrattaw iż-żewġ każijiet f'handle_info:

handle_info(#'$msg'{exchange = ?EXCHANGE, tag = tag, message = #time_resp{result = #time{unixtime = Utime}}}, State) ->
  ?debugVal(Utime),
  {noreply, State};

handle_info(#'$msg'{exchange = ?EXCHANGE, tag = tag, message = #time_resp{result = #time_error{code = ErrorCode}}}, State) ->
  ?debugVal({error, ErrorCode}),
  {noreply, State};

Rispons Talba-Chunked

L-aħjar li tevita li tibgħat messaġġi kbar. Ir-rispons u l-operat stabbli tas-sistema kollha jiddependu minn dan. Jekk ir-rispons għal mistoqsija jieħu ħafna memorja, allura l-qsim f'partijiet huwa obbligatorju.

Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Ħa nagħtikom ftit eżempji ta’ każijiet bħal dawn:

  • Il-komponenti jiskambjaw data binarja, bħal fajls. It-tkissir tar-rispons f'partijiet żgħar jgħinek taħdem b'mod effiċjenti b'fajls ta 'kull daqs u tevita l-overflows tal-memorja.
  • Listi. Pereżempju, għandna bżonn nagħżlu r-rekords kollha minn tabella enormi fid-database u tittrasferihom għal komponent ieħor.

Jien insejjaħ dawn ir-reazzjonijiet lokomottivi. Fi kwalunkwe każ, 1024 messaġġ ta' 1 MB huma aħjar minn messaġġ wieħed ta' 1 GB.

Fil-cluster Erlang, niksbu benefiċċju addizzjonali - tnaqqas it-tagħbija fuq il-punt tal-iskambju u n-netwerk, peress li r-risposti jintbagħtu immedjatament lir-riċevitur, billi jinjora l-punt tal-iskambju.

Risposta b'Talba

Din hija modifika pjuttost rari tal-mudell RPC għall-bini ta 'sistemi ta' djalogu.

Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Publish-subscribe (siġra tad-distribuzzjoni tad-dejta)

Sistemi mmexxija mill-avvenimenti jwassluhom lill-konsumaturi hekk kif id-dejta tkun lesta. Għalhekk, is-sistemi huma aktar suxxettibbli għal mudell push milli għal mudell pull jew poll. Din il-karatteristika tippermettilek tevita li taħli r-riżorsi billi titlob u tistenna kontinwament id-dejta.
Il-figura turi l-proċess ta 'distribuzzjoni ta' messaġġ lill-konsumaturi abbonati għal suġġett speċifiku.

Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Eżempji klassiċi tal-użu ta 'dan il-mudell huma d-distribuzzjoni tal-istat: id-dinja tal-logħob fil-logħob tal-kompjuter, id-dejta tas-suq dwar l-iskambji, l-informazzjoni utli fid-data feeds.

Ejja nħarsu lejn il-kodiċi tal-abbonat:

init(_Args) ->
  %% подписываемся на обменник, ключ = key
  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),
  {ok, #{}}.

handle_info(#exchange_die{exchange = ?SUBSCRIPTION}, State) ->
  %% если точка обмена недоступна, то пытаемся переподключиться
  messaging:subscribe(?SUBSCRIPTION, key, tag, self()),
  {noreply, State};

%% обрабатываем пришедшие сообщения
handle_info(#'$msg'{exchange = ?SUBSCRIPTION, message = Msg}, State) ->
  ?debugVal(Msg),
  {noreply, State};

%% при остановке потребителя - отключаемся от точки обмена
terminate(_Reason, _State) ->
  messaging:unsubscribe(?SUBSCRIPTION, key, tag, self()),
  ok.

Is-sors jista' jsejjaħ il-funzjoni biex jippubblika messaġġ fi kwalunkwe post konvenjenti:

messaging:publish_message(Exchange, Key, Message).

skambju - isem il-punt tal-iskambju,
Ewlenin - ċavetta tar-rotta
messaġġ - tagħbija

Inverted Publish-abbona

Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Billi tespandi pub-sub, tista 'tikseb mudell konvenjenti għall-illoggjar. Is-sett ta 'sorsi u konsumaturi jistgħu jkunu kompletament differenti. Il-figura turi każ b'konsumatur wieħed u sorsi multipli.

Mudell tad-distribuzzjoni tal-kompitu

Kważi kull proġett jinvolvi ħidmiet ta' pproċessar differit, bħall-ġenerazzjoni ta' rapporti, it-twassil ta' notifiki, u l-irkupru ta' data minn sistemi ta' partijiet terzi. It-throughput tas-sistema li twettaq dawn il-kompiti jista 'jiġi skalat faċilment billi jiżdiedu handlers. Kulma jibqa' għalina huwa li niffurmaw grupp ta' proċessuri u nqassmu l-kompiti bejniethom b'mod ugwali.

Ejja nħarsu lejn is-sitwazzjonijiet li jinqalgħu billi tuża l-eżempju ta '3 handlers. Anke fl-istadju tad-distribuzzjoni tal-kompiti, tqum il-kwistjoni tal-ġustizzja tad-distribuzzjoni u l-overflow tal-handlers. Id-distribuzzjoni round-robin se tkun responsabbli għall-ġustizzja, u biex tiġi evitata sitwazzjoni ta 'overflow ta' handlers, se nintroduċu restrizzjoni prefetch_limit. F'kundizzjonijiet temporanji prefetch_limit se jipprevjeni handler wieħed milli jirċievi l-kompiti kollha.

Il-messaġġi jimmaniġġjaw il-kjuwijiet u l-prijorità tal-ipproċessar. Il-proċessuri jirċievu kompiti hekk kif jaslu. Il-kompitu jista’ jitlesta b’suċċess jew ifalli:

  • messaging:ack(Tack) - imsejħa jekk il-messaġġ jiġi pproċessat b'suċċess
  • messaging:nack(Tack) - imsejjaħ fis-sitwazzjonijiet kollha ta' emerġenza. Ladarba l-kompitu jiġi rritornat, il-messaġġi jgħadduha lil handler ieħor.

Elementi ta' bini ta' applikazzjonijiet imqassma. L-ewwel approċċ

Ejja nassumu li seħħet falliment kumpless waqt l-ipproċessar ta 'tliet kompiti: il-proċessur 1, wara li rċieva l-kompitu, ġġarraf mingħajr ma kellu ħin biex jirrapporta xejn lill-punt tal-iskambju. F'dan il-każ, il-punt tal-iskambju se jittrasferixxi l-kompitu lil handler ieħor wara li l-ack timeout ikun skada. Għal xi raġuni, handler 3 abbanduna l-kompitu u bagħat nack; bħala riżultat, il-kompitu ġie trasferit ukoll lil handler ieħor li temmha b'suċċess.

Sommarju preliminari

Aħna koprejna l-blokki bażiċi ta 'sistemi distribwiti u ksibna fehim bażiku tal-użu tagħhom f'Erlang/Elixir.

Billi tgħaqqad mudelli bażiċi, tista 'tibni paradigmi kumplessi biex issolvi problemi emerġenti.

Fil-parti finali tas-serje, se nħarsu lejn kwistjonijiet ġenerali ta 'organizzazzjoni tas-servizzi, rotta u bilanċjar, u nitkellmu wkoll dwar in-naħa prattika tal-iskalabbiltà u t-tolleranza tal-ħsarat tas-sistemi.

Tmiem it-tieni parti.

Фото Marius Christensen
Illustrazzjonijiet ippreparati bl-użu tal-websequencediagrams.com

Sors: www.habr.com

Żid kumment