Бөлінген қолданбалардың құрылыс блоктары. Екінші жуықтау

Хабарландыру

Әріптестер, жаздың ортасында мен кезек жүйелерін жобалау бойынша тағы бір мақалалар сериясын шығаруды жоспарлап отырмын: «VTrade эксперименті» - сауда жүйелері үшін негізді жазу әрекеті. Серия биржа, аукцион және дүкен құрудың теориясы мен тәжірибесін қарастырады. Мақаланың соңында сізді қызықтыратын тақырыптарға дауыс беруге шақырамын.

Бөлінген қолданбалардың құрылыс блоктары. Екінші жуықтау

Бұл Erlang/Elixir-тегі бөлінген реактивті қолданбалар сериясының соңғы мақаласы. IN бірінші мақала реактивті архитектураның теориялық негіздерін таба аласыз. Екінші мақала мұндай жүйелерді құрудың негізгі үлгілері мен механизмдерін суреттейді.

Бүгін біз кодтық базаны және жалпы жобаларды дамыту мәселелерін көтереміз.

Қызмет көрсетуді ұйымдастыру

Нақты өмірде қызметті әзірлеу кезінде жиі бір контроллерде бірнеше өзара әрекеттесу үлгілерін біріктіруге тура келеді. Мысалы, жобаның пайдаланушы профильдерін басқару мәселесін шешетін пайдаланушылар қызметі req-resp сұрауларына жауап беруі және pub-sub арқылы профиль жаңартулары туралы есеп беруі керек. Бұл жағдай өте қарапайым: хабар алмасудың артында қызмет логикасын жүзеге асыратын және жаңартуларды жариялайтын бір контроллер бар.

Ақауларға төзімді таратылған қызметті енгізу қажет болғанда жағдай күрделене түседі. Пайдаланушыларға қойылатын талаптар өзгерді деп елестетейік:

  1. енді қызмет 5 кластер түйініндегі сұрауларды өңдеуі керек,
  2. фондық өңдеу тапсырмаларын орындай алу,
  3. сонымен қатар профиль жаңартуларына жазылу тізімдерін динамикалық түрде басқара алады.

Ескерту: Біз деректерді дәйекті сақтау және қайталау мәселесін қарастырмаймыз. Бұл мәселелер бұрын шешілген және жүйеде сенімді және масштабталатын сақтау қабаты бар және өңдеушілер онымен әрекеттесу механизмдері бар деп есептейік.

Пайдаланушылар қызметінің ресми сипаттамасы күрделене түсті. Бағдарламалаушының көзқарасы бойынша, хабар алмасуды қолдануға байланысты өзгерістер ең аз болады. Бірінші талапты қанағаттандыру үшін біз req-resp алмасу нүктесінде теңгерімдеуді конфигурациялауымыз керек.

Фондық тапсырмаларды өңдеу талабы жиі орын алады. Пайдаланушыларда бұл пайдаланушы құжаттарын тексеру, жүктелген мультимедианы өңдеу немесе деректерді әлеуметтік медиамен синхрондау болуы мүмкін. желілер. Бұл тапсырмаларды кластер ішінде қандай да бір түрде бөлу және орындалу барысын бақылау қажет. Сондықтан, бізде екі шешім нұсқасы бар: алдыңғы мақаладағы тапсырманы тарату үлгісін пайдаланыңыз немесе ол сәйкес келмесе, процессорлар пулын бізге қажет жолмен басқаратын теңшелетін тапсырма жоспарлаушысын жазыңыз.

3-тармақ pub-sub үлгісі кеңейтімін қажет етеді. Ал іске асыру үшін паб-суб алмасу нүктесін жасағаннан кейін, біздің қызметімізде осы нүктенің контроллерін қосымша іске қосу керек. Осылайша, біз жазылымдарды өңдеу логикасын және хабар алмасу деңгейінен бас тартуды пайдаланушыларды іске асыруға ауыстырып жатқандай боламыз.

Нәтижесінде, мәселенің ыдырауы талаптарды қанағаттандыру үшін әртүрлі түйіндерде қызметтің 5 данасын іске қосып, жазылымға жауапты қосымша субъект – паб-суб контроллерін құру қажет екенін көрсетті.
5 өңдеушілерді іске қосу үшін қызмет кодын өзгерту қажет емес. Жалғыз қосымша әрекет - айырбастау нүктесінде теңдестіру ережелерін орнату, ол туралы сәл кейінірек айтатын боламыз.
Сондай-ақ қосымша күрделілік бар: pub-қосалқы контроллері және реттелетін тапсырма жоспарлаушысы бір көшірмеде жұмыс істеуі керек. Тағы да, хабар алмасу қызметі іргелі қызмет ретінде көшбасшыны таңдау механизмін қамтамасыз етуі керек.

Көшбасшының таңдауы

Бөлінген жүйелерде көшбасшыны сайлау - бұл кейбір жүктемені үлестірілген өңдеуді жоспарлауға жауапты бір процесті тағайындау процедурасы.

Орталықтандыруға бейім емес жүйелерде әмбебап және консенсусқа негізделген алгоритмдер, мысалы, paxos немесе raft қолданылады.
Хабарлама брокер және орталық элемент болғандықтан, ол барлық қызмет контроллерлері - кандидат көшбасшылары туралы біледі. Хабарлама дауыс берусіз көшбасшыны тағайындай алады.

Іске қосу және алмасу нүктесіне қосылғаннан кейін барлық қызметтер жүйелік хабарлама алады #'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers}. Егер LeaderPid сәйкес келеді pid ағымдағы процесс, ол жетекші ретінде тағайындалады, және тізімі Servers барлық түйіндерді және олардың параметрлерін қамтиды.
Қазіргі уақытта жаңасы пайда болады және жұмыс істейтін кластер түйіні ажыратылады, барлық қызмет контроллерлері #'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} и #'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} тиісінше.

Осылайша, барлық құрамдас бөліктер барлық өзгерістерден хабардар болады және кластерге кез келген уақытта бір көшбасшыға кепілдік беріледі.

Делдалдар

Күрделі үлестірілген өңдеу процестерін жүзеге асыру үшін, сондай-ақ бар архитектураны оңтайландыру мәселелерінде делдалдарды пайдалану ыңғайлы.
Қызмет кодын өзгертпеу және мысалы, қосымша өңдеу, бағыттау немесе хабарламаларды тіркеу мәселелерін шешпеу үшін барлық қосымша жұмыстарды орындайтын қызмет алдында прокси өңдеушісін қосуға болады.

Pub-sub оңтайландыруының классикалық мысалы нарықтағы баға өзгерістері сияқты жаңарту оқиғаларын жасайтын бизнес өзегі бар таратылған қолданба және веб-клиенттер үшін websocket API қамтамасыз ететін кіру деңгейі - N серверлері.
Егер сіз тікелей шешім қабылдасаңыз, тұтынушыларға қызмет көрсету келесідей болады:

  • клиент платформамен байланыс орнатады. Трафикті тоқтататын сервер жағында осы қосылымға қызмет көрсету үшін процесс іске қосылады.
  • Қызмет көрсету процесінің контекстінде авторизация және жаңартуларға жазылу орын алады. Процесс тақырыптарға жазылу әдісін шақырады.
  • Оқиға ядрода жасалғаннан кейін ол қосылымдарға қызмет көрсететін процестерге жеткізіледі.

Бізде «жаңалықтар» тақырыбына 50000 5 жазылушы бар деп елестетіп көрейік. Жазылушылар 50000 серверге біркелкі бөлінеді. Нәтижесінде айырбастау нүктесіне келген әрбір жаңарту 10000 XNUMX рет қайталанады: әр серверде ондағы жазылушылардың санына сәйкес XNUMX XNUMX рет. Өте тиімді схема емес, солай ма?
Жағдайды жақсарту үшін алмасу нүктесімен бірдей аты бар проксиді енгізейік. Жаһандық атау тіркеушісі ең жақын процесті аты бойынша қайтара алуы керек, бұл маңызды.

Осы проксиді кіру деңгейі серверлерінде іске қосайық және websocket api-ге қызмет көрсететін барлық процестеріміз ядродағы бастапқы pub-sub алмасу нүктесіне емес, оған жазылады. Прокси ядроға бірегей жазылым жағдайында ғана жазылады және кіріс хабарды өзінің барлық жазылушыларына қайталайды.
Нәтижесінде ядро ​​мен кіру серверлері арасында 5 50000 емес, XNUMX хабарлама жіберіледі.

Маршрутизация және теңгерімдеу

Сұраныс-жауап

Ағымдағы хабар алмасуда 7 сұранысты тарату стратегиясы бар:

  • default. Сұраныс барлық контроллерлерге жіберіледі.
  • round-robin. Сұраулар тізімделеді және контроллерлер арасында циклдік түрде бөлінеді.
  • consensus. Қызметке қызмет көрсететін контроллерлер көшбасшылар мен құлдарға бөлінеді. Сұраныс тек басшыға жіберіледі.
  • consensus & round-robin. Топтың басшысы бар, бірақ сұраулар барлық мүшелер арасында бөлінеді.
  • sticky. Хэш функциясы есептеледі және белгілі бір өңдеушіге тағайындалады. Осы қолтаңбасы бар кейінгі сұраулар сол өңдеушіге өтеді.
  • sticky-fun. Айырбастау нүктесін инициализациялау кезінде хэшті есептеу функциясы sticky теңгеру.
  • fun. Жабысқақ қызық сияқты, тек сіз оны қосымша қайта бағыттай аласыз, қабылдамайсыз немесе алдын ала өңдей аласыз.

Тарату стратегиясы алмасу нүктесі инициализацияланған кезде орнатылады.

Теңдестіруге қоса, хабар алмасу нысандарды белгілеуге мүмкіндік береді. Жүйедегі тегтердің түрлерін қарастырайық:

  • Қосылым тегі. Оқиғалардың қандай байланыс арқылы келгенін түсінуге мүмкіндік береді. Контроллер процесі бір алмасу нүктесіне, бірақ әртүрлі бағыттау кілттерімен қосылғанда қолданылады.
  • Қызмет белгісі. Өңдеушілерді бір қызмет үшін топтарға біріктіруге және маршруттау мен теңдестіру мүмкіндіктерін кеңейтуге мүмкіндік береді. req-resp үлгісі үшін маршруттау сызықты болып табылады. Біз айырбастау нүктесіне сұраныс жібереміз, содан кейін ол оны қызметке жібереді. Бірақ өңдеушілерді логикалық топтарға бөлу қажет болса, онда бөлу тегтердің көмегімен орындалады. Тегті көрсету кезінде сұрау контроллерлердің белгілі бір тобына жіберіледі.
  • Сұраныс белгісі. Жауаптарды ажыратуға мүмкіндік береді. Жүйеміз асинхронды болғандықтан, қызмет жауаптарын өңдеу үшін сұрау жіберу кезінде RequestTag көрсету мүмкіндігі болуы керек. Одан бізге қандай сұраныстың келгенін түсіне аламыз.

Паб-суб

Pub-sub үшін бәрі біршама қарапайым. Бізде хабарламалар жарияланатын алмасу нүктесі бар. Айырбастау нүктесі қажетті маршруттық кілттерге жазылған абоненттер арасында хабарламаларды таратады (бұл тақырыптарға ұқсас деп айта аламыз).

Масштабтау және ақауларға төзімділік

Тұтастай алғанда жүйенің масштабтылығы жүйенің қабаттары мен құрамдас бөліктерінің масштабталу дәрежесіне байланысты:

  • Қызметтер осы қызмет үшін өңдеушілері бар кластерге қосымша түйіндерді қосу арқылы масштабталады. Сынақ жұмысы кезінде оңтайлы теңдестіру саясатын таңдауға болады.
  • Жеке кластердегі хабар алмасу қызметінің өзі әдетте ерекше жүктелген алмасу нүктелерін бөлек кластер түйіндеріне жылжыту арқылы немесе кластердің ерекше жүктелген аймақтарына прокси процестерін қосу арқылы масштабталады.
  • Сипаттама ретінде бүкіл жүйенің масштабтылығы архитектураның икемділігіне және жеке кластерлерді ортақ логикалық нысанға біріктіру мүмкіндігіне байланысты.

Жобаның сәттілігі көбінесе масштабтаудың қарапайымдылығы мен жылдамдығына байланысты. Ағымдағы нұсқасында хабар алмасу қолданбамен бірге өседі. Бізге 50-60 техника кластері жетіспесе де, федерацияға жүгінуге болады. Өкінішке орай, федерация тақырыбы бұл мақаланың шеңберінен тыс.

Брондау

Жүктемені теңестіруді талдау кезінде біз қызмет контроллерлерінің артық болуын талқыладық. Дегенмен, хабар алмасуды да сақтау керек. Түйін немесе құрылғы бұзылған жағдайда хабар алмасу мүмкіндігінше қысқа мерзімде автоматты түрде қалпына келуі керек.

Мен өз жобаларымда құлаған жағдайда жүктемені көтеретін қосымша түйіндерді қолданамын. Erlang бағдарламасында OTP қолданбалары үшін стандартты таратылған режимді іске асыру бар. Бөлінген режим сәтсіз бағдарламаны бұрын іске қосылған басқа түйінде іске қосу арқылы сәтсіз болған жағдайда қалпына келтіруді жүзеге асырады. Процесс мөлдір; сәтсіздіктен кейін қолданба автоматты түрде ауыстыру түйініне ауысады. Бұл функция туралы толығырақ оқуға болады осында.

өнімділік

Ең болмағанда rabbitmq өнімділігін және реттелетін хабар алмасуды шамамен салыстыруға тырысайық.
Мен таптым ресми нәтижелер openstack командасынан rabbitmq сынағы.

6.14.1.2.1.2.2 тармағында. Түпнұсқа құжат RPC CAST нәтижесін көрсетеді:
Бөлінген қолданбалардың құрылыс блоктары. Екінші жуықтау

Біз ОЖ ядросына немесе erlang VM жүйесіне алдын ала ешқандай қосымша параметрлерді жасамаймыз. Тестілеу шарттары:

  • erl опциялары: +A1 +sbtu.
  • Бір erlang түйініндегі сынақ мобильді нұсқадағы ескі i7 нұсқасы бар ноутбукта орындалады.
  • Кластерлік сынақтар 10G желісі бар серверлерде жүргізіледі.
  • Код докер контейнерлерінде жұмыс істейді. NAT режиміндегі желі.

Сынақ коды:

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-сценарий: Сынақ ескі i7 мобильді нұсқасы бар ноутбукта орындалады. Сынақ, хабар алмасу және қызмет бір Docker контейнеріндегі бір түйінде орындалады:

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: Docker (NAT) астында әртүрлі машиналарда жұмыс істейтін 3 түйін.

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)

Барлық жағдайларда процессорды пайдалану 250% аспады.

Нәтижелері

Бұл цикл ақыл-ой қоқысына ұқсамайды және менің тәжірибем бөлінген жүйелерді зерттеушілерге де, бизнес жүйелері үшін бөлінген архитектураларды құрудың басында тұрған және Erlang/Elixir-ге қызығушылықпен қарайтын тәжірибешілерге де нақты пайдалы болады деп үміттенемін. , бірақ бұл тұр ма деген күмәніңіз бар...

фото @chuttersnap

Сауалнамаға тек тіркелген пайдаланушылар қатыса алады. Кіру, өтінемін.

VTrade Experiment сериясының бөлігі ретінде қандай тақырыптарды толығырақ қарастыруым керек?

  • Теория: Нарықтар, тапсырыстар және олардың уақыты: DAY, GTD, GTC, IOC, FOK, MOO, MOC, LOO, LOC

  • Тапсырыстар кітабы. Топтастыру арқылы кітапты жүзеге асырудың теориясы мен практикасы

  • Сауда-саттықтың көрнекілігі: кенелер, жолақтар, рұқсаттар. Қалай сақтау керек және қалай желімдеу керек

  • Бэк-офис. Жоспарлау және дамыту. Қызметкерлерді бақылау және оқиғаны тергеу

  • API. Қандай интерфейстер қажет екенін және оларды қалай жүзеге асыру керектігін анықтайық

  • Ақпаратты сақтау: сауда жүйелеріндегі PostgreSQL, Timescale, Tarantool

  • Сауда жүйелеріндегі реактивтілік

  • Басқа. Мен түсініктемелерде жазамын

6 пайдаланушы дауыс берді. 4 пайдаланушы қалыс қалды.

Ақпарат көзі: www.habr.com

пікір қалдыру