kpi

Magazín KPI

Pieskovisko — nekontrolované články

Aplikačný rámec pre vývoj škálovateľných backendov

Táto práca sa venuje návrhu a vývoju aplikačného rámca, ktorý bude podporovať škálovanie serverov a synchronizáciu dát medzi nimi.

Úvod

S rozmachom veľkých spoločností, ktoré potrebujú svoje dáta uchovávať, distribuovať a mať ich dostupné pre používateľov na celom svete, sa kladie veľký dôraz na škálovateľnosť backendov. V súčasnosti existuje mnoho aplikačných rámcov a technológií, ktoré umožňujú rýchly a agilný vývoj backendov.

Možnosti prístupu k vývoju škálovateľného backendu sú rôzne. Rozlišujeme monolitické aplikácie, ktoré sú veľké, komplexné a ich škálovanie väčšinou znamená nasadenie celej aplikácie na nový hardvér. Microservice architektúra zase ponúka možnosť aplikáciu rozdeliť na veľké množstvo navzájom komunikujúcich častí, ktoré môžu byť napísané v rôznych programovacích jazykoch a používať odlišné aplikačné rámce. Škálovanie je v tomto prípade flexibilnejšie, keď nám stačí nasadiť len tie časti aplikácie, na ktoré je vyvíjaná veľká záťaž.

Cieľom práce je navrhnúť a implementovať aplikačný rámec, pomocou ktorého bude mať potenciálny zákazník možnosť nakonfigurovať rozdistribuované backendy. Následne by mala prebiehať nastavená forma komunikácie medzi nasadenou hierarchiou serverov. Dôležité bude docieliť spoľahlivú konzistenciu dát v databázach naprieč jednotlivými servermi.

Backend

V softvérovom inžinierstve sa pri využívaní komunikácie typu client-server stretávame s pojmami frontend a backend. Tieto termíny predstavujú separáciu úloh v aplikácii medzi prezentačnou vrstvou (frontendová časť) a vrstvou pristupujúcou k dátam (backendová časť). Používateľ prichádza do styku s používateľským rozhraním FE časti a do vnútorných procesov, ktoré majú na starosti biznis logiku a prístup k dátovej vrstve nevidí. Táto backenová časť nemusí byť nutne nainštalovaná/nasadená na klientskom zariadení. Môže sa nachádzať na vzdialenom serveri.

Možnosti škálovania backendu

Škálovateľnosť je schopnosť systému, aplikácie alebo siete spracovávať narastajúci počet práce, požiadaviek, používateľov. Systém, ktorého výkon sa pri narastajúcej záťaži zväčšuje pridaním zdrojov sa nazýva škálovateľným. Škálovaním hore systém získava výkon a škálovaním dole cenovú efektivitu, keď zákazník nemusí platiť za prebytočné zdroje napr. u cloudového providera.

Monolitické aplikácie

Tento typ aplikácie je zabalený a nasadený ako monolit v súborovom type jar, war alebo zip. Takéto aplikácie sú rozšírené a majú mnoho výhod ako ľahkú pochopiteľnosť, vývoj, testovanie, spravovanie a nasadzovanie. Škálujú jednoducho spustením viacerých kópií s load balancerom (vyvažovač zaťaženia).

Architektúra monolitickej aplikácie
Obrázok 1: Architektúra monolitickej aplikácie

Medzi nevýhody patrí to, že sa v aplikácii po čase ťažko orientuje, používa konkrétny jazyk a rámce, ktoré je ťažké obmeniť kvôli naviazaniu na mnoho častí aplikácie. Monolitická aplikácia stáva po čase príťažou, keďže aj najmenšia zmena systému si vyžaduje prebuildovanie a znovunasadenie celej aplikácie. Nasadzuje ako celok, a teda nemôžeme jej zmeny vypúšťať postupne. Zdroje nie sú optimalizované, keďže rôzne komponenty majú rôzne nároky na hardvér a nemôžu sa škálovať oddelene. Na obrázku 1 je znázornená architektúra monolitickej aplikácie.

Microservice architektúra

Veľa nevýhod monolitickej architektúry aplikácií rieši microservices (mikroservisová) architektúra. V tejto architektúre je aplikácia rozdelená na mnoho častí, ktoré sa spravujú ako celok. Je využívaná mnohými organizáciami ako Amazon, Netflix a mnoho iných. Cieľom je vytvorenie prepojených služieb. Každá časť implementuje časť funkcionality napr. správa: používateľov, objednávok, košíka, katalógov a vyhľadávania.

Každá časť je vyvíjaná, testovaná a nasadzovaná oddelene. Jediný vzťah medzi jednotlivými microservice-ami je dátová výmena prostredníctvom API, ktoré odhaľujú. Každá microservice služba môže byť napísaná v inom programovacom jazyku a rámci, keďže je nezávislá od ostatných. Klient by mal mnoho problémov s touto komplexnosťou, komunikáciou a autentifikáciou k rôznym službám a spravovaním prístupových bodov. Všetky tieto čiastkové služby sú preto skryté za ďalšou väčšou služobnou vrstvou nazývanou ako API brána.

Znázornená microservice architektúra
Obrázok 2: Znázornená microservice architektúra

Medzi výhody patrí ľahšie škálovanie v porovnaní s monolitickými aplikáciami, keďže nie je nutné duplikovať celú aplikáciu, ale len tie časti, ktoré potrebujeme. Ďalšou výhodou je väčšia flexibilita pri inováciách a zmenách. Rýchlejšie sa spúšťajú a IDE vie s menšími projektami rýchlejšie pracovať. Na obrázku 2 je znázornená microservice architektúra.

Spring vs ASP.NET

Výhodou technológií využívajúcich Javu teda napr. Spring MVC je kvalitnejšia a väčšia ponuka IDE a ich rozšírenosť. Obmedzený štýl kódu prispieva k jeho lepšej čitateľnosti. V Spring rámci je nutná vysoká miera konfigurácie prostredníctvom XML súborov. Podpora pre vlákna a asynchrónnu komunikáciu je slabšia ako u konkurenta ASP.NET.

U rámcov .NET, ASP.NET je jediným najlepším IDE od samotného Microsoftu a to Visual Studio, čoho výsledkom je väčšia integrácia. ASP.NET ponúka rýchlejšiu implementáciu a lepšiu dokumentáciu. Konfigurácia je používateľsky prívetivejšia a nevyžaduje veľa XML a iných konfiguračných súborov. Nízkoúrovňové jazykové konštrukcie ponúkajú lepšiu optimalizáciu softvéru. Výber aplikačného rámca, ktorý som využíval v tejto práci bol jednoduchý, keďže sme chceli použiť technológie jednej spoločnosti na vývoj frontendu aj backendu. Microsoft ponúka rámec Xamarin, ktorý umožňuje vyvíjať veľkú časť FE aplikácie jednotným spôsobom pre všetky mobilné platformy a desktopové systémy.

Na vývoj backendovej časti sa použije ASP.NET Core, mnoho rámcov od spoločnosti Microsoft a na obidvoch stranách ich vývojové prostredie Visual Studio 2017, ku ktorému máme ako študenti plný prístup. Výhodou je aj možnosť využiť Microsoft Imagine študentský účet na nasadzovanie a testovanie backendu na cloudového providera spoločnosti Microsoft Azure.

Nasadenie na Azure

Možnosti nasadenia backendovej časti sú v dnešnej dobe bohaté. Existuje veľa overených produktov od veľkých hráčov alebo opensource riešenia. Medzi najväčšie a najrozšírenejšie web servery patria Apache HTTP server a IIS (Internet Information Services).

V súčasnosti existuje mnoho cloudových providerov, ktorí ponúkajú svoje služby v obmedzenom režime aj zadarmo. Pre účely testovania bude takýto účet dostačujúci a voľnú licenciu Microsoft Imagine nám ponúka ako študentom zadarmo. Cloud computing služby ponúka Microsoft, Google, Amazon a mnoho iných. Služba je určená na buildovanie, testovanie, nasadzovanie, manažovanie aplikácií a manažovanie služieb prostredníctvom globálnej siete dátových centier spoločnosti Microsoft.

Azure konfigurácia aplikácie a služieb
Obrázok 3: Azure konfigurácia aplikácie a služieb

Vo Visual Studiu je nutné nastaviť náš Azure účet, či už s licenciou Microsoft Imagine alebo Pay as you go. Vieme si nastaviť názov aplikácie, plán služby a názov skupiny zdrojov, ktorý by mal byť jedinečný pre každú novo nasadenú inštanciu. V novom okne nakonfigurujeme novú SQL databázu. Vyplníme položky názov databázy a reťazec pripojenia (connection string). Pridáme nový SQL server, na ktorom nám bude databáza bežať (Obrázok 3). V konfigurácii SQL servera je dôležité vyplniť názov servera, meno a heslo administrátora. Po nakonfigurovaní aplikácie aj databázového servera, môžeme vytvoriť inštancie nášho servera na Azure prostredí.

Obrázok 4 znázorňuje architektúru Thin servera, ktorý bude škálovateľný nasadením na rôzny počet serverov a cloudových providerov. Na ľavej časti je zobrazená klientská aplikácia, ktorá bude multiplatformová. Bude bežať na všetkých mobilných operačných systémov aj na desktope s OS Windows. Používateľ bude prostredníctvom prezentačnej vrstvy komunikovať so serverom cez API rozhranie. Server spracuje požiadavku, vykoná biznis logiku, prípadne rozdistribuuje dáta nadradeným/podradeným serverom. Počas spracovávanie server pristupuje k potrebným dátam prostredníctvom databázovej abstrakcie, aplikačného rámca Entity Framework od spoločnosti Microsoft.

Komponenty frontnedu a backendu cieľového systému
Obrázok 4: Komponenty frontnedu a backendu cieľového systému

Na obrázku 5 sú zobrazené projekty/knižnice, ktoré tvoria Solution. Žltou farbou sú znázornené priečinky, ktoré tvoria rámec zabezpečujúci škálovanie backendov. Tento rámec bol v celkovom projekte rozšírený o doménu POS. ShopBackend obsahuje Controllery, ktoré sú časťou zabezpečujúcou komunikáciu prostredníctvom REST rozhrania. Controllery v podpriečinku Server konfigurujú nasadené servery a ich celkovú hierarchiu. Dôležitým je priečinok Sync, ktorý obsahuje implementáciu, pomocou ktorej je možné ľahko synchronizovať servery v hierarchii, to znamená posielať dáta rodičovským/podradeným serverom.

Komponenty serveru
Obrázok 5: Komponenty serveru

Projekt ShopBackend.Data tvorí vrstvu obsahujúcu repozitáre prostredníctvom, ktorých sa z controllerov pristupuje cez rozhranie entity rámca k dátam. Dáta sú reprezentované ako modely v priečinku Entities projektu ShopBackend.Model. Ďalej tento projekt obsahuje pohľady (views). Modrou farbou sú na obrázku zobrazené časti v Solution tvoriace doménu. Vytvorenie aplikačnej domény do Solution sa skladá z minimálne týchto 3 častí: vytvorenie modelov, ktoré budú reprezentované v databáze ako tabuľky, vytvorenie a implementácia príslušných repozitárov k entitám a implementácia controllerov rozšírená o funkcionalitu synchronizácie zabezpečenou triedou SyncData.

Trieda SyncData obsahuje nasledujúce metódy zabezpečujúce synchronizáciu dát v nasadenej hierarchii serverov.

//synchronizácia od centrálneho servera
public async Task SyncCentralTask(String endpoint, Object body, int idToDelete, RequestMethod enumValue)
//synchronizácia smerom nahor 
public async Task SyncUpTask(String endpoint, Object body, int idToDelete, RequestMethod enumValue)
//synchronizácia smerom nadol 
public async Task SyncDownTask(String endpoint, Object body, int idToDelete, RequestMethod enumValue)
//hlavná synchronizačná metóda 
public async Task SyncTask(String endpoint, String accessToken, Object body, int idToDelete, RequestMethod enumValue)

Medzi nasadenými servermi bude dochádzať k vzájomnej komunikácii prostredníctvom REST rozhrania. V rámci softvérového rámca, ktorý bude samotným serverom, bude možné nastavovať smer komunikácie. Komunikácia medzi jednotlivými servermi bude zabezpečovať konzistenciu dát naprieč celým systémom, teda hierarchiou serverov.

Hierarchia nasadených serverov
Obrázok 6: Hierarchia nasadených serverov

Obrázok 6 znázorňuje diagram hierarchie serverov, ktoré reprezentujú fyzickú štruktúru organizácie obchodov, keďže je aplikačný rámec odprezentovaný na POS (Point of Sale) doméne. V horných vrstvách sú napríklad headquarter a reťazce. Spodná vrstva serverov reprezentuje obchody alebo pokladne, počítače s backendom. Zákazník si bude môcť nastaviť 3 typy smeru synchronizovania údajov. Možnosť synchronizácie bude prístupná pre hocijakú doménu zvolenú zákazníkom. Dáta špecifickej domény bude možné synchronizovať zavolaním príslušných metód triedy Sync na úrovni REST metód POST, UPDATE, DELETE v controlleroch.

Pre niektoré dáta nie je nutné aby boli konzistentné naprieč celou hierarchiou serverov. Po nablokovaní bločku, ktorý sa uloží lokálne, sa zároveň pošle rodičovskému serveru. Keďže je logika implementovaná rovnako v každom serveri, synchronizácia dát smerom nahor bude prebiehať dovtedy pokiaľ trieda Sync nájde nadradený server aktuálneho servera. Táto synchronizácia je znázornená na obrázku 6 červenými šípkami.

Prípad synchronizácie naprieč všetkými servermi je na obrázku 6 zobrazený zelenými šípkami. V našej doméne bude používaný pri operáciách POST, UPDATE, DELETE vykonávaných manažérom. Pri dátach upravených manažérom v systéme je nutné aby sa nesynchronizovali len smerom hore/dole ale do celej hierarchie serverov. V prvom kroku sa zistí používateľská rola (manažér/pokladník/server). Ak danú metódu vyvolal manažér z prostredia back officu napr. voči serveru 11 zavolá sa metóda SyncCentralTask(), aby poslala daný request centrálnemu serveru (1). Následne sa vykoná metóda SyncDownTask(), aby sa zosynchronizovali aj podservery aktuálneho servera (111, 112). Predchádzajúca metóda SyncCentralTask() zabezpečí synchronizáciu ostatných serverov (12, 121, 122,...), keďže pri vykonaní bude prechádzať len metódou SyncDownTask(). Nakoniec sa uloží nový vytvorený model z POST requestu alebo upravený z PUT requestu do databázy jednotlivých serverov.

Skúsenosť s Azure - Pay as you go

Aplikačný rámec podporujúci škálovanie backendov a ich vzájomnú komunikáciu (synchronizáciu dát) sme otestovali aj nasadením hierarchie serverov na cloudovú službu Azure.

Začali sme so študentským účtom Microsoft Imagine, ktorý sme využívali niekoľko mesiacov v prvotných fázach vývoja. Po niekoľkých mesiacoch však jeho platnosť vypršala a zablokovala kľúčové funkcie potrebné pre nasadenie serveru do cloudového priestoru. Dostali sme však príležitosť skúsiť typ členstva Pay as you go, ktoré účtuje poplatky za využité zdroje priebežne a dynamicky podľa využívania.

Graf znázorňujúci počet requestov na server
Obrázok 7: Graf znázorňujúci počet requestov na server

Na vyhodnotenie ceny pre potenciálneho zákazníka/obchod, sme z prostredia Azure vybrali štatistiku počtu requestov na server Shoppingbackend20180419222222. Graf priebehu počtu requestov v časovom období 20.apríla – 22.apríla je zobrazený na obrázku 7. Predpokladajme, že na vybavenie jedného zákazníka/kupujúceho potrebujeme 10 requestov (skenovanie 6 produktov + prijatie pokladničného bloku serverom a synchronizácia s 3 rodičovskými servermi).

Keď zanedbáme občasné dopĺňanie tovaru, úpravu cien, DPH manažérom môžeme vypočítať približnú priemernú cenu na vybavenie jedného nakupujúceho zákazníka. Ďalej predpokladáme, že cena za službu je vypočítavaná len na základe počtu requestov na server. 884 requestov by nám v tomto prípade stačilo na vybavenie 88 kupujúcich zákazníkov a obchod by to stálo 1,79 eura. Finančné zaťaženie na prevádzku serverov obchodmi by na jedného nakupujúceho zákazníka bolo 2 euro centy.