Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

An dësem Artikel wäert ech schwätzen iwwer wéi de Projet, un deem ech schaffen, vun engem grousse Monolith an eng Rei vu Mikroservicer transforméiert gouf.

De Projet huet seng Geschicht viru laanger Zäit ugefaang, Ufank 2000. Déi éischt Versioune goufen a Visual Basic 6 geschriwwen. Mat der Zäit gouf kloer datt d'Entwécklung an dëser Sprooch an Zukunft schwéier z'ënnerstëtzen, well d'IDE an d'Sprooch selwer sinn schlecht entwéckelt. Um Enn vun den 2000er gouf decidéiert op déi méi villverspriechend C # ze wiesselen. Déi nei Versioun gouf parallel mat der Revisioun vun der aler geschriwwen, no an no gouf ëmmer méi Code am .NET geschriwwe. Backend am C # war am Ufank op eng Servicearchitektur konzentréiert, awer wärend der Entwécklung goufen allgemeng Bibliothéike mat Logik benotzt, a Servicer goufen an engem eenzege Prozess lancéiert. D'Resultat war eng Applikatioun déi mir e "Service Monolith" genannt hunn.

Ee vun de wéinege Virdeeler vun dëser Kombinatioun war d'Fäegkeet vu Servicer fir sech duerch eng extern API ze ruffen. Et waren kloer Viraussetzunge fir den Iwwergank zu engem méi korrekt Service, an an Zukunft, Microservice Architektur.

Mir hunn eis Aarbecht un der Zersetzung ëm 2015 ugefaangen. Mir hunn nach net en idealen Zoustand erreecht - et ginn nach Deeler vun engem grousse Projet, déi kaum Monolithen genannt ginn, awer si kucken och net wéi Mikroservicer. Trotzdem ass de Fortschrëtt bedeitend.
Ech wäert doriwwer am Artikel schwätzen.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Inhalt

Architektur a Problemer vun der bestehend Léisung


Am Ufank huet d'Architektur esou ausgesinn: d'UI ass eng separat Applikatioun, de monolitheschen Deel ass a Visual Basic 6 geschriwwen, d'.NET Applikatioun ass eng Rei vu verbonne Servicer déi mat enger zimlech grousser Datebank schaffen.

Nodeeler vun der viregter Léisung

Eenzege Punkt vun Echec
Mir haten een eenzege Punkt vum Echec: d'.NET Applikatioun leeft an engem eenzege Prozess. Wann e Modul gescheitert ass, ass déi ganz Applikatioun gescheitert an huet missen nei gestart ginn. Well mir eng grouss Zuel vu Prozesser fir verschidde Benotzer automatiséieren, wéinst engem Feeler an engem vun hinnen, konnt jidderee fir eng Zäit net schaffen. An am Fall vun engem Software Feeler, souguer Backupsatellit huet net gehollef.

Schlaang vun Verbesserungen
Dësen Nodeel ass éischter organisatoresch. Eis Applikatioun huet vill Clienten, a si wëllen se all sou séier wéi méiglech verbesseren. Virdrun war et onméiglech dëst parallel ze maachen, an all Clienten stoungen an der Linn. Dëse Prozess war negativ fir d'Entreprisen, well se hu misse beweisen datt hir Aufgab wäertvoll war. An d'Entwécklungsteam huet Zäit verbruecht fir dës Schlaang ze organiséieren. Dëst huet vill Zäit an Effort gedauert, an d'Produkt konnt schlussendlech net sou séier änneren wéi se gär hätten.

Suboptimal Notzung vu Ressourcen
Wa mir Servicer an engem eenzege Prozess hosten, hu mir d'Konfiguratioun ëmmer komplett vu Server op Server kopéiert. Mir wollten déi am meeschte belaaschte Servicer getrennt placéieren fir net Ressourcen ze verschwenden a méi flexibel Kontroll iwwer eis Deployment Schema ze kréien.

Schwiereg modern Technologien ëmzesetzen
E Problem kennt all Entwéckler: et ass e Wonsch modern Technologien an de Projet aféieren, mä et gëtt keng Chance. Mat enger grousser monolithescher Léisung gëtt all Aktualiséierung vun der aktueller Bibliothéik, fir net den Iwwergank op eng nei ze ernimmen, an eng zimlech net-trivial Aufgab. Et dauert laang Zäit fir dem Teamleader ze beweisen datt dëst méi Bonus bréngt wéi verschwenden Nerven.

Schwieregkeeten Ännerungen erausginn
Dëst war de seriösten Problem - mir hunn all zwee Méint Verëffentlechungen verëffentlecht.
All Verëffentlechung gouf zu enger realer Katastroph fir d'Bank, trotz den Testen an Efforten vun den Entwéckler. D'Geschäft huet verstanen datt am Ufank vun der Woch e puer vu senge Funktionalitéit net funktionnéiert. An d'Entwéckler hunn verstanen datt eng Woch vu schlëmmen Tëschefäll op si waarden.
Jiddereen hat e Wonsch d'Situatioun ze änneren.

Erwaardungen vun microservices


Ausgab vun Komponente wann prett. Liwwerung vu Komponenten wann se prett sinn andeems d'Léisung zerstéiert a verschidde Prozesser trennt.

Kleng Produktteams. Dëst ass wichteg well e grousst Team, deen um alen Monolith geschafft huet, schwéier ze managen war. Esou eng Equipe war gezwongen no engem strikte Prozess ze schaffen, mä si wollten méi Kreativitéit an Onofhängegkeet. Nëmmen kleng Equipen konnten sech dat leeschten.

Isolatioun vu Servicer a getrennte Prozesser. Idealerweis wollt ech et an Containeren isoléieren, awer eng grouss Zuel vu Servicer, déi am .NET Framework geschriwwe sinn, lafen nëmmen op Windows. Servicer baséiert op .NET Core erschéngen elo, awer et sinn nach e puer vun hinnen.

Deployment Flexibilitéit. Mir wëllen Servicer kombinéieren wéi mir se brauchen, an net wéi de Code et forcéiert.

Notzung vun neien Technologien. Dëst ass interessant fir all Programméierer.

Iwwergangsproblemer


Natierlech, wann et einfach wier e Monolith a Mikroservicer ze briechen, da wier et net néideg doriwwer op Konferenzen ze schwätzen an Artikelen ze schreiwen. Et gi vill Falen an dësem Prozess; Ech wäert déi Haapt beschreiwen, déi eis behënnert hunn.

Den éischte Problem typesch fir déi meescht Monolithen: Kohärenz vun der Geschäftslogik. Wa mir e Monolith schreiwen, wëlle mir eis Klassen nei benotzen fir net onnéideg Code ze schreiwen. A wann Dir op Mikroservicer plënnert, gëtt dëst e Problem: all Code ass zimlech enk gekoppelt, an et ass schwéier d'Servicer ze trennen.

Zu der Zäit vum Start vun der Aarbecht hat de Repository méi wéi 500 Projeten a méi wéi 700 Tausend Codelinnen. Dëst ass eng zimlech grouss Entscheedung an zweete Problem. Et war net méiglech et einfach ze huelen an et a Mikroservicer opzedeelen.

Drëtte Problem - Mangel un néideg Infrastruktur. Tatsächlech hu mir de Quellcode manuell op d'Server kopéiert.

Wéi vum Monolith op Mikroservicer ze plënneren


Dispositioun vun Microservices

Als éischt hu mir direkt fir eis selwer festgestallt datt d'Trennung vu Mikroservicer en iterative Prozess ass. Mir waren ëmmer verlaangt Affär Problemer parallel ze entwéckelen. Wéi mir dat technesch ëmsetzen ass schonn eise Problem. Dofir hu mir op en iterative Prozess virbereet. Et funktionnéiert net op eng aner Manéier wann Dir eng grouss Applikatioun hutt an et ass am Ufank net prett fir nei geschriwwe ze ginn.

Wéi eng Methode benotze mir fir Mikroservicer ze isoléieren?

Déi éischt Manéier - réckelen bestehend Moduler als Servicer. An dëser Hisiicht ware mir Gléck: et ware scho registréiert Servicer déi mam WCF-Protokoll geschafft hunn. Si goufen an getrennten Versammlungen getrennt. Mir hunn se separat portéiert, e klenge Launcher fir all Bau bäigefüügt. Et gouf geschriwwen mat der wonnerbarer Topshelf Bibliothéik, déi Iech erlaabt d'Applikatioun souwuel als Service wéi och als Konsol ze lafen. Dëst ass bequem fir Debugging well keng zousätzlech Projeten an der Léisung erfuerderlech sinn.

D'Servicer goufen no der Geschäftslogik verbonnen, well se gemeinsam Versammlungen benotzt hunn a mat enger gemeinsamer Datebank geschafft hunn. Si kéinte kaum Mikroservicer a senger reiner Form genannt ginn. Wéi och ëmmer, mir kënnen dës Servicer separat ubidden, a verschiddene Prozesser. Dëst eleng huet et méiglech hiren Afloss op all aner ze reduzéieren, reduzéieren de Problem mat parallel Entwécklung an engem eenzege Punkt vun Echec.

Assemblée mam Host ass just eng Zeil Code an der Programmklass. Mir hunn d'Aarbecht mat Topshelf an enger Hëllefsklass verstoppt.

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

       }
    }
}

Déi zweet Manéier fir Mikroservicer ze verdeelen ass: schafen se fir nei Problemer ze léisen. Wann gläichzäiteg de Monolith net wächst, ass dëst schonn exzellent, dat heescht datt mir an déi richteg Richtung bewegen. Fir nei Problemer ze léisen, hu mir probéiert separat Servicer ze kreéieren. Wann et esou eng Geleeënheet war, hu mir méi "kanonesch" Servicer erstallt, déi hiren eegene Datemodell komplett verwalten, eng separat Datebank.

Mir, wéi vill, ugefaang mat Authentifikatioun an Autorisatioun Servicer. Si si perfekt fir dëst. Si sinn onofhängeg, als Regel, si hunn eng separat Datemodell. Si selwer interagéieren net mam Monolith, nëmmen et dréit sech un hinnen fir e puer Probleemer ze léisen. Mat dëse Servicer kënnt Dir den Iwwergank zu enger neier Architektur ufänken, d'Infrastruktur op hinnen debuggen, probéieren e puer Approche am Zesummenhang mat Netzwierkbibliothéiken, etc. Mir hu keng Teams an eiser Organisatioun déi keen Authentifikatiounsservice erstellen konnten.

Déi drëtt Manéier fir Mikroservicer ze verdeelenDee mir benotzen ass e bësse spezifesch fir eis. Dëst ass d'Entfernung vu Geschäftslogik aus der UI Schicht. Eis Haapt UI Applikatioun ass Desktop; et ass, wéi de Backend, an C # geschriwwen. D'Entwéckler hunn periodesch Feeler gemaach an Deeler vun der Logik op d'UI transferéiert, déi am Backend sollt existéieren a weiderbenotzt ginn.

Wann Dir e richtegt Beispill aus dem Code vum UI Deel kuckt, kënnt Dir gesinn datt déi meescht vun dëser Léisung richteg Geschäftslogik enthält déi nëtzlech ass an anere Prozesser, net nëmme fir d'UI Form ze bauen.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Déi richteg UI Logik ass nëmmen do an de leschte puer Zeilen. Mir hunn et op de Server transferéiert fir datt et erëmbenotzt ka ginn, doduerch d'UI reduzéiert an déi richteg Architektur erreechen.

De véierten a wichtegste Wee fir Mikroservicer ze isoléieren, wat et méiglech mécht de Monolith ze reduzéieren, ass d'Entfernung vun existente Servicer mat der Veraarbechtung. Wa mir existéierend Moduler eraushuelen wéi et ass, ass d'Resultat net ëmmer dem Entwéckler gär, an de Geschäftsprozess ka verännert ginn zënter der Funktionalitéit erstallt gouf. Mat Refactoring kënne mir en neie Geschäftsprozess ënnerstëtzen, well d'Geschäftsfuerderunge konstant änneren. Mir kënnen de Quellcode verbesseren, bekannte Mängel ewechhuelen an e besseren Datemodell erstellen. Et gi vill Virdeeler déi opkommen.

D'Trennung vu Servicer vun der Veraarbechtung ass onloschterlech mam Konzept vum begrenzte Kontext verbonnen. Dëst ass e Konzept vum Domain Driven Design. Et heescht eng Sektioun vum Domainmodell an deem all d'Begrëffer vun enger eenzeger Sprooch eenzegaarteg definéiert sinn. Kucke mer als Beispill de Kontext vun der Assurance an de Rechnungen. Mir hunn eng monolithic Applikatioun, a mir mussen mat de Kont an Versécherung schaffen. Mir erwaarden datt den Entwéckler eng existent Kont Klass an enger anerer Versammlung fënnt, et aus der Versécherungsklass referéiert, a mir hunn Aarbechtscode. Den DRY Prinzip gëtt respektéiert, d'Aufgab gëtt méi séier gemaach andeems Dir existente Code benotzt.

Als Resultat, stellt sech eraus, datt de Kontext vun Konten an Assurance verbonne sinn. Wéi nei Ufuerderunge entstinn, wäert dës Kupplung d'Entwécklung stéieren, d'Komplexitéit vun der scho komplexer Geschäftslogik erhéijen. Fir dëse Problem ze léisen, musst Dir d'Grenzen tëscht Kontexter am Code fannen an hir Violatioune läschen. Zum Beispill, am Versécherungskontext ass et ganz méiglech datt eng 20-Zifferen Zentralbankkontonummer an den Datum wou de Kont opgemaach gouf, genuch sinn.

Fir dës begrenzte Kontexter vuneneen ze trennen an de Prozess unzefänken fir Mikroservicer vun enger monolithescher Léisung ze trennen, hu mir eng Approche benotzt wéi extern APIen an der Applikatioun erstellen. Wa mir woussten datt e Modul e Mikrodéngscht sollt ginn, iergendwéi am Prozess geännert, dann hu mir direkt Uruff un d'Logik gemaach, déi zu engem anere limitéierten Kontext gehéiert duerch extern Uruff. Zum Beispill, iwwer REST oder WCF.

Mir hunn fest decidéiert datt mir kee Code vermeiden deen verdeelt Transaktiounen erfuerdert. An eisem Fall war et ganz einfach dës Regel ze verfollegen. Mir hunn nach net Situatiounen begéint wou strikt verdeelt Transaktioune wierklech gebraucht ginn - déi lescht Konsistenz tëscht Moduler ass ganz genuch.

Loosst eis e spezifescht Beispill kucken. Mir hunn d'Konzept vun engem Orchester - eng Pipeline déi d'Entitéit vun der "Applikatioun" veraarbecht. Hien schaaft e Client, e Kont an eng Bankkaart am Tour. Wann de Client an de Kont erfollegräich erstallt ginn, awer d'Kaart Kreatioun feelt, geet d'Applikatioun net op de Status "erfollegräich" a bleift am Status "Kaart net erstallt". An Zukunft wäert d'Hannergrond Aktivitéit et ophuelen a fäerdeg maachen. De System ass zënter enger Zäit an engem Zoustand vun Inkonsistenz, mä mir sinn allgemeng zefridde mat dësem.

Wann eng Situatioun entsteet wann et néideg ass en Deel vun den Donnéeën konsequent ze späicheren, wäerte mir héchstwahrscheinlech fir d'Konsolidéierung vum Service goen fir se an engem Prozess ze veraarbecht.

Loosst eis e Beispill kucken fir e Mikroservice ze verdeelen. Wéi kënnt Dir et relativ sécher an d'Produktioun bréngen? An dësem Beispill hu mir e separaten Deel vum System - e Paieziedel Service Modul, ee vun de Code Rubriken vun deem mir gären microservice ze maachen.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Als éischt erstelle mir e Mikroservice andeems Dir de Code nei schreift. Mir verbesseren e puer Aspekter mat deenen mir net zefridden waren. Mir implementéieren nei Geschäftsfuerderunge vum Client. Mir addéieren en API Gateway fir d'Verbindung tëscht der UI an dem Backend, deen Uruff Forwarding gëtt.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Als nächst verëffentleche mir dës Konfiguratioun an Operatioun, awer an engem Pilotstaat. Déi meescht vun eise Benotzer schaffen nach ëmmer mat alen Geschäftsprozesser. Fir nei Benotzer entwéckelen mir eng nei Versioun vun der monolithescher Applikatioun déi dëse Prozess net méi enthält. Wesentlech hu mir eng Kombinatioun vun engem Monolith an engem Mikroservice deen als Pilot funktionnéiert.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Mat engem erfollegräiche Pilot verstinn mir datt déi nei Konfiguratioun wierklech funktionnéiert ass, mir kënnen den alen Monolith aus der Equatioun ewechhuelen an déi nei Konfiguratioun an der Plaz vun der aler Léisung verloossen.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Am Ganzen benotze mir bal all existent Methoden fir de Quellcode vun engem Monolith opzedeelen. All vun hinnen erlaaben eis d'Gréisst vun Deeler vun der Applikatioun ze reduzéieren an se an nei Bibliothéiken ze iwwersetzen, fir bessere Quellcode ze maachen.

Schafft mat der Datebank


D'Datebank kann méi schlëmm wéi de Quellcode opgedeelt ginn, well se net nëmmen dat aktuellt Schema enthält, awer och akkumuléiert historesch Daten.

Eis Datebank, wéi vill anerer, hat eng aner wichteg Nodeel - seng grouss Gréisst. Dës Datebank gouf no der komplizéierter Geschäftslogik vun engem Monolith entworf, a Relatiounen cumuléiert tëscht den Dëscher vu verschiddene begrenzte Kontexter.

An eisem Fall, fir all d'Problemer (grouss Datebank, vill Verbindungen, heiansdo onkloer Grenzen tëscht Dëscher) opzemaachen, ass e Problem entstanen, deen a ville grousse Projete geschitt: d'Benotzung vun der gemeinsamer Datebank Schabloun. Daten goufen aus Dëscher duerch Vue, duerch Replikatioun geholl, an an aner Systemer geschéckt wou dës Replikatioun gebraucht gouf. Als Resultat konnte mir d'Dëscher net an e separat Schema réckelen, well se aktiv benotzt goufen.

Déiselwecht Divisioun a limitéierte Kontexter am Code hëlleft eis bei der Trennung. Et gëtt eis normalerweis eng zimlech gutt Iddi wéi mir d'Donnéeën um Datebankniveau ofbriechen. Mir verstinn wéi eng Dëscher zu engem begrenzte Kontext gehéieren a wéi eng zu engem aneren.

Mir hunn zwou global Methode vun der Datebankpartitionéierung benotzt: Partitionéierung vun existente Dëscher a Partitionéierung mat Veraarbechtung.

D'Ofdeelung vun existente Dëscher ass eng gutt Method fir ze benotzen wann d'Datestruktur gutt ass, Geschäftsbedéngungen entsprécht, a jidderee mat deem zefridden ass. An dësem Fall kënne mir existéierend Dëscher an e separat Schema trennen.

En Departement mat Veraarbechtung ass gebraucht wann de Geschäftsmodell sech staark verännert huet, an d'Dëscher eis guer net méi zefridden stellen.

Splitting bestehend Dëscher. Mir mussen bestëmmen wat mir trennen. Ouni dëst Wëssen wäert näischt funktionnéieren, an hei hëlleft d'Trennung vu begrenzte Kontexter am Code eis. Als Regel, wann Dir d'Grenze vu Kontexter am Quellcode versteet, gëtt et kloer wéi eng Tabellen an der Lëscht fir den Departement abegraff sinn.

Loosst eis virstellen datt mir eng Léisung hunn an där zwee Monolith Moduler mat enger Datebank interagéieren. Mir mussen sécherstellen datt nëmmen ee Modul mat der Sektioun vun getrennten Dëscher interagéiert, an deen aneren fänkt mat der API ze interagéieren. Fir unzefänken ass et genuch datt nëmmen d'Opname duerch d'API duerchgefouert gëtt. Dëst ass eng noutwendeg Bedingung fir eis iwwer d'Onofhängegkeet vu Mikroservicer ze schwätzen. Liesverbindunge kënne bleiwen soulaang et kee grousse Problem ass.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

De nächste Schrëtt ass datt mir d'Sektioun vum Code trennen, déi mat getrennten Dëscher funktionnéiert, mat oder ouni Veraarbechtung, an e getrennten Mikroservice an et an engem getrennten Prozess, e Container lafen. Dëst wäert e separaten Service sinn mat enger Verbindung mat der Monolith-Datebank an déi Dëscher déi net direkt dozou bezéien. De Monolith interagéiert nach ëmmer fir ze liesen mam eraushuelbare Deel.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Spéider wäerte mir dës Verbindung ewechhuelen, dat heescht, d'Liesen vun Daten aus enger monolithescher Applikatioun aus getrennten Dëscher gëtt och op d'API transferéiert.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Als nächst wäerte mir aus der allgemenger Datebank d'Tabellen auswielen, mat deenen nëmmen den neie Mikroservice funktionnéiert. Mir kënnen d'Dëscher op e getrennten Schema réckelen oder souguer op eng separat kierperlech Datebank. Et gëtt nach ëmmer eng Liesverbindung tëscht dem Mikroservice an der Monolithdatenbank, awer et gëtt näischt ze Suergen, an dëser Konfiguratioun kann et zimmlech laang liewen.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

De leschte Schrëtt ass all Verbindungen komplett ze läschen. An dësem Fall musse mir eventuell Daten aus der Haaptdatenbank migréieren. Heiansdo wëlle mir e puer Donnéeën oder Verzeichnisser replizéiert vun externe Systemer a verschiddenen Datenbanken weiderbenotzen. Dat geschitt eis periodesch.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Veraarbechtung Departement. Dës Method ass ganz ähnlech wéi déi éischt, nëmmen an ëmgedréint Uerdnung. Mir verdeelen direkt eng nei Datebank an en neie Mikroservice, deen mam Monolith iwwer eng API interagéiert. Awer gläichzäiteg bleift et eng Rei vun Datebank Dëscher déi mir an Zukunft wëllen läschen. Mir brauchen et net méi, mir hunn et am neie Modell ersat.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Fir datt dëse Schema funktionnéiert, brauche mir méiglecherweis eng Iwwergangsperiod.

Et ginn dann zwou méiglech Approche.

Déi éischt: Mir duplizéieren all Daten an den neien an alen Datenbanken. An dësem Fall hu mir Datenredundanz a Synchroniséierungsproblemer kënnen entstoen. Mee mir kënnen zwee verschidde Clienten huelen. Een wäert mat der neier Versioun schaffen, déi aner mat der aler.

Déi zweet: mir deelen d'Donnéeën no e puer Geschäftskriterien. Zum Beispill hu mir 5 Produkter am System, déi an der aler Datebank gespäichert goufen. Mir setzen de sechsten an der neier Geschäftstask an enger neier Datebank. Awer mir brauche en API Gateway deen dës Donnéeën synchroniséiert an de Client weist wou a wat fir ze kommen.

Béid Approche funktionnéieren, wielt ofhängeg vun der Situatioun.

Nodeems mir sécher sinn, datt alles funktionnéiert, kann den Deel vum Monolith, deen mat alen Datebankstrukturen funktionnéiert, ausgeschalt ginn.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

De leschte Schrëtt ass déi al Datestrukturen ze läschen.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Fir ze resuméieren, kënne mir soen datt mir Probleemer mat der Datebank hunn: et ass schwéier mat deem ze schaffen am Verglach zum Quellcode, et ass méi schwéier ze deelen, awer et kann a soll gemaach ginn. Mir hunn e puer Weeër fonnt, déi eis erlaben dëst ganz sécher ze maachen, awer et ass ëmmer méi einfach Feeler mat Daten ze maachen wéi mat Quellcode.

Schafft mat Quellcode


Dëst ass wéi d'Quellcode Diagramm ausgesinn wéi mir ugefaang de monolithesche Projet ze analyséieren.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Et kann ongeféier an dräi Schichten opgedeelt ginn. Dëst ass eng Schicht vu lancéierte Moduler, Plugins, Servicer an eenzel Aktivitéiten. Tatsächlech waren dës Entréen an enger monolithescher Léisung. All vun hinnen goufen enk mat enger gemeinsamer Schicht versiegelt. Et hat eng Geschäftslogik déi d'Servicer gedeelt hunn a vill Verbindungen. All Service a Plugin benotzt bis zu 10 oder méi gemeinsam Versammlungen, ofhängeg vun hirer Gréisst an dem Gewësse vun den Entwéckler.

Mir haten d'Gléck fir Infrastrukturbibliothéiken ze hunn déi separat benotzt kënne ginn.

Heiansdo ass eng Situatioun entstanen, wann e puer gemeinsam Objeten eigentlech net zu dëser Schicht gehéieren, mee Infrastrukturbibliothéike waren. Dëst gouf geléist andeems se ëmbenennen.

Déi gréisste Suerg war begrenzte Kontexter. Et ass geschitt datt 3-4 Kontexter an enger gemeinsamer Versammlung gemëscht goufen a sech an deene selwechte Geschäftsfunktiounen benotzt hunn. Et war néideg ze verstoen wou dëst ënnerdeelt ginn a laanscht wat Grenzen, a wat nächst ze maachen mat Kartéierung dëser Divisioun an Quellcode Assemblée.

Mir hunn e puer Reegele fir de Code Spaltprozess formuléiert.

Déi éischt: Mir wollten net méi Geschäftslogik tëscht Servicer, Aktivitéiten a Plugins deelen. Mir wollten d'Geschäftslogik onofhängeg bannent Mikroservicer maachen. Mikroservicer, op der anerer Säit, sinn am Idealfall geduecht als Servicer déi komplett onofhängeg existéieren. Ech gleewen, datt dës Approche e bësse verschwendend ass, an et ass schwéier z'erreechen, well zum Beispill Servicer an C # wäerten op alle Fall vun enger Standardbibliothéik verbonne sinn. Eise System ass an C # geschriwwe ginn; mir hunn nach keng aner Technologien benotzt. Dofir hu mir décidéiert datt mir eis leeschte kënnen gemeinsam technesch Versammlungen ze benotzen. Den Haapt Saach ass datt se keng Fragmenter vun der Geschäftslogik enthalen. Wann Dir e Komfort-Wrapper iwwer den ORM hutt, deen Dir benotzt, da kopéiert se vum Service zum Service ganz deier.

Eist Team ass e Fan vum Domain-gedriwwenen Design, sou datt d'Zwiebelarchitektur gutt fir eis passt. D'Basis vun eise Servicer ass net d'Datenaccess Layer, mee eng Versammlung mat Domain Logik, déi nëmmen Geschäftslogik enthält a keng Verbindunge mat der Infrastruktur huet. Zur selwechter Zäit kënne mir d'Domainversammlung onofhängeg änneren fir Probleemer am Zesummenhang mat Kaderen ze léisen.

Op dëser Etapp hu mir eisen éischte sérieux Problem begéint. De Service huet missen op eng Domainversammlung bezéien, mir wollten d'Logik onofhängeg maachen, an den DRY-Prinzip huet eis hei staark behënnert. D'Entwéckler wollte Klassen aus Nopeschversammlungen nei benotzen fir Duplikatioun ze vermeiden, an als Resultat hunn d'Domänen erëm matenee verbonnen. Mir hunn d'Resultater analyséiert an decidéiert datt vläicht de Problem och am Beräich vum Quellcode-Späicherapparat läit. Mir haten e grousse Repository mat all de Quellcode. D'Léisung fir de ganze Projet war ganz schwéier op enger lokaler Maschinn ze montéieren. Dofir goufen separat kleng Léisunge fir Deeler vum Projet erstallt, a keen huet verbueden eng gemeinsam oder Domainversammlung derbäi ze addéieren an se ze benotzen. Dat eenzegt Tool dat eis net erlaabt huet dëst ze maachen war Code review. Mee heiansdo huet et och gescheitert.

Duerno hu mir ugefaang op e Modell mat getrennten Repositories ze plënneren. D'Geschäftslogik fléisst net méi vu Service zum Service, Domänen si wierklech onofhängeg ginn. Begrenzte Kontexter ginn méi kloer ënnerstëtzt. Wéi benotze mir Infrastrukturbibliothéike weider? Mir hunn se an e getrennten Repository getrennt, hunn se dann an Nuget Packagen gesat, déi mir an Artifactory gesat hunn. Mat all Ännerung geschitt d'Versammlung an d'Publikatioun automatesch.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Eis Servicer hunn ugefaang intern Infrastruktur Packagen op déiselwecht Manéier ze referenzéieren wéi extern. Mir download extern Bibliothéiken aus Nuget. Fir mat Artifactory ze schaffen, wou mir dës Packagen plazéiert hunn, hu mir zwee Packagemanager benotzt. A klenge Repositories hu mir och Nuget benotzt. A Repositories mat multiple Servicer hu mir Paket benotzt, wat méi Versiounskonsistenz tëscht Moduler ubitt.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Also, andeems mir um Quellcode schaffen, d'Architektur liicht änneren an d'Repositories trennen, maache mir eis Servicer méi onofhängeg.

Infrastrukturproblemer


Déi meescht vun den Nodeeler fir op Mikroservicer ze plënneren sinn Infrastruktur verbonnen. Dir braucht automatiséiert Deployment, Dir braucht nei Bibliothéike fir d'Infrastruktur ze bedreiwen.

Manuell Installatioun an Ëmfeld

Am Ufank hu mir d'Léisung fir Ëmfeld manuell installéiert. Fir dëse Prozess ze automatiséieren, hu mir eng CI / CD Pipeline erstallt. Mir hunn de kontinuéierleche Liwwerprozess gewielt well kontinuéierlech Deployment nach net akzeptabel ass fir eis aus der Siicht vu Geschäftsprozesser. Dofir gëtt d'Schécken fir d'Operatioun mat engem Knäppchen duerchgefouert, a fir ze testen - automatesch.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Mir benotzen Atlassian, Bitbucket fir Quellcode Späicheren a Bambus fir ze bauen. Mir schreiwen gär Build Scripten am Cake well et d'selwecht ass wéi C #. Fäerdeg Pakete kommen op Artifactory, an Ansible kënnt automatesch op d'Testserver, duerno kënnen se direkt getest ginn.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Separat Logged


Eng Kéier war eng vun den Iddie vum Monolith fir gemeinsame Logbicher ze bidden. Mir mussen och verstoen wat mir maache mat den eenzelne Logbicher déi op den Disken sinn. Eis Logbicher ginn op Textdateien geschriwwe. Mir hunn decidéiert e Standard ELK Stack ze benotzen. Mir hunn d'ELK net direkt duerch d'Provider geschriwwen, awer decidéiert datt mir d'Textprotokoller finaliséieren an d'Spuer-ID an hinnen als Identifizéierer schreiwen, de Servicenumm bäigefüügt, sou datt dës Logbicher spéider kënne parséiert ginn.

Den Iwwergank vum Monolith op Mikroservicer: Geschicht a Praxis

Mat Filebeat kréien mir d'Méiglechkeet eis Logbicher vu Serveren ze sammelen, se dann transforméieren, Kibana benotze fir Ufroen an der UI ze bauen a kucken wéi den Uruff tëscht Servicer gaang ass. Trace ID hëlleft vill mat dësem.

Testen an Debugging verbonne Servicer


Am Ufank hu mir net ganz verstan wéi d'Servicer ze debuggen déi entwéckelt ginn. Alles war einfach mam Monolith; Mir hunn et op enger lokaler Maschinn gelaf. Am Ufank hu se probéiert datselwecht mat Mikroservicer ze maachen, awer heiansdo fir e Mikroservice komplett ze starten, musst Dir e puer anerer starten, an dëst ass onbequem. Mir hu gemierkt datt mir op e Modell musse plënneren, wou mir op der lokaler Maschinn nëmmen de Service oder Servicer verloossen, déi mir wëllen Debuggen. Déi reschtlech Servicer gi vu Servere benotzt déi mat der Konfiguratioun mat Prod passen. Nom Debugging, während dem Test, fir all Aufgab, ginn nëmmen déi geännert Servicer op den Testserver ausgestallt. Also gëtt d'Léisung an der Form getest an där se an der Zukunft an der Produktioun erscheint.

Et gi Serveren déi nëmme Produktiounsversioune vu Servicer lafen. Dës Servere sinn am Fall vun Tëschefäll gebraucht, fir d'Liwwerung virum Asaz ze kontrolléieren a fir intern Training.

Mir hunn en automatiséierten Testprozess mat der populärer Specflow Bibliothéik bäigefüügt. Tester lafen automatesch mat NUnit direkt nom Ofbau vun Ansible. Wann d'Taskofdeckung voll automatesch ass, da gëtt et kee Besoin fir manuell Tester. Och wann heiansdo zousätzlech manuell Tester nach ëmmer erfuerderlech sinn. Mir benotzen Tags am Jira fir ze bestëmmen wéi eng Tester fir e spezifescht Thema lafen.

Zousätzlech ass de Besoin fir Laaschtestung eropgaang, virdrun gouf et nëmmen a rare Fäll duerchgefouert. Mir benotzen JMeter fir Tester auszeféieren, InfluxDB fir se ze späicheren, a Grafana fir Prozessgrafiken ze bauen.

Wat hu mir erreecht?


Als éischt hu mir d'Konzept vun "Verëffentlechung" entlooss. Gone sinn déi zwee-Mount monstréis Verëffentlechungen, wann dëse Koloss an engem Produktiounsëmfeld ofgesat gouf, temporär d'Geschäftsprozesser stéieren. Elo setzen mir Servicer am Duerchschnëtt all 1,5 Deeg aus, gruppéiere se well se no der Genehmegung a Betrib ginn.

Et gi keng fatale Feeler an eisem System. Wa mir e Mikroservice mat engem Feeler verëffentlechen, da gëtt d'Funktionalitéit verbonne mat deem gebrach, an all aner Funktionalitéit gëtt net beaflosst. Dëst verbessert immens d'Benotzererfarung.

Mir kënnen den Ofbaumuster kontrolléieren. Dir kënnt Gruppe vu Servicer separat aus dem Rescht vun der Léisung auswielen, wann néideg.

Zousätzlech hu mir de Problem mat enger grousser Schlaang vu Verbesserunge wesentlech reduzéiert. Mir hunn elo separat Produktteams déi onofhängeg mat e puer vun de Servicer schaffen. De Scrum Prozess ass scho gutt hei. E spezifescht Team kann e separaten Produktbesëtzer hunn, deen et Aufgaben zouginn.

Summary

  • Mikroservicer si gutt gëeegent fir komplex Systemer ofzebauen. Am Prozess fänken mir un ze verstoen wat an eisem System ass, wéi eng limitéiert Kontexter et sinn, wou hir Grenze leien. Dëst erlaabt Iech Verbesserungen tëscht Moduler korrekt ze verdeelen an Code Duercherneen ze verhënneren.
  • Mikroservicer bidden organisatoresch Virdeeler. Si ginn dacks nëmmen als Architektur geschwat, awer all Architektur ass gebraucht fir Geschäftsbedürfnisser ze léisen, an net eleng. Dofir kënne mir soen datt Mikroservicer gutt gëeegent sinn fir Probleemer a klenge Teams ze léisen, well Scrum elo ganz populär ass.
  • Trennung ass en iterative Prozess. Dir kënnt eng Applikatioun net huelen an se einfach a Mikroservicer opdeelen. Dat resultéierend Produkt ass onwahrscheinlech funktionell. Wann Dir Mikroservicer widmen, ass et gutt fir déi existent Legacy ëmzeschreiwen, dat heescht, et a Code ëmzewandelen, dee mir gär hunn a besser entsprécht Geschäftsbedürfnisser a punkto Funktionalitéit a Geschwindegkeet.

    E klengen Opgepasst: D'Käschte fir op Mikroservicer ze plënneren sinn zimlech bedeitend. Et huet laang gedauert fir den Infrastrukturproblem alleng ze léisen. Also wann Dir eng kleng Applikatioun hutt déi keng spezifesch Skaléierung erfuerdert, ausser Dir hutt eng grouss Zuel vu Clienten déi fir d'Opmierksamkeet an d'Zäit vun Ärem Team konkurréiere, da sinn Mikroservicer vläicht net dat wat Dir haut braucht. Et ass zimlech deier. Wann Dir de Prozess mat Mikroservicer ufänkt, da wäerten d'Käschte ufanks méi héich sinn wéi wann Dir dee selwechte Projet mat der Entwécklung vun engem Monolith starten.

    PS Eng méi emotional Geschicht (a wéi fir Iech perséinlech) - laut Link.
    Hei ass déi komplett Versioun vum Bericht.

Source: will.com

Setzt e Commentaire