{"id":35906,"date":"2019-10-31T22:07:29","date_gmt":"2019-10-31T19:07:29","guid":{"rendered":"https:\/\/prohoster.info\/blog\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\/"},"modified":"2019-10-31T22:07:29","modified_gmt":"2019-10-31T19:07:29","slug":"perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","title":{"rendered":"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>W tym artykule opowiem o tym, jak projekt, w kt\u00f3rym pracuj\u0119, przekszta\u0142ca\u0142 si\u0119 z du\u017cego monolitu w zestaw mikroserwis\u00f3w.<\/p>\n<p>Projekt rozpocz\u0105\u0142 swoj\u0105 histori\u0119 do\u015b\u0107 dawno, na pocz\u0105tku lat 2000. Pierwsze wersje by\u0142y napisane w Visual Basic 6. Z biegiem czasu sta\u0142o si\u0119 jasne, \u017ce rozw\u00f3j w tym j\u0119zyku w przysz\u0142o\u015bci b\u0119dzie trudny do utrzymania, poniewa\u017c IDE i sam j\u0119zyk rozwijaj\u0105 si\u0119 s\u0142abo. Pod koniec lat 2000 postanowiono przej\u015b\u0107 na bardziej obiecuj\u0105cy C#. Nowa wersja by\u0142a tworzona r\u00f3wnolegle z udoskonalaniem starej, stopniowo coraz wi\u0119cej kodu by\u0142o na .NET. Backend w C# pocz\u0105tkowo koncentrowa\u0142 si\u0119 na architekturze serwisowej, jednak w trakcie rozwoju wykorzystywano wsp\u00f3lne biblioteki z logik\u0105, a us\u0142ugi uruchamiane by\u0142y w jednym procesie. Powsta\u0142a aplikacja, kt\u00f3r\u0105 nazywali\u015bmy \u201eserwisowym monolitem\u201d. <\/p>\n<p>Jedn\u0105 z nielicznych zalet takiego po\u0142\u0105czenia by\u0142a mo\u017cliwo\u015b\u0107 wywo\u0142ywania us\u0142ug przez siebie za pomoc\u0105 zewn\u0119trznego API. Istnia\u0142y wyra\u017ane przes\u0142anki do przej\u015bcia na bardziej poprawn\u0105 architektur\u0119 serwisow\u0105, a w przysz\u0142o\u015bci mikroserwisow\u0105. <\/p>\n<p>Prac\u0119 nad dekompozycj\u0105 rozpocz\u0119li\u015bmy oko\u0142o 2015 roku. Wci\u0105\u017c nie osi\u0105gn\u0119li\u015bmy idealnego stanu \u2014 pozosta\u0142y cz\u0119\u015bci du\u017cego projektu, kt\u00f3re trudno ju\u017c nazwa\u0107 monolitami, ale te\u017c nie przypominaj\u0105 mikroserwis\u00f3w. Niemniej jednak, post\u0119p jest znaczny. <br \/>\nO nim opowiem w artykule.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/132bb4ea6b9dbcdd202ee090f2b86289.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Spis tre\u015bci<\/h3>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#1\"> Architektura i problemy istniej\u0105cego rozwi\u0105zania<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#2\">Oczekiwania wobec mikroserwis\u00f3w<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#3\">Problemy przej\u015bcia<\/a><\/noindex><\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"#4\">Jak przej\u015b\u0107 od monolitu do mikroserwis\u00f3w<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#5\">Pierwszy spos\u00f3b<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#6\">Drugi spos\u00f3b<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#7\">Trzeci spos\u00f3b<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#8\">Czwarty spos\u00f3b<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#9\">Utw\u00f3rzmy baz\u0119 danych \u2013 MySQL. Je\u015bli masz zainstalowane PhpMyAdmin, utw\u00f3rz now\u0105 baz\u0119 danych \"<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#10\">Oddzielenie istniej\u0105cych tabel<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#11\">Oddzielenie z przer\u00f3bk\u0105<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#12\">Praca z kodem \u017ar\u00f3d\u0142owym<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#13\">Problemy infrastruktury<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#16\">R\u0119czna instalacja w \u015brodowiskach<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#14\">Oddzielne logowanie<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#15\">Testowanie i debugging powi\u0105zanych us\u0142ug<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><noindex><a rel=\"nofollow\" name=\"1\"><\/a><\/noindex><b><\/p>\n<h3>Architektura i problemy istniej\u0105cego rozwi\u0105zania<\/h3>\n<p><\/b><br \/>\nPocz\u0105tkowo architektura wygl\u0105da\u0142a nast\u0119puj\u0105co: UI \u2014 osobna aplikacja, cz\u0119\u015b\u0107 monolityczna napisana w Visual Basic 6, aplikacja na .NET stanowi\u0142a zestaw powi\u0105zanych us\u0142ug, dzia\u0142aj\u0105cych z do\u015b\u0107 du\u017c\u0105 baz\u0105 danych.<\/p>\n<p><b>Wady wcze\u015bniejszego rozwi\u0105zania<\/b><\/p>\n<p><u>Jednolita znacznie awarii<\/u><br \/>\nMieli\u015bmy punkt awarii: aplikacja na .NET dzia\u0142a\u0142a w jednym procesie. Je\u015bli w kt\u00f3rymkolwiek z modu\u0142\u00f3w wyst\u0105pi\u0142 b\u0142\u0105d, ca\u0142a aplikacja przestawa\u0142a dzia\u0142a\u0107 i trzeba by\u0142o j\u0105 ponownie uruchomi\u0107. Poniewa\u017c automatyzujemy wiele proces\u00f3w dla r\u00f3\u017cnych u\u017cytkownik\u00f3w, z powodu awarii jednego z nich przez pewien czas nie mog\u0142y dzia\u0142a\u0107 wszystkie. A w przypadku b\u0142\u0119du programowego r\u00f3wnie\u017c rezerwacja nie pomaga\u0142a. <\/p>\n<p><u>Kolejka wdro\u017ce\u0144<\/u><br \/>\nTa wada by\u0142a raczej organizacyjna. W naszej aplikacji jest wielu klient\u00f3w, kt\u00f3rzy chc\u0105 jak najszybciej wprowadzi\u0107 poprawki. Wcze\u015bniej nie da\u0142o si\u0119 tego robi\u0107 r\u00f3wnolegle, wi\u0119c wszyscy klienci stawali w kolejce. Proces ten wywo\u0142ywa\u0142 negatywne skutki w biznesie, poniewa\u017c musieli udowodni\u0107, \u017ce ich zadanie ma warto\u015b\u0107. Zesp\u00f3\u0142 deweloperski traci\u0142 czas na organizowanie tej kolejki. Odbywa\u0142o si\u0119 to kosztem wiele czasu i energii, a produkt nie m\u00f3g\u0142 na koniec zmienia\u0107 si\u0119 tak szybko, jakby tego oczekiwano.<\/p>\n<p><u>Nieoptymalne wykorzystanie zasob\u00f3w<\/u><br \/>\nPodczas uruchamiania us\u0142ug w jednym procesie zawsze kopiowali\u015bmy konfiguracj\u0119 z serwera na serwer. Chcieli\u015bmy umie\u015bci\u0107 najbardziej obci\u0105\u017cone us\u0142ugi oddzielnie, aby nie marnowa\u0107 zasob\u00f3w i uzyska\u0107 bardziej elastyczne zarz\u0105dzanie naszym schematem wdro\u017cenia.<\/p>\n<p><u>Trudno\u015bci we wdra\u017caniu nowoczesnych technologii<\/u><br \/>\nZnany wszystkim deweloperom problem: ch\u0119\u0107 wprowadzenia nowoczesnych technologii do projektu, ale brak mo\u017cliwo\u015bci. W przypadku du\u017cego monolitu ka\u017cda aktualizacja obecnej biblioteki, nie m\u00f3wi\u0105c ju\u017c o przej\u015bciu na now\u0105, staje si\u0119 do\u015b\u0107 z\u0142o\u017conym zadaniem. Trzeba d\u0142ugo przekonywa\u0107 lidera zespo\u0142u, \u017ce przyniesie to wi\u0119cej korzy\u015bci ni\u017c nerw\u00f3w. <\/p>\n<p><u>Trudno\u015bci w wydawaniu zmian<\/u><br \/>\nTo by\u0142 najwi\u0119kszy problem \u2013 wydawali\u015bmy nowe wersje co dwa miesi\u0105ce. <br \/>\nKa\u017cda wersja stawa\u0142a si\u0119 prawdziw\u0105 katastrof\u0105 dla banku, mimo test\u00f3w i wysi\u0142k\u00f3w deweloper\u00f3w. Biznes wiedzia\u0142, \u017ce na pocz\u0105tku tygodnia cz\u0119\u015b\u0107 funkcjonalno\u015bci nie b\u0119dzie dzia\u0142a\u0107. Deweloperzy zdawali sobie spraw\u0119, \u017ce czeka ich tydzie\u0144 powa\u017cnych incydent\u00f3w. <br \/>\nWszyscy chcieli zmieni\u0107 t\u0119 sytuacj\u0119. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"2\"><\/a><\/noindex><b><\/p>\n<h3>Oczekiwania wobec mikroserwis\u00f3w<\/h3>\n<p><\/b><br \/>\n<u>Wydawanie komponent\u00f3w wed\u0142ug gotowo\u015bci. <\/u>Wydawanie komponent\u00f3w w miar\u0119 gotowo\u015bci dzi\u0119ki dekompozycji rozwi\u0105zania i oddzieleniu r\u00f3\u017cnych proces\u00f3w.<\/p>\n<p><u>Ma\u0142e zespo\u0142y produktowe.<\/u> To wa\u017cne, poniewa\u017c du\u017cym zespo\u0142em pracuj\u0105cym nad starym monolitem trudno by\u0142o zarz\u0105dza\u0107. Taki zesp\u00f3\u0142 musia\u0142 pracowa\u0107 wed\u0142ug \u015bcis\u0142ego procesu, podczas gdy chciano wi\u0119cej kreatywno\u015bci i niezale\u017cno\u015bci. To mog\u0142y sobie pozwoli\u0107 tylko ma\u0142e zespo\u0142y.<\/p>\n<p><u>Izolacja us\u0142ug w osobnych procesach.<\/u> Idealnie chcia\u0142oby si\u0119 izolowa\u0107 w kontenerach, ale du\u017ca liczba us\u0142ug napisanych w .NET Framework uruchamiana jest tylko pod Windows. Teraz pojawiaj\u0105 si\u0119 us\u0142ugi oparte na .NET Core, ale jest ich jeszcze ma\u0142o.<\/p>\n<p><u>Elastyczno\u015b\u0107 wdra\u017cania.<\/u> Chcieliby\u015bmy \u0142\u0105czy\u0107 us\u0142ugi tak, jak to jest dla nas potrzebne, a nie tak, jak wymusza kod.<\/p>\n<p><u>Wykorzystanie nowych technologii.<\/u> To interesuje ka\u017cdego programist\u0119.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"3\"><\/a><\/noindex><b><\/p>\n<h3>Problemy przej\u015bcia<\/h3>\n<p><\/b><br \/>\nOczywi\u015bcie, gdyby podzia\u0142 monolitu na mikrous\u0142ugi by\u0142 prosty, nie trzeba by o tym m\u00f3wi\u0107 na konferencjach i pisa\u0107 artyku\u0142\u00f3w. W tym procesie jest wiele pu\u0142apek, opisz\u0119 te g\u0142\u00f3wne, kt\u00f3re nam przeszkadza\u0142y.<\/p>\n<p><b>Pierwszy problem<\/b> typowe dla wi\u0119kszo\u015bci monolit\u00f3w: sp\u00f3jno\u015b\u0107 logiki biznesowej. Gdy piszemy monolit, chcemy ponownie wykorzysta\u0107 nasze klasy, aby nie pisa\u0107 zb\u0119dnego kodu. A przy przej\u015bciu na mikrous\u0142ugi staje si\u0119 to problemem: ca\u0142y kod jest do\u015b\u0107 mocno powi\u0105zany i trudno jest podzieli\u0107 us\u0142ugi.<\/p>\n<p>W momencie rozpocz\u0119cia prac w repozytorium by\u0142o ponad 500 projekt\u00f3w i ponad 700 tys. linii kodu. To do\u015b\u0107 du\u017ce rozwi\u0105zanie i <b>drugi problem<\/b>. Po prostu wzi\u0119cie i podzielenie go na mikrous\u0142ugi nie wydawa\u0142o si\u0119 mo\u017cliwe.<\/p>\n<p><b>The third problem<\/b> \u2014 brak niezb\u0119dnej infrastruktury. Faktycznie zajmowali\u015bmy si\u0119 r\u0119cznym kopiowaniem kodu \u017ar\u00f3d\u0142owego na serwery.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"4\"><\/a><\/noindex><b><\/p>\n<h3>Jak przej\u015b\u0107 od monolitu do mikroserwis\u00f3w<\/h3>\n<p><\/b><br \/>\n<u>Wydzielanie mikrous\u0142ug<\/u><\/p>\n<p>Po pierwsze, od razu okre\u015blili\u015bmy, \u017ce podzia\u0142 mikrous\u0142ug jest procesem iteracyjnym. Od nas zawsze wymagano r\u00f3wnoleg\u0142ego prowadzenia rozwoju zada\u0144 biznesowych. Jak zrealizujemy to technicznie \u2014 to ju\u017c nasz problem. Dlatego przygotowali\u015bmy si\u0119 na proces iteracyjny. W przeciwnym razie si\u0119 nie uda, je\u015bli masz du\u017c\u0105 aplikacj\u0119, kt\u00f3ra z za\u0142o\u017cenia nie jest gotowa do tego, aby j\u0105 przepisa\u0107.<\/p>\n<p>Jakie metody stosujemy do wydzielania mikrous\u0142ug?<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"5\"><\/a><\/noindex><b>Pierwszy spos\u00f3b <\/b>\u2014 wprowadza\u0107 istniej\u0105ce modu\u0142y jako us\u0142ugi. W tym przypadku mieli\u015bmy szcz\u0119\u015bcie: ju\u017c istnia\u0142y sformatowane us\u0142ugi dzia\u0142aj\u0105ce na protokole WCF. By\u0142y one rozdzielone na oddzielne zestawy. Przenosili\u015bmy je oddzielnie, dodaj\u0105c do ka\u017cdego zestawu ma\u0142y modu\u0142 uruchamiaj\u0105cy. Zosta\u0142 on napisany przy u\u017cyciu doskona\u0142ej biblioteki Topshelf, kt\u00f3ra pozwala uruchamia\u0107 aplikacj\u0119 zar\u00f3wno jako us\u0142ug\u0119, jak i konsol\u0119. To jest wygodne do debugowania, poniewa\u017c nie wymagane s\u0105 dodatkowe projekty w rozwi\u0105zaniu.<\/p>\n<p>Us\u0142ugi by\u0142y powi\u0105zane logicznie w zale\u017cno\u015bci od biznesu, poniewa\u017c wykorzystywa\u0142y wsp\u00f3lne zestawy i pracowa\u0142y z wsp\u00f3ln\u0105 baz\u0105 danych. Trudno je by\u0142o nazwa\u0107 mikrous\u0142ugami w czystym tego s\u0142owa znaczeniu. Niemniej jednak, mogli\u015bmy te us\u0142ugi udost\u0119pnia\u0107 oddzielnie, w r\u00f3\u017cnych procesach. Ju\u017c to pozwoli\u0142o zmniejszy\u0107 jednolite wp\u0142ywy mi\u0119dzy nimi, ograniczaj\u0105c problem zwi\u0105zany z r\u00f3wnoleg\u0142ym rozwojem i pojedynczym punktem awarii.<\/p>\n<p>Zestaw z hostem to zaledwie jedna linia kodu w klasie Program. Prac\u0119 z Topshelf schowali\u015bmy w pomocniczej klasie.<\/p>\n<pre><code class=\"plaintext\">namespace RBA.Services.Accounts.Host\n{\n   internal class Program\n   {\n      private static void Main(string[] args)\n      {\n        HostRunner.Run(\"RBA.Services.Accounts.Host\");\n\n       }\n    }\n}\n<\/code><\/pre>\n<p>\n<noindex><a rel=\"nofollow\" name=\"6\"><\/a><\/noindex><b>Drugi spos\u00f3b wyodr\u0119bnienia mikrous\u0142ug:<\/b> tworzenie ich w celu rozwi\u0105zania nowych zada\u0144. Je\u015bli przy tym monolit nie ro\u015bnie, to ju\u017c dobrze, oznacza to, \u017ce idziemy w dobrym kierunku. W celu rozwi\u0105zania nowych zada\u0144 starali\u015bmy si\u0119 tworzy\u0107 oddzielne us\u0142ugi. Je\u015bli by\u0142a taka mo\u017cliwo\u015b\u0107, tworzyli\u015bmy bardziej \"kanoniczne\" us\u0142ugi, kt\u00f3re w pe\u0142ni zarz\u0105dzaj\u0105 swoim modelem danych oraz oddzieln\u0105 baz\u0105 danych. <\/p>\n<p>My, jak wielu innych, zaczynali\u015bmy od us\u0142ug uwierzytelniania i autoryzacji. Idealnie si\u0119 do tego nadaj\u0105. S\u0105 niezale\u017cne, zazwyczaj maj\u0105 odr\u0119bny model danych. Nie interaguj\u0105 bezpo\u015brednio z monolitem, to on zwraca si\u0119 do nich w celu realizacji pewnych zada\u0144. Na tych us\u0142ugach mo\u017cna rozpocz\u0105\u0107 przej\u015bcie na now\u0105 architektur\u0119, zdebugowa\u0107 infrastruktur\u0119, wypr\u00f3bowa\u0107 r\u00f3\u017cne podej\u015bcia zwi\u0105zane z bibliotekami sieciowymi itd. W naszej organizacji nie ma zespo\u0142\u00f3w, kt\u00f3re nie by\u0142yby w stanie zbudowa\u0107 us\u0142ugi uwierzytelniania. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"7\"><\/a><\/noindex><b>Trzeci spos\u00f3b wyodr\u0119bnienia mikrous\u0142ug<\/b>, z kt\u00f3rego korzystamy, jest dla nas nieco specyficzny. To wydzielenie logiki biznesowej z warstwy UI. Nasza g\u0142\u00f3wna aplikacja UI to aplikacja desktopowa, napisana, podobnie jak backend, w C#. Programi\u015bci od czasu do czasu pope\u0142niali b\u0142\u0119dy, umieszczaj\u0105c w UI cz\u0119\u015bci logiki, kt\u00f3re powinny istnie\u0107 w backendzie i by\u0107 wielokrotnie wykorzystywane. <\/p>\n<p>Je\u015bli spojrzymy na prawdziwy przyk\u0142ad z kodu cz\u0119\u015bci UI, wida\u0107, \u017ce znaczna cz\u0119\u015b\u0107 tego rozwi\u0105zania zawiera prawdziw\u0105 logik\u0119 biznesow\u0105, kt\u00f3ra jest przydatna w innych procesach, nie tylko do budowania formularza UI. <\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/74c7b90ff94b343816ab3ac2fa0673c6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nRealna logika UI to tylko ostatnia para wierszy. Przenie\u015bli\u015bmy j\u0105 na serwer, aby mo\u017cna j\u0105 by\u0142o wielokrotnie wykorzystywa\u0107, zmniejszaj\u0105c tym samym UI i osi\u0105gaj\u0105c prawid\u0142ow\u0105 architektur\u0119.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"8\"><\/a><\/noindex><b>Czwarty, najwa\u017cniejszy spos\u00f3b wydzielania mikroserwis\u00f3w<\/b>, kt\u00f3ry pozwala zmniejszy\u0107 monolit \u2014 to wydzielenie istniej\u0105cych serwis\u00f3w z przer\u00f3bk\u0105. Gdy wydzielamy istniej\u0105ce modu\u0142y takimi, jakie s\u0105, rezultat nie zawsze podoba si\u0119 programistom, a proces biznesowy od czasu stworzenia funkcjonalno\u015bci m\u00f3g\u0142 si\u0119 zestarze\u0107. Dzi\u0119ki refaktoryzacji mo\u017cemy wspiera\u0107 nowy proces biznesowy, poniewa\u017c wymagania biznesowe stale si\u0119 zmieniaj\u0105. Mo\u017cemy poprawi\u0107 kod \u017ar\u00f3d\u0142owy, usun\u0105\u0107 znane defekty, stworzy\u0107 bardziej jako\u015bciowy model danych. Zyskujemy wiele korzy\u015bci.<\/p>\n<p>Wydzielanie serwis\u00f3w z przer\u00f3bk\u0105 jest nierozerwalnie zwi\u0105zane z poj\u0119ciem ograniczonego kontekstu. To poj\u0119cie pochodzi z projektowania zorientowanego na przedmiot. Oznacza to fragment modelu dziedziny, w kt\u00f3rym wszystkie terminy jednolitego j\u0119zyka s\u0105 jednoznacznie zdefiniowane. We\u017amy za przyk\u0142ad kontekst ubezpiecze\u0144 i rachunk\u00f3w. Mamy monolityczn\u0105 aplikacj\u0119 i konieczne jest w ubezpieczeniach praca ze spraw\u0105 rachunku. Oczekujemy, \u017ce programista znajdzie w innej kompilacji istniej\u0105c\u0105 klas\u0119 \u201eRachunek\u201d, zrobi do niej odniesienie z klasy \u201eUbezpieczenie\u201d, a my otrzymamy dzia\u0142aj\u0105cy kod. Zasada DRY b\u0119dzie przestrzegana, zadanie dzi\u0119ki wykorzystaniu istniej\u0105cego kodu b\u0119dzie zrealizowane szybciej.<\/p>\n<p>Okazuje si\u0119, \u017ce konteksty rachunk\u00f3w i ubezpiecze\u0144 s\u0105 ze sob\u0105 powi\u0105zane. Kiedy pojawi\u0105 si\u0119 nowe wymagania, to powi\u0105zanie utrudni rozw\u00f3j, zwi\u0119kszaj\u0105c z\u0142o\u017cono\u015b\u0107 i tak ju\u017c skomplikowanej logiki biznesowej. Aby rozwi\u0105za\u0107 ten problem, nale\u017cy w kodzie znale\u017a\u0107 granice mi\u0119dzy kontekstami i usun\u0105\u0107 ich naruszenia. Na przyk\u0142ad, dla kontekstu ubezpiecze\u0144 wystarczy 20-cyfrowy numer rachunku NBP i data otwarcia rachunku. <\/p>\n<p>Aby oddzieli\u0107 te ograniczone konteksty od siebie i rozpocz\u0105\u0107 proces wydzielania mikroserwis\u00f3w z monolitycznego rozwi\u0105zania, zastosowali\u015bmy podej\u015bcie polegaj\u0105ce na tworzeniu wewn\u0119trznych API w aplikacji. Je\u015bli wiedzieli\u015bmy, \u017ce jaki\u015b modu\u0142 powinien sta\u0107 si\u0119 mikroserwisem lub zmieni\u0107 si\u0119 w ramach procesu, od razu wykonywali\u015bmy wywo\u0142ania logiki, kt\u00f3ra nale\u017cy do innego ograniczonego kontekstu, poprzez zewn\u0119trzne wywo\u0142ania. Na przyk\u0142ad, przez REST lub WCF.<\/p>\n<p>Postanowili\u015bmy, \u017ce nie b\u0119dziemy unika\u0107 kodu, kt\u00f3ry b\u0119dzie wymaga\u0142 realizacji rozproszonych transakcji. W naszym przypadku okaza\u0142o si\u0119 to wystarczaj\u0105co \u0142atwe do przestrzegania. Do tej pory nie mieli\u015bmy takich sytuacji, w kt\u00f3rych rzeczywi\u015bcie potrzebne by\u0142yby rygorystyczne rozproszone transakcje \u2014 wystarcza ko\u0144cowa sp\u00f3jno\u015b\u0107 mi\u0119dzy modu\u0142ami.<\/p>\n<p>Rozwa\u017cmy konkretny przyk\u0142ad. Mamy poj\u0119cie orkiestratora \u2014 procesu, kt\u00f3ry przetwarza obiekt \"wniosku\". Po kolei tworzy klienta, rachunek i kart\u0119 bankow\u0105. Je\u015bli klient i rachunek zosta\u0142y pomy\u015blnie utworzone, a tworzenie karty si\u0119 nie powiod\u0142o, wniosek nie przechodzi w status \"zrealizowany\" i pozostaje w statusie \"karta nie zosta\u0142a utworzona\". W przysz\u0142o\u015bci aktywno\u015b\u0107 poboczna przechwyci go i zako\u0144czy. System przez pewien czas znajduje si\u0119 w stanie niesp\u00f3jno\u015bci, ale og\u00f3lnie nam to odpowiada.<\/p>\n<p>W przypadku, gdy pojawi si\u0119 sytuacja, w kt\u00f3rej nale\u017cy sp\u00f3jnie zapisa\u0107 cz\u0119\u015b\u0107 danych, prawdopodobnie zdecydujemy si\u0119 na rozbudowanie us\u0142ugi, aby obs\u0142u\u017cy\u0107 to w jednym procesie. <\/p>\n<p>Rozwa\u017cmy przyk\u0142ad wydzielania mikroserwisu. Jak mo\u017cna relatywnie bezpiecznie doprowadzi\u0107 go do produkcji? W tym przyk\u0142adzie mamy oddzieln\u0105 cz\u0119\u015b\u0107 systemu \u2014 modu\u0142 obs\u0142ugi p\u0142ac, z kt\u00f3rego jeden fragment kodu chcieliby\u015bmy przekszta\u0142ci\u0107 w mikroserwis.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/346af271b0c3f99897d330e56f713f18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNa pocz\u0105tku tworzymy mikroserwis, przepisywuj\u0105c kod. Poprawiamy niekt\u00f3re elementy, kt\u00f3re nam nie odpowiada\u0142y. Realizujemy nowe wymagania biznesowe od klienta. Dodajemy do po\u0142\u0105czenia mi\u0119dzy UI a backendem API Gateway, kt\u00f3ry b\u0119dzie zapewnia\u0142 przekazywanie wywo\u0142a\u0144. <\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/bec8d68f20f3ec53af0cef225a51c2b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNast\u0119pnie wprowadzamy t\u0119 konfiguracj\u0119 do eksploatacji w trybie pilota. Wi\u0119kszo\u015b\u0107 naszych u\u017cytkownik\u00f3w wci\u0105\u017c korzysta ze starych proces\u00f3w biznesowych. Dla nowych u\u017cytkownik\u00f3w opracowujemy now\u0105 wersj\u0119 monolitycznej aplikacji, kt\u00f3ra ju\u017c nie zawiera tego procesu. W zasadzie w trybie pilota dzia\u0142a po\u0142\u0105czenie monolitu i mikroserwisu.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/27e98812746bb7f142fa3a3c3a03b52f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPrzy udanym pilocie rozumiemy, \u017ce nowa konfiguracja naprawd\u0119 dzia\u0142a, mo\u017cemy usun\u0105\u0107 stary monolit z r\u00f3wnania i zostawi\u0107 now\u0105 konfiguracj\u0119 na miejscu starego rozwi\u0105zania.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/11dcf1d771b57d3921c0aa91b82646e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPodsumowuj\u0105c, u\u017cywamy praktycznie wszystkich istniej\u0105cych metod podzia\u0142u kodu \u017ar\u00f3d\u0142owego monolitu. Wszystkie one pozwalaj\u0105 nam zmniejsza\u0107 rozmiar cz\u0119\u015bci aplikacji i przenosi\u0107 je na nowe biblioteki, tworz\u0105c lepszej jako\u015bci kod \u017ar\u00f3d\u0142owy.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"9\"><\/a><\/noindex><b><\/p>\n<h3>Utw\u00f3rzmy baz\u0119 danych \u2013 MySQL. Je\u015bli masz zainstalowane PhpMyAdmin, utw\u00f3rz now\u0105 baz\u0119 danych \"<\/h3>\n<p><\/b><br \/>\nBaza danych podlega podzia\u0142owi w gorszym stopniu ni\u017c kod \u017ar\u00f3d\u0142owy, poniewa\u017c zawiera nie tylko bie\u017c\u0105c\u0105 schem\u0119, ale tak\u017ce zgromadzone dane historyczne.<\/p>\n<p>Nasza baza danych, jak wiele innych, mia\u0142a jeszcze jeden wa\u017cny problem \u2014 ogromny rozmiar. Ta baza danych zosta\u0142a zaprojektowana zgodnie ze skomplikowan\u0105 logik\u0105 biznesow\u0105 monolitu, a mi\u0119dzy tabelami r\u00f3\u017cnych ograniczonych kontekst\u00f3w nagromadzi\u0142y si\u0119 powi\u0105zania.<\/p>\n<p>W naszym przypadku w dodatku do wszystkich problem\u00f3w (du\u017ca baza danych, wiele powi\u0105za\u0144, czasami niejasne granice mi\u0119dzy tabelami) pojawi\u0142 si\u0119 problem, kt\u00f3ry wyst\u0119puje w wielu du\u017cych projektach: u\u017cycie wzorca shared database. Dane by\u0142y pobierane z tabel przez widoki, za pomoc\u0105 replikacji i by\u0142y przekazywane do innych system\u00f3w, gdzie by\u0142a potrzebna ta replikacja. W rezultacie nie mogli\u015bmy przenie\u015b\u0107 tabel do osobnej schemy, poniewa\u017c by\u0142y one aktywnie wykorzystywane.<\/p>\n<p>W podziale pomaga nam w\u0142a\u015bnie rozbicie na ograniczone konteksty w kodzie. Zazwyczaj daje nam to do\u015b\u0107 dobre wyobra\u017cenie o tym, jak dzielimy dane na poziomie bazy danych. Rozumiemy, kt\u00f3re tabele odnosz\u0105 si\u0119 do jednego ograniczonego kontekstu, a kt\u00f3re do drugiego.<\/p>\n<p>Zastosowali\u015bmy dwa globalne sposoby separacji bazy danych: oddzielenie istniej\u0105cych tabel i oddzielenie z przebudow\u0105.<\/p>\n<p>Oddzielenie istniej\u0105cych tabel to metoda, kt\u00f3r\u0105 dobrze zastosowa\u0107, gdy struktura danych jest wysokiej jako\u015bci, spe\u0142nia wymagania biznesowe i wszystkim odpowiada. W takim przypadku mo\u017cemy wyr\u00f3\u017cni\u0107 istniej\u0105ce tabele w osobnej schemacie.<\/p>\n<p>Separacja z przebudow\u0105 jest potrzebna wtedy, gdy model biznesowy znacznie si\u0119 zmieni\u0142, a tabele ju\u017c nas nie satysfakcjonuj\u0105.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"10\"><\/a><\/noindex><b>Oddzielenie istniej\u0105cych tabel.<\/b> Musimy okre\u015bli\u0107, co b\u0119dziemy oddziela\u0107. Bez tej wiedzy nie uda si\u0119 nic zrealizowa\u0107, a tutaj pomo\u017ce nam separacja ograniczonych kontekst\u00f3w w kodzie. Zazwyczaj, je\u015bli uda si\u0119 zrozumie\u0107 granice kontekst\u00f3w w kodzie \u017ar\u00f3d\u0142owym, stanie si\u0119 jasne, kt\u00f3re tabele powinny by\u0107 umieszczone na li\u015bcie do oddzielenia.<\/p>\n<p>Za\u0142\u00f3\u017cmy, \u017ce mamy rozwi\u0105zanie, w kt\u00f3rym dwa modu\u0142y monolitu wsp\u00f3\u0142dzia\u0142aj\u0105 z jedn\u0105 baz\u0105 danych. Musimy zorganizowa\u0107, aby z cz\u0119\u015bci\u0105 oddzielanych tabel wsp\u00f3\u0142dzia\u0142a\u0142 tylko jeden modu\u0142, a drugi zacz\u0105\u0142 z nim komunikowa\u0107 si\u0119 przez API. Na pocz\u0105tku wystarczy, aby przez API odbywa\u0142 si\u0119 tylko zapis. To jest warunek konieczny, aby\u015bmy mogli m\u00f3wi\u0107 o niezale\u017cno\u015bci mikrous\u0142ug. Powi\u0105zania do odczytu mog\u0105 pozosta\u0107, dop\u00f3ki nie b\u0119dzie to stanowi\u0142o du\u017cego problemu.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/1602637ad752ac055f475cfa45d95e95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKolejnym krokiem mo\u017cemy ju\u017c wydzieli\u0107 cz\u0119\u015b\u0107 kodu, pracuj\u0105c\u0105 z oddzielanymi tabelami, z przebudow\u0105 lub bez niej, w osobn\u0105 mikrous\u0142ug\u0119 i uruchomi\u0107 j\u0105 w osobnym procesie, kontenerze. To b\u0119dzie osobna us\u0142uga z po\u0142\u0105czeniem z baz\u0105 danych monolitu i tymi tabelami, kt\u00f3re nie s\u0105 bezpo\u015brednio zwi\u0105zane z nim. Monolit wci\u0105\u017c wsp\u00f3\u0142dzia\u0142a w trybie odczytu z oddzielon\u0105 cz\u0119\u015bci\u0105. <\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/36011f4e6be4f6a2f19f2f074b645dcb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nP\u00f3\u017aniej usuniemy to po\u0142\u0105czenie, to znaczy odczyt danych aplikacji monolotowej z oddzielanych tabel r\u00f3wnie\u017c zostanie przeniesiony na API.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/290f91bbfccac2a4b384078e4cf4e337.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNast\u0119pnie wyr\u00f3\u017cnimy z og\u00f3lnej bazy danych tabele, z kt\u00f3rymi pracuje tylko nowa mikrous\u0142uga. Mo\u017cemy przenie\u015b\u0107 tabele do osobnej schemy lub nawet do oddzielnej fizycznej bazy danych. Pozosta\u0142o po\u0142\u0105czenie do odczytu mi\u0119dzy mikrous\u0142ug\u0105 a baz\u0105 danych monolitu, ale nie ma w tym nic z\u0142ego, w takiej konfiguracji mo\u017ce ona funkcjonowa\u0107 wystarczaj\u0105co d\u0142ugo.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/ab947ac6a38ffbccd4e2b51103aef609.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOstatni krok to ca\u0142kowite usuni\u0119cie wszystkich powi\u0105za\u0144. W takim przypadku mo\u017ce by\u0107 konieczna migracja danych z g\u0142\u00f3wnej bazy. Czasami chcemy ponownie wykorzysta\u0107 w r\u00f3\u017cnych bazach dane replikowane z system\u00f3w zewn\u0119trznych lub s\u0142owniki. Spotykamy si\u0119 z tym okresowo.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/f40cf17dd56b9575751e370c44f08344.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<noindex><a rel=\"nofollow\" name=\"11\"><\/a><\/noindex><b>Oddzia\u0142 z przer\u00f3bk\u0105.<\/b> Ta metoda jest bardzo podobna do pierwszej, tylko przebiega w odwrotnym kierunku. Natychmiast tworzymy now\u0105 baz\u0119 danych i nowy mikrous\u0142ug\u0119, kt\u00f3ry wsp\u00f3\u0142dzia\u0142a z monolitem przez API. Jednak pozostaje zestaw tabel bazy danych, kt\u00f3re chcemy w przysz\u0142o\u015bci usun\u0105\u0107. Nie b\u0119d\u0105 nam ju\u017c potrzebne, w nowym modelu je zast\u0105pili\u015bmy.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/c94932033e47cfa1fd56595ab9a19246.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAby ten schemat zadzia\u0142a\u0142, prawdopodobnie b\u0119dziemy potrzebowa\u0107 okresu przej\u015bciowego.<\/p>\n<p>Dalej s\u0105 dwa mo\u017cliwe podej\u015bcia.<\/p>\n<p><b>Pierwszy<\/b>: duplikujemy wszystkie dane w nowej i starej bazie. W takim przypadku pojawia si\u0119 nadmiarowo\u015b\u0107 danych, mog\u0105 wyst\u0105pi\u0107 problemy z synchronizacj\u0105. Ale mo\u017cemy zyska\u0107 dw\u00f3ch r\u00f3\u017cnych klient\u00f3w. Jeden b\u0119dzie pracowa\u0142 z now\u0105 wersj\u0105, drugi ze star\u0105.<\/p>\n<p><b>Drugi<\/b>: dzielimy dane wed\u0142ug jakiego\u015b kryterium biznesowego. Na przyk\u0142ad, w naszym systemie by\u0142o 5 produkt\u00f3w, kt\u00f3re by\u0142y przechowywane w starej bazie danych. Sz\u00f3sty w ramach nowego zadania biznesowego umieszczamy w nowej bazie danych. Potrzebujemy jednak API Gateway, kt\u00f3ry zsynchronizuje te dane i poka\u017ce klientowi, sk\u0105d i co pobiera\u0107.<\/p>\n<p>Obydwa podej\u015bcia s\u0105 wykonalne, wybierz w zale\u017cno\u015bci od sytuacji.<\/p>\n<p>Po upewnieniu si\u0119, \u017ce wszystko dzia\u0142a, cz\u0119\u015b\u0107 monolitu obs\u0142uguj\u0105cego stare struktury bazy danych mo\u017cna wy\u0142\u0105czy\u0107. <\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/973bf5015bdf49a290a5b901f89628cc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOstatnim krokiem b\u0119dzie usuni\u0119cie starych struktur danych. <\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/fe83acc07077b7eb3717138e3c20c005.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPodsumowuj\u0105c, mo\u017cna powiedzie\u0107, \u017ce mamy problemy z baz\u0105 danych: trudniej si\u0119 z ni\u0105 pracuje w por\u00f3wnaniu z kodem \u017ar\u00f3d\u0142owym, trudniej jest dzieli\u0107, ale mo\u017cna i nale\u017cy to zrobi\u0107. Znale\u017ali\u015bmy pewne sposoby, kt\u00f3re pozwalaj\u0105 to robi\u0107 wystarczaj\u0105co bezpiecznie, w ko\u0144cu z danymi \u0142atwiej pope\u0142ni\u0107 b\u0142\u0105d ni\u017c z kodem \u017ar\u00f3d\u0142owym. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"12\"><\/a><\/noindex><b><\/p>\n<h3>Praca z kodem \u017ar\u00f3d\u0142owym<\/h3>\n<p><\/b><br \/>\nTak wygl\u0105da\u0142 schemat kodu \u017ar\u00f3d\u0142owego, kiedy zacz\u0119li\u015bmy analizowa\u0107 monolityczny projekt.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/a6d886e37117ccf8f63106d6616aa653.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMo\u017cna j\u0105 w zasadzie podzieli\u0107 na trzy warstwy. To warstwa uruchamianych modu\u0142\u00f3w, wtyczek, serwis\u00f3w i r\u00f3\u017cnych aktywno\u015bci. Faktycznie, by\u0142y to punkty dost\u0119pu w ramach monolitycznego rozwi\u0105zania. Wszystkie by\u0142y trwale po\u0142\u0105czone warstw\u0105 Common. Zawiera\u0142a logik\u0119 biznesow\u0105, kt\u00f3ra by\u0142a wsp\u00f3lnie wykorzystywana przez serwisy oraz wiele powi\u0105za\u0144. Ka\u017cdy serwis i wtyczka korzysta\u0142y z 10 i wi\u0119cej wsp\u00f3lnych zbior\u00f3w, w zale\u017cno\u015bci od ich rozmiaru i sumienia tw\u00f3rc\u00f3w.<\/p>\n<p>Mieli\u015bmy szcz\u0119\u015bcie, posiadali\u015bmy biblioteki infrastrukturalne, kt\u00f3re mo\u017cna by\u0142o wykorzystywa\u0107 samodzielnie. <\/p>\n<p>Czasami zdarza\u0142a si\u0119 sytuacja, w kt\u00f3rej niekt\u00f3re obiekty Common w rzeczywisto\u015bci nie odnosi\u0142y si\u0119 do tej warstwy, a by\u0142y bibliotekami infrastrukturalnymi. Rozwi\u0105zywano to przez ich przemianowanie.<\/p>\n<p>Najwi\u0119cej zmartwie\u0144 budzi\u0142y ograniczone konteksty. Zdarza\u0142o si\u0119, \u017ce 3-4 konteksty by\u0142y mieszane w jednym zbiorze Common i korzysta\u0142y z siebie nawzajem w ramach tych samych funkcji biznesowych. Nale\u017ca\u0142o zrozumie\u0107, gdzie mo\u017cna to podzieli\u0107 oraz wed\u0142ug jakich granic, i co dalej zrobi\u0107 z mapowaniem tego podzia\u0142u na zbiory kodu \u017ar\u00f3d\u0142owego.<\/p>\n<p>Sformu\u0142owali\u015bmy kilka zasad dla procesu dzielenia kodu.<\/p>\n<p><b>Pierwsze<\/b>: nie chcieli\u015bmy ju\u017c dzielenia logiki biznesowej pomi\u0119dzy serwisami, aktywno\u015bciami i wtyczkami. Chcieli\u015bmy, aby logika biznesowa by\u0142a niezale\u017cna w ramach mikrous\u0142ug. Z drugiej strony, mikrous\u0142ugi, w idealnym przypadku, postrzegane s\u0105 jako serwisy, kt\u00f3re istniej\u0105 ca\u0142kowicie niezale\u017cnie. Uwa\u017cam, \u017ce to podej\u015bcie jest nieco marnotrawne, a jego osi\u0105gni\u0119cie jest trudne, poniewa\u017c na przyk\u0142ad serwisy w C# b\u0119d\u0105 w ka\u017cdym przypadku po\u0142\u0105czone standardow\u0105 bibliotek\u0105. Nasz system jest napisany w C#, innych technologii na razie nie musieli\u015bmy u\u017cywa\u0107. Dlatego zdecydowali\u015bmy, \u017ce mo\u017cemy sobie pozwoli\u0107 na korzystanie z wsp\u00f3lnych zbior\u00f3w technicznych. Najwa\u017cniejsze, aby nie zawiera\u0142y \u017cadnych fragment\u00f3w logiki biznesowej. Je\u017celi macie wygodn\u0105 os\u0142on\u0119 nad ORM, kt\u00f3rego u\u017cywacie, to skopiowanie jej z serwisu do serwisu jest bardzo kosztowne.<\/p>\n<p>Nasz zesp\u00f3\u0142 jest fanatykami projektowania opartego na domenach, dlatego \u201earchitektura cebuli\u201d doskonale do nas pasowa\u0142a. Podstaw\u0105 naszych us\u0142ug nie by\u0142a warstwa dost\u0119pu do danych, lecz zestawienie z logik\u0105 domenow\u0105, kt\u00f3ra zawiera tylko logik\u0119 biznesow\u0105 i jest wolna od powi\u0105za\u0144 z infrastruktur\u0105. Dzi\u0119ki temu mo\u017cemy niezale\u017cnie rozwija\u0107 domenowy zestaw dla rozwi\u0105zywania problem\u00f3w zwi\u0105zanych z frameworkami.<\/p>\n<p>Na tym etapie napotkali\u015bmy pierwszy powa\u017cny problem. Us\u0142uga mia\u0142a korzysta\u0107 z jednego zestawu domenowego, chcia\u0142em, aby logika by\u0142a niezale\u017cna, a zasada DRY bardzo nam w tym przeszkadza\u0142a. Programi\u015bci chcieli, aby unikn\u0105\u0107 duplikacji, ponownie wykorzystywali klasy z s\u0105siednich zestaw\u00f3w, w rezultacie domeny znowu zacz\u0119\u0142y si\u0119 ze sob\u0105 wi\u0105za\u0107. Przeanalizowali\u015bmy wyniki i zdecydowali\u015bmy, \u017ce problem mo\u017ce le\u017ce\u0107 tak\u017ce w sposobie przechowywania kodu \u017ar\u00f3d\u0142owego. Mieli\u015bmy du\u017cy repozytorium, w kt\u00f3rym znajdowa\u0142y si\u0119 wszystkie kody \u017ar\u00f3d\u0142owe. Solution dla ca\u0142ego projektu by\u0142o bardzo trudno zbudowa\u0107 na lokalnej maszynie. Dlatego dla cz\u0119\u015bci projektu tworzono oddzielne ma\u0142e solution, i nikt nie zabrania\u0142 dodawania do nich jakiegokolwiek zestawu Common lub domenowego i ponownego u\u017cywania. Jedynym narz\u0119dziem, kt\u00f3re uniemo\u017cliwia\u0142o nam to, by\u0142a recenzja kodu. Ale czasami i ona zawodzi\u0142a.<\/p>\n<p>Wtedy zacz\u0119li\u015bmy przechodzi\u0107 na model z oddzielnymi repozytoriami. Logika biznesowa przesta\u0142a wycieka\u0107 z us\u0142ugi do us\u0142ugi, a domeny naprawd\u0119 sta\u0142y si\u0119 niezale\u017cne. Ograniczone konteksty s\u0105 bardziej wyra\u017anie wspierane. Jak w tym przypadku ponownie wykorzystujemy biblioteki infrastrukturalne? Wydzielili\u015bmy je do oddzielnego repozytorium, a nast\u0119pnie umie\u015bcili\u015bmy w pakietach Nuget, kt\u00f3re umie\u015bcili\u015bmy w Artifactory. Przy ka\u017cdej zmianie, budowa i publikacja odbywa si\u0119 automatycznie.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/8ddbc750dc7c6d397a459acf7825de90.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNasze us\u0142ugi zacz\u0119\u0142y odnosi\u0107 si\u0119 do wewn\u0119trznych pakiet\u00f3w infrastrukturalnych tak samo, jak do zewn\u0119trznych. Zewn\u0119trzne biblioteki pobieramy z Nuget. Do pracy z Artifactory, gdzie umieszczali\u015bmy te pakiety, zastosowali\u015bmy dwa mened\u017cery pakiet\u00f3w. W ma\u0142ych repozytoriach r\u00f3wnie\u017c u\u017cywali\u015bmy Nuget. W repozytoriach z wieloma us\u0142ugami korzystali\u015bmy z Pakietu, kt\u00f3ry zapewnia wi\u0119ksz\u0105 sp\u00f3jno\u015b\u0107 wersji mi\u0119dzy modu\u0142ami.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/672a25a70a481bff68baebe963184ccd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nW ten spos\u00f3b, pracuj\u0105c nad kodem \u017ar\u00f3d\u0142owym, nieco zmieniaj\u0105c architektur\u0119 i dziel\u0105c repozytoria, czynimy nasze us\u0142ugi bardziej niezale\u017cnymi.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"13\"><\/a><\/noindex><b><\/p>\n<h3>Problemy infrastruktury<\/h3>\n<p><\/b><br \/>\nWi\u0119kszo\u015b\u0107 problem\u00f3w przy przej\u015bciu na mikroserwisy wi\u0105\u017ce si\u0119 z infrastruktur\u0105. B\u0119dziesz potrzebowa\u0107 zautomatyzowanego wdro\u017cenia oraz nowych bibliotek do obs\u0142ugi infrastruktury.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"16\"><\/a><\/noindex><b>R\u0119czna instalacja w \u015brodowiskach<\/b><\/p>\n<p>Pocz\u0105tkowo instalowali\u015bmy rozwi\u0105zania w \u015brodowiskach r\u0119cznie. Aby zautomatyzowa\u0107 ten proces, stworzyli\u015bmy pipeline CI\/CD. Wybrali\u015bmy proces continuous delivery, poniewa\u017c continuous deployment jest dla nas na razie nieakceptowalne z perspektywy proces\u00f3w biznesowych. Dlatego wdro\u017cenie odbywa si\u0119 za pomoc\u0105 przycisku, a testowanie \u2014 automatycznie.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/0fc092326a48813398c6f3a031197bab.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nU\u017cywamy Atassian, Bitbucket do przechowywania kod\u00f3w \u017ar\u00f3d\u0142owych oraz Bamboo do budowania. Lubimy pisa\u0107 skrypty budowlane w Cake, poniewa\u017c to ten sam C#. W Artifactory trafiaj\u0105 ju\u017c gotowe pakiety, a Ansible automatycznie l\u0105duje na serwerach testowych, po czym mo\u017cna je od razu testowa\u0107.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/fcc743cfaa4a24b906ceeb40ec1ba0a0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<noindex><a rel=\"nofollow\" name=\"14\"><\/a><\/noindex><b><\/p>\n<h3>Oddzielne logowanie<\/h3>\n<p><\/b><br \/>\nW swoim czasie jednym z pomys\u0142\u00f3w monolitu by\u0142o zapewnienie wsp\u00f3lnego logowania. Musieli\u015bmy r\u00f3wnie\u017c zrozumie\u0107, co zrobi\u0107 z oddzielnymi logami, kt\u00f3re znajduj\u0105 si\u0119 na dyskach. Logi piszemy w plikach tekstowych. Postanowili\u015bmy u\u017cy\u0107 standardowego stosu ELK. Nie pisali\u015bmy bezpo\u015brednio do ELK przez dostawc\u00f3w, lecz uznali\u015bmy, \u017ce przerobimy logi tekstowe, dodaj\u0105c identyfikator \u015bledzenia w postaci ID, dodaj\u0105c nazw\u0119 us\u0142ugi, aby te logi mo\u017cna by\u0142o p\u00f3\u017aniej analizowa\u0107.<\/p>\n<p><img decoding=\"async\" alt=\"Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka\" src=\"\/wp-content\/uploads\/2019\/07\/8e58c66ac134e65abe34b59939f31483.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDzi\u0119ki Filebeat uzyskujemy mo\u017cliwo\u015b\u0107 zbierania naszych log\u00f3w z <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/pl\/server\/\"   title=\"serwer\u00f3w\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"1338\">serwer\u00f3w<\/a>, przekszta\u0142cania ich, a za pomoc\u0105 Kibany budowania zapyta\u0144 w interfejsie u\u017cytkownika i obserwowania, jak przebiega\u0142o wywo\u0142anie mi\u0119dzy us\u0142ugami. W tym bardzo pomaga identyfikator \u015bledzenia.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"15\"><\/a><\/noindex><b><\/p>\n<h3>Testowanie i debugging powi\u0105zanych us\u0142ug<\/h3>\n<p><\/b><br \/>\nNa pocz\u0105tku nie do ko\u0144ca rozumieli\u015bmy, jak debugowa\u0107 rozwijane serwisy. Z monolitem wszystko by\u0142o proste, uruchamiali\u015bmy go na lokalnej maszynie. Tak samo pr\u00f3bowali\u015bmy robi\u0107 z mikrous\u0142ugami, ale czasami, aby uruchomi\u0107 jedn\u0105 mikrous\u0142ug\u0119, trzeba uruchomi\u0107 kilka innych, co jest niewygodne. Zrozumieli\u015bmy, \u017ce musimy przej\u015b\u0107 do modelu, w kt\u00f3rym na lokalnej maszynie zostawiamy tylko serwis lub serwisy, kt\u00f3re chcemy debugowa\u0107. Pozosta\u0142e serwisy s\u0105 u\u017cywane z serwer\u00f3w, kt\u00f3re maj\u0105 tak\u0105 sam\u0105 konfiguracj\u0119 jak prod. Po debugowaniu, przy testowaniu, na serwer testowy wydawane s\u0105 tylko zmienione serwisy dla ka\u017cdego zadania. W ten spos\u00f3b testowane jest rozwi\u0105zanie w takiej postaci, w jakiej w przysz\u0142o\u015bci znajdzie si\u0119 na prod.<\/p>\n<p>S\u0105 serwery, na kt\u00f3rych dzia\u0142aj\u0105 tylko produkcyjne wersje serwis\u00f3w. Serwery te s\u0105 potrzebne na wypadek incydent\u00f3w, do weryfikacji dostaw przed wdro\u017ceniem oraz do szkole\u0144 wewn\u0119trznych.<\/p>\n<p>Wprowadzili\u015bmy proces automatycznego testowania za pomoc\u0105 popularnej biblioteki Specflow. Testy s\u0105 uruchamiane automatycznie za pomoc\u0105 NUnit zaraz po wdro\u017ceniu z Ansible. Je\u015bli pokrycie zadania jest ca\u0142kowicie automatyczne, nie ma potrzeby przeprowadzania test\u00f3w manualnych. Chocia\u017c czasami nadal wymagane s\u0105 dodatkowe testy manualne. Aby okre\u015bli\u0107, kt\u00f3re testy uruchomi\u0107 dla konkretnego zadania, u\u017cywamy tag\u00f3w w Jira.<\/p>\n<p>Dodatkowo wzros\u0142a potrzeba testowania obci\u0105\u017ceniowego, wcze\u015bniej odbywa\u0142o si\u0119 to tylko w rzadkich przypadkach. Do uruchamiania test\u00f3w u\u017cywamy JMeter, do ich przechowywania \u2013 InfluxDB, a do tworzenia wykres\u00f3w procesu \u2013 Grafana.<\/p>\n<p><b><\/p>\n<h3>Co osi\u0105gn\u0119li\u015bmy?<\/h3>\n<p><\/b><br \/>\nPo pierwsze, pozbyli\u015bmy si\u0119 poj\u0119cia \u201ewydanie\u201d. Znikn\u0119\u0142y dwumiesi\u0119czne, ogromne wydania, kiedy ta machina by\u0142a wdra\u017cana w \u015brodowisku produkcyjnym, czasowo \u0142ami\u0105c procesy biznesowe. Obecnie wdra\u017camy serwisy \u015brednio co 1,5 dnia, grupuj\u0105c je, poniewa\u017c wchodz\u0105 do eksploatacji po akceptacji.<\/p>\n<p>W naszym systemie nie ma krytycznych awarii. Je\u015bli wydali\u015bmy mikrous\u0142ug\u0119 z b\u0142\u0119dem, zwi\u0105zana z ni\u0105 funkcjonalno\u015b\u0107 b\u0119dzie uszkodzona, natomiast ca\u0142a pozosta\u0142a funkcjonalno\u015b\u0107 nie ucierpi. To znacznie poprawia do\u015bwiadczenia u\u017cytkownik\u00f3w.<\/p>\n<p>Mo\u017cemy zarz\u0105dza\u0107 schematem wdra\u017cania. Mo\u017cna wydziela\u0107 grupy us\u0142ug oddzielnie od reszty rozwi\u0105zania, je\u015bli zajdzie taka potrzeba.<\/p>\n<p>Ponadto znacznie zminimalizowali\u015bmy problem z d\u0142ugimi kolejkami poprawek. Pojawi\u0142y si\u0119 oddzielne zespo\u0142y produktowe, kt\u00f3re pracuj\u0105 z cz\u0119\u015bci\u0105 us\u0142ug niezale\u017cnie. Tu \u015bwietnie sprawdza si\u0119 proces Scrum. Ka\u017cdy zesp\u00f3\u0142 mo\u017ce mie\u0107 oddzielnego w\u0142a\u015bciciela produktu, kt\u00f3ry wyznacza mu zadania. <\/p>\n<p><b><\/p>\n<h3>Podsumowanie<\/h3>\n<p><\/b><\/p>\n<ul>\n<li>Mikrous\u0142ugi s\u0105 idealne do dekompozycji z\u0142o\u017conych system\u00f3w. W trakcie tego procesu zaczynamy rozumie\u0107, co znajduje si\u0119 w naszym systemie, jakie wyst\u0119puj\u0105 ograniczone konteksty, gdzie przebiegaj\u0105 ich granice. To pozwala poprawnie przydziela\u0107 poprawki do modu\u0142\u00f3w i zapobiega\u0107 zawirowaniom w kodzie. <\/li>\n<li>Mikrous\u0142ugi daj\u0105 przewagi organizacyjne. Cz\u0119sto m\u00f3wi si\u0119 o nich tylko w kontek\u015bcie architektury, ale ka\u017cda architektura ma na celu zaspokojenie potrzeb biznesowych, a nie jest warto\u015bci\u0105 sam\u0105 w sobie. Dlatego mo\u017cemy powiedzie\u0107, \u017ce mikrous\u0142ugi s\u0105 dobrze dopasowane do rozwi\u0105zywania zada\u0144 przez ma\u0142e zespo\u0142y, bior\u0105c pod uwag\u0119, \u017ce obecnie bardzo popularny jest Scrum.<\/li>\n<li>Podzia\u0142 to proces iteracyjny. Nie mo\u017cna po prostu wzi\u0105\u0107 aplikacji i podzieli\u0107 j\u0105 na mikrous\u0142ugi. Otrzymany produkt raczej nie b\u0119dzie dzia\u0142a\u0142 poprawnie. Przy wydzielaniu mikrous\u0142ug korzystnie jest przepisa\u0107 istniej\u0105ce legacy, czyli przekszta\u0142ci\u0107 je w kod, kt\u00f3ry nam odpowiada i lepiej spe\u0142nia potrzeby biznesowe dotycz\u0105ce funkcjonalno\u015bci i szybko\u015bci.\n<p><i>Ma\u0142e ostrze\u017cenie:<\/i> koszty przej\u015bcia na mikrous\u0142ugi s\u0105 do\u015b\u0107 znacz\u0105ce. Tylko rozwi\u0105zanie problemu infrastruktury zaj\u0119\u0142o du\u017co czasu. Dlatego, je\u015bli masz ma\u0142\u0105 aplikacj\u0119, kt\u00f3ra nie wymaga specyficznego skalowania, i nie ma du\u017cej liczby klient\u00f3w, kt\u00f3rzy walcz\u0105 o uwag\u0119 i czas twojego zespo\u0142u, to by\u0107 mo\u017ce mikrous\u0142ugi nie s\u0105 tym, czego potrzebujesz dzisiaj. To do\u015b\u0107 drogie. Je\u015bli zaczynasz proces z mikrous\u0142ugami, to koszty na pocz\u0105tku b\u0119d\u0105 wy\u017csze ni\u017c w przypadku, gdy ten sam projekt zaczynasz z rozwoju monolitu. <\/p>\n<p>P.S. Bardziej emocjonalna opowie\u015b\u0107 (jakby osobista) \u2013 na <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=qTNbx18DzpQ\">linkiem<\/a><\/noindex>. <br \/>\nTutaj znajduje si\u0119 pe\u0142na wersja wyst\u0105pienia.<\/li>\n<\/ul>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/raiffeisenbank\/blog\/458404\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000. \u041f\u0435\u0440\u0432\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u044b\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 Visual Basic 6. \u0421 \u0442\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a IDE [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":26858,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35906","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c: \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:07:29+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:07:29+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Przej\u015bcie od monolitu do mikroserwis\u00f3w: historia i praktyka | ProHoster","description":"W tym artykule opowiem o tym, jak projekt, w kt\u00f3rym pracuj\u0119, przekszta\u0142ca\u0142 si\u0119 z du\u017cego monolitu w zestaw mikroserwis\u00f3w. Projekt ma swoj\u0105 histori\u0119 do\u015b\u0107 dawno, na pocz\u0105tku lat 2000.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c: \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 | ProHoster","og:description":"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000.","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:07:29+00:00","article:modified_time":"2019-10-31T19:07:29+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35906","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-02-09 17:04:56","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:54:38","updated":"2026-02-09 17:04:56","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/35906","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=35906"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/35906\/revisions"}],"predecessor-version":[{"id":158582,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/35906\/revisions\/158582"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/26858"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=35906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=35906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=35906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}