Oxirida
- So'rov - javob
- So'rovga bo'lingan javob
- So'rov bilan javob
- Nashr qilish - obuna bo'lish
- Inverted Publish-obuna
- Vazifalarni taqsimlash
SOA, MSA va Messaging
SOA, MSA - bu tizimlarni qurish qoidalarini belgilaydigan tizim arxitekturalari, xabar almashish esa ularni amalga oshirish uchun primitivlarni ta'minlaydi.
Men u yoki bu tizim arxitekturasini targ'ib qilishni xohlamayman. Men aniq loyiha va biznes uchun eng samarali va foydali amaliyotlardan foydalanish tarafdoriman. Qaysi paradigmani tanlamasligimizdan qat'iy nazar, Unix-way-ga e'tibor qaratgan holda tizim bloklarini yaratish yaxshiroqdir: minimal ulanishga ega komponentlar, individual ob'ektlar uchun javobgardir. API usullari ob'ektlar bilan mumkin bo'lgan eng oddiy amallarni bajaradi.
Xabarlar, nomidan ko'rinib turibdiki, xabar brokeridir. Uning asosiy maqsadi xabarlarni qabul qilish va yuborishdir. U ma'lumotni jo'natish interfeyslari, tizim ichida ma'lumotlarni uzatish uchun mantiqiy kanallarni shakllantirish, marshrutlash va muvozanatlash, shuningdek tizim darajasida nosozliklarni bartaraf etish uchun javobgardir.
Biz ishlab chiqayotgan xabarlar rabbitmq bilan raqobatlashishga yoki almashtirishga harakat qilmaydi. Uning asosiy xususiyatlari:
- Tarqatish.
Ayirboshlash nuqtalari barcha klaster tugunlarida ularni ishlatadigan kodga iloji boricha yaqinroqda yaratilishi mumkin. - Oddiylik
Qozon kodini va foydalanish qulayligini minimallashtirishga e'tibor qarating. - Yaxshi ishlash.
Biz rabbitmq funksiyasini takrorlamoqchi emasmiz, lekin xarajatlarni minimallashtirib, OTP ga imkon qadar sodda tarzda moslashtirgan faqat me'moriy va transport qatlamini ta'kidlaymiz. - Moslashuvchanlik
Har bir xizmat ko'plab almashinuv shablonlarini birlashtira oladi. - Dizayn bo'yicha chidamlilik.
- Masshtablilik.
Xabarlar ilova bilan o'sib boradi. Yuk ortib borishi bilan siz almashinuv nuqtalarini alohida mashinalarga ko'chirishingiz mumkin.
BELOQ. Kodni tashkil qilish nuqtai nazaridan meta-loyihalar murakkab Erlang/Elixir tizimlari uchun juda mos keladi. Barcha loyiha kodi bitta omborda joylashgan - soyabon loyihasi. Shu bilan birga, mikroservislar maksimal darajada izolyatsiya qilingan va alohida ob'ekt uchun mas'ul bo'lgan oddiy operatsiyalarni bajaradi. Ushbu yondashuv bilan butun tizimning API-ni saqlash oson, o'zgartirishlar kiritish oson, birlik va integratsiya testlarini yozish qulay.
Tizim komponentlari to'g'ridan-to'g'ri yoki broker orqali o'zaro ta'sir qiladi. Xabar almashinuvi nuqtai nazaridan, har bir xizmat bir necha hayot bosqichlariga ega:
- Xizmatni ishga tushirish.
Ushbu bosqichda xizmatni bajaradigan jarayon va bog'liqliklar sozlanadi va ishga tushiriladi. - Ayirboshlash nuqtasini yaratish.
Xizmat tugun konfiguratsiyasida ko'rsatilgan statik almashinuv nuqtasidan foydalanishi yoki dinamik ravishda almashinuv nuqtalarini yaratishi mumkin. - Xizmatni ro'yxatdan o'tkazish.
Xizmat so'rovlarga xizmat ko'rsatishi uchun uni almashtirish punktida ro'yxatdan o'tkazish kerak. - Oddiy ishlash.
Xizmat foydali ishlarni ishlab chiqaradi. - O'chirish; yopish.
O'chirishning 2 turi mavjud: oddiy va favqulodda. Oddiy ishlash vaqtida xizmat almashinuv nuqtasidan uziladi va to'xtaydi. Favqulodda vaziyatlarda xabar almashish muvaffaqiyatsiz skriptlardan birini amalga oshiradi.
Bu juda murakkab ko'rinadi, lekin kod unchalik qo'rqinchli emas. Sharhlar bilan kod misollari biroz keyinroq shablonlarni tahlil qilishda beriladi.
birjalari
Ayirboshlash nuqtasi - bu xabar almashish shablonidagi komponentlar bilan o'zaro ta'sir qilish mantiqini amalga oshiradigan xabar almashish jarayoni. Quyida keltirilgan barcha misollarda komponentlar almashinuv nuqtalari orqali o'zaro ta'sir qiladi, ularning kombinatsiyasi xabarlarni shakllantiradi.
Xabar almashish shakllari (MEP)
Global miqyosda ayirboshlash sxemalarini ikki tomonlama va bir tomonlama bo'lish mumkin. Birinchisi kiruvchi xabarga javobni bildiradi, ikkinchisi esa yo'q. Mijoz-server arxitekturasida ikki tomonlama naqshning klassik namunasi so'rov-javob naqshidir. Keling, shablonni va uning o'zgartirishlarini ko'rib chiqaylik.
So'rov-javob yoki RPC
RPC boshqa jarayondan javob olishimiz kerak bo'lganda ishlatiladi. Bu jarayon bitta tugunda yoki boshqa qit'ada joylashgan bo'lishi mumkin. Quyida xabar almashish orqali mijoz va server o'rtasidagi o'zaro ta'sir diagrammasi keltirilgan.
Xabar almashish butunlay asinxron bo'lganligi sababli, mijoz uchun almashinuv 2 bosqichga bo'linadi:
-
So'rov yuborish
messaging:request(Exchange, ResponseMatchingTag, RequestDefinition, HandlerProcess).
ayirboshlash β almashinuv punktining noyob nomi
ResponseMatchingTag β javobni qayta ishlash uchun mahalliy yorliq. Masalan, turli foydalanuvchilarga tegishli bir nechta bir xil so'rovlar yuborilganda.
RequestDefinition - so'rov organi
HandlerProcess β ishlov beruvchining PID. Bu jarayon serverdan javob oladi. -
Javobni qayta ishlash
handle_info(#'$msg'{exchange = EXCHANGE, tag = ResponseMatchingTag,message = ResponsePayload}, State)
ResponsePayload - server javobi.
Server uchun jarayon ham 2 bosqichdan iborat:
- Ayirboshlash nuqtasini ishga tushirish
- Qabul qilingan so'rovlarni qayta ishlash
Keling, ushbu shablonni kod bilan ko'rsatamiz. Aytaylik, biz bitta aniq vaqt usulini taqdim etadigan oddiy xizmatni amalga oshirishimiz kerak.
Server kodi
Keling, api.hrl da xizmat API ni aniqlaymiz:
%% =====================================================
%% 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{}
}).
Keling, time_controller.erl da xizmat boshqaruvchisini aniqlaymiz
%% Π ΠΏΡΠΈΠΌΠ΅ΡΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ ΡΠΎΠ»ΡΠΊΠΎ Π·Π½Π°ΡΠΈΠΌΡΠΉ ΠΊΠΎΠ΄. ΠΡΡΠ°Π²ΠΈΠ² Π΅Π³ΠΎ Π² ΡΠ°Π±Π»ΠΎΠ½ 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.
Mijoz kodi
Xizmatga so'rov yuborish uchun siz mijozning istalgan joyida xabar almashish so'rovi API ga qo'ng'iroq qilishingiz mumkin:
case messaging:request(?EXCHANGE, tag, #time_req{opts = #{}}, self()) of
ok -> ok;
_ -> %% repeat or fail logic
end
Tarqalgan tizimda komponentlar konfiguratsiyasi juda boshqacha bo'lishi mumkin va so'rov vaqtida xabar almashish hali boshlanmasligi mumkin yoki xizmat boshqaruvchisi so'rovga xizmat ko'rsatishga tayyor bo'lmaydi. Shuning uchun biz xabar almashish javobini tekshirishimiz va xatolik holatini hal qilishimiz kerak.
Muvaffaqiyatli yuborilgandan so'ng, mijoz xizmatdan javob yoki xatolik oladi.
Keling, handle_info da ikkala holatni ko'rib chiqaylik:
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};
So'rovga bo'lingan javob
Katta hajmdagi xabarlarni yuborishdan qochish yaxshidir. Butun tizimning sezgirligi va barqaror ishlashi bunga bog'liq. Agar so'rovga javob juda ko'p xotirani egallasa, uni qismlarga bo'lish majburiydir.
Sizga bunday holatlarga bir nechta misol keltiraman:
- Komponentlar fayllar kabi ikkilik ma'lumotlarni almashadi. Javobni kichik qismlarga ajratish har qanday o'lchamdagi fayllar bilan samarali ishlashga va xotira to'lib ketishining oldini olishga yordam beradi.
- Ro'yxatlar. Masalan, biz ma'lumotlar bazasidagi ulkan jadvaldan barcha yozuvlarni tanlashimiz va ularni boshqa komponentga o'tkazishimiz kerak.
Men bu javoblarni lokomotiv deb atayman. Har holda, 1024 MB hajmdagi 1 xabar 1 GB hajmdagi bitta xabardan yaxshiroqdir.
Erlang klasterida biz qo'shimcha afzalliklarga ega bo'lamiz - almashinuv punkti va tarmoqdagi yukni kamaytiradi, chunki javoblar almashish nuqtasini chetlab o'tib, darhol qabul qiluvchiga yuboriladi.
So'rov bilan javob
Bu dialog tizimlarini qurish uchun RPC naqshining juda kam uchraydigan modifikatsiyasi.
Nashr qilish-obuna bo'lish (ma'lumotlarni tarqatish daraxti)
Voqealarga asoslangan tizimlar ularni ma'lumotlar tayyor bo'lishi bilanoq iste'molchilarga etkazib beradi. Shunday qilib, tizimlar tortish yoki so'rov modelidan ko'ra surish modeliga ko'proq moyil bo'ladi. Bu xususiyat doimiy ravishda ma'lumotlarni so'rash va kutish orqali resurslarni isrof qilishdan qochish imkonini beradi.
Rasmda ma'lum bir mavzuga obuna bo'lgan iste'molchilarga xabar tarqatish jarayoni ko'rsatilgan.
Ushbu naqshdan foydalanishning klassik misollari davlatning taqsimlanishi: kompyuter o'yinlaridagi o'yin dunyosi, birjalardagi bozor ma'lumotlari, ma'lumotlar tasmasidagi foydali ma'lumotlar.
Keling, abonent kodini ko'rib chiqaylik:
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.
Manba istalgan qulay joyda xabarni chop etish funksiyasini chaqirishi mumkin:
messaging:publish_message(Exchange, Key, Message).
ayirboshlash - almashinuv punktining nomi;
kalit - marshrut kaliti
Xabar - foydali yuk
Inverted Publish-obuna
Pub-sub-ni kengaytirish orqali siz jurnalga kirish uchun qulay naqsh olishingiz mumkin. Manbalar va iste'molchilar to'plami butunlay boshqacha bo'lishi mumkin. Rasmda bitta iste'molchi va bir nechta manbalar bilan ish ko'rsatilgan.
Vazifalarni taqsimlash sxemasi
Deyarli har bir loyiha hisobotlarni yaratish, bildirishnomalarni yuborish va uchinchi tomon tizimlaridan ma'lumotlarni olish kabi kechiktirilgan qayta ishlash vazifalarini o'z ichiga oladi. Ushbu vazifalarni bajaradigan tizimning o'tkazish qobiliyati ishlov beruvchilarni qo'shish orqali osonlik bilan o'lchanishi mumkin. Bizga faqat protsessorlar klasterini shakllantirish va ular o'rtasida vazifalarni teng taqsimlash qoladi.
Keling, 3 ta ishlov beruvchi misolida yuzaga keladigan vaziyatlarni ko'rib chiqaylik. Vazifalarni taqsimlash bosqichida ham taqsimlashning adolatliligi va ishlovchilarning to'lib ketishi haqida savol tug'iladi. Raund-robin taqsimoti adolat uchun javobgar bo'ladi va ishlovchilar to'lib ketishiga yo'l qo'ymaslik uchun biz cheklov kiritamiz. prefetch_limit. Vaqtinchalik sharoitlarda prefetch_limit bitta ishlov beruvchiga barcha vazifalarni qabul qilishiga to'sqinlik qiladi.
Xabarlar navbatlar va qayta ishlash ustuvorligini boshqaradi. Protsessorlar kelishi bilan vazifalarni oladilar. Vazifa muvaffaqiyatli yoki muvaffaqiyatsiz bajarilishi mumkin:
messaging:ack(Tack)
- agar xabar muvaffaqiyatli qayta ishlansa chaqiriladimessaging:nack(Tack)
- barcha favqulodda vaziyatlarda chaqiriladi. Vazifa qaytarilgach, xabarlar uni boshqa ishlov beruvchiga uzatadi.
Aytaylik, uchta vazifani bajarishda murakkab nosozlik yuz berdi: 1-protsessor topshiriqni olgandan so'ng, almashinuv nuqtasiga hech narsa xabar berishga ulgurmay ishlamay qoldi. Bunday holda, qabul qilish muddati tugagandan so'ng, almashinuv nuqtasi vazifani boshqa ishlov beruvchiga o'tkazadi. Ba'zi sabablarga ko'ra, ishlov beruvchi 3 topshiriqdan voz kechdi va nack yubordi; Natijada, vazifa ham uni muvaffaqiyatli bajargan boshqa ishlov beruvchiga o'tkazildi.
Dastlabki xulosa
Biz taqsimlangan tizimlarning asosiy qurilish bloklarini koβrib chiqdik va ulardan Erlang/Eliksirda foydalanish haqida asosiy tushunchaga ega boβldik.
Asosiy naqshlarni birlashtirib, siz paydo bo'lgan muammolarni hal qilish uchun murakkab paradigmalarni yaratishingiz mumkin.
Seriyaning yakuniy qismida biz xizmatlarni tashkil qilish, marshrutlash va muvozanatlashning umumiy masalalarini ko'rib chiqamiz, shuningdek tizimlarning masshtabliligi va xatolarga chidamliligining amaliy tomoni haqida gapiramiz.
Ikkinchi qismning oxiri.
foto
Tasvirlar websequencediagrams.com yordamida tayyorlangan
Manba: www.habr.com