Selles artiklis rÀÀgin, kuidas projekt, milles töötan, muutus suurest monoliidist mikroteenuste kogumiks.
Projekt alustas oma teekonda ĂŒsna ammu, 2000. aasta alguses. Esimesed versioonid olid kirjutatud Visual Basic 6-s. Aja jooksul sai selgeks, et selle keele arendamine tulevikus osutub keeruliseks, kuna IDE ja keel ise arenesid aeglaselt. 2000. aastate lĂ”pus otsustati liikuda perspektiivikama C# keele juurde. Uus versioon kirjutati paralleelselt vana tĂ€iustamisega, kus jĂ€rjest rohkem koodi viidi .NET-i. C#-il pĂ”hinev tagaplaan oli algselt suunatud teenuse arhitektuurile, kuid arendamisel kasutati tavalisi raamatukogusid koos loogikaga, ja teenuseid kĂ€ivitati ĂŒhes protsessis. Tulemusena saime rakenduse, mida nimetasime "teenuse monoliidiks".
Ăheks vĂ€hestest sellise ĂŒhenduse eelistest oli vĂ”imalus teenustel ĂŒksteist vĂ€lise API kaudu kutsuda. Oli ilmseid eeltingimusi liikuda Ă”ige teenuse ja tulevikus ka mikroteenuse arhitektuuri poole.
Meie dekomposteerimise töö algas umbes 2015. aastal. Veel pole me saavutanud ideaalset seisundit - on alles jÀÀnud osi suurest projektist, mida on raske nimeta monoliitideks, aga nad ei sarnane ka mikroteenustega. Sellegipoolest on edusamm mÀrkimisvÀÀrne.
Seda ma ka artiklis kirjeldan.

Sisu
Olemasoleva lahenduse arhitektuur ja probleemid
Algne arhitektuur nĂ€gi vĂ€lja jĂ€rgmine: UI - eraldi rakendus, monoliitne osa oli kirjutatud Visual Basic 6-s, .NET rakendus oli koosne lahti seotud teenustest, mis töötasid ĂŒsna suure andmebaasiga.
Eelmise lahenduse puudused
Ăksik rikkepunkt
Meil oli ĂŒks tĂ”rke koht: .NET rakendus kĂ€itus ĂŒhes protsessis. Kui mĂ”nes moodulis esines rike, kukkus kogu rakendus Ă€ra ja tuli see taaskĂ€ivitada. Kuna automatiseerime suurt hulka protsesse erinevatele kasutajatele, ei saanud me mĂ”neks ajaks töötada kĂ”ik, kui ĂŒks neist ebaĂ”nnestus. Ja programmitĂ”rge korral ei aidanud ka varundamine.
Töötundide jÀrjekord
See probleem on pigem organisatsiooniline. Meie rakenduses on palju kliente, ja kĂ”ik nad soovivad oma arendustöödega vĂ”imalikult kiiresti edasi minna. Varem polnud seda vĂ”imalik samaaegselt teha ja kĂ”ik kliendid said jĂ€rjekorda. See protsess tekitas Ă€ri seas negatiivset suhtumist, kuna neil tuli tĂ”estada, et nende ĂŒlesanne on vÀÀrtuslik. Arendusmeeskond kulutas aega, et seda jĂ€rjekorda korraldada. See vĂ”ttis palju aega ja energiat, ning toode ei suutnud lĂ”puks muutuda nii kiiresti, kui nad oleksid soovinud.
Ressursside ebapiisav kasutamine
Teenuste paigutamine ĂŒhte protsessi tĂ€hendas, et me kopeerisime alati konfiguratsiooni serverilt serverile tĂ€ielikult. Soovisime paigutada kĂ”ige koormatud teenused eraldi, et mitte raisata ressursse ja saavutada oma kasutamise skeemi paindlikum juhtimine.
Moodsa tehnoloogia rakendamine on keeruline.
Tuttav probleem igale arendajale: on soov tuua projekti moodsaid tehnoloogiaid, kuid vĂ”imalused puuduvad. Suure monoliitse lahenduse puhul muutub iga olemasoleva teegi vĂ€rskendamine, rÀÀkimata uuele ĂŒleminekust, ĂŒsna keeruliseks ĂŒlesandeks. Tuleb pika aega tĂ”estada tiimijuhile, et see toodab rohkem kasu kui kulutatud nĂ€rve.
Muudatuste vÀljastamise keerukus.
See oli kÔige tÔsisem probleem - andsime vÀlja versioone iga kahe kuu tagant.
Iga versioon muutus pangale tĂ”eliseks katastroofiks, hoolimata testimisest ja arendajate pingutustest. Ări mĂ”istis, et tal ei ole nĂ€dal alguses osa funktsionaalsusest kasutamiseks. Ja arendajad mĂ”istsid, et neid ootab ees nĂ€dal tĂ”siste probleemidega.
Soov olukorda muuta oli kÔigil.
Ootused mikroteenustele
Komponendid antakse vÀlja nende valmiduse jÀrgi. Komponendid antakse vÀlja valmiduse jÀrgi lahenduse dekompositsiooni ja erinevate protsesside eraldamise tÔttu.
VÀikesed tootemeeskonnad. See on oluline, kuna suure meeskonna, kes töötas vana monoliidi kallal, haldamine oli keeruline. Selline meeskond pidi töötama rangete protsesside jÀrgi, kuid sooviti rohkem loovust ja iseseisvust. Selleks saaksid endale lubada ainult vÀiksed meeskonnad.
Teenuste isoleerimine eraldi protsessides. Ideaalis oleks soovinud isoleerida konteineritesse, kuid suur hulk .NET Frameworki pĂ”hiseid teenuseid töötab ainult Windowsi all. Praegu on kĂŒll hakanud ilmuma teenuseid .NET Core'i peal, kuid neid on veel vĂ€he.
Paigaldamise paindlikkus. Sooviksime kombineerida teenuseid nii, nagu meile vajalik, mitte nii, nagu kood sunnib.
Uute tehnoloogiate kasutamine. See huvitab iga programmeerijat.
Ălemineku probleemid
Muidugi, kui monoliidi jagamine mikroteenusteks oleks lihtne, ei rÀÀgiks me sellest konverentsidel ja ei kirjutaks artikleid. Sellel protsessil on palju undercurrents'e, kirjeldan peamisi, mis takistasid meid.
Esimene probleem tĂŒĂŒpiline enamikule monoliitidele: Ă€riloogika sidusus. Kui me kirjutame monoliiti, tahame taaskasutada meie klasse, et mitte kirjutada liigset koodi. Kuid mikroteenustele ĂŒleminek toob selle probleemina esile: kogu kood on piisavalt rangelt seotud ja teenuste eraldamine on keeruline.
Tööde alustamise hetkeks oli hoidlates ĂŒle 500 projekti ja rohkem kui 700 tuhat koodirea. See on piisavalt suur lahendus ja teine probleem. Lihtsalt vĂ”tta ja jagada see mikroteenusteks ei olnud vĂ”imalik.
Kolmas probleem â vajaliku infrastruktuuri puudumine. Tegelikult tegelesime algkoodi kĂ€sitsi kopeerimisega serveritesse.
Kuidas liikuda monoliidilt mikroteenustele
Mikroteenuste eraldamine
Esiteks, me mÀÀratlesime endale kohe, et mikroteenuste eraldamine on iteratiivne protsess. Meilt nĂ”uti alati samaaegselt Ă€riĂŒlesannete arendamist. Kuidas me seda tehniliselt teostame â see on juba meie probleem. SeetĂ”ttu valmistusime iteratiivseks protsessiks. Teistmoodi ei ole vĂ”imalik, kui teil on suur rakendus, ja see ei ole algselt valmis selleks, et seda uuesti kirjutada.
Milliseid meetodeid me mikroteenuste eraldamiseks kasutame?
Esimene meetod â tuua olemasolevad moodulid teenustena vĂ€lja. Meil on selles osas vedanud: juba oli olemas teenuseid, mis töötasid WCF protokolli kaudu. Need olid jaotatud eraldi kogumitesse. Me edastasime need eraldi, lisades igale kogumile vĂ€ikese kĂ€ivitamismooduli. See oli kirjutatud suurepĂ€rase Topshelf raamatukogu abil, mis vĂ”imaldab rakendust kĂ€ivitada nii teenusena kui ka konsoolidena. See on mugav silumise jaoks, kuna ei ole vaja lisa projekte lahendusse.
Teenused olid seotud Ă€riloogikaga, kuna nad kasutasid ĂŒhiseid kogumeid ja töötasid ĂŒhise andmebaasiga. Neid oli raske pidada puhtaks mikroteenuseks. Kuid me saime neid teenuseid vĂ€lja anda eraldi erinevates protsessides. Isegi see vĂ”imaldas vĂ€hendada nendevahelist mĂ”ju, vĂ€hendades paralleelse arenduse probleemi ja ĂŒhte rikkepunkti.
Hosti kogumik on Program klassis vaid ĂŒks koodirida. Tööd Topshelfiga oleme peitnud abiklassi.
namespace RBA.Services.Accounts.Host
{
internal class Program
{
private static void Main(string[] args)
{
HostRunner.Run("RBA.Services.Accounts.Host");
}
}
}
Teine mikroteenuste eraldamise viis: luua neid uute probleemide lahendamiseks. Kui samas monoliit ei kasva, on see juba hea, see tĂ€hendab, et liikume Ă”iges suunas. Uute probleemide lahendamiseks oleme pĂŒĂŒdnud teha eraldi teenuseid. Kui see oli vĂ”imalik, siis oleme loonud rohkem âkanonilisiâ teenuseid, mis haldavad tĂ€ielikult oma andmemudelit ja eraldi andmebaasi.
Meie, nagu paljud teised, alustasime autentimis- ja autoriseerimisteenustega. Need sobivad selleks ideaalselt. Nad on iseseisvad, nende andmemudel on tavaliselt eraldi. Nad ei suhtu monoliiti, vaid ainult monoliit pöördub nende poole teatud probleemide lahendamiseks. Nendel teenustel on vĂ”imalik alustada ĂŒleminekut uuele arhitektuurile, testida nende peal infrastruktuuri, katsetada erinevaid lĂ€henemisviise, mis on seotud vĂ”rgurakendustega jne. Meie organisatsioonis ei ole tiime, kellel ei oleks Ă”nnestunud luua autentimisteenust.
Kolmas viis mikroteenuste eristamiseks, mida me kasutame, on meie jaoks veidi spetsiifiline. See on Àriloogika eraldamine UI-kihist. Meie peamine UI-rakendus on desktop-versioon, mis on nagu ka backend kirjutatud C#-s. Arendajad eksisid perioodiliselt ja eraldasid UI-sse loogika osi, mis pidanuks eksisteerima backend-is ja mida oleks vÔinud taaskasutada.
Kui vaadata tÔelist nÀidet UI-osa koodist, siis on selge, et suur osa sellest lahendusest sisaldab tÔeliselt Àriloogikat, mis on kasulik muudes protsessides, mitte ainult UI-vormi koostamisel.

Tegelikku UI loogikat on seal ainult viimasel paaril real. Me viisime selle serverisse, et oleks vÔimalik taaskasutada, vÀhendades seelÀbi UI-d ja saavutades Ôige arhitektuuri.
Neljas, kĂ”ige olulisem viis mikroteenuste eraldamiseks, mis vĂ”imaldab monoliiti vĂ€hendada, on olemasolevate teenuste vĂ€lja viimine koos ĂŒmbertöötamisega. Kui me viime olemasolevad moodulid sellisena vĂ€lja, ei pruugi tulemus alati arendajatele meeldida, ja Ă€ri protsess ajast, mil funktsionaalsus loodi, vĂ”ib olla vananenud. Refaktooringu abil saame toetada uut Ă€riprotsessi, kuna Ă€ri nĂ”uded muutuvad pidevalt. Saame parandada algkoodi, eemaldada teadaolevaid vigu, luua kvaliteetsem andmemudel. Saame palju eeliseid.
Teenuste eraldamine, millel on piiratud kontekst, on tihedalt seotud spetsiifilise disainiga. See mĂ”isted on seotud domeenimudeli osaga, kus kĂ”ik termini on ĂŒheselt mÀÀratletud. Vaadakem nĂ€iteks kindlustuste ja arvete konteksti. Meil on monoliitne rakendus, kus on vaja kindlustustes töötada arvega. Me eeldame, et arendaja leiab teisest komplektist olemasoleva klassi âArveâ, seob selle klassiga âKindlustusâ ning me saame töötava koodi. DRY printsiip on jĂ€rgitud, ĂŒlesanne lĂ€heb olemasoleva koodi kasutamise tĂ”ttu kiiremini tĂ€idetud.
Tulemuseks selgub, et arvete ja kindlustuste kontekstid on omavahel seotud. Kui tulevad uued nÔudmised, siis see seos takistab arendust, suurendades juba niigi keerulise Àriloogika keerukust. Selle probleemi lahendamiseks tuleb koodis leida piirid kontekstide vahel ja eemaldada nende rikkumised. NÀiteks vÔib kindlustuste konteksti jaoks olla piisav 20-kohaline arve number ja arve avamise kuupÀev.
Ette eristada neid piiratud kontekste ĂŒksteisest ja alustada mikroteenuste eraldamise protsessi monoliitsest lahendusest, kasutasime lĂ€henemist, mis hĂ”lmas vĂ€list API loomist rakenduse sees. Kui me teadsime, et mĂ”ni moodul peab muutuma mikroteenuseks, muudetakse seda protsessi raames, tegime me kohe vĂ€ljakutseid sellele loogikale, mis kuulub teise piiratud konteksti, lĂ€bi vĂ€liste kĂ”nede. NĂ€iteks REST-i vĂ”i WCF kaudu.
Oleme endale kindlalt otsustanud, et ei vÀldi koodi, mis nÔuab jaotatud tehingute tegemist. Meie puhul osutus selle reegli jÀrgimine piisavalt lihtsaks. Meie jaoks ei ole kunagi tekkinud olukordi, kus ranged jaotatud tehingud oleksid tÔeliselt vajalikud - moodulite vahelise lÔppkooskÔla tagamine on tÀiesti piisav.
Vaatame ĂŒhte konkreetset nĂ€idet. Meil on orkestrite mĂ”isted â konveier, mis töötleb "taotluse" objekti. See loob jĂ€rjestikku kliendi, konto ja pangakaardi. Kui klient ja konto on edukalt loodud, kuid kaardi loomine ebaĂ”nnestub, ei muutu taotlus staatuseks "edukalt" ja jÀÀb staatuseks "kaart ei ole loodud". Tulevikus lĂ”pusĂŒsteem haarab selle ja lĂ”petab selle. SĂŒsteem on mĂ”nda aega ebakĂ”las, kuid see meid ĂŒldiselt rahuldab.
Kui siiski tekib olukord, kus tuleb koosolekuks osa andmeid salvestada, peame tĂ”enĂ€oliselt minema teenuse suuremaks koondamiseks, et seda ĂŒhes protsessis töödelda.
Vaatame mikroteenuse eraldamise nĂ€idet. Kuidas saaksime seda suhteliselt ohutult tootmisse viia? Selles nĂ€ites on meil sĂŒsteemi eraldi osa â palgahalduse moodul, mille koodist soovime osa muuta mikroteenuseks.

Esiteks loome mikroteenuse, kirjutades koodi ĂŒmber. Parandame mĂ”ned detailid, mis meid mitte rahuldatud. Rakendame uusi Ă€rianalĂŒĂŒse kliendi poolt. Lisame ĂŒhendusse UI ja tagaplaani vahel API Gateway, mis tagab kĂ”nede edastamise.

SeejÀrel juurutame selle konfiguratsiooni tootmisse, kuid pilootseisundis. Enamik meie kasutajatest jÀtkab endiselt töötlust vanade Àriprotsesside kaudu. Uute kasutajate jaoks arendame vÀlja uue versiooni monoliitset rakendust, mis seda protsessi enam ei sisalda. Tegelikult toimib meil pilootina monoliidi ja mikroteenuse kombinatsioon.

Eduka piloodi korral mÔistame, et uus konfiguratsioon on tÔeliselt toimiv ning saame vanade monoliite tasakaalust eemaldada ja jÀtta uue konfiguratsiooni vana lahenduse kohale.

KokkuvÔttes kasutame praktiliselt kÔiki olemasolevaid meetodeid monoliitse lÀhtekoodi jagamiseks. KÔik need vÔimaldavad meil vÀhendada rakenduse osi ja viia need uutele raamatukogudele, tagades kvaliteetsemat lÀhtekoodi.
Töö andmebaasiga
Andmed ei jagune nii hÀsti nagu lÀhtekood, kuna need sisaldavad mitte ainult praegust skeemi, vaid ka kogunenud ajaloolisi andmeid.
Meie andmebaasil, nagu paljudel teistel, oli veel ĂŒks oluline puudus â tohutu suurus. Seda andmebaasi kavandati segase monoliidi Ă€ri loogika jÀÀgiga, ja erinevate piiratud kontekstide tabelite vahel tekkisid seosed.
Meie puhul, lisaks kĂ”igile muredele (suur andmebaas, hulk seoseid, mĂ”nikord arusaamatud piirid tabelite vahel), tekkis probleem, millega paljudes suurtes projektides kokku puututakse: jagatud andmebaasi mustri kasutamine. Andmed vĂ”eti tabelitest vaate kaudu, replikatsiooniga ja saadetud teistesse sĂŒsteemidesse, kus seda replikatsiooni vajati. Tulemuseks oli see, et me ei saanud tabeleid eraldi skeemi viia, sest neid kasutati aktiivselt.
Jagamisel aitab meid just see piiramine, mis koodis olemas on. See annab tavaliselt meile piisavalt hea ĂŒlevaate sellest, kuidas me jagame andmeid andmebaasi tasandil. Me mĂ”istame, millised tabelid kuuluvad ĂŒhte piiratud konteksti ja millised teise.
Oleme rakendanud kahte globaalselt meetodit andmebaasi eraldamiseks: olemasolevate tabelite eraldamine ja eraldamine ĂŒmberehitamisega.
Olemasolevate tabelite eraldamine on meetod, mida on hea rakendada, kui andmestruktuur on kvaliteetne, rahuldab Ă€rianalĂŒĂŒse ning kĂ”ik on sellega rahul. Sel juhul saame olemasolevad tabelid eraldada eraldi skeemiks.
Eraldamine ĂŒmberehitamisega on vajalik, kui Ă€ri mudel on oluliselt muutunud ja tabelid ei rahulda meid enam ĂŒldse.
Olemasolevate tabelite eraldamine. Peame mÀÀrama, mida me eraldame. Ilma selle teadmisega ei saa midagi saavutada, ja siin aitab meid koodi piiratud konteksti eraldamine. Reeglina, kui suudame mÔista konteksti piire algkoodis, saame aru, millised tabelid peaksid eraldamist saama.
Kujutage ette lahendust, kus kaks monoliidi moodulit suhtlevad ĂŒhe andmebaasiga. Me peame tagama, et eraldatavate tabelite osaga suudleb ainult ĂŒks moodul, samas kui teine hakkab sellega suhtlema API kaudu. Esialgu piisab, kui API kaudu toimub ainult kirjutamine. See on hĂ€davajalik tingimus, et saaksime rÀÀkida mikroteenuste sĂ”ltumatusest. Lugemise seosed vĂ”ivad jÀÀda, kuni see ei tekita suurt probleemi.

JĂ€rgmise sammuna saame juba koodiosa, mis töötab eraldatavate tabelitega, koos vĂ”i ilma ĂŒmber töötamiseta, eraldi mikroteenuseks eraldada ja kĂ€ivitada eraldi protsessis, konteineris. See on eraldi teenus, millel on seos monoliidi andmebaasiga ja nende tabelitega, mis ei kuulu otseselt tema alla. Monoliit suhtleb endiselt lugemise kaudu eraldatud osaga.

Hiljem eemaldame selle seose, mille puhul ka monoliidi rakenduse andmete lugemine eraldatavatest tabelitest viiakse API peale.

Eemaldame esmalt peamisest andmebaasist tabelid, millega töötab ainult uus mikrosĂŒsteem. Me saame tabelid viia eraldi skeemi vĂ”i isegi eraldi fĂŒĂŒsilisse andmebaasi. Ăhendus lugemiseks mikrosĂŒsteemi ja monoliidi andmebaasi vahel jÀÀb, kuid selles pole midagi hullu; sellises konfiguratsioonis vĂ”ib see piisavalt kaua töötada.

Viimane samm on kĂ”ik sidemed tĂ€ielikult eemaldada. Sel juhul vĂ”ib meil olla vajalik andmete migreerimine peamisest andmebaasist. MĂ”nikord tahame taaskasutada mĂ”ningaid vĂ€lisosistest sĂŒsteemidest replikatsioone, vĂ”i katalooge mitmes andmebaasis. See juhtub meil perioodiliselt.

Eraldamine koos töötlemisega. See meetod on vĂ€ga sarnane esimesele, ainult et see toimub vastupidises jĂ€rjestuses. Meil ĐČŃЎДлŃĐ”ŃŃŃ kohe uus andmebaas ja uus mikrosĂŒsteem, mis suhtleb monoliidiga API kaudu. Kuid selle juurde jÀÀb andmebaasi tabelite kogum, mille tahame tulevikus eemaldada. Me ei vaja seda enam, uues mudelis asendasime selle.

Selle skeemi toimimiseks vajame ilmselt ĂŒleminekuperioodi.
Edasi on kaks vÔimalikku lÀhenemist.
Esimene: me dublime kĂ”ik andmed uutes ja vanades andmebaasides. Sellisel juhul tekib meil andmete ĂŒlepakkumine, mis vĂ”ib pĂ”hjustada sĂŒnkroonimisprobleeme. Kuid saame siiski vĂ”tta kaks erinevat klienti. Ăks töötab uue versiooniga, teine vanaga.
Teine: jagame andmeid mingite Ă€ri tunnuste jĂ€rgi. NĂ€iteks, meil oli sĂŒsteemis 5 toodet, mis on salvestatud vanasse andmebaasi. Kuues toode uue Ă€riprojekti raames paigutatakse uude andmebaasi. Kuid meil on vaja API Gateway't, mis sĂŒnkroonib need andmed ja nĂ€itab kliendile, kust ja mida vĂ”tta.
MÔlemad lÀhenemised on töötavad, valige vastavalt olukorrale.
PĂ€rast seda, kui kinnitame, et kĂ”ik töötab, saab osa monoliidist, mis töötab vanade andmebaasi struktuuridega, vĂ€lja lĂŒlitada.

Viimase sammuna on vana andmestruktuuri eemaldamine.

KokkuvÔtteks vÔib öelda, et meil on andmebaasidega probleeme: keeruline on nendega töötada vÔrreldes lÀhtekoodiga, jagamine on keerulisem, kuid seda saab ja tuleb teha. Oleme leidnud mÔned viisid, mis vÔimaldavad seda teha piisavalt turvaliselt; siiski andmete osas on viga lihtsam teha kui lÀhtekoodiga.
Töö lÀhtekoodiga
Nii nĂ€gi algkoodi skeem vĂ€lja, kui hakkasime monoliitset projekti analĂŒĂŒsima.

Seda saab tinglikult jagada kolmeks kihiks. See on kĂ€ivitavate moodulite, pistikute, teenuste ja eraldi tegevuste kiht. Tegelikult olid need sissepÀÀsupunktid monoliitses lahenduses. KĂ”ik need olid tihedalt seotud Common kihiga. Selles oli Ă€riloogika, mida teenused kasutasid ĂŒhiselt, ning palju seoseid. Iga teenus ja pistikupesa kasutas kuni 10 ja enam common-kogumit, olenevalt nende suurusest ja arendajate aususest.
Meil oli Ônne, meil olid infrastruktuuri raamatukogud, mida sai kasutada eraldi.
MĂ”nikord juhtus, et mĂ”ned Common-objektid ei kuulunud tegelikult sellesse kihti, vaid olid infrastruktuuri raamatukogud. See lahendati ĂŒmbernimetamisega.
KĂ”ige enam tekitas muret piiratud kontekstid. MĂ”nikord segunesid 3-4 konteksti ĂŒhes Common'i kogus ja kasutasid ĂŒksteist sama Ă€rifunktsiooni raames. Oli vajalik mĂ”ista, kus on need vĂ”imalikud eraldada ja milliste piiride jĂ€rgi, ning mida edasi teha selle eraldamise kaardistamisega lĂ€htekoodi kogudele.
Me koostasime mÔned reeglid koodi jagamise protsessiks.
Esimene: me enamorado de la idea de no querer compartir la lĂłgica de negocios entre servicios, actividades y plugins. QuerĂamos hacer que la lĂłgica de negocios fuera independiente dentro de los microservicios. Por otro lado, los microservicios, en un escenario ideal, se perciben como servicios que existen completamente de forma independiente. Creo que este enfoque es algo derrochador y difĂcil de alcanzar, ya que, por ejemplo, los servicios en C# estarĂĄn siempre conectados a la biblioteca estĂĄndar. Nuestro sistema estĂĄ escrito en C#, otras tecnologĂas aĂșn no se han utilizado. Por lo tanto, decidimos que podĂamos permitirnos usar compilaciones tĂ©cnicas comunes. Lo principal es que no contengan fragmentos de lĂłgica de negocios. Si tienes un envoltorio conveniente sobre la ORM que utilizas, copiarlo de un servicio a otro es muy costoso.
Meie meeskond on asjatundjate erialase disaini fÀnn, seetÔttu sobis meile suurepÀraselt "sibulaarhitektuur". Meie teenuste aluseks ei ole data access layer, vaid domeeniloogikaga koostamine, mis sisaldab ainult Àriloogikat ja on vabastatud infrastruktuuri seosest. Samuti saame me domeenikoostist iseseisvalt tÀiendada raamistikest tulenevate probleemide lahendamiseks.
Sel hetkel kohtasime esmakordselt tĂ”sist probleemi. Teenus pidi viitama ĂŒhele domeenikogule, loogika soovisime teha sĂ”ltumatuks, ja DRY pĂ”himĂ”te segas meid tugevalt. Arendajad soovisid vĂ€ltida dubleerimist, kasutades naaberkogude klasse, ja tulemuseks hakkasid domeenid jĂ€lle omavahel siduma. AnalĂŒĂŒsisime tulemusi ja otsustasime, et probleem vĂ”ib olla seotud ka lĂ€htekoodi hoidlaga. Meil oli suur repoid, kus asusid kĂ”ik lĂ€htekoodid. Projekti lahendust oli vĂ€ga keeruline kohalikult masinal kokku panna. SeetĂ”ttu loodi projekti osade jaoks eraldi vĂ€iksed lahendused, ja keegi ei pidanud keelama neid lisada mĂ”nda ĂŒhiskogusse vĂ”i domeenikogusse ja seda uuesti kasutada. Ainsaks tööriistaks, mis ei lubanud meil seda teha, oli koodivaatlus. Kuid mĂ”nikord andis ka see tĂ”rkeid.
Seega hakkasime liikuma eraldi hoidlate mudeli suunas. Ări loogika ei voolanud enam teenusest teenusesse, domeenid muutusid tĂ”eliselt sĂ”ltumatuks. Piiratud kontekste toetatakse selgemalt. Kuidas me samas infrastruktuuri raamatukogusid taaskasutame? Me eraldasime need eraldi hoidlasse, seejĂ€rel panime need Nuget-pakettideks, mille panime Artifactory'sse. Iga muudatusega toimub ehitamine ja avaldamine automaatselt.

Meie teenused hakkasid viitama sisemistele infrastruktuuri pakettidele tĂ€pselt nagu vĂ€limistele. VĂ€limised raamatukogud laadime alla Nugetist. Artifactory'ga, kuhu me need paketid panime, töötamiseks kasutasime kahte paketihaldurit. VĂ€ikestes hoidlates kasutasime samuti Nugetit. Mitme teenusega hoidlates kasutasime Paket'i, mis tagab suurema versioonide ĂŒhtsuse moodulite vahel.

Nii et töötades lÀhtekoodiga, muutes veidi arhitektuuri ja eraldades hoidlaid, muudame oma teenused sÔltumatumaks.
Infrastruktuuri probleemid
Enamik mikroteenustele ĂŒlemineku probleemidest on seotud infrastruktuuriga. Teil on vaja automatiseeritud juurutamist ning uusi teeke, et infrastruktuur töötaks.
KĂ€sitsi installimine keskkondadesse
Esialgu paigaldasime lahendused keskkondadesse kÀsitsi. Selle protsessi automatiseerimiseks lÔime CI/CD torustiku. Valisime pideva tarnimise (continuous delivery) protsessi, kuna pidev juurutamine (continuous deployment) ei sobi meie Àriprotsesside jaoks veel. SeetÔttu toimub juurutamine nupu vajutamisega, testimine aga automaatselt.

Kasutame Atlassianit, Bitbucketit lÀhtekoodi hoidmiseks ja Bamboo't ehitamiseks. Meile meeldib kirjutada ehitusskripte Cake'is, kuna see on sama, mis C#. Artifactory'sse tulevad juba valmis paketid, ning Ansible saadetakse automaatselt testserveritesse, mille jÀrel saab neid kohe testida.

Erinev logimine
Oma ajal oli monoliidi ideedest ĂŒks ĂŒhise logimise tagamine. Me pidime ka aru saama, mida teha eraldi logidega, mis on kettale salvestatud. Logid meie juures kirjutatakse tekstifailidesse. Otsustasime kasutada standardset ELK-steki. Me ei hakanud logima otse ELK-sse teenusepakkujate kaudu, vaid otsustasime, et tĂ€iustame tekstiloge ja salvestame neisse jĂ€lgimise ID identifikaatorina, lisades teenuse nime, et neid logisid hiljem saaks analĂŒĂŒsida.

Filebeati abil saame vÔimaluse koguda meie logisid serverite, seejÀrel neid muuta, kasutada Kibanat pÀringute loomiseks kasutajaliideses ja vaadata, kuidas teenuste vahel kutsumine toimus. Selle juures aitab ID jÀlgimine suuresti.
Seotud teenuste testimine ja silumine
Alguses ei olnud meil tĂ€pselt arusaamist, kuidas arendatavaid teenuseid siluda. Monoliidiga oli kĂ”ik lihtne, kĂ€ivitasime selle kohalikel masinatel. Alguses proovisime sama teha ka mikroteenustega, kuid mĂ”nikord on ĂŒhe mikroteenuse tĂ€ielikuks kĂ€ivitamiseks vajalik kĂ€ivitada ka mitu muud teenust, mis on ebamugav. Me mĂ”istsime, et on vajalik liikuda mudelile, kus jĂ€tame kohalikele masinatele ainult teenuse vĂ”i teenused, mida soovime siluda. ĂlejÀÀnud teenuseid kasutatakse serveritest, mis vastavad tootmise konfiguratsioonile. PĂ€rast silumist, testimise kĂ€igus, vĂ€ljastatakse testimise serverile ainult muudetud teenused iga ĂŒlesande jaoks. Nii testitakse lahendust sellises vormis, nagu see tulevikus tootmises olema hakkab.
On serverid, millel on ainult teenuste tootmisversioonid. Need serverid on vajalikud intsidentide puhul, tarnimise kontrollimise jaoks enne juurutamist ja sisemiste koolituste jaoks.
Meil on lisandunud automaatse testimise protsess, kasutades populaarset Specflow teeki. Testid kĂ€ivitatakse automaatselt NUnit'i abil kohe pĂ€rast juurutamist Ansible'ist. Kui ĂŒlesande katmine on tĂ€ielikult automaatne, pole kĂ€sitsi testimist vaja. Kuigi mĂ”nikord on siiski vajalik tĂ€iendav kĂ€sitsi testimine. Teatud ĂŒlesande jaoks kĂ€ivitatavate testide mÀÀratlemiseks kasutame Jira sildiaid.
TÀiendavalt on suurenenud vajadus koormustestimise jÀrele, mida varem viidi lÀbi vaid harvadel juhtudel. Testide kÀivitamiseks kasutame JMeter'i, nende sÀilitamiseks InfluxDB-d ning protsessi graafikute koostamiseks Grafana't.
Mida me saavutasime?
Esiteks oleme vabanenud mĂ”isted 'vabastamine'. Kaks kuud kestnud monstruehivad vabastamised, mil see hiiglane juurutati tootmisotsustesse, katkestades ajutiselt Ă€ri protsessid, on kadunud. NĂŒĂŒd juurutame teenuseid keskmiselt iga 1,5 pĂ€eva tagant, koondades neid, kuna nad lĂ€hevad kasutusele pĂ€rast kooskĂ”lastamist.
Meie sĂŒsteemis ei esine kriitilisi rikkeid. Kui me vĂ€ljastame mikroteenuse veaga, siis seonduv funktsionaalsus lĂ”petab töö, kuid ĂŒlejÀÀnud funktsionaalsus ei kahjustu. See parandab tunduvalt kasutajakogemust.
Me saame hallata juurutamise skeemi. Saame eraldada teenuste grupid eraldi ĂŒlejÀÀnud lahendusest, kui see on vajalik.
Lisaks oleme oluliselt vĂ€hendanud suurt muudatusprotsesside jĂ€rjekorda. Meil on tekkinud eraldi tootmismeeskonnad, mis töötavad osa teenustega sĂ”ltumatult. Siin sobib juba hĂ€sti Scrum-protsess. Konkreetse meeskonna vĂ”ib omada eraldi tooteomanik, kes seab neile ĂŒlesandeid.
KokkuvÔte
- Mikroteenused sobivad hĂ€sti keeruliste sĂŒsteemide dekomponeerimiseks. Protsessi kĂ€igus hakkame aru saama, mis meie sĂŒsteemis on, millised piiratud kontekstid esinevad ja kus nende piirid asuvad. See vĂ”imaldab Ă”igesti jaotada muudatused moodulite lĂ”ikes, vĂ€ltides samas koodi segadusseminemist.
- Mikroteenused pakuvad organisatsioonilisi eeliseid. Nendest rÀÀgitakse sageli ainult arhitektuurina, kuid iga arhitektuur on vajalik Ă€ri vajaduste rahuldamiseks, mitte iseenesest. SeetĂ”ttu vĂ”ime öelda, et mikroteenused sobivad hĂ€sti vĂ€ikeste meeskondade ĂŒlesannete lahendamiseks, arvestades, et Scrum on praegu vĂ€ga populaarne.
- Jagamine on iteratiivne protsess. Ei saa vĂ”tta rakendust ja lihtsalt jagada seda mikroteenusteks. Tootest, mis nii saadakse, on vĂ€ga vĂ€he tĂ”enĂ€olist, et see töötab. Mikroteenuste eraldamisel on kasulik olemasolev pĂ€rand ĂŒmber kirjutada, muutes selle koodiks, mis meile meeldib ja mis paremini rahuldab Ă€ri vajadusi funktsionaalsuse ja kiirusel.
VĂ€ike ettevaatus: Mikroteenuste kasutuselevĂ”tmise kulud on piisavalt suured. Ainult infrastruktuuriprobleemide lahendamiseks kulus palju aega. SeetĂ”ttu, kui teil on vĂ€ike rakendus, mis ei vaja spetsiifilist skaleerimist, ega ole palju kliente, kes konkureerivad teie meeskonna tĂ€helepanu ja aja nimel, siis vĂ”ib-olla ei ole mikroteenused tĂ€na teie jaoks vajalikud. See on ĂŒsna kulukas. Kui alustada protsessi mikroteenustega, on algkulud suuremad kui sama projekti alustamine monoliidi arendamisega.
P.S. Veel emotsionaalsem jutustus (nagu isiklikult teile) â .
Siin on ettekande tÀisversioon.
Allikas: habr.com
