Editor – Esta série de artigos em sete partes está agora completa:
Você também pode baixar o conjunto completo de artigos, além de informações sobre a implementação de microsserviços usando o NGINX Plus, como um e-book – Microsserviços: Do design à implantação . E veja nossa série sobre a Arquitetura de Referência de Microsserviços e a página Soluções de Microsserviços .
Este é o sétimo e último artigo da minha série sobre criação de aplicativos com microsserviços. O primeiro artigo apresenta o padrão de arquitetura de microsserviços e discute os benefícios e desvantagens do uso de microsserviços. Os artigos a seguir discutem diferentes aspectos da arquitetura de microsserviços: uso de um API Gateway<.htmla>, comunicação entre processos , descoberta de serviços , gerenciamento de dados orientado a eventos e implantação de microsserviços . Neste artigo, analisamos estratégias para migrar um aplicativo monolítico para microsserviços.
Espero que esta série de artigos tenha lhe dado uma boa compreensão da arquitetura de microsserviços, seus benefícios e desvantagens e quando usá-los. Talvez a arquitetura de microsserviços seja uma boa opção para sua organização.
No entanto, há uma boa chance de você estar trabalhando em um aplicativo monolítico grande e complexo. Sua experiência diária de desenvolvimento e implantação de seu aplicativo é lenta e penosa. Os microsserviços parecem um nirvana distante. Felizmente, existem estratégias que você pode usar para escapar do inferno monolítico. Neste artigo, descrevo como refatorar incrementalmente um aplicativo monolítico em um conjunto de microsserviços.
O processo de transformar um aplicativo monolítico em microsserviços é uma forma de modernização de aplicativos . Isso é algo que os desenvolvedores vêm fazendo há décadas. Como resultado, há algumas ideias que podemos reutilizar ao refatorar um aplicativo em microsserviços.
Uma estratégia que não deve ser usada é a reescrita do “Big Bang”. É quando você concentra todos os seus esforços de desenvolvimento na criação de um novo aplicativo baseado em microsserviços do zero. Embora pareça atraente, é extremamente arriscado e provavelmente terminará em fracasso. Como Martin Fowler teria dito , “a única coisa que uma reescrita do Big Bang garante é um Big Bang!”
Em vez de uma reescrita do Big Bang, você deve refatorar incrementalmente seu aplicativo monolítico. Você cria gradualmente um novo aplicativo composto de microsserviços e o executa em conjunto com seu aplicativo monolítico. Com o tempo, a quantidade de funcionalidade implementada pelo aplicativo monolítico diminui até que ele desapareça completamente ou se torne apenas mais um microsserviço. Essa estratégia é semelhante a fazer a manutenção do seu carro enquanto você dirige na rodovia a 70 mph – desafiador, mas muito menos arriscado do que tentar reescrever o Big Bang.
Martin Fowler se refere a essa estratégia de modernização de aplicativos como Strangler Application . O nome vem da trepadeira estranguladora (também conhecida como figueira estranguladora) encontrada em florestas tropicais. Uma trepadeira estranguladora cresce ao redor de uma árvore para alcançar a luz do sol acima da copa da floresta. Às vezes, a árvore morre, deixando uma videira em forma de árvore. A modernização de aplicativos segue o mesmo padrão. Construiremos um novo aplicativo composto de microsserviços em torno do aplicativo legado, que eventualmente morrerá.
Vamos analisar diferentes estratégias para fazer isso.
A Lei dos Buracos diz que sempre que você estiver em um buraco você deve parar de cavar. Este é um ótimo conselho a seguir quando seu aplicativo monolítico se torna incontrolável. Em outras palavras, você deve parar de aumentar o tamanho do monólito. Isso significa que, ao implementar uma nova funcionalidade, você não deve adicionar mais código ao monólito. Em vez disso, a grande ideia dessa estratégia é colocar esse novo código em um microsserviço autônomo. O diagrama a seguir mostra a arquitetura do sistema após a aplicação dessa abordagem.
Além do novo serviço e do monólito legado, há dois outros componentes. O primeiro é um roteador de solicitação, que lida com solicitações de entrada (HTTP). É semelhante ao gateway de API descrito em um artigo anterior<.htmla>. O roteador envia solicitações correspondentes à nova funcionalidade para o novo serviço. Ele encaminha solicitações legadas para o monólito.
O outro componente é o código de colagem, que integra o serviço com o monólito. Um serviço raramente existe de forma isolada e muitas vezes precisa acessar dados de propriedade do monólito. O código de colagem, que reside no monólito, no serviço ou em ambos, é responsável pela integração de dados. O serviço usa o código de colagem para ler e gravar dados de propriedade do monólito.
Existem três estratégias que um serviço pode usar para acessar os dados do monólito:
O código de cola às vezes é chamado de camada anticorrupção . Isso ocorre porque o código de colagem impede que o serviço, que tem seu próprio modelo de domínio original, seja poluído por conceitos do modelo de domínio do monólito legado. O código de cola é traduzido entre os dois modelos diferentes. O termo camada anticorrupção apareceu pela primeira vez no livro de leitura obrigatória Domain Driven Design, de Eric Evans, e depois foi refinado em um white paper . Desenvolver uma camada anticorrupção pode ser uma tarefa nada trivial. Mas é essencial criar uma se você quiser crescer e sair desse inferno monolítico.
Implementar uma nova funcionalidade como um serviço leve tem alguns benefícios. Isso evita que o monólito se torne ainda mais incontrolável. O serviço pode ser desenvolvido, implantado e dimensionado independentemente do monólito. Você experimenta os benefícios da arquitetura de microsserviços para cada novo serviço que cria.
Entretanto, essa abordagem não faz nada para resolver os problemas do monólito. Para corrigir esses problemas, você precisa quebrar o monólito. Vejamos estratégias para fazer isso.
Uma estratégia que reduz o tamanho do aplicativo monolítico é separar a camada de apresentação das camadas de lógica de negócios e de acesso a dados. Um aplicativo empresarial típico consiste em pelo menos três tipos diferentes de componentes:
Geralmente, há uma separação clara entre a lógica de apresentação de um lado e a lógica de negócios e acesso a dados do outro. A camada de negócios tem uma API de granulação grossa que consiste em uma ou mais fachadas, que encapsulam componentes de lógica de negócios. Esta API é uma junção natural ao longo da qual você pode dividir o monólito em dois aplicativos menores. Um aplicativo contém a camada de apresentação. O outro aplicativo contém a lógica comercial e de acesso a dados. Após a divisão, o aplicativo de lógica de apresentação faz chamadas remotas para o aplicativo de lógica de negócios. O diagrama a seguir mostra a arquitetura antes e depois da refatoração.
Dividir um monólito dessa maneira tem dois benefícios principais. Ele permite que você desenvolva, implante e dimensione os dois aplicativos independentemente um do outro. Em particular, ele permite que os desenvolvedores da camada de apresentação iterem rapidamente na interface do usuário e realizem facilmente testes A/B, por exemplo. Outro benefício dessa abordagem é que ela expõe uma API remota que pode ser chamada pelos microsserviços que você desenvolve.
Essa estratégia, no entanto, é apenas uma solução parcial. É muito provável que um ou ambos os aplicativos sejam um monólito incontrolável. Você precisa usar a terceira estratégia para eliminar o monólito ou monólitos restantes.
A terceira estratégia de refatoração é transformar módulos existentes dentro do monólito em microsserviços autônomos. Cada vez que você extrai um módulo e o transforma em um serviço, o monólito encolhe. Depois de converter módulos suficientes, o monólito deixará de ser um problema. Ou ele desaparece completamente ou se torna pequeno o suficiente para ser apenas mais um serviço.
Um aplicativo monolítico grande e complexo consiste em dezenas ou centenas de módulos, todos candidatos à extração. Descobrir quais módulos converter primeiro costuma ser desafiador. Uma boa abordagem é começar com alguns módulos que sejam fáceis de extrair. Isso lhe dará experiência com microsserviços em geral e com o processo de extração em particular. Depois disso, você deve extrair os módulos que lhe darão o maior benefício.
Converter um módulo em um serviço normalmente consome tempo. Você quer classificar os módulos pelo benefício que receberá. Geralmente é benéfico extrair módulos que mudam com frequência. Depois de converter um módulo em um serviço, você pode desenvolvê-lo e implantá-lo independentemente do monólito, o que acelerará o desenvolvimento.
Também é benéfico extrair módulos que tenham requisitos de recursos significativamente diferentes daqueles do restante do monólito. É útil, por exemplo, transformar um módulo que possui um banco de dados na memória em um serviço, que pode então ser implantado em hosts com grandes quantidades de memória. Da mesma forma, pode valer a pena extrair módulos que implementam algoritmos computacionalmente caros, já que o serviço pode então ser implantado em hosts com muitas CPUs. Ao transformar módulos com requisitos de recursos específicos em serviços, você pode tornar seu aplicativo muito mais fácil de escalar.
Ao descobrir quais módulos extrair, é útil procurar por limites de granulação grossa existentes (também conhecidos como costuras). Eles tornam mais fácil e barato transformar módulos em serviços. Um exemplo desse limite é um módulo que se comunica com o restante do aplicativo apenas por meio de mensagens assíncronas. Pode ser relativamente barato e fácil transformar esse módulo em um microsserviço.
O primeiro passo para extrair um módulo é definir uma interface de granulação grossa entre o módulo e o monólito. É mais provável que seja uma API bidirecional, já que o monólito precisará de dados de propriedade do serviço e vice-versa. Muitas vezes é desafiador implementar uma API desse tipo por causa das dependências confusas e dos padrões de interação refinados entre o módulo e o restante do aplicativo. A lógica de negócios implementada usando o padrão de Modelo de Domínio é especialmente desafiadora de refatorar devido às inúmeras associações entre classes de modelo de domínio. Muitas vezes, você precisará fazer alterações significativas no código para quebrar essas dependências. O diagrama a seguir mostra a refatoração.
Depois de implementar a interface de granulação grossa, você transforma o módulo em um serviço independente. Para fazer isso, você deve escrever um código para permitir que o monólito e o serviço se comuniquem por meio de uma API que usa um mecanismo de comunicação entre processos (IPC). O diagrama a seguir mostra a arquitetura antes, durante e depois da refatoração.
Neste exemplo, o Módulo Z é o módulo candidato a ser extraído. Seus componentes são usados pelo Módulo X e ele usa o Módulo Y. O primeiro passo da refatoração é definir um par de APIs de granulação grossa. A primeira interface é uma interface de entrada usada pelo Módulo X para invocar o Módulo Z. A segunda é uma interface de saída usada pelo Módulo Z para invocar o Módulo Y.
A segunda etapa de refatoração transforma o módulo em um serviço autônomo. As interfaces de entrada e saída são implementadas por código que usa um mecanismo IPC. Provavelmente, você precisará criar o serviço combinando o Módulo Z com uma estrutura de Microservice Chassis que lida com questões transversais, como descoberta de serviço.
Depois de extrair um módulo, você tem outro serviço que pode ser desenvolvido, implantado e dimensionado independentemente do monólito e de quaisquer outros serviços. Você pode até mesmo reescrever o serviço do zero; nesse caso, o código da API que integra o serviço ao monólito se torna uma camada anticorrupção que faz a tradução entre os dois modelos de domínio. Cada vez que você extrai um serviço, você dá mais um passo na direção dos microsserviços. Com o tempo, o monólito diminuirá e você terá um número crescente de microsserviços.
O processo de migração de um aplicativo existente para microsserviços é uma forma de modernização de aplicativos. Você não deve migrar para microsserviços reescrevendo seu aplicativo do zero. Em vez disso, você deve refatorar incrementalmente seu aplicativo em um conjunto de microsserviços. Há três estratégias que você pode usar: implementar novas funcionalidades como microsserviços; separar os componentes de apresentação dos componentes de negócios e de acesso a dados; e converter módulos existentes no monólito em serviços. Com o tempo, o número de microsserviços aumentará, e a agilidade e a velocidade da sua equipe de desenvolvimento aumentarão.
Editor – Esta série de artigos em sete partes está agora completa:
Você também pode baixar o conjunto completo de artigos, além de informações sobre a implementação de microsserviços usando o NGINX Plus, como um e-book – Microsserviços: Do design à implantação . E veja nossa série sobre a Arquitetura de Referência de Microsserviços e a página Soluções de Microsserviços .
O blogueiro convidado Chris Richardson é o fundador do CloudFoundry.com original, um dos primeiros Java PaaS (Plataforma como Serviço) para Amazon EC2. Agora, ele presta consultoria a organizações para melhorar a maneira como elas desenvolvem e implantam aplicativos. Ele também escreve regularmente sobre microsserviços em https://microservices.io
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."