Погодни архитектонски обрасци

Хеј Хабр!

У светлу актуелних дешавања услед корона вируса, велики број интернет сервиса је почео да добија повећано оптерећење. На пример, Један од малопродајних ланаца у Великој Британији једноставно је зауставио свој сајт за наручивање на мрежи., јер није било довољно капацитета. И није увек могуће убрзати сервер једноставним додавањем моћније опреме, али захтеви клијената морају бити обрађени (или ће ићи конкурентима).

У овом чланку ћу укратко говорити о популарним праксама које ће вам омогућити да направите брзу услугу отпорну на грешке. Међутим, од могућих развојних шема одабрао сам само оне које су тренутно једноставан за коришћење. За сваку ставку имате или готове библиотеке, или имате прилику да решите проблем помоћу платформе у облаку.

Хоризонтално скалирање

Најједноставнија и најпознатија тачка. Конвенционално, најчешће две шеме расподеле оптерећења су хоризонтално и вертикално скалирање. У првом случају дозвољавате сервисима да раде паралелно, распоређујући на тај начин оптерећење између њих. У другом наручите моћније сервере или оптимизујете код.

На пример, узећу апстрактно складиште датотека у облаку, односно неки аналог ОвнЦлоуд-а, ОнеДриве-а и тако даље.

Стандардна слика таквог кола је испод, али она само показује сложеност система. На крају крајева, морамо некако да синхронизујемо услуге. Шта се дешава ако корисник сачува датотеку са таблета, а затим жели да је погледа са телефона?

Погодни архитектонски обрасци
Разлика између приступа: у вертикалном скалирању спремни смо да повећамо снагу чворова, ау хоризонталном скалирању спремни смо да додамо нове чворове да бисмо распоредили оптерећење.

ЦКРС

Одвајање одговорности за командни упит Прилично важан образац, јер омогућава различитим клијентима не само да се повежу на различите услуге, већ и да примају исте токове догађаја. Његове предности нису толико очигледне за једноставну примену, али су изузетно важне (и једноставне) за прометну услугу. Његова суштина: долазни и одлазни токови података не би требало да се укрштају. То јест, не можете послати захтев и очекивати одговор; уместо тога, шаљете захтев сервису А, али добијате одговор од сервиса Б.

Први бонус овог приступа је могућност прекида везе (у ширем смислу те речи) док се извршава дуг захтев. На пример, узмимо мање-више стандардни низ:

  1. Клијент је послао захтев серверу.
  2. Сервер је започео дуго време обраде.
  3. Сервер је одговорио клијенту са резултатом.

Замислимо да је у тачки 2 веза прекинута (или се мрежа поново повезала, или је корисник отишао на другу страницу, прекинувши везу). У овом случају, серверу ће бити тешко да пошаље одговор кориснику са информацијама о томе шта је тачно обрађено. Користећи ЦКРС, редослед ће бити мало другачији:

  1. Клијент се претплатио на ажурирања.
  2. Клијент је послао захтев серверу.
  3. Сервер је одговорио „захтев је прихваћен“.
  4. Сервер је одговорио резултатом преко канала из тачке „1“.

Погодни архитектонски обрасци

Као што видите, шема је мало компликованија. Штавише, овде недостаје интуитивни приступ захтев-одговор. Међутим, као што видите, прекид везе током обраде захтева неће довести до грешке. Штавише, ако је корисник у ствари повезан са услугом са неколико уређаја (на пример, са мобилног телефона и са таблета), можете бити сигурни да ће одговор доћи на оба уређаја.

Занимљиво је да код за обраду долазних порука постаје исти (не 100%) како за догађаје на које је утицао сам клијент, тако и за друге догађаје, укључујући и оне од других клијената.

Међутим, у стварности добијамо додатни бонус због чињенице да се једносмерним протоком може управљати у функционалном стилу (користећи РКС и слично). И ово је већ озбиљан плус, јер се у суштини апликација може учинити потпуно реактивном, а такође и коришћењем функционалног приступа. За масне програме, ово може значајно уштедети ресурсе за развој и подршку.

Ако комбинујемо овај приступ са хоризонталним скалирањем, онда као бонус добијамо могућност да шаљемо захтеве једном серверу и примамо одговоре од другог. Дакле, клијент може изабрати услугу која му одговара, а систем изнутра ће и даље моћи исправно да обрађује догађаје.

Извор догађаја

Као што знате, једна од главних карактеристика дистрибуираног система је одсуство заједничког времена, заједничког критичног одељка. За један процес можете извршити синхронизацију (на истим мутексима), у оквиру које сте сигурни да нико други не извршава овај код. Међутим, ово је опасно за дистрибуирани систем, јер ће захтевати додатне трошкове, а такође ће убити сву лепоту скалирања - све компоненте ће и даље чекати на једну.

Одавде добијамо важну чињеницу – брзи дистрибуирани систем не може да се синхронизује, јер ћемо тада смањити перформансе. С друге стране, често нам је потребна одређена доследност између компоненти. А за ово можете користити приступ са евентуална доследност, где је загарантовано да ако нема промена података током неког временског периода након последњег ажурирања („евентуално“), сви упити ће вратити последњу ажурирану вредност.

Важно је разумети да се за класичне базе података прилично често користи јака доследност, где сваки чвор има исте информације (ово се често постиже у случају када се трансакција сматра успостављеном тек након што други сервер одговори). Овде постоје неке релаксације због нивоа изолације, али општа идеја остаје иста - можете живети у потпуно хармонизованом свету.

Међутим, вратимо се првобитном задатку. Ако се део система може изградити са евентуална доследност, онда можемо конструисати следећи дијаграм.

Погодни архитектонски обрасци

Важне карактеристике овог приступа:

  • Сваки долазни захтев се ставља у један ред чекања.
  • Током обраде захтева, услуга такође може да постави задатке у друге редове.
  • Сваки долазни догађај има идентификатор (који је неопходан за дедупликацију).
  • Ред идеолошки функционише према шеми „само додај“. Не можете уклонити елементе из њега или их преуредити.
  • Ред ради по ФИФО шеми (извините на таутологији). Ако треба да извршите паралелно извршавање, онда би у једној фази требало да преместите објекте у различите редове.

Да вас подсетим да разматрамо случај онлајн складиштења датотека. У овом случају, систем ће изгледати отприлике овако:

Погодни архитектонски обрасци

Важно је да услуге у дијаграму не значе нужно посебан сервер. Чак и процес може бити исти. Још једна ствар је важна: идеолошки, те ствари су раздвојене на начин да се хоризонтално скалирање може лако применити.

А за два корисника дијаграм ће изгледати овако (услуге намењене различитим корисницима су означене различитим бојама):

Погодни архитектонски обрасци

Бонуси од такве комбинације:

  • Услуге обраде информација су одвојене. Редови су такође раздвојени. Ако треба да повећамо пропусност система, онда само треба да покренемо више услуга на више сервера.
  • Када добијемо информацију од корисника, не морамо да чекамо да се подаци у потпуности сачувају. Напротив, само треба да одговоримо „ок“ и онда постепено да почнемо да радимо. У исто време, ред изглађује врхове, пошто се додавање новог објекта дешава брзо, а корисник не мора да чека потпуни пролазак кроз цео циклус.
  • Као пример, додао сам услугу дедупликације која покушава да споји идентичне датотеке. Ако дуго ради у 1% случајева, клијент ће то једва приметити (види горе), што је велики плус, јер се више не тражи да будемо XNUMX% брзи и поуздани.

Међутим, недостаци су одмах видљиви:

  • Наш систем је изгубио своју строгу доследност. То значи да ако се, на пример, претплатите на различите услуге, онда теоретски можете добити другачије стање (пошто једна од услуга можда неће имати времена да прими обавештење из интерног реда). Као друга последица, систем сада нема заједничко време. То јест, немогуће је, на пример, све догађаје сортирати једноставно по времену доласка, пошто сатови између сервера можда нису синхрони (штавише, исто време на два сервера је утопија).
  • Ниједан догађај се сада не може једноставно вратити (као што се може урадити са базом података). Уместо тога, морате да додате нови догађај − компензациони догађај, што ће променити последње стање у тражено. Као пример из сличне области: без поновног писања историје (што је лоше у неким случајевима), не можете вратити урезивање у гит-у, али можете направити посебан роллбацк урезивање, што у суштини само враћа старо стање. Међутим, и погрешно урезивање и враћање остаће у историји.
  • Шема података се може мењати од издања до издања, али стари догађаји више неће моћи да се ажурирају на нови стандард (пошто се догађаји у принципу не могу мењати).

Као што видите, извор догађаја добро функционише са ЦКРС. Штавише, имплементација система са ефикасним и погодним редовима, али без раздвајања токова података, већ је сама по себи тешка, јер ћете морати да додате тачке синхронизације које ће неутралисати цео позитиван ефекат редова. Примењујући оба приступа одједном, потребно је мало прилагодити програмски код. У нашем случају, при слању датотеке на сервер, одговор долази само „ок“, што само значи да је „операција додавања датотеке сачувана“. Формално, то не значи да су подаци већ доступни на другим уређајима (на пример, услуга дедупликације може поново да направи индекс). Међутим, након неког времена, клијент ће добити обавештење у стилу „датотека Кс је сачувана“.

Као резултат:

  • Број статуса слања датотека се повећава: уместо класичног „датотека послата“, добијамо два: „датотека је додата у ред на серверу“ и „датотека је сачувана у складишту“. Ово последње значи да други уређаји већ могу да почну да примају датотеку (прилагођено чињеници да редови раде различитим брзинама).
  • Због чињенице да информације о подношењу сада долазе кроз различите канале, морамо да смислимо решења за добијање статуса обраде датотеке. Као последица овога: за разлику од класичног захтева-одговора, клијент се може поново покренути током обраде датотеке, али ће статус саме обраде бити исправан. Штавише, ова ставка функционише, у суштини, ван кутије. Као последица: сада смо толерантнији на неуспехе.

Схардинг

Као што је горе описано, системима за проналажење догађаја недостаје строга доследност. То значи да можемо да користимо неколико складишта без икакве синхронизације између њих. Приближавајући се нашем проблему, можемо:

  • Одвојите датотеке по типу. На пример, слике/видео записи се могу декодирати и изабрати ефикаснији формат.
  • Одвојите рачуне по земљи. Због многих закона, ово може бити потребно, али ова шема архитектуре пружа такву могућност аутоматски

Погодни архитектонски обрасци

Ако желите да пренесете податке из једног складишта у друго, стандардна средства више нису довољна. Нажалост, у овом случају, морате зауставити ред, извршити миграцију, а затим га покренути. У општем случају, подаци се не могу пренети „у ходу“, међутим, ако је ред догађаја у потпуности ускладиштен, а имате снимке претходних стања складиштења, можемо поново да репродукујемо догађаје на следећи начин:

  • У извору догађаја, сваки догађај има свој идентификатор (идеално, неопадајући). То значи да можемо додати поље у складиште - ид последњег обрађеног елемента.
  • Дуплицирамо ред тако да се сви догађаји могу обрадити за неколико независних складишта (прво је оно у коме су подаци већ ускладиштени, а друго је ново, али још увек празно). Други ред се, наравно, још не обрађује.
  • Покрећемо други ред (то јест, почињемо да репродукујемо догађаје).
  • Када је нови ред релативно празан (то јест, просечна временска разлика између додавања елемента и његовог преузимања је прихватљива), можете почети да пребацујете читаче на ново складиште.

Као што видите, ми нисмо имали, а немамо ни строгу доследност у нашем систему. Постоји само евентуална конзистентност, односно гаранција да се догађаји обрађују истим редоследом (али могуће са различитим кашњењима). И, користећи ово, можемо релативно лако пренети податке без заустављања система на другу страну света.

Дакле, настављајући наш пример о онлајн складиштењу датотека, таква архитектура нам већ даје бројне бонусе:

  • Можемо на динамичан начин приближити објекте корисницима. На тај начин можете побољшати квалитет услуге.
  • Неке податке можемо чувати унутар компанија. На пример, корисници предузећа често захтевају да се њихови подаци чувају у контролисаним центрима података (да би се избегло цурење података). Кроз дијељење можемо то лако подржати. А задатак је још лакши ако корисник има компатибилан облак (нпр. Азуре селф хостед).
  • И најважније је да то не морамо да радимо. На крају крајева, за почетак, били бисмо прилично задовољни једним складиштем за све налоге (да бисмо брзо почели да радимо). А кључна карактеристика овог система је да иако је проширив, у почетној фази је прилично једноставан. Једноставно не морате одмах да пишете код који ради са милион засебних независних редова итд. Ако је потребно, то се може учинити у будућности.

Хостовање статичког садржаја

Ова тачка може изгледати прилично очигледна, али је и даље неопходна за више или мање стандардно учитану апликацију. Његова суштина је једноставна: сав статички садржај се дистрибуира не са истог сервера на коме се налази апликација, већ са посебних посвећених овом задатку. Као резултат тога, ове операције се изводе брже (условни нгинк опслужује датотеке брже и јефтиније од Јава сервера). Плус ЦДН архитектура (Цонтент Деливери Нетворк) нам омогућава да своје датотеке лоцирамо ближе крајњим корисницима, што позитивно утиче на погодност рада са услугом.

Најједноставнији и најстандарднији пример статичког садржаја је скуп скрипти и слика за веб локацију. Са њима је све једноставно – унапред су познати, затим се архива учитава на ЦДН сервере, одакле се дистрибуира крајњим корисницима.

Међутим, у стварности, за статички садржај можете користити приступ донекле сличан ламбда архитектури. Вратимо се нашем задатку (онлајн складиштење датотека), у којем треба да дистрибуирамо датотеке корисницима. Најједноставније решење је креирање сервиса који за сваки захтев корисника ради све потребне провере (ауторизација и сл.), а затим преузима датотеку директно из нашег складишта. Главни недостатак овог приступа је што се статички садржај (а датотека са одређеном ревизијом, у ствари, статички садржај) дистрибуира од стране истог сервера који садржи пословну логику. Уместо тога, можете направити следећи дијаграм:

  • Сервер обезбеђује УРЛ за преузимање. Може бити у облику филе_ид + кључ, где је кључ мини-дигитални потпис који даје право приступа ресурсу у наредна 24 сата.
  • Датотека се дистрибуира једноставним нгинк-ом са следећим опцијама:
    • Кеширање садржаја. Пошто овај сервис може да се налази на посебном серверу, оставили смо себи резерву за будућност са могућношћу чувања свих најновијих преузетих фајлова на диску.
    • Провера кључа у тренутку креирања везе
  • Опционо: обрада стриминг садржаја. На пример, ако компримујемо све датотеке у сервису, онда можемо да распакујемо директно у овом модулу. Као последица: ИО операције се раде тамо где им је место. Архивер у Јави ће лако доделити много додатне меморије, али преписивање услуге са пословном логиком у Руст/Ц++ условне може такође бити неефикасно. У нашем случају се користе различити процеси (или чак и услуге) и стога можемо прилично ефикасно одвојити пословну логику и ИО операције.

Погодни архитектонски обрасци

Ова шема није много слична дистрибуцији статичког садржаја (пошто не учитавамо негде цео статички пакет), али се у стварности овај приступ бави управо дистрибуцијом непроменљивих података. Штавише, ова шема се може генерализовати на друге случајеве где садржај није једноставно статичан, већ се може представити као скуп непроменљивих и неизбрисивих блокова (иако се могу додати).

Као још један пример (за појачање): ако сте радили са Јенкинс/ТеамЦити, онда знате да су оба решења написана у Јави. Оба су Јава процес који се бави и оркестрацијом изградње и управљањем садржајем. Конкретно, обојица имају задатке попут „пренос датотеке/фолдера са сервера“. Као пример: издавање артефаката, пренос изворног кода (када агент не преузима код директно из спремишта, већ сервер то ради уместо њега), приступ евиденцијама. Сви ови задаци се разликују по свом ИО оптерећењу. Односно, испоставља се да сервер одговоран за сложену пословну логику мора истовремено бити у стању да ефикасно прогура велике токове података кроз себе. И оно што је најинтересантније је да се таква операција може делегирати истом нгинк-у по потпуно истој шеми (осим што захтеву треба додати кључ података).

Међутим, ако се вратимо на наш систем, добићемо сличан дијаграм:

Погодни архитектонски обрасци

Као што видите, систем је постао радикално сложенији. Сада то није само мини-процес који складишти датотеке локално. Сада оно што је потребно није најједноставнија подршка, контрола верзије АПИ-ја итд. Стога, након што су сви дијаграми нацртани, најбоље је детаљно проценити да ли је проширивост вредна трошкова. Међутим, ако желите да будете у могућности да проширите систем (укључујући рад са још већим бројем корисника), онда ћете морати да се одлучите за слична решења. Али, као резултат, систем је архитектонски спреман за повећано оптерећење (скоро свака компонента се може клонирати за хоризонтално скалирање). Систем се може ажурирати без заустављања (једноставно ће неке операције бити мало успорене).

Као што сам рекао на самом почетку, сада су бројни интернет сервиси почели да добијају повећано оптерећење. А неки од њих су једноставно почели да престају да раде исправно. Заправо, системи су заказали управо у тренутку када је посао требало да заради. То јест, уместо одложене испоруке, уместо да сугерише купцима да „испланирају испоруку за наредне месеце“, систем је једноставно рекао „идите својим конкурентима“. У ствари, ово је цена ниске продуктивности: губици ће настати управо када би профит био највећи.

Закључак

Сви ови приступи су били познати и раније. Исти ВК већ дуго користи идеју о хостовању статичког садржаја за приказ слика. Многе онлајн игре користе шему шардинга да поделе играче на регионе или да одвоје локације за игру (ако је свет један). Приступ изворима догађаја се активно користи у е-пошти. Већина апликација за трговање у којима се подаци стално примају заправо су изграђене на ЦКРС приступу како би се могли филтрирати примљени подаци. Па, хоризонтално скалирање се већ дуго користи у многим услугама.

Међутим, што је најважније, сви ови обрасци су постали веома лаки за примену у савременим апликацијама (ако су, наравно, прикладни). Цлоудс одмах нуди разбијање и хоризонтално скалирање, што је много лакше него да сами наручите различите наменске сервере у различитим центрима података. ЦКРС је постао много лакши, макар само због развоја библиотека као што је РКС. Пре отприлике 10 година, ретка веб локација је могла да подржи ово. Догађај извор је такође невероватно једноставан за подешавање захваљујући готовим контејнерима са Апацхе Кафка. Пре 10 година ово би била иновација, сада је уобичајено. Исто је и са статичним хостингом садржаја: због практичнијих технологија (укључујући и чињеницу да постоји детаљна документација и велика база података), овај приступ је постао још једноставнији.

Као резултат тога, имплементација низа прилично сложених архитектонских образаца сада је постала много једноставнија, што значи да је боље да је боље погледате унапред. Ако је у апликацији старој десет година једно од горе наведених решења напуштено због високих трошкова имплементације и рада, сада, у новој апликацији, или након рефакторисања, можете креирати сервис који ће већ архитектонски бити и проширив ( у погледу перформанси) и спремни за нове захтеве клијената (на пример, за локализацију личних података).

И што је најважније: немојте користити ове приступе ако имате једноставну апликацију. Да, лепи су и занимљиви, али за сајт са вршном посетом од 100 људи, често се може проћи са класичним монолитом (барем споља, све унутра се може поделити на модуле итд.).

Извор: ввв.хабр.цом

Додај коментар