Azkenean
- Eskaera-erantzuna
- Eskaeraren zatikako erantzuna
- Eskaerarekin erantzuna
- Argitaratu-harpidetu
- Alderantzikatua argitaratu Harpidetza
- Zereginen banaketa
SOA, MSA eta mezularitza
SOA, MSA sistema-arkitekturak dira, sistemak eraikitzeko arauak definitzen dituztenak, eta mezularitzak horiek inplementatzeko primitiboak eskaintzen ditu.
Ez dut sistemaren arkitektura hau edo beste hedatu nahi. Proiektu eta negozio jakin baterako praktika eraginkorrenak eta erabilgarrienak aplikatzearen alde nago. Aukeratzen dugun paradigma edozein dela ere, hobe da sistema-blokeak sortzea Unix-era begira: konektagarritasun minimoa duten osagaiak, entitate indibidualen arduradunak. API metodoek ekintza errazenak egiten dituzte entitateekin.
Mezularitza - izenak dioen bezala - mezuen bitartekari bat. Bere helburu nagusia mezuak jasotzea eta bidaltzea da. Informazioa bidaltzeko interfazeez arduratzen da, sistemaren barruan informazioa transmititzeko kanal logikoen eraketaz, bideratzeaz eta orekatzeaz, baita sistema mailan akatsak kudeatzeaz ere.
Garatutako mezuak ez du saiatzen rabbitmq-rekin lehiatzen edo ordezkatzen. Bere ezaugarri nagusiak:
- Banaketa.
Truke-puntuak klusterreko nodo guztietan sor daitezke, haiek erabiltzen dituen kodetik ahalik eta hurbilen. - Sinpletasuna.
Zentratu erregulazio-kodea murriztera eta erabiltzeko erraztasuna. - Errendimendu hobea.
Ez gara rabbitmq-en funtzionaltasuna errepikatzen saiatzen ari, baizik eta arkitektura eta garraio geruza soilik hautatzen dugu, OTPn ahalik eta modurik errazenean sartzen duguna, kostuak gutxituz. - Malgutasuna.
Zerbitzu bakoitzak truke-txantiloi asko konbina ditzake. - Erresilientzia diseinuaren arabera.
- Eskalagarritasuna.
Mezularitza aplikazioarekin hazten da. Karga handitzen doan heinean, truke-puntuak makina bereizietara eraman ditzakezu.
Oharra. Kodearen antolaketari dagokionez, meta-proiektuak oso egokiak dira Erlang/Elixir sistema konplexuetarako. Proiektu-kode guztia biltegi batean dago - aterki proiektu batean. Aldi berean, mikrozerbitzuak ahalik eta gehien isolatzen dira eta entitate bereizi baten arduradun diren eragiketa errazak egiten dituzte. Planteamendu honekin, erraza da sistema osoaren APIa mantentzea, erraza da aldaketak egitea, komenigarria da unitate eta integrazio probak idaztea.
Sistemaren osagaiek zuzenean edo broker baten bidez elkarreragiten dute. Mezularitzaren posiziotik, zerbitzu bakoitzak hainbat bizitza-fase ditu:
- Zerbitzua hasieratzea.
Fase honetan, zerbitzua eta mendekotasunak exekutatzen dituen prozesuaren konfigurazioa eta abiarazte egiten da. - Sortu truke-puntu bat.
Zerbitzuak ostalariaren konfigurazioan zehaztutako truke-puntu estatiko bat erabil dezake, edo dinamikoki truke-puntuak sor ditzake. - Zerbitzuaren erregistroa.
Zerbitzuak eskaerak betetzeko, truke puntuan erregistratu behar da. - Funtzionamendu normala.
Zerbitzuak lan erabilgarria egiten du. - Lanak amaitzea.
2 itzalaldi mota daude: ohikoa eta larrialdikoa. Ohiko zerbitzu batekin, truke-puntutik deskonektatu eta gelditzen da. Larrialdi-kasuetan, mezuak hutsegiteko agertokietako bat exekutatzen du.
Nahiko konplikatua dirudi, baina kodea ez da hain beldurgarria. Iruzkinekin kode-adibideak txantiloien azterketan emango dira pixka bat geroago.
Trukeak
Truke-puntu bat mezularitza txantiloiaren barruan osagaiekin elkarreraginaren logika ezartzen duen mezularitza-prozesu bat da. Beheko adibide guztietan, osagaiek elkartruke puntuen bidez elkarreragiten dute, eta horien konbinazioak mezularitza osatzen du.
Mezuak trukatzeko ereduak (MEP)
Mundu mailan, truke-ereduak bi aldeetan eta alde bakarrean bana daitezke. Lehenengoek sarrerako mezuari erantzuna ematen diote, bigarrenek ez. Bezero-zerbitzariaren arkitekturan bi norabideko ereduaren adibide klasiko bat Eskaera-erantzun eredua da. Kontuan hartu txantiloia eta haren aldaketak.
Eskaera-erantzuna edo RPC
RPC beste prozesu baten erantzuna jaso behar dugunean erabiltzen da. Prozesu hau ostalari berean edo kontinente ezberdin batean egon daiteke. Jarraian, mezuen bidez bezeroaren eta zerbitzariaren arteko elkarrekintzaren diagrama bat dago.
Mezularitza guztiz asinkronoa denez, bezeroaren trukea 2 fasetan banatzen da:
-
Bidali eskaera
messaging:request(Exchange, ResponseMatchingTag, RequestDefinition, HandlerProcess).
Exchange β truke-puntu izen bakarra
ResponseMatchingTag β Erantzuna prozesatzeko tokiko etiketa. Esaterako, erabiltzaile ezberdinei dagozkien hainbat eskaera berdin bidaltzearen kasuan.
Eskaeraren Definizioa β eskaera gorputza
KudeatzaileaProzesua β Kudeatzailearen PID. Prozesu honek zerbitzariaren erantzuna jasoko du. -
Erantzunaren tratamendua
handle_info(#'$msg'{exchange = EXCHANGE, tag = ResponseMatchingTag,message = ResponsePayload}, State)
ErantzunPayload - zerbitzariaren erantzuna.
Zerbitzariari dagokionez, prozesuak 2 fase ditu:
- Truke-puntua hasieratzea
- Jasotako eskaerak prozesatzea
Ilustra dezagun txantiloi hau kodearekin. Demagun denbora zehatzeko metodo bakarra eskaintzen duen zerbitzu sinple bat ezarri behar dugula.
Zerbitzariaren kodea
Muga dezagun zerbitzuaren APIaren definizioa api.hrl-era:
%% =====================================================
%% 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{}
}).
Definitu zerbitzu-kontrolatzailea time_controller.erl-en
%% Π ΠΏΡΠΈΠΌΠ΅ΡΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ ΡΠΎΠ»ΡΠΊΠΎ Π·Π½Π°ΡΠΈΠΌΡΠΉ ΠΊΠΎΠ΄. ΠΡΡΠ°Π²ΠΈΠ² Π΅Π³ΠΎ Π² ΡΠ°Π±Π»ΠΎΠ½ 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.
Bezeroaren kodea
Zerbitzu bati eskaera bat bidaltzeko, mezularitza-eskaeraren APIra deitu dezakezu bezeroaren edozein tokitan:
case messaging:request(?EXCHANGE, tag, #time_req{opts = #{}}, self()) of
ok -> ok;
_ -> %% repeat or fail logic
end
Banatutako sistema batean, osagaien konfigurazioa oso desberdina izan daiteke, eta eskaera egiten den unean, baliteke mezularitza oraindik ez abiatzea, edo zerbitzu-kontrolatzailea ez egongo da eskaera zerbitzatzeko prest. Hori dela eta, mezularitzaren erantzuna egiaztatu eta hutsegite kasua kudeatu behar dugu.
Bezeroari ongi bidali ondoren, zerbitzuak erantzun bat edo errore bat jasoko du.
Kudea ditzagun bi kasuak handle_info-n:
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};
Eskaeraren zatikako erantzuna
Hobe da mezu handiak bidaltzea saihestea. Sistema osoaren erantzuna eta funtzionamendu egonkorra horren araberakoak dira. Kontsulta baten erantzunak memoria asko hartzen badu, orduan zatitzea derrigorrezkoa da.
Hona hemen horrelako kasuen adibide pare bat:
- Osagaiek datu bitarrak trukatzen dituzte, hala nola fitxategiak. Erantzuna zati txikitan zatitzeak edozein tamainatako fitxategiekin modu eraginkorrean lan egiten laguntzen du eta memoria gainezka ez harrapatzen.
- Zerrendak. Adibidez, datu-baseko taula handi batetik erregistro guztiak hautatu eta beste osagai batera pasatu behar ditugu.
Horrelako erantzunei lokomotora deitzen diet. Nolanahi ere, 1024 1MB mezu hobeak dira 1GB mezu bakarra baino.
Erlang klusterrean, abantaila gehigarri bat lortzen dugu: truke-puntuan eta sarean karga murriztea, erantzunak berehala bidaltzen baititu hartzailearengana, truke-puntua saihestuz.
Eskaerarekin erantzuna
Hau elkarrizketa-sistemak eraikitzeko RPC ereduaren aldaketa arraroa da.
Argitaratu-harpidetza (datuen banaketaren zuhaitza)
Gertaerak gidatutako sistemek kontsumitzaileei datuak ematen dizkiete eskuragarri dauden heinean. Hortaz, sistemak bultzatzeko eredurako joera handiagoa dute pull edo poll eredurako baino. Ezaugarri honek baliabideak ez xahutzea ahalbidetzen du, datuak etengabe eskatuz eta itxaronez.
Irudiak gai jakin batera harpidetutako kontsumitzaileei mezu bat banatzeko prozesua erakusten du.
Eredu hau erabiltzeko adibide klasikoak dira estatuaren banaketa: jokoen mundua ordenagailu jokoetan, trukeei buruzko merkatuko datuak, datu-jarioetan informazio erabilgarria.
Kontuan hartu harpidedun kodea:
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.
Iturburuak mezuaren argitaratze-funtzioari dei diezaioke edozein lekutan:
messaging:publish_message(Exchange, Key, Message).
Exchange - Truke puntuaren izena,
Key β bideratze-gakoa
Mezua - zama erabilgarria
Alderantzikatua argitaratu Harpidetza
Pub-sub zabalduz, saioa hasteko erosoa den eredua lor dezakezu. Iturri eta kontsumitzaileen multzoa guztiz ezberdina izan daiteke. Irudiak kontsumitzaile bat eta iturri asko dituen kasu bat erakusten du.
Zereginen banaketa eredua
Ia proiektu guztietan, prozesamendu geroratuko zereginak daude, hala nola, txostenak sortzea, jakinarazpenak entregatzea eta hirugarrenen sistemetatik datuak jasotzea. Zeregin horiek egiten dituen sistema baten errendimendua erraz eskalatzen da prozesadoreak gehituz. Prozesadore multzo bat osatzea eta haien artean zereginak uniformeki banatzea besterik ez zaigu geratzen.
Kontuan hartu 3 kudeatzaileen adibidea erabiliz sortzen diren egoerak. Zereginen banaketaren fasean ere, kudeatzaileen banaketaren eta gainezkatzearen bidezkotasunaren galdera sortzen da. Banaketa biribila zuzentasunaren ardura izango da, eta kudeatzaileen gainezka egoera saihesteko, murrizketa bat ezarriko dugu. prefetch_limit. Trantsizio moduetan prefetch_limit ez du baimenduko kudeatzaile batek zeregin guztiak jasotzea.
Mezularitzak ilarak eta prozesatzeko lehentasuna kudeatzen ditu. Prozesadoreek iristen diren heinean jasotzen dituzte zereginak. Zereginak arrakastaz edo huts egin dezake:
messaging:ack(Tack)
β deitzen da mezua arrakastaz prozesatzen badamessaging:nack(Tack)
β larrialdi egoera guztietan deituta. Ataza itzuli ondoren, mezuak beste kudeatzaile bati pasatuko dio.
Demagun hiru zeregin prozesatzen ari ziren bitartean hutsegite konplexu bat gertatu dela: 1. kudeatzaileak, zeregina jaso ondoren, huts egin duela truke-puntuari ezer jakinarazteko astirik izan gabe. Kasu honetan, truke-puntuak lana beste kudeatzaile bati transferituko dio ack denbora-muga igaro ondoren. 3. kudeatzaileak, arrazoiren batengatik, zeregina bertan behera utzi zuen eta nack bat bidali zuen, ondorioz, zeregina arrakastaz amaitu zuen beste kudeatzaile bati ere pasatu zitzaion.
Aurretiazko laburpena
Banatutako sistemen oinarrizko eraikuntza-blokeak banatu ditugu eta Erlang/Elixir-en erabileraren oinarrizko ulermena lortu dugu.
Oinarrizko txantiloiak konbinatuz, paradigma konplexuak eraiki daitezke sortzen ari diren arazoak konpontzeko.
Zikloaren azken zatian, zerbitzuak antolatzeko, bideratze eta orekatzeko gai orokorrak aztertuko ditugu, eta sistemen eskalagarritasunaren eta akatsen tolerantziaren alde praktikoari buruz ere hitz egingo dugu.
Bigarren zatiaren amaiera.
Photo Shoot
Ilustrazioak websequencediagrams.com-ren eskutik
Iturria: www.habr.com