{"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\/pt\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","title":{"rendered":"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Neste artigo, vou falar sobre como o projeto em que trabalho se transformou de um grande monolito em um conjunto de microsservi\u00e7os.<\/p>\n<p>O projeto come\u00e7ou sua hist\u00f3ria h\u00e1 bastante tempo, no in\u00edcio dos anos 2000. As primeiras vers\u00f5es foram escritas em Visual Basic 6. Com o passar do tempo, ficou claro que desenvolver nesse idioma seria dif\u00edcil de manter, pois a IDE e a pr\u00f3pria linguagem evolu\u00edam lentamente. No final dos anos 2000, decidimos migrar para o C# mais promissor. A nova vers\u00e3o foi desenvolvida paralelamente \u00e0 melhoria da antiga, e gradualmente, mais c\u00f3digo foi escrito em .NET. O backend em C# inicialmente tinha foco em uma arquitetura de servi\u00e7os, no entanto, us\u00e1vamos bibliotecas comuns com l\u00f3gica e os servi\u00e7os eram executados em um \u00fanico processo. O resultado foi um aplicativo que chamamos de 'monolito de servi\u00e7os'. <\/p>\n<p>Uma das poucas vantagens dessa combina\u00e7\u00e3o era a capacidade de os servi\u00e7os chamarem uns aos outros atrav\u00e9s de uma API externa. Havia claras premissas para a transi\u00e7\u00e3o para uma arquitetura de servi\u00e7os mais adequada e, no futuro, para uma arquitetura de microsservi\u00e7os. <\/p>\n<p>Come\u00e7amos nosso trabalho de decomposi\u00e7\u00e3o por volta de 2015. Embora ainda n\u00e3o tenhamos alcan\u00e7ado o estado ideal \u2014 ainda existem partes do grande projeto que j\u00e1 s\u00e3o dif\u00edceis de chamar de monolitos, mas tamb\u00e9m n\u00e3o se parecem com microsservi\u00e7os. No entanto, o progresso \u00e9 significativo. <br \/>\nSobre isso, falarei no artigo.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" 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>Conte\u00fado<\/h3>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#1\"> Arquitetura e Problemas da Solu\u00e7\u00e3o Existente<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#2\">Expectativas com Microsservi\u00e7os<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#3\">Problemas da Transi\u00e7\u00e3o<\/a><\/noindex><\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"#4\">Como Migrar de Monolitos para Microsservi\u00e7os<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#5\">A primeira maneira<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#6\">Segunda maneira<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#7\">Terceiro M\u00e9todo<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#8\">Quarto M\u00e9todo<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#9\">Trabalho com BD<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#10\">Separa\u00e7\u00e3o de Tabelas Existentes<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#11\">Separa\u00e7\u00e3o com Reestrutura\u00e7\u00e3o<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#12\">Trabalho com C\u00f3digo-Fonte<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#13\">Problemas de Infraestrutura<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#16\">Instala\u00e7\u00e3o Manual em Ambientes<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#14\">Registro de Logs Separado<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#15\">Teste e Depura\u00e7\u00e3o de Servi\u00e7os Relacionados<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><noindex><a rel=\"nofollow\" name=\"1\"><\/a><\/noindex><b><\/p>\n<h3>Arquitetura e Problemas da Solu\u00e7\u00e3o Existente<\/h3>\n<p><\/b><br \/>\nOriginalmente, a arquitetura parecia a seguinte: UI \u2014 aplica\u00e7\u00e3o separada, a parte monol\u00edtica escrita em Visual Basic 6, e a aplica\u00e7\u00e3o em .NET era um conjunto de servi\u00e7os relacionados, trabalhando com um banco de dados bastante grande.<\/p>\n<p><b>Desvantagens da Solu\u00e7\u00e3o Anterior<\/b><\/p>\n<p><u>Ponto \u00danico de Falha<\/u><br \/>\nT\u00ednhamos um \u00fanico ponto de falha: o aplicativo .NET era executado em um \u00fanico processo. Se algum dos m\u00f3dulos falhasse, todo o aplicativo parava e precisava ser reiniciado. Como automatizamos um grande n\u00famero de processos para diferentes usu\u00e1rios, devido a uma falha em um deles, todos ficavam impossibilitados de trabalhar por algum tempo. E em caso de erro de programa\u00e7\u00e3o, a redund\u00e2ncia n\u00e3o ajudava. <\/p>\n<p><u>Fila de melhorias<\/u><br \/>\nEssa defici\u00eancia \u00e9 mais organizacional. Nosso aplicativo possui muitos clientes, todos querendo implementar melhorias o mais r\u00e1pido poss\u00edvel. Anteriormente, isso era imposs\u00edvel de ser feito em paralelo, e todos os clientes ficavam na fila. Esse processo gerava insatisfa\u00e7\u00e3o nos neg\u00f3cios, que precisavam provar que sua demanda tinha valor. E a equipe de desenvolvimento perdia tempo para organizar essa fila. Isso consumia muito tempo e esfor\u00e7o, e o produto, no final, n\u00e3o conseguia se adaptar t\u00e3o rapidamente quanto esperado.<\/p>\n<p><u>Uso n\u00e3o otimizado de recursos<\/u><br \/>\nAo hospedar servi\u00e7os em um \u00fanico processo, sempre copi\u00e1vamos completamente a configura\u00e7\u00e3o de servidor para servidor. Quer\u00edamos alocar os servi\u00e7os mais sobrecarregados separadamente, para n\u00e3o desperdi\u00e7ar recursos, e obter uma gest\u00e3o mais flex\u00edvel do nosso esquema de implanta\u00e7\u00e3o.<\/p>\n<p><u>Dificuldade em implementar tecnologias modernas<\/u><br \/>\nUm problema conhecido por todos os desenvolvedores: h\u00e1 o desejo de implementar tecnologias modernas no projeto, mas n\u00e3o h\u00e1 possibilidade. Com uma solu\u00e7\u00e3o monol\u00edtica grande, qualquer atualiza\u00e7\u00e3o da biblioteca atual, para n\u00e3o dizer a transi\u00e7\u00e3o para uma nova, se torna uma tarefa bastante complexa. \u00c9 necess\u00e1rio convencer o l\u00edder da equipe por um bom tempo de que isso trar\u00e1 mais benef\u00edcios do que nervos gastos. <\/p>\n<p><u>Complexidade na entrega de altera\u00e7\u00f5es<\/u><br \/>\nEsse foi o problema mais s\u00e9rio \u2014 faz\u00edamos lan\u00e7amentos a cada dois meses. <br \/>\nCada lan\u00e7amento se tornava uma verdadeira cat\u00e1strofe para o banco, apesar dos testes e esfor\u00e7os dos desenvolvedores. A equipe de neg\u00f3cios entendia que parte da funcionalidade n\u00e3o estaria dispon\u00edvel no in\u00edcio da semana. E os desenvolvedores sabiam que enfrentariam uma semana de s\u00e9rios incidentes. <br \/>\nTodos desejavam mudar a situa\u00e7\u00e3o. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"2\"><\/a><\/noindex><b><\/p>\n<h3>Expectativas com Microsservi\u00e7os<\/h3>\n<p><\/b><br \/>\n<u>Entrega de componentes \u00e0 medida que ficam prontos. <\/u>Entrega de componentes conforme sua prontid\u00e3o, gra\u00e7as \u00e0 decomposi\u00e7\u00e3o da solu\u00e7\u00e3o e separa\u00e7\u00e3o de diferentes processos.<\/p>\n<p><u>Pequenas equipes de produtos.<\/u> Isso \u00e9 importante, pois era dif\u00edcil gerenciar uma grande equipe trabalhando em um antigo mon\u00f3lito. Essa equipe era obrigada a seguir um processo rigoroso, enquanto havia uma necessidade de mais criatividade e independ\u00eancia. Apenas pequenas equipes conseguiam isso.<\/p>\n<p><u>Isolamento de servi\u00e7os em processos separados.<\/u> Idealmente, gostar\u00edamos de isolar em containers, mas muitos servi\u00e7os escritos no .NET Framework s\u00f3 podem ser executados no Windows. Agora est\u00e3o surgindo servi\u00e7os no .NET Core, mas ainda h\u00e1 poucos.<\/p>\n<p><u>Flexibilidade de implanta\u00e7\u00e3o.<\/u> Gostar\u00edamos de combinar servi\u00e7os da maneira que nos \u00e9 necess\u00e1ria, e n\u00e3o da forma que o c\u00f3digo exige.<\/p>\n<p><u>Uso de novas tecnologias.<\/u> Isso \u00e9 interessante para qualquer programador.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"3\"><\/a><\/noindex><b><\/p>\n<h3>Problemas da Transi\u00e7\u00e3o<\/h3>\n<p><\/b><br \/>\nClaro, se a divis\u00e3o de um mon\u00f3lito em microservi\u00e7os fosse f\u00e1cil, n\u00e3o precisar\u00edamos falar sobre isso em confer\u00eancias ou escrever artigos. Este processo tem muitos desafios; descreverei os principais que nos atrapalharam.<\/p>\n<p><b>O primeiro problema<\/b> t\u00edpica da maioria dos mon\u00f3litos: a interconex\u00e3o da l\u00f3gica de neg\u00f3cios. Quando escrevemos um mon\u00f3lito, queremos reutilizar nossas classes para n\u00e3o escrever c\u00f3digo desnecess\u00e1rio. E ao mudar para microservi\u00e7os, isso se torna um problema: todo o c\u00f3digo est\u00e1 bastante rigidamente ligado, tornando dif\u00edcil a separa\u00e7\u00e3o de servi\u00e7os.<\/p>\n<p>No in\u00edcio do trabalho havia mais de 500 projetos no reposit\u00f3rio e mais de 700 mil linhas de c\u00f3digo. Esta \u00e9 uma solu\u00e7\u00e3o bastante grande e <b>o segundo problema<\/b>. Simplesmente dividir isso em microservi\u00e7os n\u00e3o era vi\u00e1vel.<\/p>\n<p><b>O terceiro problema<\/b> \u2014 a falta de infraestrutura necess\u00e1ria. De fato, est\u00e1vamos fazendo c\u00f3pias manuais do c\u00f3digo-fonte nos servidores.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"4\"><\/a><\/noindex><b><\/p>\n<h3>Como Migrar de Monolitos para Microsservi\u00e7os<\/h3>\n<p><\/b><br \/>\n<u>Extra\u00e7\u00e3o de microservi\u00e7os<\/u><\/p>\n<p>Em primeiro lugar, definimos para n\u00f3s mesmos que a separa\u00e7\u00e3o de microservi\u00e7os \u00e9 um processo iterativo. Sempre fomos exigidos a desenvolver paralelamente tarefas de neg\u00f3cios. Como vamos realizar isso tecnicamente \u2014 esse \u00e9 o nosso problema. Portanto, est\u00e1vamos nos preparando para um processo iterativo. N\u00e3o h\u00e1 outra maneira se voc\u00ea tiver um grande aplicativo, e ele n\u00e3o estiver inicialmente preparado para ser reescrito.<\/p>\n<p>Quais m\u00e9todos usamos para extrair microservi\u00e7os?<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"5\"><\/a><\/noindex><b>A primeira maneira <\/b>\u2014 implementar m\u00f3dulos existentes como servi\u00e7os. Temos sorte neste aspecto: j\u00e1 haviam servi\u00e7os formatados que funcionavam com o protocolo WCF. Eles foram separados em assemblies distintos. N\u00f3s os transferimos separadamente, adicionando a cada assembly um pequeno m\u00f3dulo de inicializa\u00e7\u00e3o. Este foi criado com a incr\u00edvel biblioteca Topshelf, que permite executar o aplicativo tanto como servi\u00e7o quanto como console. Isso \u00e9 conveniente para depura\u00e7\u00e3o, pois n\u00e3o exige projetos adicionais na solu\u00e7\u00e3o.<\/p>\n<p>Os servi\u00e7os estavam ligados pela l\u00f3gica de neg\u00f3cios, pois usavam assemblies comuns e trabalhavam com um banco de dados compartilhado. Era dif\u00edcil cham\u00e1-los de microsservi\u00e7os no sentido puro. Entretanto, pod\u00edamos expor esses servi\u00e7os separadamente, em diferentes processos. Isso j\u00e1 permitia reduzir a influ\u00eancia que tinham entre si, minimizando problemas com desenvolvimento paralelo e pontos \u00fanicos de falha.<\/p>\n<p>O assembly com o host \u00e9 apenas uma linha de c\u00f3digo na classe Program. Ocultamos o trabalho com Topshelf em uma classe auxiliar.<\/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 segunda abordagem para destacar microsservi\u00e7os:<\/b> criar servi\u00e7os para resolver novas tarefas. Se o mon\u00f3lito n\u00e3o crescer durante esse processo, isso j\u00e1 \u00e9 excelente, o que significa que estamos indo na dire\u00e7\u00e3o certa. Para resolver novas tarefas, tentamos criar servi\u00e7os separados. Quando havia essa possibilidade, cri\u00e1vamos servi\u00e7os mais \"can\u00f4nicos\", que gerenciam completamente seu pr\u00f3prio modelo de dados e possuem um banco de dados separado. <\/p>\n<p>N\u00f3s, assim como muitos, come\u00e7amos com servi\u00e7os de autentica\u00e7\u00e3o e autoriza\u00e7\u00e3o. Eles s\u00e3o ideais para isso. S\u00e3o independentes, geralmente possuem um modelo de dados separado. Eles n\u00e3o interagem com o mon\u00f3lito, apenas ele os consulta para resolver certas tarefas. Esses servi\u00e7os podem ser o ponto de partida para a transi\u00e7\u00e3o para uma nova arquitetura, onde se pode ajustar a infraestrutura, experimentar diversas abordagens relacionadas a bibliotecas de rede, etc. Em nossa organiza\u00e7\u00e3o, n\u00e3o existem equipes que n\u00e3o consigam implementar um servi\u00e7o de autentica\u00e7\u00e3o. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"7\"><\/a><\/noindex><b>A terceira abordagem para destacar microsservi\u00e7os<\/b>, que utilizamos, \u00e9 um pouco espec\u00edfico para n\u00f3s. Isso se refere \u00e0 extra\u00e7\u00e3o da l\u00f3gica de neg\u00f3cios da camada de interface do usu\u00e1rio. Nosso principal aplicativo de interface do usu\u00e1rio \u00e9 desktop, assim como o backend, ele \u00e9 escrito em C#. Os desenvolvedores ocasionalmente cometiam erros e colocavam na interface do usu\u00e1rio partes da l\u00f3gica que deveriam existir no backend e serem reutilizadas. <\/p>\n<p>Se olharmos para um exemplo real do c\u00f3digo da parte da interface do usu\u00e1rio, veremos que grande parte dessa solu\u00e7\u00e3o cont\u00e9m l\u00f3gica de neg\u00f3cios real, que \u00e9 \u00fatil em outros processos, n\u00e3o apenas para a constru\u00e7\u00e3o da forma da interface do usu\u00e1rio. <\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/74c7b90ff94b343816ab3ac2fa0673c6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA l\u00f3gica real da interface do usu\u00e1rio est\u00e1 apenas nas \u00faltimas linhas. N\u00f3s a movimentamos para o servidor para que pudesse ser reutilizada, diminuindo assim a interface do usu\u00e1rio e alcan\u00e7ando a arquitetura correta.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"8\"><\/a><\/noindex><b>A quarta, e mais importante, forma de destacar microsservi\u00e7os<\/b>, que permite reduzir o mon\u00f3lito, \u00e9 a extra\u00e7\u00e3o de servi\u00e7os existentes com reformula\u00e7\u00e3o. Quando extra\u00edmos m\u00f3dulos existentes tal como est\u00e3o, o resultado nem sempre agrada aos desenvolvedores, e o processo de neg\u00f3cios desde a cria\u00e7\u00e3o da funcionalidade pode ter se tornado obsoleto. Atrav\u00e9s da refatora\u00e7\u00e3o, conseguimos apoiar novos processos de neg\u00f3cios, pois as exig\u00eancias do neg\u00f3cios est\u00e3o sempre mudando. Podemos melhorar o c\u00f3digo-fonte, eliminar defeitos conhecidos e criar um modelo de dados mais qualificado. Muitas vantagens s\u00e3o acumuladas.<\/p>\n<p>A separa\u00e7\u00e3o de servi\u00e7os com reformula\u00e7\u00e3o est\u00e1 intrinsecamente ligada ao conceito de contexto limitado. Este conceito \u00e9 da designa\u00e7\u00e3o orientada a objetos. Significa uma \u00e1rea do modelo de dom\u00ednio, onde todos os termos de uma linguagem comum est\u00e3o claramente definidos. Vamos considerar o exemplo do contexto de seguros e contas. Temos um aplicativo monol\u00edtico e precisamos trabalhar com a conta nos seguros. Esperamos que o desenvolvedor encontre na outra montagem a classe existente 'Conta', fa\u00e7a uma refer\u00eancia a ela a partir da classe 'Seguro', e teremos um c\u00f3digo funcional. O princ\u00edpio DRY ser\u00e1 respeitado, e a tarefa ser\u00e1 mais r\u00e1pida devido ao uso de c\u00f3digo existente.<\/p>\n<p>No final, percebe-se que os contextos de contas e seguros est\u00e3o interligados. Quando surgirem novas demandas, essa conex\u00e3o dificultar\u00e1 o desenvolvimento, aumentando a complexidade da l\u00f3gica de neg\u00f3cios j\u00e1 complicada. Para resolver esse problema, \u00e9 necess\u00e1rio identificar os limites entre os contextos no c\u00f3digo e eliminar suas viola\u00e7\u00f5es. Por exemplo, o contexto de seguros talvez precise apenas de um n\u00famero de conta do BC de 20 d\u00edgitos e da data de abertura da conta. <\/p>\n<p>Para separar esses contextos limitados e iniciar o processo de extra\u00e7\u00e3o de microservi\u00e7os de uma solu\u00e7\u00e3o monol\u00edtica, adotamos uma abordagem como a cria\u00e7\u00e3o de APIs externas dentro do aplicativo. Se soub\u00e9ssemos que algum m\u00f3dulo deveria se tornar um microservi\u00e7o, ou se modificar de alguma forma durante o processo, faz\u00edamos chamadas \u00e0 l\u00f3gica pertencente a outro contexto limitado atrav\u00e9s de chamadas externas. Por exemplo, via REST ou WCF.<\/p>\n<p>Decidimos firmemente que n\u00e3o evitar\u00edamos c\u00f3digo que exigisse a realiza\u00e7\u00e3o de transa\u00e7\u00f5es distribu\u00eddas. No nosso caso, acabou sendo relativamente f\u00e1cil seguir essa regra. At\u00e9 agora, n\u00e3o tivemos situa\u00e7\u00f5es em que transa\u00e7\u00f5es distribu\u00eddas r\u00edgidas foram realmente necess\u00e1rias \u2014 a consist\u00eancia final entre os m\u00f3dulos tem sido suficiente.<\/p>\n<p>Vamos considerar um exemplo concreto. Temos o conceito de orquestrador \u2014 um pipeline que processa a entidade \u2018pedido\u2019. Ele cria, sequencialmente, o cliente, a conta e o cart\u00e3o banc\u00e1rio. Se o cliente e a conta forem criados com sucesso, mas a cria\u00e7\u00e3o do cart\u00e3o falhar, o pedido n\u00e3o mudar\u00e1 para o status 'sucesso' e permanecer\u00e1 com o status 'cart\u00e3o n\u00e3o criado'. No futuro, uma atividade em segundo plano poder\u00e1 captur\u00e1-lo e finaliz\u00e1-lo. O sistema ficar\u00e1 em um estado de inconsist\u00eancia por algum tempo, mas isso, em geral, nos satisfaz.<\/p>\n<p>Caso surja uma situa\u00e7\u00e3o em que seja necess\u00e1rio salvar parte dos dados de forma consistente, provavelmente optaremos por agregar o servi\u00e7o, para process\u00e1-lo em um \u00fanico fluxo. <\/p>\n<p>Vamos considerar um exemplo de extra\u00e7\u00e3o de microservi\u00e7o. Como podemos, de maneira relativamente segura, lev\u00e1-lo \u00e0 produ\u00e7\u00e3o? Neste exemplo, temos uma parte separada do sistema \u2014 um m\u00f3dulo de gerenciamento de sal\u00e1rios, um dos trechos de c\u00f3digo que gostar\u00edamos de transformar em um microservi\u00e7o.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/346af271b0c3f99897d330e56f713f18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nA primeira coisa a fazer \u00e9 criar um microsservi\u00e7o reescrevendo o c\u00f3digo. Melhoramos alguns pontos que n\u00e3o nos agradavam. Implementamos novos requisitos de neg\u00f3cios do cliente. Adicionamos um API Gateway \u00e0 integra\u00e7\u00e3o entre a UI e o backend, que garantir\u00e1 a passagem das chamadas. <\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/bec8d68f20f3ec53af0cef225a51c2b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm seguida, lan\u00e7amos essa configura\u00e7\u00e3o em opera\u00e7\u00e3o, mas em estado de piloto. A maioria dos nossos usu\u00e1rios ainda trabalha com os antigos processos de neg\u00f3cios. Para novos usu\u00e1rios, estamos desenvolvendo uma nova vers\u00e3o da aplica\u00e7\u00e3o monol\u00edtica, que n\u00e3o cont\u00e9m mais esse processo. Na verdade, temos em modo piloto uma integra\u00e7\u00e3o entre o mon\u00f3lito e o microsservi\u00e7o.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/27e98812746bb7f142fa3a3c3a03b52f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCom o piloto bem-sucedido, entendemos que a nova configura\u00e7\u00e3o realmente funciona, podemos remover o antigo mon\u00f3lito e deixar a nova configura\u00e7\u00e3o no lugar da solu\u00e7\u00e3o antiga.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/11dcf1d771b57d3921c0aa91b82646e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm resumo, utilizamos praticamente todos os m\u00e9todos existentes de separa\u00e7\u00e3o do c\u00f3digo-fonte do mon\u00f3lito. Todos eles nos permitem reduzir o tamanho das partes do aplicativo e transferi-las para novas bibliotecas, criando um c\u00f3digo-fonte de maior qualidade.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"9\"><\/a><\/noindex><b><\/p>\n<h3>Trabalho com BD<\/h3>\n<p><\/b><br \/>\nO banco de dados se separa pior do que o c\u00f3digo-fonte, pois cont\u00e9m n\u00e3o apenas o esquema atual, mas tamb\u00e9m os dados hist\u00f3ricos acumulados.<\/p>\n<p>O nosso banco de dados, assim como muitos outros, tinha outro problema importante \u2014 o tamanho enorme. Este banco de dados foi projetado com base na l\u00f3gica de neg\u00f3cios confusa do mon\u00f3lito, e entre as tabelas de diferentes contextos limitados, acumularam-se rela\u00e7\u00f5es.<\/p>\n<p>No nosso caso, para piorar a situa\u00e7\u00e3o (banco de dados grande, muitas rela\u00e7\u00f5es, fronteiras \u00e0s vezes confusas entre as tabelas), surgiu um problema comum em muitos grandes projetos: o uso do padr\u00e3o de banco de dados compartilhado. Os dados eram retirados de tabelas atrav\u00e9s de views, atrav\u00e9s de replica\u00e7\u00e3o e enviados para outros sistemas onde essa replica\u00e7\u00e3o era necess\u00e1ria. Como resultado, n\u00e3o consegu\u00edamos mover tabelas para um esquema separado, pois eram amplamente utilizadas.<\/p>\n<p>A separa\u00e7\u00e3o \u00e9 ajudada pela divis\u00e3o em contextos limitados no c\u00f3digo. Isso, geralmente, nos d\u00e1 uma boa no\u00e7\u00e3o de como dividimos os dados no n\u00edvel do banco de dados. Entendemos quais tabelas pertencem a um contexto limitado e quais pertencem a outro.<\/p>\n<p>Aplicamos duas abordagens globais para a separa\u00e7\u00e3o do banco de dados: a separa\u00e7\u00e3o de tabelas existentes e a separa\u00e7\u00e3o com reaprimoramento.<\/p>\n<p>A separa\u00e7\u00e3o das tabelas existentes \u00e9 um m\u00e9todo que deve ser utilizado quando a estrutura de dados \u00e9 de qualidade, atende aos requisitos de neg\u00f3cios e satisfaz a todos os envolvidos. Nesse caso, podemos destacar as tabelas existentes em um esquema separado.<\/p>\n<p>A separa\u00e7\u00e3o com reaprimoramento \u00e9 necess\u00e1ria quando o modelo de neg\u00f3cios mudou significativamente e as tabelas n\u00e3o nos satisfazem mais.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"10\"><\/a><\/noindex><b>Separa\u00e7\u00e3o de tabelas existentes.<\/b> Precisamos definir o que vamos separar. Sem esse conhecimento, nada funcionar\u00e1, e aqui a separa\u00e7\u00e3o de contextos limitados no c\u00f3digo nos ajudar\u00e1. Geralmente, se conseguimos compreender as fronteiras dos contextos no c\u00f3digo-fonte, fica claro quais tabelas devem ser inclu\u00eddas na lista para separa\u00e7\u00e3o.<\/p>\n<p>Suponha que temos uma solu\u00e7\u00e3o onde dois m\u00f3dulos de um mon\u00f3lito interagem com um \u00fanico banco de dados. Precisamos garantir que a parte das tabelas que estamos separando interaja apenas com um m\u00f3dulo, enquanto o outro comece a interagir com ele atrav\u00e9s de uma API. Para come\u00e7ar, \u00e9 suficiente que apenas grava\u00e7\u00f5es sejam feitas atrav\u00e9s da API. Esta \u00e9 uma condi\u00e7\u00e3o necess\u00e1ria para que possamos falar sobre a independ\u00eancia dos microsservi\u00e7os. As conex\u00f5es de leitura podem continuar, desde que isso n\u00e3o represente um grande problema.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/1602637ad752ac055f475cfa45d95e95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO pr\u00f3ximo passo \u00e9 destacar a parte do c\u00f3digo que trabalha com as tabelas a serem separadas, seja com reaprimoramento ou sem, em um microsservi\u00e7o distinto que ser\u00e1 executado em um processo ou cont\u00eainer separado. Esse ser\u00e1 um servi\u00e7o separado com conex\u00e3o ao banco de dados do mon\u00f3lito e \u00e0s tabelas que n\u00e3o est\u00e3o diretamente relacionadas a ele. O mon\u00f3lito ainda interage em leitura com a parte separada. <\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/36011f4e6be4f6a2f19f2f074b645dcb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPosteriormente, removeremos essa conex\u00e3o, ou seja, a leitura de dados do aplicativo monol\u00edtico a partir das tabelas separadas tamb\u00e9m ser\u00e1 transferida para a API.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/290f91bbfccac2a4b384078e4cf4e337.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm seguida, destacaremos da base de dados geral as tabelas com as quais apenas o novo microsservi\u00e7o trabalha. Podemos mover as tabelas para um esquema separado ou at\u00e9 mesmo para um banco de dados f\u00edsico separado. A conex\u00e3o de leitura entre o microsservi\u00e7o e o banco de dados do mon\u00f3lito permanece, mas isso n\u00e3o \u00e9 um problema, pois essa configura\u00e7\u00e3o pode existir por um tempo consider\u00e1vel.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/ab947ac6a38ffbccd4e2b51103aef609.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO \u00faltimo passo \u00e9 remover todas as conex\u00f5es completamente. Neste caso, pode ser necess\u00e1ria a migra\u00e7\u00e3o de dados da base de dados principal. \u00c0s vezes, vamos querer reutilizar alguns dados ou diret\u00f3rios replicados de sistemas externos em v\u00e1rias bases. Isso ocorre periodicamente conosco.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" 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>Divis\u00e3o com reprocessamento.<\/b> Este m\u00e9todo \u00e9 muito semelhante ao primeiro, apenas na ordem inversa. Criamos imediatamente uma nova base de dados e um novo microservi\u00e7o que interage com o mon\u00f3lito atrav\u00e9s da API. Por\u00e9m, permanece um conjunto de tabelas de BD que pretendemos remover no futuro. Elas n\u00e3o ser\u00e3o mais necess\u00e1rias; na nova modelagem, foram substitu\u00eddas.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/c94932033e47cfa1fd56595ab9a19246.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPara que esse esquema funcione, provavelmente precisaremos de um per\u00edodo de transi\u00e7\u00e3o.<\/p>\n<p>Aqui existem duas abordagens poss\u00edveis.<\/p>\n<p><b>Primeiro<\/b>: duplicamos todos os dados nas novas e antigas bases. Nesse caso, h\u00e1 redund\u00e2ncia de dados e podem surgir problemas de sincroniza\u00e7\u00e3o. Por\u00e9m, podemos atender a dois clientes diferentes. Um usar\u00e1 a nova vers\u00e3o, outro a antiga.<\/p>\n<p><b>Segundo<\/b>: dividimos os dados com base em algum crit\u00e9rio de neg\u00f3cio. Por exemplo, em nosso sistema havia 5 produtos armazenados na antiga base de dados. O sexto, dentro de uma nova demanda de neg\u00f3cio, ser\u00e1 colocado na nova BD. Por\u00e9m, precisaremos de um API Gateway para sincronizar esses dados e mostrar ao cliente de onde e o que pegar.<\/p>\n<p>Ambas as abordagens s\u00e3o vi\u00e1veis; escolha conforme a situa\u00e7\u00e3o.<\/p>\n<p>Ap\u00f3s confirmarmos que tudo est\u00e1 funcionando, a parte do mon\u00f3lito que opera com as antigas estruturas de BD pode ser desligada. <\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/973bf5015bdf49a290a5b901f89628cc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nO \u00faltimo passo ser\u00e1 a remo\u00e7\u00e3o das antigas estruturas de dados. <\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/fe83acc07077b7eb3717138e3c20c005.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm resumo, podemos afirmar que temos problemas com a BD: \u00e9 dif\u00edcil trabalhar com ela em compara\u00e7\u00e3o ao c\u00f3digo-fonte, a separa\u00e7\u00e3o \u00e9 mais complicada, mas \u00e9 algo que podemos e devemos fazer. Encontramos algumas maneiras que tornam isso bastante seguro, afinal, \u00e9 mais f\u00e1cil cometer um erro com dados do que com o c\u00f3digo-fonte. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"12\"><\/a><\/noindex><b><\/p>\n<h3>Trabalho com C\u00f3digo-Fonte<\/h3>\n<p><\/b><br \/>\nAssim era o esquema do c\u00f3digo-fonte quando come\u00e7amos a analisar o projeto monol\u00edtico.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/a6d886e37117ccf8f63106d6616aa653.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEla pode ser dividida, em termos condicionais, em tr\u00eas camadas. Esta \u00e9 a camada de m\u00f3dulos execut\u00e1veis, plugins, servi\u00e7os e atividades individuais. Na verdade, esses eram os pontos de entrada dentro de uma solu\u00e7\u00e3o monol\u00edtica. Todos eles estavam solidamente ligados por uma camada comum. Nela estava a l\u00f3gica de neg\u00f3cios que era utilizada em conjunto pelos servi\u00e7os, e v\u00e1rias interconex\u00f5es. Cada servi\u00e7o e plugin utilizava at\u00e9 10 ou mais assemblies comuns, dependendo de seu tamanho e da integridade dos desenvolvedores.<\/p>\n<p>Tivemos sorte, t\u00ednhamos bibliotecas de infraestrutura que podiam ser utilizadas separadamente. <\/p>\n<p>\u00c0s vezes surgiam situa\u00e7\u00f5es em que alguns objetos comuns na verdade n\u00e3o pertenciam a essa camada, mas eram bibliotecas de infraestrutura. Isso era resolvido com renomea\u00e7\u00f5es.<\/p>\n<p>Os contextos limitados eram os que mais preocupavam. \u00c0s vezes, 3-4 contextos se misturavam em um \u00fanico assembly comum e usavam um ao outro dentro de fun\u00e7\u00f5es de neg\u00f3cios. Era necess\u00e1rio entender onde isso poderia ser dividido e quais seriam os limites, e o que fazer em seguida com o mapeamento dessa divis\u00e3o para os assemblies do c\u00f3digo fonte.<\/p>\n<p>Formulamos algumas regras para o processo de divis\u00e3o de c\u00f3digo.<\/p>\n<p><b>Primeiro<\/b>: n\u00e3o quer\u00edamos mais compartilhar a l\u00f3gica de neg\u00f3cios entre servi\u00e7os, atividades e plugins. Quer\u00edamos tornar a l\u00f3gica de neg\u00f3cios independente dentro dos microservi\u00e7os. Por outro lado, microservi\u00e7os, idealmente, s\u00e3o vistos como servi\u00e7os que existem completamente de forma independente. Acredito que essa abordagem \u00e9 um pouco desperd\u00edcio, al\u00e9m de ser dif\u00edcil de alcan\u00e7ar, pois, por exemplo, servi\u00e7os em C# estar\u00e3o de qualquer forma conectados por uma biblioteca padr\u00e3o. Nosso sistema \u00e9 escrito em C#, outras tecnologias n\u00e3o foram utilizadas at\u00e9 agora. Portanto, decidimos que poder\u00edamos nos permitir usar assemblies t\u00e9cnicos comuns. O principal \u00e9 que n\u00e3o deve haver fragmentos da l\u00f3gica de neg\u00f3cios neles. Se voc\u00ea tem um wrapper conveniente sobre o ORM que est\u00e1 utilizando, ent\u00e3o copi\u00e1-lo de servi\u00e7o para servi\u00e7o \u00e9 muito custoso.<\/p>\n<p>A nossa equipe \u00e9 f\u00e3 do design orientado a dom\u00ednio, por isso a \"arquitetura cebola\" se encaixou perfeitamente para n\u00f3s. A base dos nossos servi\u00e7os n\u00e3o \u00e9 uma camada de acesso a dados, mas uma constru\u00e7\u00e3o com l\u00f3gica de dom\u00ednio, que cont\u00e9m apenas a l\u00f3gica de neg\u00f3cios e \u00e9 isenta de v\u00ednculos com a infraestrutura. Assim, podemos aprimorar independentemente a constru\u00e7\u00e3o de dom\u00ednio para resolver problemas relacionados aos frameworks.<\/p>\n<p>Nesse est\u00e1gio, encontramos o primeiro grande problema. O servi\u00e7o deveria referenciar uma \u00fanica constru\u00e7\u00e3o de dom\u00ednio, quer\u00edamos que a l\u00f3gica fosse independente, e o princ\u00edpio DRY estava nos atrapalhando. Os desenvolvedores queriam reutilizar classes de constru\u00e7\u00f5es vizinhas para evitar duplica\u00e7\u00f5es, e, como resultado, os dom\u00ednios come\u00e7aram a se conectar novamente. Analisamos os resultados e decidimos que, talvez, o problema tamb\u00e9m estivesse na forma como o armazenamento do c\u00f3digo-fonte estava estruturado. T\u00ednhamos um grande reposit\u00f3rio, onde todo o c\u00f3digo-fonte era armazenado. Era muito dif\u00edcil montar a solu\u00e7\u00e3o do projeto em uma m\u00e1quina local. Portanto, para partes do projeto, eram criadas solu\u00e7\u00f5es separadas, e ningu\u00e9m impedia que uma constru\u00e7\u00e3o comum ou de dom\u00ednio fosse adicionada e reutilizada. O \u00fanico instrumento que n\u00e3o nos permitia fazer isso era a revis\u00e3o de c\u00f3digo. Mas \u00e0s vezes at\u00e9 isso falhava.<\/p>\n<p>Ent\u00e3o come\u00e7amos a transi\u00e7\u00e3o para um modelo com reposit\u00f3rios separados. A l\u00f3gica de neg\u00f3cios deixou de vazar de um servi\u00e7o para outro, e os dom\u00ednios realmente se tornaram independentes. Os contextos delimitados s\u00e3o mantidos de forma mais clara. Como reutilizamos as bibliotecas de infraestrutura? Separaram-se em um reposit\u00f3rio distinto e, em seguida, colocamos em pacotes Nuget, que foram armazenados no Artifactory. Qualquer altera\u00e7\u00e3o resulta em uma constru\u00e7\u00e3o e publica\u00e7\u00e3o autom\u00e1ticas.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/8ddbc750dc7c6d397a459acf7825de90.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNossos servi\u00e7os passaram a referenciar pacotes de infraestrutura interna exatamente da mesma forma que as bibliotecas externas. As bibliotecas externas s\u00e3o baixadas do Nuget. Para trabalhar com o Artifactory, onde armazenamos esses pacotes, utilizamos dois gerenciadores de pacotes. Em reposit\u00f3rios pequenos, tamb\u00e9m usamos o Nuget. Em reposit\u00f3rios com v\u00e1rios servi\u00e7os, utilizamos o Paket, que oferece maior consist\u00eancia de vers\u00f5es entre os m\u00f3dulos.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/672a25a70a481bff68baebe963184ccd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAssim, ao trabalhar no c\u00f3digo-fonte, alterando um pouco a arquitetura e separando os reposit\u00f3rios, tornamos nossos servi\u00e7os mais independentes.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"13\"><\/a><\/noindex><b><\/p>\n<h3>Problemas de Infraestrutura<\/h3>\n<p><\/b><br \/>\nA maioria das desvantagens ao migrar para microservi\u00e7os est\u00e1 relacionada \u00e0 infraestrutura. Voc\u00ea precisar\u00e1 de uma implanta\u00e7\u00e3o automatizada e de novas bibliotecas para a opera\u00e7\u00e3o da infraestrutura.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"16\"><\/a><\/noindex><b>Instala\u00e7\u00e3o Manual em Ambientes<\/b><\/p>\n<p>Inicialmente, n\u00f3s instal\u00e1vamos as solu\u00e7\u00f5es em ambientes manualmente. Para automatizar esse processo, criamos um pipeline de CI\/CD. Optamos pelo processo de entrega cont\u00ednua, pois a implanta\u00e7\u00e3o cont\u00ednua ainda n\u00e3o \u00e9 vi\u00e1vel do ponto de vista dos processos empresariais. Assim, a implementa\u00e7\u00e3o \u00e9 feita por bot\u00e3o, enquanto os testes s\u00e3o autom\u00e1ticos.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/0fc092326a48813398c6f3a031197bab.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUsamos Atlassian, Bitbucket para armazenar c\u00f3digos-fonte e Bamboo para a compila\u00e7\u00e3o. Gostamos de escrever scripts de compila\u00e7\u00e3o em Cake, porque \u00e9 o mesmo que C#. Pacotes prontos chegam ao Artifactory, e o Ansible automaticamente \u00e9 enviado para os servidores de teste, onde podem ser testados imediatamente.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" 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>Registro de Logs Separado<\/h3>\n<p><\/b><br \/>\nNa \u00e9poca, uma das ideias do monolito era garantir o registro conjunto. Tamb\u00e9m precis\u00e1vamos entender o que fazer com os logs separados armazenados nos discos. Os logs s\u00e3o gravados em arquivos de texto. Decidimos usar a pilha ELK padr\u00e3o. N\u00e3o gravamos diretamente no ELK atrav\u00e9s de provedores, mas decidimos aprimorar os logs de texto e registrar neles o ID de rastreamento como um identificador, adicionando o nome do servi\u00e7o, para que esses logs pudessem ser analisados posteriormente.<\/p>\n<p><img decoding=\"async\" alt=\"A transi\u00e7\u00e3o de mon\u00f3litos para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica\" src=\"\/wp-content\/uploads\/2019\/07\/8e58c66ac134e65abe34b59939f31483.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCom o Filebeat, conseguimos coletar nossos logs de <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/pt\/server\/\"   title=\"servidores\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"1338\">servidores<\/a>, transform\u00e1-los, construir consultas na interface do usu\u00e1rio usando o Kibana e visualizar como as chamadas foram feitas entre os servi\u00e7os. O ID de rastreamento \u00e9 de grande ajuda nesse processo.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"15\"><\/a><\/noindex><b><\/p>\n<h3>Teste e Depura\u00e7\u00e3o de Servi\u00e7os Relacionados<\/h3>\n<p><\/b><br \/>\nNo in\u00edcio, n\u00e3o entend\u00edamos completamente como debugar os servi\u00e7os que est\u00e1vamos desenvolvendo. Com o mon\u00f3lito, tudo era simples; n\u00f3s o execut\u00e1vamos na m\u00e1quina local. Tentamos fazer o mesmo com os microsservi\u00e7os, mas, \u00e0s vezes, para iniciar um microsservi\u00e7o, \u00e9 necess\u00e1rio iniciar v\u00e1rios outros, o que \u00e9 inconveniente. Percebemos que precis\u00e1vamos mudar para um modelo em que deixamos na m\u00e1quina local apenas o servi\u00e7o ou servi\u00e7os que desejamos depurar. Os outros servi\u00e7os s\u00e3o utilizados a partir de servidores que t\u00eam a mesma configura\u00e7\u00e3o do ambiente de produ\u00e7\u00e3o. Ap\u00f3s a depura\u00e7\u00e3o, durante os testes, apenas os servi\u00e7os modificados s\u00e3o implantados no servidor de teste para cada tarefa. Assim, testamos a solu\u00e7\u00e3o da forma como ela ser\u00e1 no ambiente de produ\u00e7\u00e3o.<\/p>\n<p>Existem servidores que possuem apenas vers\u00f5es de produ\u00e7\u00e3o dos servi\u00e7os. Esses servidores s\u00e3o necess\u00e1rios para lidar com incidentes, para verificar a entrega antes da implanta\u00e7\u00e3o e para treinamentos internos.<\/p>\n<p>Adicionamos um processo de testes automatizados usando a popular biblioteca Specflow. Os testes s\u00e3o executados automaticamente com o NUnit logo ap\u00f3s a implanta\u00e7\u00e3o atrav\u00e9s do Ansible. Se a cobertura da tarefa \u00e9 totalmente autom\u00e1tica, n\u00e3o h\u00e1 necessidade de testes manuais. Embora, \u00e0s vezes, testes manuais adicionais ainda sejam necess\u00e1rios. Para determinar quais testes executar para uma tarefa espec\u00edfica, utilizamos tags no Jira.<\/p>\n<p>Al\u00e9m disso, a demanda por testes de carga aumentou, sendo que antes isso ocorria apenas em casos raros. Para executar os testes, usamos o JMeter, para armazen\u00e1-los usamos o InfluxDB, e para criar gr\u00e1ficos do processo, utilizamos o Grafana.<\/p>\n<p><b><\/p>\n<h3>O que conseguimos?<\/h3>\n<p><\/b><br \/>\nEm primeiro lugar, eliminamos o conceito de 'release'. Desapareceram as monstruosas releases de dois meses, quando essa m\u00e1quina era implantada no ambiente de produ\u00e7\u00e3o, interrompendo temporariamente os processos de neg\u00f3cios. Agora, implantamos servi\u00e7os em m\u00e9dia a cada 1,5 dias, agrupando-os, pois entram em opera\u00e7\u00e3o ap\u00f3s aprova\u00e7\u00e3o.<\/p>\n<p>Em nosso sistema, n\u00e3o h\u00e1 falhas fatais. Se lan\u00e7amos um microsservi\u00e7o com um erro, a funcionalidade relacionada a ele ser\u00e1 afetada, mas toda a outra funcionalidade n\u00e3o ser\u00e1 prejudicada. Isso melhora significativamente a experi\u00eancia do usu\u00e1rio.<\/p>\n<p>Podemos gerenciar o esquema de implanta\u00e7\u00e3o. \u00c9 poss\u00edvel destacar grupos de servi\u00e7os separadamente do restante da solu\u00e7\u00e3o, se necess\u00e1rio.<\/p>\n<p>Al\u00e9m disso, conseguimos reduzir significativamente o problema das longas filas de solicita\u00e7\u00f5es. Formamos equipes de produto separadas que trabalham com partes dos servi\u00e7os de forma independente. Aqui, o processo Scrum j\u00e1 se encaixa bem. Uma equipe espec\u00edfica pode ter um propriet\u00e1rio de produto separado que define as tarefas para ela. <\/p>\n<p><b><\/p>\n<h3>Resumo<\/h3>\n<p><\/b><\/p>\n<ul>\n<li>Microsservi\u00e7os s\u00e3o adequados para a decomposi\u00e7\u00e3o de sistemas complexos. No processo, come\u00e7amos a entender o que existe em nosso sistema, quais s\u00e3o os contextos limitados e onde est\u00e3o suas fronteiras. Isso permite distribuir corretamente as solicita\u00e7\u00f5es entre os m\u00f3dulos e evitar confus\u00e3o no c\u00f3digo. <\/li>\n<li>Microsservi\u00e7os oferecem vantagens organizacionais. Muitas vezes, falamos sobre eles apenas como arquitetura, mas toda arquitetura serve para resolver necessidades de neg\u00f3cios, e n\u00e3o por si s\u00f3. Portanto, podemos afirmar que microsservi\u00e7os s\u00e3o adequados para resolver problemas em pequenas equipes, considerando que o Scrum \u00e9 muito popular atualmente.<\/li>\n<li>A separa\u00e7\u00e3o \u00e9 um processo iterativo. N\u00e3o se pode simplesmente pegar um aplicativo e dividi-lo em microsservi\u00e7os. O produto resultante provavelmente n\u00e3o funcionar\u00e1. Ao destacar microsservi\u00e7os, \u00e9 vantajoso reescrever o legado existente, ou seja, transform\u00e1-lo em um c\u00f3digo que gostamos e que melhor atende \u00e0s necessidades do neg\u00f3cio em termos de funcionalidade e velocidade.\n<p><i>Um pequeno aviso:<\/i> os custos de transi\u00e7\u00e3o para microsservi\u00e7os s\u00e3o bastante significativos. Somente para resolver o problema de infraestrutura, gastou-se muito tempo. Portanto, se voc\u00ea tem um pequeno aplicativo que n\u00e3o requer escalabilidade espec\u00edfica, e n\u00e3o h\u00e1 um grande n\u00famero de clientes disputando a aten\u00e7\u00e3o e o tempo da sua equipe, ent\u00e3o, talvez, microsservi\u00e7os n\u00e3o sejam o que voc\u00ea precisa hoje. Isso \u00e9 bastante caro. Se voc\u00ea iniciar o processo com microsservi\u00e7os, os custos iniciais ser\u00e3o maiores do que se o mesmo projeto fosse iniciado com o desenvolvimento de um monolito. <\/p>\n<p>P.S. Uma narrativa mais emocional (como se fosse pessoalmente para voc\u00ea) \u2013 em <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=qTNbx18DzpQ\">link<\/a><\/noindex>. <br \/>\nAqui est\u00e1 a vers\u00e3o completa da apresenta\u00e7\u00e3o.<\/li>\n<\/ul>\n<p>Fonte: <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.3 - 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\/pt\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\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\/pt\/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\udd47A transi\u00e7\u00e3o de monolito para microsservi\u00e7os: hist\u00f3ria e pr\u00e1tica | ProHoster","description":"Neste artigo, vou falar sobre como o projeto em que estou trabalhando se transformou de um grande monolito em um conjunto de microsservi\u00e7os. O projeto come\u00e7ou sua hist\u00f3ria h\u00e1 bastante tempo, no in\u00edcio dos anos 2000.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/35906","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=35906"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/35906\/revisions"}],"predecessor-version":[{"id":158582,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/35906\/revisions\/158582"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/26858"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=35906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=35906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=35906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}