Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

Oxirida maqola Biz reaktiv arxitekturaning nazariy asoslarini ko'rib chiqdik. Ma'lumotlar oqimlari, reaktiv Erlang/Elixir tizimlarini amalga oshirish usullari va ulardagi xabar almashish naqshlari haqida gapirish vaqti keldi:

  • 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.

Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

Xabar almashish butunlay asinxron bo'lganligi sababli, mijoz uchun almashinuv 2 bosqichga bo'linadi:

  1. 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.

  2. Javobni qayta ishlash

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

    ResponsePayload - server javobi.

Server uchun jarayon ham 2 bosqichdan iborat:

  1. Ayirboshlash nuqtasini ishga tushirish
  2. 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.

Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

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.

Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

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.

Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

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

Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

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 chaqiriladi
  • messaging:nack(Tack) - barcha favqulodda vaziyatlarda chaqiriladi. Vazifa qaytarilgach, xabarlar uni boshqa ishlov beruvchiga uzatadi.

Tarqalgan ilovalarning qurilish bloklari. Birinchi yondashuv

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 Marius Kristensen
Tasvirlar websequencediagrams.com yordamida tayyorlangan

Manba: www.habr.com

a Izoh qo'shish