Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Selles artiklis rÀÀgin, kuidas projekt, millega töötan, muutus suurest monoliidist mikroteenuste kogumiks.

Projekt alustas oma teekonda ĂŒsna ammu, 2000. aastate alguses. Esimesed versioonid kirjutati Visual Basic 6-s. Aja jooksul sai selgeks, et selle keele arendamine tulevikus on keeruline, kuna IDE ja keel ise arenesid aeglaselt. 2000. aastate lĂ”pus otsustati liikuda perspektiivikama C#-ni. Uut versiooni kirjutati paralleelselt vana tĂ€iendamisega, jĂ€rjest rohkem koodi oli .NET-is. Backend C#-is oli algselt suunatud teenuse arhitektuurile, kuid arendamise kĂ€igus kasutati ĂŒhiseid raamatukogusid, mis sisaldasid loogikat, ja teenuseid kĂ€ivitati ĂŒhes protsessis. Tulemuseks oli rakendus, mida me nimetasime "teenusteks mĂ”eldud monoliidiks".

Üks vĂ€heseid sellise ĂŒhenduse eeliseid oli see, et teenused said ĂŒksteist vĂ€lise API kaudu kutsuda. Oli ilmseid eeltingimusi ĂŒleminekuks Ă”igemale teenuse arhitektuurile ja tulevikus ka mikroteenuste arhitektuurile.

Oma dekodeerimistööd alustasime umbes 2015. aastal. Kuigi me ei ole veel saavutanud ideaalset olekut — suur projekt, millest osad on juba raskesti nimetatavad monoliitideks, kuid ka mikroteenusteks nad ei sarnane. Siiski on edusamm mĂ€rkimisvÀÀrne.
Sellest rÀÀgin artiklis.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Sisukord

Arhitektuur ja olemasoleva lahenduse probleemid


Algne arhitektuur nĂ€gi vĂ€lja jĂ€rgmine: UI - eraldi rakendus, monoliitne osa kirjutatud Visual Basic 6-s, .NET rakendus oli seotud teenuste kogum, mis töötas ĂŒsna suure andmebaasiga.

Endise lahenduse puudused

Üksik veaallikas
Meil oli ĂŒksikud tĂ”rkepunkt: .NET rakendus töötas ĂŒhes protsessis. Kui mĂ”nes moodulis tekkis tĂ”rge, lakkas kogu rakendus töötamast ja tuli taaskĂ€ivitada. Kuna automatiseerime suures koguses protsesse erinevatele kasutajatele, ei saanud kĂ”ik nende tĂ”ttu mĂ”nda aega tööd teha. Ja programmivea korral ei aidanud ka varukoopia.

Töötlemise jÀrjekord
See puudus on pigem organisatsiooniline. Meie rakenduses on palju kliente, ja kĂ”ik nad tahavad, et arendustööd tehtaks vĂ”imalikult kiiresti. Varem ei olnud seda paralleelselt teha vĂ”imalik ja kĂ”ik kliendid pidid jĂ€rjekorras olema. See protsess tekitas Ă€ri seas negatiivset tagasisidet, kuna nad pidid tĂ”estama, et nende ĂŒlesanne on vÀÀrtuslik. Arendusmeeskond kulutas aega jĂ€rjekorra korraldamisele. See vĂ”ttis palju aega ja energiat, ning toode ei saanud lĂ”puks muutuda nii kiiresti, kui nad sooviksid.

Ebaoptimaalne ressursside kasutamine
Teenuste paigutamisel ĂŒhte protsessi kopeerisime alati konfiguratsiooni tĂ€ielikult serverilt serverile. Soovisime paigutada kĂ”ige koormatumad teenused eraldi, et mitte raisata ressursse, ning saavutada paindlikum hallatavus meie deploymendi skeemis.

Kaasaegsete tehnoloogiate rakendamine on keeruline
Loodud arendajatele tuntud probleem: on soov rakendada projekti kaasaegseid tehnoloogiaid, kuid vĂ”imalust pole. Suure monoliitse lahenduse korral muutub iga praeguse teegi uuendamine, rÀÀkimata uuele ĂŒleminekust, ĂŒsna keeruliseks ĂŒlesandeks. Peab kaua tĂ”estama tiimijuhile, et see toob rohkem kasu kui kulutatud nĂ€rvid.

Muudatuste vÀljaandmise keerukus
See oli kĂ”ige tĂ”sisem probleem – andsime vĂ€lja versioone iga kahe kuu tagant.
Iga vĂ€ljaanne muutus pangale tĂ”eliseks katastroofiks, vaatamata testimisele ja arendajate pingutustele. Äri mĂ”istis, et neil ei tööta nĂ€dala alguses osa funktsionaalsusest. Arendajad mĂ”istsid, et neid ootab ees tĂ”siste sĂŒndmuste nĂ€dal.
Soov olukorda muuta oli kÔigil.

Ootused mikroteenustelt


Komponentide vÀljaandmine valmisoleku jÀrgi. Komponentide vÀljaandmine vastavalt valmisolekule, tÀnu lahenduse dekodeerimisele ja erinevate protsesside eraldamisele.

VÀikesed tootegrupid. See on oluline, sest suure meeskonna juhtimine vanade monoliitide kallal oli keeruline. Selline meeskond pidi töötama rangete protsesside jÀrgi, samas kui rohkem loovust ja sÔltumatust oleks olnud soovitav. Seda suudavad endale lubada vaid vÀiksed meeskonnad.

Teenuste isoleerimine eraldi protsessidesse. Ideaalis oleks soovitud isoleerida konteinerites, kuid suur hulk teenuseid, mis on kirjutatud .NET Frameworkis, töötavad ainult Windowsis. Praegu ilmuvad teenused .NET Core'is, kuid neid on seni veel vÀhe.

Paindlikkus juurutamisel. Sooviksime kombineerida teenuseid nii, nagu see meile vajalik, mitte nagu kood meid sunnib.

Uute tehnoloogiate kasutamine. See on huvitav iga programmeerija jaoks.

Ülemineku probleemid


Loomulikult, kui monoliiti oleks lihtne mikroteenusteks jagada, ei rÀÀgiks sellest konverentsidel ega kirjutataks artikleid. Selles protsessis on palju takistusi, kirjeldan peamisi, mis meid segasid.

Esimene probleem tĂŒĂŒpiline enamikule monoliitidele: Ă€riloogika seotus. Kui kirjutame monoliidi, siis tahame taaskasutada meie klasse, et vĂ€ltida liigset koodi kirjutamist. Kuid mikroteenustele ĂŒleminekul muutub see probleemiks: kogu kood on piisavalt tugevalt seotud ja teenuste eristamine on keeruline.

Tööde alguse hetkel oli meie repositooriumis ĂŒle 500 projekti ja ĂŒle 700 tuhande koodi rea. See on ĂŒsna suur lahendus ja teine probleem. Lihtsalt vĂ”tta ja jagada see mikroteenusteks ei olnud vĂ”imalik.

Kolmas probleem — vajalikku infrastruktuuri puudumine. Tegelikult tegelesime allika koodi kĂ€sitsi kopeerimisega serveritesse.

Kuidas liikuda monoliidilt mikroteenustele


Mikroteenuste eristamine

Esiteks, mÀÀrasime endale kohe, et mikroteenuste eristamine on iteratiivne protsess. Meilt nĂ”uti pidevalt, et areneve idee ĂŒlesanne tehakse paralleelselt. Kuidas me seda tehniliselt teostame — see on juba meie probleem. SeetĂ”ttu olime valmis iteratiivseks protsessiks. Teistmoodi ei ole vĂ”imalik, kui teil on suur rakendus ja see ei ole algselt selleks ette valmistatud, et seda ĂŒmber kirjutatakse.

Milliseid meetodeid me kasutame mikroteenuste eristamiseks?

Esimene viis — vĂ€ljastama olemasolevaid mooduleid teenustena. Meie puhul oli Ă”nne, et olid juba loodud teenused, mis töötasid WCF protokolli jĂ€rgi. Need olid jagatud erinevatesse kogumitesse. Me edasi kandsime need eraldi, lisades igale kogumile vĂ€ikese kĂ€ivitamismoduli. See oli kirjutatud suurepĂ€rase Topshelf teegi abil, mis vĂ”imaldab rakendust kĂ€ivitada nii teenusena kui ka kĂ€surealt. See on mugav silumise jaoks, kuna ei ole vaja tĂ€iendavaid projekte lahenduses.

Teenused olid seotud Ă€riloogikaga, kuna kasutasid ĂŒhiseid kogumeid ja töötasid ĂŒhise andmebaasiga. Neid oli raske pidada puhasteks mikroteenusteks. Siiski, saime neid teenuseid eraldi vĂ€lja anda, erinevates protsessides. Isegi see vĂ”imaldas vĂ€hendada nende omavahelist mĂ”ju, leevendades paralleelse arendamise ja ĂŒhtse tĂ”rkepunkti probleemi.

Hosti kogum on Program klassis vaid ĂŒks rida koodi. Tööd Topshelfiga peitsime me tugiklassi.

namespace RBA.Services.Accounts.Host
{
   internal class Program
   {
      private static void Main(string[] args)
      {
        HostRunner.Run("RBA.Services.Accounts.Host");

       }
    }
}

Teine viis mikroteenuste eristamiseks: luua neid uute ĂŒlesannete lahendamiseks. Kui samal ajal monoliit ei kasva, on see juba suurepĂ€rane, see tĂ€hendab, et liigume Ă”iges suunas. Uute ĂŒlesannete lahendamiseks pĂŒĂŒdsime luua eraldi teenuseid. Kui see oli vĂ”imalik, siis lĂ”ime „kanonilisemaid“ teenuseid, mis haldavad tĂ€ielikult oma andmemudelit ja eraldi andmebaasi.

Me, nagu paljud, alustasime autentimise ja volitamise teenustega. Need sobivad selleks ideaalselt. Need on sĂ”ltumatud, reeglina on neil eraldi andmemudel. Need ei suhtle monoliidiga, vaid vaid monoliit pöördub nende poole, et lahendada teatud ĂŒlesandeid. Nendel teenustel saab alustada ĂŒleminekut uuele arhitektuurile, siluda neid infrastruktuuri, proovida erinevaid lĂ€henemisviise, mis on seotud vĂ”rguteekide jms-ga. Meie organisatsioonis ei ole ĂŒhtegi meeskonda, kellel ei Ă”nnestuks luua autentimise teenust.

Kolmas viis mikroteenuste eristamiseks, mida me kasutame, on meie jaoks veidi spetsiifiline. See tÀhendab Àriloogika eraldamist UI-kihist. Meie pÔhiliides on lauaarvuti rakendus, mis on nagu ka backend kirjutatud C#. Arendajad on aeg-ajalt teinud vigu ja viinud UI-sse looge, mis peaks olema backendis ja taaskasutatav.

Kui vaatame konkreetset nÀidet UI-osa koodist, siis on nÀha, et suur osa sellest lahendusest sisaldab endas tÔelist Àriloogikat, mis on kasulik ka muudes protsessides, mitte ainult UI-vormi koostamiseks.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

TÔelisest UI-logikast on seal ainult viimane paar rida. Me viisime selle serverisse, et saaksime seda taaskasutada, vÀhendades seelÀbi UI-d ja saavutades Ôige arhitektuuri.

Neljas, kĂ”ige olulisem viis mikroteenuste eraldamiseks, mis aitab vĂ€hendada monoliiti, on olemasolevate teenuste edasiviimine koos ĂŒmberehitusega. Kui me toome olemasolevad moodulid sellisena vĂ€lja, pole tulemus arendajatele alati meelepĂ€rane ja Ă€riprotsess vĂ”ib ajaga vananeda, alates funktsionaalsuse loomisest. Refaktoreerimise kaudu saame toetada uusi Ă€riprotsesse, sest Ă€ri nĂ”uded muutuvad pidevalt. Saame parandada algset koodi, eemaldada tuntud defekte ja luua kvaliteetsema andmemudeli. Saame palju eeliseid.

Teenuste eraldamine ĂŒmberehitusega on tihedalt seotud piiratud konteksti mĂ”istega. See mĂ”isted on objektorienteeritud projekteerimise termin. See tĂ€histab domeenimudeli osa, kus kĂ”ik arusaamiskeele terminid on ĂŒheselt mÀÀratletud. Vaatame nĂ€iteks kindlustuse ja arve konteksti. Meil on monoliitne rakendus ja on vajalik töötada kindlustustes arvega. Ootame, et arendaja leiab teisest kogumist olemasoleva klassi "Arve", teeb viite klassist "Kindlustus" ja me saame töötava koodi. DRY pĂ”himĂ”tet jĂ€rgides saab ĂŒlesanne, kasutades olemasolevat koodi, kiiremini teostatud.

KokkuvÔttes selgub, et arve- ja kindlustuskontekstid on omavahel seotud. Kui tekivad uued nÔuded, hÀirib see seos arendust, suurendades juba nii keerulise Àri loogika keerukust. Selle probleemi lahendamiseks tuleb koodis leida piirid kontekstide vahel ja eemaldada nende rikkumised. NÀiteks kindlustuse konteksti jaoks vÔib piisata 20-kohalisest arve numbrist ja arve avamise kuupÀevast.

Kuna need piiratud kontekstid tuleb ĂŒksteisest eraldada ja alustada mikroteenuste eraldamise protsessi monoliitsest lahendusest, kasutasime lĂ€henemist, kus loodi rakenduses vĂ€list API-d. Kui me teadsime, et mĂ”ni moodul peab muutuma mikroteenuseks, tegime kohe vĂ€ljakutseid loogikale, mis kuulub teise piiratud konteksti, vĂ€liste kutsungite kaudu. NĂ€iteks REST vĂ”i WCF kaudu.

Oleme endale kindlaks teinud, et ei vĂ€ldi koodi, mis nĂ”uab jaotatud tehingute tegemist. Meie puhul oli seda reeglit ĂŒsna lihtne jĂ€rgida. Meil ei ole siiani tekkinud selliseid olukordi, kus tĂ”eliselt vajalikud oleksid ranged jaotatud tehingud — lĂ”ppkokkuvĂ”ttes on piisav vaheline jĂ€rjepidevus moodulite vahel.

Vaatame konkreetset nĂ€idet. Meil on kontseptsioon orkestrandist — torustik, mis töötleb „taotluse“ ĂŒksust. See loob jĂ€rjestikku kliendi, arve ja pangakaardi. Kui klient ja arve on edukalt loodud, kuid kaardi loomine ebaĂ”nnestub, ei muutu taotlus olekusse „Ônnestunud“, vaid jÀÀb olekusse „kaart ei ole loodud“. Tulevikus haarab taustategevus selle ĂŒles ja lĂ”petab. SĂŒsteem on mĂ”nda aega ebasĂŒmpaatne, kuid see meid sisuliselt rahuldab.

Kui siiski tekib olukord, kus on vaja kooskĂ”las hoida osa andmeid, siis tĂ”enĂ€oliselt lĂ€heneme teenuse suurendamisele, et seda ĂŒhes protsessis töötelda.

Vaatame mikroteenuse eraldamise nĂ€idet. Kuidas saame selle suhteliselt ohutult tootmisse viia? Selles nĂ€ites on meil sĂŒsteemi eraldi osa — palgaarvestuse moodul, mille osa koodist tahame muuta mikroteenuseks.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Esimese asjana loome mikroteenuse, kirjutades koodi ĂŒmber. Parandame mĂ”ned asjad, mis meid ei rahuldanud. Rakendame uusi Ă€rinĂ”udeid tellijalt. Lisame UI ja backend'i vahele API Gateway, mis tagab kĂ”nede edastamise.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

SeejĂ€rel viime selle konfiguratsiooni tootmisse, kuid pilootseisundis. Enamik kasutajaid töötab endiselt vanade Ă€ri protsessidega. Uutele kasutajatele arendame uue versiooni monoliidist, mis seda protsessi enam ei sisalda. Sisuliselt töötab meil pilootprojekti korras monoliidi ja mikroteenuse ĂŒhendus.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Eduka pilootprojekti korral mÔistame, et uus konfiguratsioon on tÔepoolest toimiv, saame vanast monoliidist vabaneda ja jÀtta uue konfiguratsiooni vana lahenduse asemele.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

KokkuvĂ”ttes kasutame praktiliselt kĂ”iki olemasolevaid meetodeid monoliidi lĂ€htekoodi eraldamiseks. Need kĂ”ik vĂ”imaldavad meil vĂ€hendada rakenduse osi ja viia need ĂŒle uutele raamatukogudele, luues parema lĂ€htekoodi.

Töötamine BDs


Andmebaasi jagamine on keerulisem kui lÀhtekoodi jagamine, kuna see sisaldab mitte ainult praegust skeemi, vaid ka kogunenud ajaloolisi andmeid.

Meie andmebaasil, nagu paljudel teistel, oli veel ĂŒks oluline puudus — tohutu suurus. Seda andmebaasi kavandati keerulise monoliidi Ă€ri loogika kohaselt ning nende tabelite vahel, mis kuuluvad erinevatesse piiratud konteksti, on akumuleerunud seoseid.

Meie puhul, kui kĂ”ik halb on kokku tulnud (suur andmebaas, palju seoseid, vahel arusaamatud piirid tabelite vahel), tekkis probleem, millega paljudes suurtes projektides silmitsi seista: jagatud andmebaasi malli rakendamine. Andmeid vĂ”eti tabelitest vaate kaudu, replikatsiooni kaudu ja saadeti teistesse sĂŒsteemidesse, kus seda replikatsiooni nĂ”uti. Tulemuseks oli see, et me ei saanud tabeliteid eraldi skeemi viia, sest neid kasutati aktiivselt.

Jagamisel aitab meid see piiratud kontekstide eraldamine koodis. See annab meile tavaliselt piisavalt hea ĂŒlevaate andmete jagamisest andmebaasi tasandil. Me mĂ”istame, millised tabelid kuuluvad ĂŒhte piiratud konteksti ja millised teise.

Me rakendasime kahte globaalset meetodit andmebaasi jagamiseks: olemasolevate tabelite eraldamine ja eraldamine ĂŒmberkujundamisega.

Olemasolevate tabelite eraldamine on meetod, mida on hea rakendada, kui andmestruktuur on kvaliteetne, rahuldab ÀrinÔudeid ja kÔigile sobib. Sel juhul saame olemasolevad tabelid eraldada eraldi skeemi.

Eraldamine ĂŒmberkujundamisega on vajalik, kui Ă€ri mudel on oluliselt muutunud ja tabelid ei rahulda meid enam.

Olemasolevate tabelite eraldamine. Peame mÀÀratlema, mida me eraldame. Ilma selle teadmiseta ei saa me midagi teha, ja siin aitab meid koodis piiratud konteksti jagamine. Üldiselt, kui Ă”nnestub mĂ”ista konteksti piire algkoodis, saab selgeks, millised tabelid peaksid olema eraldamise loendis.

Kujutame ette, et meil on lahendus, kus kaks monoliidi moodulit suhtlevad ĂŒhe andmebaasiga. Peame tegema nii, et eraldatavate tabelite osaga suhtleb ainult ĂŒks moodul, samas kui teine hakkab sellega suhtlema lĂ€bi API. Alguses piisab, kui API kaudu on ainult kirjutamine. See on vajalik tingimus, et saaksime rÀÀkida mikroteenuste sĂ”ltumatusest. Lugemise seosed vĂ”ivad jÀÀda, seni kuni see ei pĂ”hjusta suuri probleeme.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

JĂ€rgmise sammu kĂ€igus saame juba eraldada koodiosa, mis töötab eraldatavate tabelitega, ĂŒmberkujundamisega vĂ”i ilma, eraldi mikroteenuseks ja kĂ€ivitada selle eraldi protsessis, konteineris. See on eraldi teenus, millel on ĂŒhendus monoliidi andmebaasiga ja nende tabelitega, mis ei kuulu otseselt sinna. Monoliit suhtleb veel lugemise kaudu eraldatud osaga.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Hiljem eemaldame selle seose, st monoliidi rakenduse andmete lugemine eraldatavatest tabelitest viiakse samuti API-le.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Edasi eraldame ĂŒldisest andmebaasist tabelid, millega töötab ainult uus mikroteenus. Saame tabelid viia eraldi skeemi vĂ”i isegi eraldi fĂŒĂŒsilisse andmebaasi. JÀÀb lugemise seos mikroteenuse ja monoliidi andmebaasi vahel, kuid selles pole midagi hullu; sellises konfiguratsioonis vĂ”ib see piisavalt kaua elada.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Viimane samm on tĂ€ielikult eemaldada kĂ”ik seosed. Selle korral vĂ”ib meil olla vajalik andmete migreerimine pĂ”hivaatest. MĂ”nikord soovime taaskasutada mĂ”ningaid vĂ€liste sĂŒsteemide replitseeritavaid andmeid vĂ”i registrite andmeid mitmes erinevas andmebaasis. Meil esineb seda perioodiliselt.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Üksus ĂŒleviidud töötlusega. See meetod sarnaneb vĂ€ga esimesega, kuid kĂ€ib vastupidises jĂ€rjekorras. Meil luuakse kohe uus andmebaas ja uus mikroteenus, mis suhtleb monoliidiga API kaudu. Samas jÀÀb alles andmebaasi tabelite kogum, mille me soovime tulevikus eemaldada. Me ei vaja seda enam, uues mudelis asendasime selle.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Et see skeem töötaks, on meil tĂ”enĂ€oliselt vajalik ĂŒleminekuperiood.

Edasi on kaks vÔimalikku lÀhenemist.

Esimene: dubleerime kĂ”ik andmed uutes ja vanades andmebaasides. Sel juhul tekib meil andmete ĂŒlekĂŒllus, vĂ”ivad tekkida sĂŒnkroniseerimisprobleemid. Kuid sel juhul saame vĂ”tta kaks erinevat klienti. Üks töötab uue versiooniga, teine vana versiooniga.

Teine: jagame andmeid mingi Ă€rimĂ€rgi jĂ€rgi. NĂ€iteks, meil oli sĂŒsteemis 5 toodet, mis on salvestatud vanasse andmebaasi. Kuuendat uue Ă€rilise ĂŒlesande raames paneme uude andmebaasi. Kuid meil on vaja API Gateway't, mis sĂŒnkroniseerib need andmed ja nĂ€itab kliendile, kust ja mida vĂ”tta.

MÔlemad lÀhenemised on toimivad, valige sÔltuvalt olukorrast.

PĂ€rast seda, kui oleme veendunud, et kĂ”ik töötab, saab osa monoliidist, mis töötab vanade andmebaasi struktuuridega, vĂ€lja lĂŒlitada.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Viimane samm on vanade andmestruktuuride eemaldamine.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

KokkuvÔtteks vÔib öelda, et meil on andmebaasidega probleeme: sellega on töötamine keerulisem vÔrreldes allikakoodiga, eraldamine on raskem, kuid seda on vÔimalik ja vajalik teha. Oleme leidnud mÔned meetodid, mis vÔimaldavad seda teha piisavalt ohutult, sest andmetes eksida on lihtsam kui allikakoodis.

Töö lÀhtekoodiga


Nii nĂ€gi vĂ€lja algse koodi skeem, kui me alustasime monoliitprojekti analĂŒĂŒsi.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Seda vĂ”ib tinglikult jagada kolmeks kihiks. See on kĂ€ivitatavate moodulite, pluginate, teenuste ja eraldi tegevuste kiht. Tegelikult olid need sisenemisvahendid monoliitsetes lahendustes. KĂ”ik need olid tihedalt seotud Common kihiga. See sisaldas Ă€riloogikat, mida teenused kasutasid ĂŒhiselt, ja rohkesti seoseid. Iga teenus ja plugin kasutas kuni 10 ja rohkem common-kogumite, sĂ”ltuvalt nende suurusest ja arendajate aususest.

Meil vedas, meil olid infrastruktuuri raamatukogud, mida sai eraldi kasutada.

MĂ”nikord juhtus, et mĂ”ned Common-objektid ei kuulunud tegelikult sellesse kihti, vaid olid infrastruktuuri raamatukogud. See lahendati ĂŒmbernimetamise teel.

Enim muret tekitasid piiratud kontekstid. Juhtus, et 3-4 konteksti olid segatud ĂŒhte Common-kogumisse ja kasutasid ĂŒksteist sama Ă€rifunktsioonide raames. Oli vajalik mĂ”ista, kus seda saab jagada ja millistel piiridel, ning mida edasi teha selle jagamise kaardistamisega lĂ€htekoodi kogumitesse.

Formuleerisime mÔned reeglid koodi jagamise protsessi jaoks.

Esiteks: me ei soovinud enam Ă€riloogika jagamist teenuste, tegevuste ja pluginatega. Soovisime teha Ă€riloogika mikroteenuste piires sĂ”ltumatuks. Teiselt poolt, mikroteenuseid peaks ideaaljuhul kĂ€sitlema teenustena, mis eksisteerivad tĂ€iesti iseseisvalt. Ma arvan, et see lĂ€henemine on mĂ”nevĂ”rra raiskav ja seda on raske saavutada, kuna nĂ€iteks C# teenused on igal juhul ĂŒhendatud standardraamatukoguga. Meie sĂŒsteem on kirjutatud C#-s, teisi tehnoloogiaid pole seni kasutusele vĂ”etud. SeetĂ”ttu otsustasime, et saame endale lubada kasutada ĂŒhiseid tehnilisi kogumeid. Peamine on, et neis ei tohi olla Ă€riloogika fraktsioone. Kui sul on mugav wrapper ORM-i, mida kasutad, siis selle kopeerimine teenusest teenusesse on vĂ€ga kulukas.

Meie meeskond on objekt-orienteeritud disaini fÀnne, seega sobis meile «sibula arhitektuur» suurepÀraselt. Meie teenuste aluseks pole andmejuhtimise kiht, vaid domeeniloogikaga töötlemine, mis sisaldab vaid Àriloogikat ja on eemaldatud infrastruktuuri seostest. Sel viisil saame eraldi tÀiustada domeeni töötlust, et lahendada raamistikuga seotud probleeme.

Sellel etapil puutusime kokku esimese tĂ”sise probleemiga. Teenus pidi viitama ĂŒhele domeenitöötlusele, kuid loogika soovisime teha sĂ”ltumatuks, ja DRY-printsiip takistas meid. Arendajad soovisid vĂ€ltida dubleerimist ja taaskasutada klasse naaberkomplektidest, mistĂ”ttu alustas domeenide omavaheline sidumine uuesti. AnalĂŒĂŒsime tulemusi ja otsustasime, et probleem vĂ”ib peituda ka allika koodi salvestamise struktuuris. Meil oli suur hoidla, kus olid kĂ”ik allikakoodid. Projekti lahendust oli vĂ€ga raske koguda kohalikul masinal. SeetĂ”ttu loodi projekti osade jaoks eraldi vĂ€iksed lahendused, ja keegi ei keelanud neisse lisada mingit ĂŒhiskomplekti vĂ”i domeenitöötlust ja taaskasutada. Ainsana ei lubanud seda teha koodikontroll, kuid ka see andis vahel tĂ”rkeid.

Siis hakkasime ĂŒle minema eraldi hoidlate mudelile. Äriloogika enam ei lekinud teenusest teenusesse, domeenid said tĂ”eliselt sĂ”ltumatuks. Piiritletud kontekste toetatakse selgemini. Kuidas me sel perioodil infrastruktuuri raamatukogusid taaskasutame? Me eraldasime need eraldi hoidlasse ja seejĂ€rel panime Nuget-pakettidesse, mis asus Artifactorys. Iga muudetud korral toimub kogumine ja avaldamine automaatselt.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Meie teenused hakkasid viitama sisemistele infrastruktuuri pakettidele tĂ€pselt nagu vĂ€listingimustes. VĂ€listingimuste raamatukogud laadime Nugetist alla. Artifactory tööks, kuhu me need paketid panime, kasutasime kahte pakettide haldurit. Ka vĂ€ikestes hoidlates kasutasime Nugetit. Mitme teenusega hoidlates kasutasime Paketit, mis tagab modulite versioonide vahel suurema ĂŒhtsuse.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Seega, töötades lÀhtekoodiga, muutes veidi arhitektuuri ja jagades hoidlaid, muudame meie teenused iseseisvamaks.

Infrastruktuuri probleemid


Enamik mikroteenuste ĂŒlemineku puudustest on seotud infrastruktuuriga. Teil on vaja automatiseeritud juurutamist, vajalikud on uued lood infrastruktuuri tööks.

KĂ€sitsi paigaldamine keskkondadesse

Alguses seadsime keskkonnanÔudeid kÀsitsi. Selle protsessi automatiseerimiseks lÔime CI/CD toru. Valisime pideva toimetamise protsessi, sest pidev juurutamine ei ole meie Àriprotsesside seisukohalt praegu vastuvÔetav. SeetÔttu toimub kasutuselevÔtt nupuvajutusega, testimine aga automaatselt.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Kasutame Atlassianit, Bitbucketit lÀhtekoodide talletamiseks ja Bamboo't koostamiseks. Meile meeldib kirjutada koostamisskripte Cake'is, sest see on sama, mis C#. Artifactorysse tulevad juba valmis paketid ning Ansible jÔuab automaatselt testserveritele, kus neid saab kohe testida.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Eraldi logimine


Oma aega, oli monoliidi ĂŒheks ideeks tagada ĂŒhtne logimine. Me peame ka aru saama, mida teha eraldi logidega, mis asuvad kettal. Logid kirjutatakse meil tekstifailidesse. Otsustasime kasutada standardset ELK stacki. Me ei hakanud ELKi kirjutama otse pakkujate kaudu, vaid otsustasime tĂ€iustada tekstilogisid ja salvestada neisse jĂ€lgimise ID identificatorina, lisades teenuse nime, et neid logisid hiljem analĂŒĂŒsida.

Siirdumine monoliidilt mikroteenustele: ajalugu ja praktika.

Filebeati abil saame koguda oma logisid serverid, seejÀrel neid töödelda, kasutada Kibana't pÀringute koostamiseks UI-s ja vaadata, kuidas teenuste vahel kutsed toimusid. Sellel aitab oluliselt jÀlgimise ID.

Seotud teenuste testimine ja silumine


Alguses ei mĂ”istnud me tĂ€ielikult, kuidas seadistada arendatavaid teenuseid. Monoliidi puhul oli kĂ”ik lihtne, kĂ€ivitasime selle kohalikul masinal. Alguses pĂŒĂŒdsime sama teha ka mikroteenustega, kuid mĂ”nikord, et tĂ€ielikult kĂ€ivitada ĂŒks mikroteenus, peab kĂ€ivitama ka mitmeid teisi, mis on ebamugav. MĂ”istsime, et on vaja liikuda mudelile, kus jĂ€tame kohalikule masinale ainult teenuse vĂ”i teenused, mida soovime seadistada. ÜlejÀÀnud teenuseid kasutatakse serveritelt, mis on konfiguratsioonilt kooskĂ”las tootmisserveriga. PĂ€rast seadistamist, testimise kĂ€igus antakse igale ĂŒlesandele testserveris vĂ€lja ainult muudetud teenused. Nii testitakse lahendust just selles vormis, milles see tulevikus tootmisse jĂ”uab.

On serverid, millel on ainult tootmisversioonid teenustest. Need serverid on vajalikud hÀdaolukordade puhul, tarnimise kontrollimiseks enne juurutamist ja sisekoolitusteks.

Lisandunud on automaatsete testimiste protsess populaarses Specflow teegis. Testid kĂ€ivituvad automaatselt NUnit'i abil otse pĂ€rast juurutamist Ansible'i kaudu. Kui ĂŒlesande katmine on tĂ€ielikult automatiseeritud, ei ole kĂ€sitsi testimist vajalik. Kuigi mĂ”nikord on siiski vajalik tĂ€iendav kĂ€sitsi testimine. Konkreetses ĂŒlesandes kĂ€ivitatavate testide mÀÀramiseks kasutame Jira-s silte.

Lisaks on kasvanud vajadus koormustestimise jÀrele, mida varem viidi lÀbi ainult harvade juhtumite puhul. Testide kÀivitamiseks kasutame JMeterit, nende sÀilitamiseks InfluxDB-d ja protsessi graafikute koostamiseks Grafana't.

Mida me saavutasime?


Esiteks oleme vabanenud mÔistet "vÀljalase". Kaks kuud kestnud hiiglaslikud vÀljalasked, mil see masin juurutati tootmiskeskkonnas, rikkuvad ajutiselt Àriprotsesse, on kadunud. Praegu juurutame teenuseid keskmiselt iga 1,5 pÀeva jÀrel, grupeerides need, kuna nad tulevad kasutusele pÀrast kooskÔlastamist.

Meie sĂŒsteemis pole fataalseid tĂ”rkeid. Kui oleme vĂ€lja saanud mikroteenuse, milles on viga, siis seotud funktsionaalsus lakkab toimimast, kuid ĂŒlejÀÀnud funktsionaalsus jÀÀb terveks. See parandab kasutajakogemust oluliselt.

Me saame hallata juurutusskeemi. Teenuste rĂŒhmad saavad vajadusel eralduda muu lahendusest.

Lisaks oleme oluliselt vĂ€hendanud suure tagastustööde jĂ€rjekorra probleemi. Meil on tekkinud eraldi tootemeeskonnad, mis töötavad sĂ”ltumatult osade teenustega. Siin sobib juba hĂ€sti Scrumi protsess. Konkreetse meeskonna jaoks vĂ”ib olla eraldi tooteomanik, kes seab neile ĂŒlesandeid.

Elulookirjeldus

  • Mikroteenused sobivad hĂ€sti keerukate sĂŒsteemide dekompositsiooniks. Protsessis hakkame aru saama, mis meie sĂŒsteemis on, millised on olemasolevad piiratud kontekstid ja kus need piirid kulgevad. See vĂ”imaldab Ă”igesti jaotada tĂ€iendused moodulite kaupa ning vĂ€ltida koodi segadusse ajamist.
  • Mikroteenused pakuvad organisatsioonilisi eeliseid. Neist rÀÀgitakse sageli ainult arhitektuurina, kuid iga arhitektuur on vajalik Ă€rivajaduste rahuldamiseks, mitte iseenesest. SeetĂ”ttu saame öelda, et mikroteenused sobivad vĂ€ga hĂ€sti probleemide lahendamiseks vĂ€ikeste meeskondadega, arvestades, et Scrum on hetkel vĂ€ga populaarne.
  • Eraldamine on iteratiivne protsess. Ei saa vĂ”tta rakendust ja lihtsalt jagada seda mikroteenusteks. Saadud toode ei pruugi olla töökindel. Mikroteenuste eraldamisel on kasulik olemasolev pĂ€rand kood ĂŒmber kirjutada, et muuta see meie soovide kohaselt ja paremini rahuldada Ă€rivajadusi funktsionaalsuse ja kiirusel.

    VĂ€ike hoiatuseks: ĂŒleminek mikroteenustele on ĂŒsna kulukas. Ainult infrastruktuuriprobleemi lahendamiseks kulus palju aega. SeetĂ”ttu, kui teil on vĂ€ike rakendus, mis ei vaja spetsiifilist skaleerimist, kui teil ei ole suurt hulka kliente, kes vĂ”itlevad teie meeskonna tĂ€helepanu ja aja nimel, siis vĂ”ivad mikroteenused tĂ€na olla just see, mida te ei vaja. See on piisavalt kallis. Kui alustada protsessi mikroteenustega, siis kulud alguses on suuremad kui sama projekti alustamine monoliidi arendamisega.

    P.S. Rohkem emotsionaalne jutt (ja justkui isiklikult teile) – lingil.
    Siin on ettekande tÀisteksts.

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster