Comparamos os recursos do microsserviço e da arquitetura monolítica, suas vantagens e desvantagens. O artigo foi preparado para Habr com base nos materiais de nossa meta
Hot Backend , realizada em Samara em 9 de fevereiro de 2019. Consideramos os fatores de escolha da arquitetura, dependendo da tarefa específica.
Mesmo 5 anos atrás, ninguém tinha ouvido falar em microsserviços. No entanto, sua popularidade está aumentando de ano para ano, de acordo com
estatísticas do Google Trends.

Monólito e microsserviços: exemplos
Se o projeto usar uma arquitetura monolítica, o desenvolvedor terá apenas um aplicativo, todos os componentes e módulos dos quais trabalham com uma única base.

A arquitetura de microsserviços envolve a decomposição em módulos que são executados como processos separados e podem ter servidores separados. Cada microsserviço trabalha com seu próprio banco de dados e todos esses serviços podem se comunicar de forma síncrona (http) e assíncrona. Além disso, para otimizar a arquitetura, é desejável minimizar o relacionamento entre os serviços.
O diagrama abaixo é simplificado, reflete, em primeiro lugar, os componentes de negócios.

Microsserviços: benefícios
Há pelo menos quatro vantagens da arquitetura de microsserviço:
Dimensionamento e implantação independentesUma implantação independente é fornecida para cada microsserviço, e isso é conveniente ao atualizar módulos individuais. Se a carga no módulo aumentar, o microsserviço correspondente poderá ser escalado sem afetar os outros. Isso permite distribuir de forma flexível a carga e economizar recursos.
Desenvolvimento independenteCada microsserviço (por exemplo, um módulo de memória) pode ser desenvolvido por uma equipe para aumentar a velocidade de criação de um produto de software.
SustentabilidadeA falha de um microsserviço não afeta o desempenho de outros módulos.
HeterogeneidadeCada equipe é livre para escolher seu próprio idioma e tecnologia para implementar microsserviços, no entanto, é desejável que eles tenham interfaces compatíveis.
Entre os desenvolvedores, você pode ouvir a opinião de que a arquitetura monolítica está desatualizada, é difícil de manter e dimensionar, cresce rapidamente em um "grande pedaço de terra" e é praticamente antipadrão, ou seja, sua presença no código é indesejável. Grandes empresas, como a Netflix, que mudaram para a arquitetura de microsserviço em seus projetos, são frequentemente citadas como evidência dessa opinião.
Vamos ver se todos realmente devem mudar de um monólito para microsserviços, seguindo o exemplo das maiores marcas?
Mudando para microsserviços: possíveis dificuldades
Problema Um: DecomposiçãoIdealmente, o aplicativo deve ser dividido em microsserviços para que eles interajam o mínimo possível, caso contrário, o aplicativo será difícil de manter. Ao mesmo tempo, é difícil implementar a decomposição no início do desenvolvimento, quando os problemas de negócios e a área de assunto ainda podem mudar com o advento de novos requisitos. A refatoração é cara.
Se for necessário transferir parte das funções do serviço A para o serviço B, pode haver dificuldades: por exemplo, os serviços são executados em diferentes idiomas, as chamadas internas aos serviços se tornam rede, outras bibliotecas devem ser conectadas. Podemos verificar a correção da refatoração apenas com a ajuda de testes.
Problema Dois: TransaçõesOutro problema é que os microsserviços não têm o conceito de transações distribuídas. Podemos garantir a integridade arquitetural de uma operação comercial apenas em um microsserviço. Se a operação envolver vários microsserviços, diferentes bancos de dados poderão ser usados lá e essa transação terá que ser abandonada. Para resolver esse problema, existem vários métodos usados nos negócios quando a acessibilidade é mais importante que a integridade. Ao mesmo tempo, mecanismos de compensação são fornecidos caso algo dê errado. Por exemplo, se as mercadorias não estiverem em estoque, você precisará fazer um reembolso na conta do comprador.
Se um monólito nos fornecer integridade arquitetural automaticamente, com os microsserviços, você precisará criar seu próprio mecanismo e usar bibliotecas com soluções prontas. Ao distribuir uma operação entre serviços, é melhor solicitar dados de forma síncrona e executar ações subseqüentes de forma assíncrona. Se for impossível acessar um dos serviços, a equipe ficará na fila assim que estiver disponível novamente.
Nesse sentido, é necessário revisar a abordagem da interface do usuário. O usuário deve ser notificado de que algumas ações não são executadas imediatamente, mas dentro de um certo tempo. Quando o aplicativo é processado, ele recebe um convite para ver os resultados.
Problema três: relatóriosSe usarmos uma arquitetura monolítica com um único banco de dados, para criar um relatório complexo, você pode escrever selecione e puxe vários rótulos de dados: mais cedo ou mais tarde eles serão exibidos. No entanto, em microsserviços, esses dados podem ser espalhados em diferentes bases.
Por exemplo, precisamos listar empresas com métricas específicas. Com uma lista simples de empresas, tudo funciona. E se você precisar adicionar métricas que estejam em outro banco de dados? Sim, podemos fazer uma solicitação adicional e solicitar métricas pelo TIN. E se essa lista precisar ser filtrada e classificada? A lista de empresas pode ser muito grande e, em seguida, precisamos introduzir um serviço adicional com seu próprio banco de dados - relatórios.
Problema quatro: alta complexidade de desenvolvimentoO trabalho em serviços distribuídos é mais complicado: todas as solicitações são feitas pela rede e podem ser desativadas; é necessário fornecer um mecanismo de retorno de chamada (será que a ligação será feita novamente? Quantas vezes?). Estes são os "tijolos" que gradualmente se acumulam e contribuem para aumentar a complexidade do projeto.
Os serviços podem ser desenvolvidos por várias equipes diferentes, e você precisa documentá-los, manter a documentação atualizada, avisar outras equipes ao alterar a versão. Estes são custos adicionais de mão-de-obra.
Se cada equipe tiver uma implantação independente, você precisará manter pelo menos a versão anterior e desabilitá-la somente depois que todos os consumidores do serviço tiverem mudado para a nova API.
Obviamente, podemos levar todas as APIs para algum tipo de artefato que estará disponível ao público. Mas, primeiro, os serviços podem ser escritos em diferentes idiomas e, segundo, isso não é recomendado. Por exemplo, em um de nossos projetos, recusamos isso a pedido do cliente, relacionado a considerações de segurança. Cada microsserviço possui um repositório separado e o cliente não dá acesso a eles.
No processo de desenvolvimento, tudo pode funcionar corretamente, e então - não. Acontece que, no caso de exceções, o aplicativo tenta infinitamente processá-las, e isso gera uma grande carga - todo o sistema "estabelece". Para evitar tais situações, você precisa configurar tudo, por exemplo, para limitar o número de tentativas, para não retornar esta chamada para a fila no mesmo segundo, etc.

O quinto problema: a complexidade do teste, rastreamento e depuraçãoPara testar um problema, você precisa baixar todos os microsserviços envolvidos. A depuração se torna uma tarefa não trivial e todos os logs precisam ser coletados em algum lugar do mesmo local. Nesse caso, você precisa do maior número possível de logs para descobrir o que aconteceu. Para rastrear o problema, você precisa entender todo o caminho que a mensagem percorreu. Os testes de unidade não são suficientes aqui, pois é provável que haja erros na junção de serviços. Ao fazer alterações, é possível verificar a operabilidade somente após a execução no suporte. Podemos limitar cada microsserviço a uma certa quantidade de memória (por exemplo, 500 megabytes), mas há momentos de pico de carga quando são necessários dois gigabytes. Há momentos em que o sistema começa a ficar mais lento. Como resultado, os recursos podem ser gastos em algo que não pertence às tarefas imediatas do cliente: por exemplo, existem apenas dois microsserviços comerciais e metade dos recursos são gastos em três microsserviços adicionais que dão suporte ao trabalho dos outros.

Microsserviço ou monólito: critérios de seleção
Ao escolher entre arquitetura monolítica e microsserviços, primeiro, você precisa prosseguir da complexidade da área de assunto e da necessidade de dimensionamento.
Se a área de assunto for simples e não for esperado um aumento global no número de usuários, os microsserviços poderão ser usados sem dúvida. Em outros casos, é melhor iniciar o desenvolvimento em um monólito e economizar recursos se a escala não for necessária. Se a área de assunto é complexa e, no estágio inicial, os requisitos finais não são definidos, também é melhor começar com um monólito - para não refazer os microsserviços várias vezes. Com o desenvolvimento do projeto, é possível distinguir suas partes individuais em microsserviços.

Uma vantagem é a presença de limites no início do projeto, pois isso ajudará a não quebrá-los durante o processo de desenvolvimento. Também faz sentido começar com um banco de dados, mas definir um esquema para cada módulo (por exemplo, um esquema de pagamento). Posteriormente, isso ajudará a simplificar a divisão dos módulos em microsserviços. Nesse caso, observamos os limites dos módulos e podemos usar microsserviços.
Cada módulo deve ter sua própria API, para que mais tarde possa ser alocado e transformou o módulo em um microsserviço.

Depois de determinar os limites dos módulos, você pode proceder à decomposição em microsserviços, se necessário. Em cerca de 90% dos casos, será possível permanecer no monólito, mas, se necessário, será mais fácil e barato alterar a arquitetura.
Em nossa prática de trabalhar com monólitos e microsserviços, chegamos às seguintes conclusões:
- Não mude para microsserviços apenas porque eles são usados pelo Netflix, Twitter, Facebook
- Comece com dois ou três microsserviços que interagem entre si, elabore detalhadamente todos os requisitos não funcionais (segurança, tolerância a falhas, escalabilidade etc.) e só depois passe para outros serviços
- Automatize tudo o que é possível
- Configurar monitoramento
- Gravar autotestes
- Não use transações distribuídas (mas esse não é um motivo para recusar a garantia de integridade dos dados).
- Se você deseja usar uma arquitetura de microsserviço, esteja preparado para o fato de que o desenvolvimento pode custar cerca de três vezes mais do que em um monólito. No entanto, ambas as tecnologias têm suas próprias desvantagens e vantagens, cada uma delas com seu próprio nicho.