{"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\/ro\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","title":{"rendered":"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00cen acest articol, voi vorbi despre cum proiectul la care lucrez s-a transformat dintr-un monolit mare \u00eentr-un set de microservicii.<\/p>\n<p>Proiectul \u0219i-a \u00eenceput povestea acum ceva timp, la \u00eenceputul anilor 2000. Primele versiuni au fost scrise \u00een Visual Basic 6. Pe m\u0103sur\u0103 ce timpul a trecut, a devenit clar c\u0103 dezvoltarea \u00een acest limbaj va fi dificil de \u00eentre\u021binut pe termen lung, deoarece IDE-ul \u0219i limbajul \u00een sine evoluau \u00eencet. La sf\u00e2r\u0219itul anilor 2000, s-a decis trecerea la un C# mai promi\u021b\u0103tor. Noua versiune a fost scris\u0103 paralel cu \u00eembun\u0103t\u0103\u021birea versiunii vechi, iar treptat, din ce \u00een ce mai mult cod a fost scris \u00een .NET. Backend-ul \u00een C# s-a orientat ini\u021bial spre o arhitectur\u0103 de servicii, cu toate c\u0103 \u00een timpul dezvolt\u0103rii s-au folosit biblioteci comune cu logic\u0103, iar serviciile erau lansate \u00eentr-un singur proces. A rezultat o aplica\u021bie pe care noi o numeam \u201emonolitul de servicii\u201d. <\/p>\n<p>Unul dintre pu\u021binele avantaje ale unei astfel de combina\u021bii era posibilitatea serviciilor de a se apela reciproc prin intermediul unei API externe. Existau premise clare pentru tranzi\u021bia c\u0103tre o arhitectur\u0103 mai corect\u0103 de servicii \u0219i, \u00een perspectiv\u0103, chiar spre o arhitectur\u0103 de microservicii. <\/p>\n<p>Am \u00eenceput lucrul la decompunere \u00een jurul anului 2015. Deocamdat\u0103 nu am atins o stare ideal\u0103 - au r\u0103mas p\u0103r\u021bi ale marelui proiect, care se numesc greu monolite, dar nici microservicii nu se aseam\u0103n\u0103. Cu toate acestea, progresul este semnificativ. <br \/>\nDespre asta voi vorbi \u00een articol.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" 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>Cuprins<\/h3>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#1\"> Arhitectura \u0219i problemele solu\u021biei existente<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#2\">A\u0219tept\u0103rile de la microservicii<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#3\">Problemele tranzi\u021biei<\/a><\/noindex><\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"#4\">Cum s\u0103 treci de la monolit la microservicii<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#5\">Prima metod\u0103<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#6\">A doua metod\u0103<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#7\">A treia metod\u0103<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#8\">A patra metod\u0103<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#9\">Lucrul cu Baza de Date<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#10\">Separarea tabelelor existente<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#11\">Separarea cu reproiectare<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#12\">Lucrul cu codul surs\u0103<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#13\">Problemele infrastructurii<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#16\">Instalarea manual\u0103 \u00een medii<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#14\">Logare separat\u0103<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#15\">Testarea \u0219i depanarea serviciilor interconectate<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><noindex><a rel=\"nofollow\" name=\"1\"><\/a><\/noindex><b><\/p>\n<h3>Arhitectura \u0219i problemele solu\u021biei existente<\/h3>\n<p><\/b><br \/>\nIni\u021bial, arhitectura ar\u0103ta \u00een felul urm\u0103tor: UI - aplica\u021bie separat\u0103, partea monolitic\u0103 a fost scris\u0103 \u00een Visual Basic 6, aplica\u021bia \u00een .NET era un set de servicii interconectate, lucr\u00e2nd cu o baz\u0103 de date destul de mare.<\/p>\n<p><b>Dezavantajele solu\u021biei anterioare<\/b><\/p>\n<p><u>Punct unic de e\u0219ec<\/u><br \/>\nAm avut un punct unic de e\u0219ec: aplica\u021bia .NET rula \u00eentr-un singur proces. Dac\u0103 ap\u0103rea o problem\u0103 \u00een oricare dintre module, \u00eentreaga aplica\u021bie se bloca \u0219i trebuia repornit\u0103. Av\u00e2nd \u00een vedere c\u0103 automatiz\u0103m un num\u0103r mare de procese pentru diferi\u021bi utilizatori, o eroare \u00een unul dintre acestea f\u0103cea ca to\u021bi s\u0103 nu poat\u0103 lucra pentru o perioad\u0103. Iar \u00een cazul unei erori de programare, nu ajuta nici rezervarea. <\/p>\n<p><u>Lista de modific\u0103ri<\/u><br \/>\nAceast\u0103 problem\u0103 este \u00een principal organiza\u021bional\u0103. Aplica\u021bia noastr\u0103 are mul\u021bi clien\u021bi, iar to\u021bi doresc s\u0103-\u0219i aduc\u0103 modific\u0103rile c\u00e2t mai repede. \u00cen trecut, era imposibil s\u0103 facem acest lucru \u00een paralel, iar to\u021bi clien\u021bii trebuie s\u0103 a\u0219tepte la r\u00e2nd. Acest proces provoca frustrare \u00een r\u00e2ndul afacerii, deoarece trebuiau s\u0103 demonstreze c\u0103 sarcina lor are valoare. Iar echipa de dezvoltare \u00ee\u0219i petrecea timpul organiz\u00e2nd aceast\u0103 list\u0103 de a\u0219teptare. Asta lua mult timp \u0219i efort, iar produsul nu putea s\u0103 se schimbe la fel de repede cum \u0219i-ar fi dorit.<\/p>\n<p><u>Utilizarea ineficient\u0103 a resurselor<\/u><br \/>\nC\u00e2nd implementam servicii \u00eentr-un proces unic, \u00eentotdeauna copiam complet configura\u021bia de la server la server. Ne-am dorit s\u0103 plas\u0103m serviciile cele mai solicitate separat, pentru a nu risipi resursele \u0219i a ob\u021bine o gestionare mai flexibil\u0103 a schemei noastre de desf\u0103\u0219urare.<\/p>\n<p><u>Dificult\u0103\u021bi \u00een implementarea tehnologiilor moderne<\/u><br \/>\nO problem\u0103 cunoscut\u0103 de to\u021bi dezvoltatorii: exist\u0103 dorin\u021ba de a introduce tehnologii moderne \u00een proiect, dar nu exist\u0103 posibilitatea. \u00centr-o solu\u021bie monolitic\u0103 mare, orice actualizare a bibliotecii curente, cu at\u00e2t mai pu\u021bin trecerea la una nou\u0103, devine o sarcin\u0103 destul de complicat\u0103. Trebuie s\u0103 dovedim \u00eendelung echipei c\u0103 aceasta va aduce mai multe beneficii dec\u00e2t nervii pierdu\u021bi. <\/p>\n<p><u>Complexitatea livr\u0103rii modific\u0103rilor<\/u><br \/>\nAceasta a fost cea mai grav\u0103 problem\u0103 - eliberam versiuni la fiecare dou\u0103 luni. <br \/>\nFiecare versiune devenea o adev\u0103rat\u0103 catastrof\u0103 pentru banc\u0103, \u00een ciuda test\u0103rii \u0219i eforturilor dezvoltatorilor. Afacerea \u00een\u021belegea c\u0103 o parte din func\u021bionalitate nu va func\u021biona la \u00eenceputul s\u0103pt\u0103m\u00e2nii. Iar dezvoltatorii \u0219tiau c\u0103 \u00eei a\u0219teapt\u0103 o s\u0103pt\u0103m\u00e2n\u0103 de incidente serioase. <br \/>\nDorin\u021ba de a schimba situa\u021bia exista la toat\u0103 lumea. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"2\"><\/a><\/noindex><b><\/p>\n<h3>A\u0219tept\u0103rile de la microservicii<\/h3>\n<p><\/b><br \/>\n<u>Livrarea componentelor pe m\u0103sur\u0103 ce sunt gata. <\/u>Livrarea componentelor pe m\u0103sur\u0103 ce devin disponibile, datorit\u0103 decompozi\u021biei solu\u021biei \u0219i separ\u0103rii diferitelor procese.<\/p>\n<p><u>Echipe mici de produse.<\/u> Acest lucru este important deoarece este dificil de gestionat o echip\u0103 mare care lucreaz\u0103 la un vechi monolit. O astfel de echip\u0103 a fost nevoit\u0103 s\u0103 lucreze conform unui proces strict, iar dorin\u021ba era de mai mult\u0103 creativitate \u0219i independen\u021b\u0103. Numai echipele mici \u00ee\u0219i puteau permite acest lucru.<\/p>\n<p><u>Izolarea serviciilor \u00een procese separate.<\/u> Ideal ar fi fost s\u0103 se izoleze \u00een containere, dar un num\u0103r mare de servicii scrise pe .NET Framework ruleaz\u0103 doar pe Windows. Acum apar servicii pe .NET Core, dar sunt \u00eenc\u0103 pu\u021bine.<\/p>\n<p><u>Flexibilitatea desf\u0103\u0219ur\u0103rii.<\/u> Ar fi fost util s\u0103 combin\u0103m serviciile a\u0219a cum avem nevoie, nu a\u0219a cum impune codul.<\/p>\n<p><u>Utilizarea unor tehnologii noi.<\/u> Acest lucru este interesant pentru orice programator.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"3\"><\/a><\/noindex><b><\/p>\n<h3>Problemele tranzi\u021biei<\/h3>\n<p><\/b><br \/>\nDesigur, dac\u0103 ar fi fost simplu s\u0103 \u00eemp\u0103r\u021bim monolitul \u00een microservicii, nu ar fi fost nevoie s\u0103 discut\u0103m despre asta la conferin\u021be \u0219i s\u0103 scriem articole. Exist\u0103 multe capcane \u00een acest proces, voi descrie principalele care ne-au \u00eempiedicat.<\/p>\n<p><b>Prima problem\u0103<\/b> tipic pentru majoritatea monolitilor: leg\u0103tura logicii de afaceri. Atunci c\u00e2nd scriem un monolit, dorim s\u0103 reutiliz\u0103m clasele noastre pentru a nu scrie cod suplimentar. Dar \u00een momentul trecerii la microservicii, aceasta devine o problem\u0103: tot codul este destul de rigid legat, iar separarea serviciilor este dificil\u0103.<\/p>\n<p>La \u00eenceputul lucr\u0103rilor, \u00een depozit erau peste 500 de proiecte \u0219i peste 700.000 de linii de cod. Aceasta este o solu\u021bie destul de mare \u0219i <b>a doua problem\u0103<\/b>. Pur \u0219i simplu a lua \u0219i a \u00eemp\u0103r\u021bi \u00een microservicii nu p\u0103rea posibil.<\/p>\n<p><b>The third problem<\/b> \u2014 lipsa infrastructurii necesare. Practic, ne ocupam cu copierea manual\u0103 a codului surs\u0103 pe servere.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"4\"><\/a><\/noindex><b><\/p>\n<h3>Cum s\u0103 treci de la monolit la microservicii<\/h3>\n<p><\/b><br \/>\n<u>Separarea microservicilor<\/u><\/p>\n<p>\u00cen primul r\u00e2nd, ne-am definit de la \u00eenceput c\u0103 separarea microservicilor este un proces iterativ. Ni s-a cerut \u00eentotdeauna s\u0103 desf\u0103\u0219ur\u0103m simultan dezvoltarea sarcinilor de afaceri. Cum vom realiza acest lucru tehnic \u2014 este deja problema noastr\u0103. De aceea, ne-am preg\u0103tit pentru un proces iterativ. Altminteri nu va fi posibil, dac\u0103 ave\u021bi o aplica\u021bie mare \u0219i nu este ini\u021bial preg\u0103tit\u0103 pentru a fi rescris\u0103.<\/p>\n<p>Ce metode folosim pentru a eviden\u021bia microserviciile?<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"5\"><\/a><\/noindex><b>Prima metod\u0103 <\/b>\u2014 a performa modulele existente ca servicii. \u00cen acest sens, am avut noroc: erau deja servicii implementate care func\u021bionau pe protocolul WCF. Acestea erau separate \u00een ansambluri distincte. Le-am mutat individual, ad\u0103ug\u00e2nd unui fiecare ansamblu un mic modul de lansare. Acesta a fost scris cu ajutorul bibliotecii minunate Topshelf, care permite rularea aplica\u021biei at\u00e2t ca serviciu, c\u00e2t \u0219i ca aplica\u021bie de consol\u0103. Este convenabil pentru depanare, deoarece nu sunt necesare proiecte suplimentare \u00een solu\u021bie.<\/p>\n<p>Serviciile erau legate prin logica de afaceri, deoarece utilizau ansambluri comune \u0219i lucr\u00e2nd cu o baz\u0103 de date comun\u0103. Erau greu de numit microservicii \u00een sensul pur. Cu toate acestea, puteam oferi aceste servicii separat, \u00een procese diferite. Acest lucru a permis deja reducerea influen\u021bei reciproce, diminu\u00e2nd problema dezvolt\u0103rii paralele \u0219i a punctului unic de e\u0219ec.<\/p>\n<p>Ansamblul cu gazda este doar o singur\u0103 linie de cod \u00een clasa Program. Lucrul cu Topshelf l-am ascuns \u00eentr-o clas\u0103 auxiliar\u0103.<\/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>A doua metod\u0103 de extragere a microserviciilor:<\/b> a le crea pentru a rezolva sarcini noi. Dac\u0103 \u00een acest proces monolitul nu cre\u0219te, este deja excelent, \u00eenseamn\u0103 c\u0103 ne \u00eendrept\u0103m \u00een direc\u021bia corect\u0103. Pentru a aborda sarcini noi, am \u00eencercat s\u0103 facem servicii separate. Dac\u0103 era o oportunitate, cre\u0103m servicii mai \"canonice\", care gestioneaz\u0103 complet modelul lor de date, cu o baz\u0103 de date separat\u0103. <\/p>\n<p>La fel ca mul\u021bi, am \u00eenceput cu serviciile de autentificare \u0219i autorizare. Acestea sunt perfecte pentru acest lucru. Sunt independente, de obicei au un model de date separat. Ele nu interac\u021bioneaz\u0103 direct cu monolitul, ci doar monolitul le solicit\u0103 pentru rezolvarea anumitor sarcini. Aceste servicii pot marca \u00eenceputul tranzi\u021biei c\u0103tre o nou\u0103 arhitectur\u0103, le putem utiliza pentru a ne perfec\u021biona infrastructura, a \u00eencerca diverse abord\u0103ri legate de bibliotecile de re\u021bea etc. \u00cen organiza\u021bia noastr\u0103 nu exist\u0103 echipe care s\u0103 nu fi reu\u0219it s\u0103 implementeze un serviciu de autentificare. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"7\"><\/a><\/noindex><b>A treia metod\u0103 de extragere a microserviciilor<\/b>, pe care \u00eel folosim, este oarecum specific pentru noi. Este vorba despre extragerea logicii de afaceri din stratul UI. Principala noastr\u0103 aplica\u021bie UI este desktop, fiind scris\u0103 \u00een C#, la fel ca \u0219i backend-ul. Dezvoltatorii au gre\u0219it periodic \u0219i au mutat \u00een UI p\u0103r\u021bi ale logicii care ar fi trebuit s\u0103 existe \u00een backend \u0219i s\u0103 fie reutilizate. <\/p>\n<p>Dac\u0103 ne uit\u0103m la un exemplu real din codul p\u0103r\u021bii UI, observ\u0103m c\u0103 o mare parte din aceast\u0103 solu\u021bie con\u021bine adev\u0103rata logic\u0103 de afaceri, care este util\u0103 \u00een alte procese, nu doar pentru construirea formularului UI. <\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/74c7b90ff94b343816ab3ac2fa0673c6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCeva logic\u0103 real\u0103 \u00een UI exist\u0103 doar \u00een ultimele c\u00e2teva linii. Am mutat-o pe server pentru a putea fi reutilizat\u0103, reduc\u00e2nd astfel dimensiunea UI \u0219i ating\u00e2nd o arhitectur\u0103 corect\u0103.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"8\"><\/a><\/noindex><b>A patra \u0219i cea mai important\u0103 metod\u0103 de extragere a microserviciilor<\/b>, care permite reducerea monolitului, este extragerea serviciilor existente cu refacere. Atunci c\u00e2nd extragem modulele existente a\u0219a cum sunt, rezultatul nu \u00eentotdeauna \u00eei mul\u021bume\u0219te pe dezvoltatori, iar procesul de afaceri s-ar putea s\u0103 fi devenit dep\u0103\u0219it de la crearea func\u021bionalit\u0103\u021bii. Prin refactoring, putem sus\u021bine un nou proces de afaceri, deoarece cerin\u021bele comerciale se schimb\u0103 constant. Putem \u00eembun\u0103t\u0103\u021bi codul surs\u0103, elimina defectele cunoscute, crea un model de date de calitate superioar\u0103. Se acumuleaz\u0103 multe avantaje.<\/p>\n<p>Separarea serviciilor cu refacere este str\u00e2ns legat\u0103 de conceptul de context limitat. Acest concept provine din proiectarea orientat\u0103 pe obiect. Se refer\u0103 la o por\u021biune a modelului de domeniu, \u00een care to\u021bi termenii dintr-un limbaj unificat sunt defini\u021bi f\u0103r\u0103 ambiguitate. S\u0103 ne uit\u0103m la exemplul contextului asigur\u0103rilor \u0219i facturilor. Avem o aplica\u021bie monolitic\u0103, \u0219i este necesar s\u0103 lucr\u0103m cu factura \u00een asigur\u0103ri. Ne a\u0219tept\u0103m ca dezvoltatorul s\u0103 g\u0103seasc\u0103 \u00eentr-o alt\u0103 construc\u021bie clasa existent\u0103 \u201eFactur\u0103\u201d, s\u0103 fac\u0103 referire la ea din clasa \u201eAsigurare\u201d, iar noi s\u0103 ob\u021binem un cod func\u021bional. Principiul DRY va fi respectat, sarcina va fi finalizat\u0103 mai repede prin utilizarea codului existent.<\/p>\n<p>Se dovede\u0219te c\u0103 contexturile pentru conturi \u0219i asigur\u0103ri sunt interconectate. C\u00e2nd apar noi cerin\u021be, aceast\u0103 leg\u0103tur\u0103 va crea dificult\u0103\u021bi \u00een dezvoltare, cresc\u00e2nd complexitatea unei logici de afaceri deja complicate. Pentru a rezolva aceast\u0103 problem\u0103, trebuie s\u0103 identific\u0103m limitele dintre contexte \u00een cod \u0219i s\u0103 elimin\u0103m \u00eenc\u0103lc\u0103rile acestora. De exemplu, pentru asigur\u0103ri, este foarte posibil s\u0103 fie suficient un num\u0103r de cont de 20 de caractere de la Banca Central\u0103 \u0219i data deschiderii contului. <\/p>\n<p>Pentru a separa aceste contexte limitate \u0219i a \u00eencepe procesul de extragere a microserviciilor dintr-o solu\u021bie monolitic\u0103, am folosit o abordare de creare a API-urilor externe \u00een cadrul aplica\u021biei. Dac\u0103 \u0219tiam c\u0103 un anumit modul trebuie s\u0103 devin\u0103 un microserviciu sau s\u0103 se modifice \u00eentr-un anumit mod \u00een cadrul procesului, f\u0103ceam imediat apeluri la logica care apar\u021bine altui context limitat, prin apeluri externe. De exemplu, prin REST sau WCF.<\/p>\n<p>Am decis ferm c\u0103 nu ne vom feri de codul care va necesita realizarea de tranzac\u021bii distribuite. \u00cen cazul nostru, s-a dovedit a fi destul de u\u0219or s\u0103 respect\u0103m aceast\u0103 regul\u0103. P\u00e2n\u0103 acum nu am avut situa\u021bii \u00een care s\u0103 fie necesare tranzac\u021bii distribuite stricte \u2014 coeren\u021ba final\u0103 \u00eentre module s-a dovedit a fi suficient\u0103.<\/p>\n<p>S\u0103 lu\u0103m un exemplu concret. Avem conceptul de orchestrator \u2014 un canal care proceseaz\u0103 entitatea \u201ecerere\u201d. Acesta creeaz\u0103 \u00een ordine clientul, contul \u0219i cardul bancar. Dac\u0103 clientul \u0219i contul sunt create cu succes, iar crearea cardului e\u0219ueaz\u0103, cererea nu trece \u00een statusul \u201ereu\u0219it\u201d \u0219i r\u0103m\u00e2ne \u00een statusul \u201ecardul nu a fost creat\u201d. \u00cen viitor, o activitate de fundal o va prelua \u0219i o va finaliza. Sistemul r\u0103m\u00e2ne o vreme \u00een stare de incoeren\u021b\u0103, dar acest lucru este, \u00een general, acceptabil pentru noi.<\/p>\n<p>\u00cen cazul \u00een care va ap\u0103rea totu\u0219i o situa\u021bie \u00een care va trebui s\u0103 p\u0103str\u0103m coerent o parte din date, cel mai probabil vom opta pentru consolidarea serviciului, pentru a putea procesa aceasta \u00eentr-un singur proces. <\/p>\n<p>S\u0103 lu\u0103m un exemplu de extragere a unui microserviciu. Cum putem s\u0103-l ducem relativ sigur \u00een produc\u021bie? \u00cen acest exemplu, avem o parte separat\u0103 din sistem \u2014 modulul de servicii salariale, unul dintre segmentele de cod pe care dorim s\u0103-l transform\u0103m \u00een microserviciu.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/346af271b0c3f99897d330e56f713f18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00cen primul r\u00e2nd, cre\u0103m un microserviciu, rescriind codul. \u00cembun\u0103t\u0103\u021bim anumite aspecte care nu ne-au mul\u021bumit. Implement\u0103m noile cerin\u021be de afaceri ale clientului. Ad\u0103ug\u0103m \u00een leg\u0103tura dintre UI \u0219i backend un API Gateway, care va asigura transmiterea apelurilor. <\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/bec8d68f20f3ec53af0cef225a51c2b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nApoi, lans\u0103m aceast\u0103 configura\u021bie \u00een exploatare, dar \u00eentr-o stare pilot. Majoritatea utilizatorilor no\u0219tri continu\u0103 s\u0103 lucreze cu procesele de afaceri vechi. Pentru utilizatorii noi, dezvolt\u0103m o nou\u0103 versiune a aplica\u021biei monolitice, care nu mai con\u021bine acest proces. Practic, avem, \u00een mod pilot, o leg\u0103tur\u0103 \u00eentre monolit \u0219i microserviciu.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/27e98812746bb7f142fa3a3c3a03b52f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00cen cazul unui pilot de succes, realiz\u0103m c\u0103 noua configura\u021bie este cu adev\u0103rat func\u021bional\u0103, putem elimina din ecua\u021bie vechiul monolit \u0219i l\u0103sa noua configura\u021bie \u00een locul vechiului sistem.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/11dcf1d771b57d3921c0aa91b82646e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00cen total, folosim aproape toate metodele existente de separare a codului surs\u0103 al monolitului. Toate acestea ne permit s\u0103 reducem dimensiunea p\u0103r\u021bilor aplica\u021biei \u0219i s\u0103 le migr\u0103m pe biblioteci noi, cre\u00e2nd un cod surs\u0103 de mai bun\u0103 calitate.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"9\"><\/a><\/noindex><b><\/p>\n<h3>Lucrul cu Baza de Date<\/h3>\n<p><\/b><br \/>\nBD-ul este mai dificil de separat dec\u00e2t codul surs\u0103, deoarece con\u021bine nu doar schema curent\u0103, ci \u0219i datele istorice acumulate.<\/p>\n<p>BD-ul nostru, ca multe altele, a avut o alt\u0103 problem\u0103 important\u0103 - dimensiunea huge. Aceast\u0103 BD a fost proiectat\u0103 conform unei logici de afaceri complicate a monolitului, iar \u00eentre tabelele diferitelor contexte limitate s-au acumulat leg\u0103turi.<\/p>\n<p>\u00cen cazul nostru, pe l\u00e2ng\u0103 toate problemele (o baz\u0103 de date mare, multe leg\u0103turi, uneori grani\u021be neclare \u00eentre tabele) a ap\u0103rut o problem\u0103 \u00eent\u00e2lnit\u0103 \u00een multe proiecte mari: utilizarea modelului de baz\u0103 de date partajat\u0103. Datele erau extrase din tabele prin view-uri, prin replicare \u0219i erau livrate \u00een alte sisteme, unde era necesar\u0103 aceast\u0103 replicare. Ca urmare, nu am putut separa tabelele \u00eentr-o schem\u0103 distinct\u0103, deoarece acestea erau utilizate activ.<\/p>\n<p>\u00cen separare, ne ajut\u0103 tocmai acea fragmentare \u00een contexte limitate din cod. Aceasta ne ofer\u0103, \u00een general, o imagine destul de bun\u0103 despre cum separ\u0103m datele la nivelul bazei de date. \u00cen\u021belegem care tabele apar\u021bin aceluia\u0219i context limitat \u0219i care altuia.<\/p>\n<p>Am aplicat dou\u0103 metode globale pentru separarea bazei de date: separarea tabelelor existente \u0219i separarea cu refacere.<\/p>\n<p>Separarea tabelelor existente este o metod\u0103 care se aplic\u0103 bine atunci c\u00e2nd structura datelor este de calitate, satisfac\u0103 cerin\u021bele de business \u0219i este acceptabil\u0103 pentru to\u021bi. \u00cen acest caz, putem aloca tabelele existente \u00eentr-un schelet separat.<\/p>\n<p>Separarea cu refacere este necesar\u0103 atunci c\u00e2nd modelul de afaceri s-a schimbat considerabil, iar tabelele nu ne mai satisfac deloc.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"10\"><\/a><\/noindex><b>Separarea tabelelor existente.<\/b> Trebuie s\u0103 definim ce ne propunem s\u0103 separ\u0103m. F\u0103r\u0103 aceast\u0103 cunoa\u0219tere, nimic nu va func\u021biona, iar aici ne va ajuta separarea contextelor limitate \u00een cod. De obicei, dac\u0103 reu\u0219im s\u0103 \u00een\u021belegem limitele contextelor \u00een codul surs\u0103, devine clar ce tabele ar trebui incluse \u00een lista de separare.<\/p>\n<p>S\u0103 ne imagin\u0103m c\u0103 avem o solu\u021bie \u00een care dou\u0103 module ale monolitului interac\u021bioneaz\u0103 cu o baz\u0103 de date. Trebuie s\u0103 facem astfel \u00eenc\u00e2t doar un modul s\u0103 interac\u021bioneze cu zona de tabele separate, iar cel\u0103lalt s\u0103 \u00eenceap\u0103 s\u0103 interac\u021bioneze cu acesta prin API. Pentru \u00eenceput, este suficient ca doar scrierea s\u0103 se desf\u0103\u0219oare prin API. Aceasta este o condi\u021bie necesar\u0103 pentru a putea vorbi despre independen\u021ba microserviciilor. Rela\u021biile de citire pot r\u0103m\u00e2ne, at\u00e2ta timp c\u00e2t nu exist\u0103 mari probleme \u00een acest sens.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/1602637ad752ac055f475cfa45d95e95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUrm\u0103torul pas va fi s\u0103 extragem codul care lucreaz\u0103 cu tabelele separate, fie cu refacere, fie f\u0103r\u0103, \u00eentr-un microserviciu separat \u0219i s\u0103-l rul\u0103m \u00eentr-un proces sau container separat. Acesta va fi un serviciu separat cu leg\u0103tura la baza de date a monolitului \u0219i la acele tabele care nu sunt direct legate de acesta. Monolitul va continua s\u0103 interac\u021bioneze prin citire cu partea separat\u0103. <\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/36011f4e6be4f6a2f19f2f074b645dcb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMai t\u00e2rziu, vom elimina aceast\u0103 leg\u0103tur\u0103, adic\u0103 citirea datelor din aplica\u021bia monolitic\u0103 din tabelele separate va fi, de asemenea, transferat\u0103 pe API.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/290f91bbfccac2a4b384078e4cf4e337.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nApoi, vom separa din baza de date comun\u0103 tabelele cu care lucreaz\u0103 doar noul microserviciu. Putem muta tabelele \u00eentr-un schelet separat sau chiar \u00eentr-o baz\u0103 de date fizic\u0103 separat\u0103. A r\u0103mas leg\u0103tura de citire \u00eentre microserviciu \u0219i baza de date a monolitului, dar nu este nimic grav \u00een acest sens, \u00een aceast\u0103 configura\u021bie poate func\u021biona destul de mult timp.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/ab947ac6a38ffbccd4e2b51103aef609.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUltimul pas este s\u0103 elimin\u0103m complet toate leg\u0103turile. \u00cen acest caz, poate fi necesar\u0103 migrarea datelor din baza de date principal\u0103. Uneori, va trebui s\u0103 reutiliz\u0103m \u00een mai multe baze de date anumite date sau dic\u021bionare replicate din sisteme externe. Acest lucru se \u00eent\u00e2mpl\u0103 periodic la noi.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" 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>Sec\u021bia de reprocesare.<\/b> Aceast\u0103 metod\u0103 este foarte asem\u0103n\u0103toare cu prima, doar c\u0103 merge \u00een ordine invers\u0103. \u00cen aceast\u0103 etap\u0103, se define\u0219te imediat o nou\u0103 baz\u0103 de date \u0219i un nou microserviciu, care interac\u021bioneaz\u0103 cu monolitul prin API. Totu\u0219i, r\u0103m\u00e2ne un set de tabele din baza de date pe care dorim s\u0103 le elimin\u0103m \u00een viitor. Nu o mai avem nevoie, deoarece \u00een noul model am \u00eenlocuit-o.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/c94932033e47cfa1fd56595ab9a19246.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPentru ca acest sistem s\u0103 func\u021bioneze, cel mai probabil va fi nevoie de o perioad\u0103 de tranzi\u021bie.<\/p>\n<p>Apoi sunt dou\u0103 abord\u0103ri posibile.<\/p>\n<p><b>Primul<\/b>: duplic\u0103m toate datele \u00een noile \u0219i vechile baze de date. \u00cen acest caz, avem un surplus de date, pot ap\u0103rea probleme de sincronizare. Dar astfel putem lua doi clien\u021bi diferi\u021bi. Unul va lucra cu noua versiune, iar cel\u0103lalt cu vechea.<\/p>\n<p><b>Al doilea<\/b>: separ\u0103m datele pe baza unui criteriu de afaceri. De exemplu, \u00een sistemul nostru existau 5 produse care erau stocate \u00een vechea baz\u0103 de date. Cel de-al \u0219aselea, \u00een cadrul noii provoc\u0103ri de afaceri, \u00eel plas\u0103m \u00een noua baz\u0103 de date. Dar ne va trebui un API Gateway, care s\u0103 sincronizeze aceste date \u0219i s\u0103 arate clientului de unde \u0219i ce s\u0103 ia.<\/p>\n<p>Ambele abord\u0103ri sunt func\u021bionale, alege\u021bi \u00een func\u021bie de situa\u021bie.<\/p>\n<p>Dup\u0103 ce ne asigur\u0103m c\u0103 totul func\u021bioneaz\u0103, o parte din monolitul care interac\u021bioneaz\u0103 cu vechile structuri de baze de date poate fi oprit\u0103. <\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/973bf5015bdf49a290a5b901f89628cc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUltimul pas va fi eliminarea vechilor structuri de date. <\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/fe83acc07077b7eb3717138e3c20c005.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00cen concluzie, putem spune c\u0103 avem probleme cu baza de date: este mai greu de lucrat \u00een compara\u021bie cu codul surs\u0103, mai greu de separat, dar se poate \u0219i trebuie f\u0103cut. Am g\u0103sit c\u00e2teva modalit\u0103\u021bi care permit acest lucru destul de sigur, pentru c\u0103, totu\u0219i, s\u0103 gre\u0219e\u0219ti cu datele este mai simplu dec\u00e2t cu codul surs\u0103. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"12\"><\/a><\/noindex><b><\/p>\n<h3>Lucrul cu codul surs\u0103<\/h3>\n<p><\/b><br \/>\nA\u0219a ar\u0103ta schema codului surs\u0103 c\u00e2nd am \u00eenceput s\u0103 analiz\u0103m proiectul monolitic.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/a6d886e37117ccf8f63106d6616aa653.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEa poate fi \u00eemp\u0103r\u021bit\u0103 \u00een trei straturi. Acesta este stratul modulelor, plugin-urilor, serviciilor \u0219i activit\u0103\u021bilor active. De fapt, acestea erau punctele de intrare \u00een solu\u021bia monolitic\u0103. Toate acestea erau str\u00e2ns legate de stratul Common. \u00cen acesta se afla logica de afaceri pe care serviciile o utilizau \u00eempreun\u0103, precum \u0219i numeroase conexiuni. Fiecare serviciu \u0219i plugin folosea p\u00e2n\u0103 la 10 sau mai multe colec\u021bii comune, \u00een func\u021bie de dimensiunea lor \u0219i de con\u0219tiin\u021ba dezvoltatorilor.<\/p>\n<p>Am avut noroc, aveam biblioteci de infrastructur\u0103 pe care le puteam folosi separat. <\/p>\n<p>Uneori ap\u0103rea situa\u021bia \u00een care anumite obiecte Common nu se refereau de fapt la acest strat, ci erau biblioteci de infrastructur\u0103. Acest lucru se rezolva prin renaming.<\/p>\n<p>Cele mai mari \u00eengrijor\u0103ri erau cauzate de contextul limitat. Se \u00eent\u00e2mpla ca 3-4 contexte s\u0103 se amestece \u00eentr-o singur\u0103 colec\u021bie Common \u0219i s\u0103 se utilizeze unul pe altul \u00een cadrul unor func\u021bii de afaceri comune. Trebuia s\u0103 ne d\u0103m seama unde putea fi acestea \u00eemp\u0103r\u021bite \u0219i pe ce limite \u0219i ce s\u0103 facem \u00een continuare cu maparea acestei \u00eemp\u0103r\u021biri \u00een colec\u021biile de cod surs\u0103.<\/p>\n<p>Am formulat c\u00e2teva reguli pentru procesul de \u00eemp\u0103r\u021bire a codului.<\/p>\n<p><b>Primul<\/b>: nu ne mai doream partajarea logicii de afaceri \u00eentre servicii, activit\u0103\u021bi \u0219i plugin-uri. Vream s\u0103 facem logica de afaceri independent\u0103 \u00een cadrul microserviciilor. Pe de alt\u0103 parte, microserviciile,\u00een ideal, sunt percepute ca servicii care exist\u0103 complet independent. Cred c\u0103 aceast\u0103 abordare este oarecum risipitoare \u0219i este greu de realizat, deoarece, de exemplu, serviciile scrise \u00een C# vor fi totu\u0219i conectate prin biblioteca standard. Sistemul nostru este scris \u00een C#, iar alte tehnologii nu au fost folosite p\u00e2n\u0103 acum. A\u0219a c\u0103 am decis c\u0103 ne putem permite s\u0103 folosim colec\u021bii tehnice comune. Principalul lucru este c\u0103 nu trebuie s\u0103 existe fragmente de logic\u0103 de afaceri \u00een ele. Dac\u0103 ave\u021bi o \u00eenvelitoare convenabil\u0103 peste ORM pe care o folosi\u021bi, atunci copierea ei din serviciu \u00een serviciu este foarte costisitoare.<\/p>\n<p>Echipa noastr\u0103 este adept\u0103 a designului orientat pe obiect, a\u0219a c\u0103 arhitectura \u201e\u00een straturi\u201d ni s-a potrivit perfect. Fundamentul serviciilor noastre a fost o construc\u021bie cu logica de domeniu, care con\u021bine doar logica de afaceri \u0219i este lipsit\u0103 de leg\u0103turi cu infrastructura. \u00cen acest fel, putem \u00eembun\u0103t\u0103\u021bi independent construc\u021bia de domeniu pentru a rezolva problemele legate de cadre.<\/p>\n<p>\u00cen aceast\u0103 etap\u0103 ne-am confruntat cu prima problem\u0103 serioas\u0103. Serviciul trebuia s\u0103 se refere la o construc\u021bie de domeniu, iar logica voiam s\u0103 fie independent\u0103, iar principiul DRY ne-a dat mari b\u0103t\u0103i de cap. Dezvoltatorii doreau s\u0103 reutilizeze clase din construc\u021bii adiacente pentru a evita duplicarea, iar \u00een rezultat domeniile au \u00eenceput din nou s\u0103 se conecteze \u00eentre ele. Am analizat rezultatele \u0219i am decis c\u0103, poate, problema se reg\u0103se\u0219te \u0219i \u00een organizarea depozitului de cod surs\u0103. Aveam un depozit mare \u00een care erau toate codurile surs\u0103. Era foarte greu s\u0103 construim o solu\u021bie pentru \u00eentregul proiect pe ma\u0219ina local\u0103. A\u0219adar, pentru p\u0103r\u021bi ale proiectului se creau solu\u021bii mici separate, iar nimeni nu interzicea ad\u0103ugarea unei construc\u021bii comune sau de domeniu \u0219i reutilizarea acesteia. Singurul instrument care nu ne permitea s\u0103 facem acest lucru era revizia de cod. Dar uneori \u0219i aceasta d\u0103dea gre\u0219.<\/p>\n<p>Atunci am \u00eenceput s\u0103 trecem la un model cu depozite separate. Logica de afaceri a \u00eencetat s\u0103 se scurg\u0103 din serviciu \u00een serviciu, domeniile au devenit realmente independente. Contextul limitat este sus\u021binut mai clar. Cum reaplic\u0103m bibliotecile de infrastructur\u0103? Le-am separat \u00eentr-un depozit distinct, apoi le-am plasat \u00een pachete Nuget, pe care le-am stocat \u00een Artifactory. La orice modificare, construc\u021bia \u0219i publicarea au loc automat.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/8ddbc750dc7c6d397a459acf7825de90.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nServiciile noastre au \u00eenceput s\u0103 se refer\u0103 la pachetele interne de infrastructur\u0103 exact a\u0219a cum se refer\u0103 la cele externe. Desc\u0103rc\u0103m bibliotecile externe din Nuget. Pentru a lucra cu Artifactory, unde am plasat aceste pachete, am utilizat doi manageri de pachete. \u00cen depozitele mici am folosit, de asemenea, Nuget. \u00cen depozitele cu mai multe servicii am folosit Paket, care asigur\u0103 o mai bun\u0103 coeren\u021b\u0103 a versiunilor \u00eentre module.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/672a25a70a481bff68baebe963184ccd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPrin urmare, lucr\u00e2nd la codul surs\u0103, modific\u00e2nd pu\u021bin arhitectura \u0219i separ\u00e2nd repositoarele, facem serviciile noastre mai independente.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"13\"><\/a><\/noindex><b><\/p>\n<h3>Problemele infrastructurii<\/h3>\n<p><\/b><br \/>\nCele mai multe dezavantaje ale tranzi\u021biei la microservicii sunt legate de infrastructur\u0103. Ve\u021bi avea nevoie de desf\u0103\u0219urare automat\u0103, vor fi necesare noi biblioteci pentru func\u021bionarea infrastructurii.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"16\"><\/a><\/noindex><b>Instalarea manual\u0103 \u00een medii<\/b><\/p>\n<p>Ini\u021bial, solu\u021bia pentru medii era instalat\u0103 manual. Pentru a automatiza acest proces, am creat un pipeline CI\/CD. Am ales procesul de livrare continu\u0103, deoarece desf\u0103\u0219urarea continu\u0103 nu este \u00eenca acceptabil\u0103 din punct de vedere al proceselor de afaceri. Prin urmare, desf\u0103\u0219urarea \u00een produc\u021bie se realizeaz\u0103 cu un buton, iar pentru testare \u2014 automat.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/0fc092326a48813398c6f3a031197bab.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nFolosim Atlassian, Bitbucket pentru stocarea codurilor surs\u0103 \u0219i Bamboo pentru compilare. Ne place s\u0103 scriem scripturi de compilare \u00een Cake, deoarece este acela\u0219i C#. Pachetele gata vin \u00een Artifactory, iar Ansible se transfer\u0103 automat pe serverele de testare, dup\u0103 care pot fi testate imediat.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" 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>Logare separat\u0103<\/h3>\n<p><\/b><br \/>\nLa vremea respectiv\u0103, una dintre ideile monolitului era asigurarea unei jurnaliz\u0103ri comune. De asemenea, a trebuit s\u0103 \u00een\u021belegem ce s\u0103 facem cu jurnalele separate care se afl\u0103 pe discuri. Jurnalele noastre sunt scrise \u00een fi\u0219iere text. Am decis s\u0103 folosim stack-ul standard ELK. Nu am scris \u00een ELK direct prin furnizori, ci am decis s\u0103 \u00eembun\u0103t\u0103\u021bim jurnalele text \u0219i s\u0103 \u00eenregistr\u0103m ID-ul de urm\u0103rire sub forma unui identificator, ad\u0103ug\u00e2nd numele serviciului, astfel \u00eenc\u00e2t aceste jurnale s\u0103 poat\u0103 fi ulterior analizate.<\/p>\n<p><img decoding=\"async\" alt=\"Trecerea de la monolit la microservicii: istorie \u0219i practic\u0103\" src=\"\/wp-content\/uploads\/2019\/07\/8e58c66ac134e65abe34b59939f31483.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCu ajutorul Filebeat, avem posibilitatea de a colecta jurnalele noastre de <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/ro\/server\/\"   title=\"servere\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"1338\">servere<\/a>, apoi de a le transforma, folosind Kibana pentru a construi interog\u0103ri \u00een UI \u0219i a vedea cum a fost apelul \u00eentre servicii. ID-ul de urm\u0103rire ajut\u0103 foarte mult \u00een acest sens.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"15\"><\/a><\/noindex><b><\/p>\n<h3>Testarea \u0219i depanarea serviciilor interconectate<\/h3>\n<p><\/b><br \/>\nIni\u021bial, nu \u00een\u021belegeam pe deplin cum s\u0103 depur\u0103m serviciile dezvoltate. Cu monolitul, era simplu, \u00eel puneam \u00een func\u021biune pe ma\u0219ina local\u0103. La fel am \u00eencercat \u0219i cu microserviciile, dar uneori, pentru a lansa un microserviciu, trebuie s\u0103 lans\u0103m \u0219i alte c\u00e2teva, ceea ce este incomod. Am realizat c\u0103 trebuie s\u0103 trecem la un model \u00een care l\u0103s\u0103m pe ma\u0219ina local\u0103 doar serviciul sau serviciile pe care vrem s\u0103 le debugg\u0103m. Celalalte servicii sunt folosite de pe servere care coincid cu configura\u021bia din produc\u021bie. Dup\u0103 depanare, \u00een timpul test\u0103rii, pentru fiecare sarcin\u0103 pe serverul de testare sunt livrate doar serviciile modificate. Astfel, solu\u021bia este testat\u0103 \u00een forma \u00een care va fi \u00een viitor pe produc\u021bie.<\/p>\n<p>Exist\u0103 servere pe care sunt instalate doar versiunile de produc\u021bie ale serviciilor. Aceste servere sunt necesare \u00een caz de incidente, pentru verificarea livr\u0103rii \u00eenainte de deploy \u0219i pentru instruiri interne.<\/p>\n<p>Am ad\u0103ugat un proces de testare automat\u0103 folosind biblioteca popular\u0103 Specflow. Testele sunt executate automat cu NUnit imediat dup\u0103 implementarea din Ansible. Dac\u0103 acoperirea sarcinii este complet automat\u0103, nu este nevoie de testare manual\u0103. Cu toate acestea, uneori este necesar\u0103 o testare manual\u0103 suplimentar\u0103. Pentru a determina ce teste s\u0103 rul\u0103m pentru o sarcin\u0103 specific\u0103, folosim etichete \u00een Jira.<\/p>\n<p>\u00cen plus, a crescut nevoia de testare de stres, care anterior era efectuat\u0103 doar \u00een cazuri rare. Pentru a lansa testele folosim JMeter, pentru stocarea acestora \u2014 InfluxDB, iar pentru construirea graficelor procesului \u2014 Grafana.<\/p>\n<p><b><\/p>\n<h3>Ce am reu\u0219it?<\/h3>\n<p><\/b><br \/>\n\u00cen primul r\u00e2nd, am eliminat conceptul de \u201eversiune\u201d. Au disp\u0103rut versiunile monstruoase de dou\u0103 luni, c\u00e2nd aceast\u0103 ma\u0219in\u0103 era implementat\u0103 \u00een mediu de produc\u021bie, afect\u00e2nd temporar procesele de afaceri. Acum, lans\u0103m servicii \u00een medie la fiecare 1,5 zile, grup\u00e2ndu-le, deoarece intr\u0103 \u00een exploatare dup\u0103 aprobat.<\/p>\n<p>\u00cen sistemul nostru nu exist\u0103 defecte fatale. Dac\u0103 am lansat un microserviciu cu o eroare, atunci func\u021bionalitatea asociat\u0103 va fi afectat\u0103, iar \u00eentreaga restul func\u021bionalit\u0103\u021bii nu va suferi. Acest lucru \u00eembun\u0103t\u0103\u021be\u0219te semnificativ experien\u021ba utilizatorului.<\/p>\n<p>Putem gestiona schema de implementare. Se pot delimita grupuri de servicii separat de celelalte solu\u021bii, dac\u0103 este necesar.<\/p>\n<p>\u00cen plus, am redus semnificativ problema cu long backlog-ul de modific\u0103ri. Avem echipe de produse dedicate, care lucreaz\u0103 la o parte din servicii \u00een mod independent. Aici se pot aplica bine procesul Scrum. O echip\u0103 specific\u0103 poate avea un proprietar de produs distinct, care \u00eei stabile\u0219te sarcinile. <\/p>\n<p><b><\/p>\n<h3>Rezumat<\/h3>\n<p><\/b><\/p>\n<ul>\n<li>Microserviciile sunt potrivite pentru descompunerea sistemelor complexe. \u00cen proces, \u00eencepem s\u0103 \u00een\u021belegem ce exist\u0103 \u00een sistemul nostru, ce contexte limitate avem \u0219i unde sunt grani\u021bele lor. Acest lucru permite distribuirea corect\u0103 a modific\u0103rilor pe module \u0219i evitarea confuziei codului. <\/li>\n<li>Microserviciile ofer\u0103 avantaje organiza\u021bionale. Se vorbe\u0219te adesea despre ele doar ca despre o arhitectur\u0103, dar orice arhitectur\u0103 este necesar\u0103 pentru a r\u0103spunde nevoilor afacerii, nu este un scop \u00een sine. Prin urmare, putem spune c\u0103 microserviciile sunt excelente pentru a rezolva sarcini de echipe mici, av\u00e2nd \u00een vedere popularitatea actual\u0103 a Scrum.<\/li>\n<li>Divizarea este un proces iterativ. Nu po\u021bi lua o aplica\u021bie \u0219i s\u0103 o separi pur \u0219i simplu \u00een microservicii. Produsul rezultat va fi pu\u021bin probabil func\u021bional. C\u00e2nd se delimiteaz\u0103 microserviciile, este benefic s\u0103 rescriem legatul existent, adic\u0103 s\u0103-l transform\u0103m \u00een cod care ne place \u0219i care satisface mai bine nevoile afacerii \u00een ceea ce prive\u0219te func\u021bionalitatea \u0219i viteza.\n<p><i>O mic\u0103 avertizare:<\/i> costurile tranzi\u021biei la microservicii sunt destul de semnificative. A durat mult timp pentru a rezolva problema infrastructurii. De aceea, dac\u0103 ave\u021bi o aplica\u021bie mic\u0103 care nu necesit\u0103 scalare specific\u0103, dac\u0103 nu exist\u0103 un num\u0103r mare de clien\u021bi care se bat pentru aten\u021bia \u0219i timpul echipei dvs., poate c\u0103 microserviciile nu sunt ceea ce ave\u021bi nevoie ast\u0103zi. Este destul de scump. Dac\u0103 \u00eencepe\u021bi procesul cu microservicii, costurile ini\u021biale vor fi mai mari dec\u00e2t dac\u0103 acela\u0219i proiect ar \u00eencepe cu dezvoltarea unui monolit. <\/p>\n<p>P.S. O poveste mai emo\u021bional\u0103 (\u0219i ca \u0219i cum ar fi personal pentru dvs.) \u2013 pe <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=qTNbx18DzpQ\">linkul<\/a><\/noindex>. <br \/>\nAici este versiunea complet\u0103 a raportului.<\/li>\n<\/ul>\n<p>Sursa: <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.2.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\/ro\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Tranzi\u021bia de la monolit la microservicii: istorie \u0219i practic\u0103 | ProHoster","description":"\u00cen acest articol, voi vorbi despre cum proiectul la care lucrez s-a transformat dintr-un monolit mare \u00eentr-un set de microservicii. Proiectul a \u00eenceput s\u0103-\u0219i scrie istoria acum mult timp, la \u00eenceputul anului 2000.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/35906","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=35906"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35906\/revisions"}],"predecessor-version":[{"id":158582,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35906\/revisions\/158582"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/26858"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=35906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=35906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=35906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}