Boas práticas para construir uma arquitetura de microsserviços

Sou graduado em Ciências da Computação, tenho participação ativa em projetos de comunidades open source, trabalho com desenvolvimento e arquitetura de software há mais de 12 anos. Atualmente, trabalho desenhando soluções de arquitetura para projetos de transformação digital em organizações financeiras.

Venho através deste “post” trazer em alto nível os principais pontos para construção de uma arquitetura de microsserviços com base em experiências anteriores.

A arquitetura de microsserviços tem se tornado cada vez mais adotada pelo mercado de TI por inúmeros motivos que serão abordados posteriormente. Porém, o uso desta arquitetura aumenta significativamente a complexidade para gerenciar e implementar um software. Baseado na minha experiência e na experiência de outros colegas podemos dizer que não se trata de apenas de inserir tecnologia dentro da organização, mas também de mudar a cultura das equipes envolvidas.

Definição

Os microsserviços são um estilo de arquitetura de software que requerem uma segregação das funcionalidades de uma aplicação. Basicamente, é uma abordagem para desenvolver uma única aplicação com uma série de pequenos serviços, cada um rodando com seu próprio processo e comunicação através de APIs com transporte HTTP.

Benefícios

Um micro serviço consiste em um conjunto de endpoints que são responsáveis por prover operações dentro de um domínio específico de informação. Seguem abaixo alguns dos benefícios:

  • A segregação da aplicação por domínio de informação permite escalabilidade individual de cada micro serviço.
  • A independência dos microsserviços permite que a aplicação continue funcionando caso haja erro em algum serviço, ou seja, apenas alguma funcionalidade ficará indisponível ao invés de toda aplicação ficar indisponível.
  • Agilidade no deploy de novas funcionalidades.
  • Permite trabalhar com diferentes tecnologias por micro serviço.

Características básicas

Seguem abaixo algumas das características mais importantes que cada micro serviço deve contemplar:

  • Possuir sua própria base de dados.
  • Ter independência dos demais para desenvolvimento e para realização de deploy.
  • Possuir autorização em nível de serviço utilizando protocolos como por exemplo OAuth e JWT.
  • A comunicação entre microsserviços deverá ser realizada sempre via exposição de API REST e/ou via publicação de eventos de negócio utilizando recursos de Message Broker.
  • Possuir endpoints para health check e Metrics para que os sistemas de monitoramento coletem informações sobre a saúde do micro serviço.
  • Realizar requisições assíncronas sempre que possível.
  • Os microsserviços devem possuir a documentação da API REST em um único local compartilhado, utlizando padrões como por exemplo o Swagger.
  • Os microsserviços devem gerar seus logs em um único repositório centralizado. Pode ser realizado via integração com o serviço de logs ou então através de agentes que irão coletar os logs do servidor e enviá-los para o repositório.

Bibliotecas compartilhadas

Existem elementos que precisam ser gerenciados quando realizar a comunicação com outros serviços. Por exemplo, descoberta de serviço, autenticação, circuit breaker, pool de conexão e timeouts. Ao invés de cada time implementar a seus elementos do zero, isto pode ser implementado em uma biblioteca separada que será utilizada pelos microsserviços.

A biblioteca não deverá incluir regras de negócios de qualquer serviço. O escopo deve ser limitado para auxiliar nas questões relativas a conectividade, transporte, logs e monitoramento.

Porém, há sempre um risco quando utilizamos bibliotecas compartilhadas. O maior desafio é gerenciar as versões quando houver alterações pois os serviços que estão em produção não receberão a atualização automaticamente. Poderá levar dias ou semanas para que o time realize a atualização da biblioteca dentro do seu micro serviço. Este cenário onde todos os serviços são desenvolvidos e deployados de forma independente, faz com que estas mudanças não sejam práticas. Portanto, é muito importante limitar o escopo desta biblioteca.

Devemos evitar também a utilização de libs de POJOs com fins de reaproveitamento de código pois os microsserviços devem ser totalmente independentes e desacoplados.

Autenticação

Todos os microsserviços deverão realizar a autorização das requisições que são realizadas por usuários ou por outros sistemas. Porém, a autenticação deve ser centralizada e realizada através um serviço específico que pode ser um micro serviço implementado de acordo com a necessidade da organização ou através de serviços de terceiros.

Comunicação

A comunicação entre serviços deverá ser realizada sempre via publicação de eventos e/ou de exposição de API. Se você possui um serviço acessando a base de dados de outro serviço diretamente, você está fazendo algo muito errado.

Message Broker

A arquitetura indica que a comunicação entre os microsserviços pode ser orientada a eventos de negócios, ou seja, um micro serviço poderá gerar um evento contendo informações que podem ser relevantes para outros microsserviços que, por sua vez, deverão realizar alguma operação com as informações recebidas.

A publicação de mensagens deverá ser no formato de serialização JSON pois é estável e amplamente utilizado para transferência de dados. Não necessita de bibliotecas além de um parser/serializador e está disponível em todas as linguagens de programação.

Virtualização

A virtualização de serviços é fortemente recomendada pois encaixa perfeitamente com a arquitetura de microsserviços.

Podemos criar uma imagem para cada micro serviço e versioná-lo de forma independente. Além disso, podemos trabalhar com a escalabilidade de forma independente. É possível criar balanceadores de carga para dividir o trabalho entre as instâncias de um micro serviço.

Podemos monitorar e limitar a utilização de recursos, como por exemplo, CPU, memória, rede e etc.

Descoberta de Serviços

Em um cenário containerizado onde é possível criar e excluir instâncias em tempo real de acordo com a necessidade, fica muito difícil saber quais serviços estão rodando em quais hosts. Portanto, necessitamos de um mecanismo que permite que um serviço encontre o outro de forma rápida e simples.

Existem recursos chamados Service Registry que são responsáveis por registrar serviços e expor o catálogo de serviço informando a disponibilidade e o host onde está rodando. Estes recursos podem ser encontrados no próprio gerenciador de containers, mas existem outras implementações como por exemplo o Eureka e o Consul que podem ser utilizados como alternativa.

Os microsserviços podem se registrar automaticamente durante sua inicialização através do desenvolvimento da integração com o Service Registry, ou podem ser registrados externamente através de agentes do host.

Interações Descentralizadas

Para implementar fluxos complexos onde múltiplos serviços precisam ser coordenados juntos deve-se utilizar a abordagem de interações descentralizadas, ou seja, não haverá um orquestrador centralizado responsável por coordenar as chamadas dos serviços. Ao invés disso, os microsserviços deverão, dentro do possível, ter total responsabilidade sobre suas regras, tentar novamente quando falhar e gerar eventos quando concluir.

Interações descentralizadas possuem baixo acoplamento e alta coesão pois cada micro serviço é responsável apenas pelo seu domínio de informação. Estas características aumentam a autonomia da equipe responsável pelo micro serviço para implementação de novas funcionalidades.

ID de Rastreamento

O consumo de um endpoint de um micro serviço pode resultar em uma cadeia de execuções de outros microsserviços, isso dificulta o rastreamento dentro do fluxo quando uma ação ocorrer. A forma mais utilizada para resolver este cenário é adicionar um ID único na requisição do endpoint do micro serviço. Este ID deverá ser repassado adiante para cada serviço que será consumido. Desta forma é possível rastrear a ação no sistema centralizado de logs e de monitoramento.

Idempotência

Neste cenário onde os microsserviços podem ser reexecutados quando falharem, o desafio é identificar se o micro serviço realizou a tarefa ou não antes de falhar. Para manter o funcionamento correto do fluxo de negócio, os microsserviços precisam ser idempotentes, ou seja, o resultado do micro serviço deverá ser sempre o mesmo se as entradas forem sempre as mesmas. Além disso, isto significa que não deverá ter impacto negativo do micro serviço se for executado inúmeras vezes.

A abordagem mais utilizada para realizar este tipo de controle é criar um identificador único (hash) do payload de entrada. Este identificador deverá ser armazenado pois será consultado posteriormente para verificar se já foi processado, para então tomar a decisão se a mensagem recebida deverá ser processada ou não.

Circuit Breaker

Quando o micro serviço está falhando, é natural haver tentativas de requisições. Um serviço que está offline pode receber milhares de requisições de outros serviços. Portanto, é necessário ter um controle mais eficiente com a finalidade de reduzir custos de recursos como por exemplo a rede.

Circuit Breaker previne que requisições destinadas a falhar sejam realizadas, se as requisições estão resultando em falhas, altera a flag e interrompe as tentativas de enviar as requisições por um período de tempo. Deverá enviar apenas uma requisição periodicamente para verificar se o serviço está de volta online para que altere a flag novamente.

Esta lógica deverá estar abstraída da lógica do serviço, geralmente estará embutida em um framework ou biblioteca customizada.

Telemetria

O monitoramento centralizado dos microsserviços é um componente central corporativo, ou seja, todos os microsserviços deverão prover as informações de métricas e healthcheck de forma padronizada.

A telemetria é utilizada para monitorar a saúde de componentes como por exemplo, containers, banco de dados, message brokers e hosts. Também será utilizado para monitorar a saúde dos microsserviços compo por exemplo, a latência, as taxas de erros, quantidades de requisições, entre outros.

Poderemos atuar antecipadamente para resolver problemas do tipo de escalabilidade e de conectividade através da parametrização de métricas e geração de alertas.

Basicamente a telemetria consiste em:

  • Os microsserviços devem gerar suas próprias métricas de forma padronizada.
  • Para armazenar as métricas coletadas é necessário a utilização de um banco de dados do tipo time series.
  • Para apresentar os dashboards é necessário a utilização de ferramenta UI que irá consultar as métricas do banco de dados.

DevOps

Em um ambiente dinâmico onde microsserviços podem nascer ou podem morrer, é recomendado a utilização de imagens docker que por suas vez deverão estar armazenadas em um repositório específico para este fim.

Deve existir um repositório de código-fonte por micro serviço, pois necessitamos que ele seja versionado, empacotado e implantado de forma independente.

Os microsserviços devem possuir a parametrização em repositório externo para cada ambiente (desenvolvimento, homologação e produção).

Deve ser utilizada uma ferramenta de automação para implementar o pipeline de integração contínua e/ou deploy contínuo. Deverão existir algumas etapas no pipeline, como por exemplo, compilação, execução de testes unitários, execução de testes de integração, empacotamento, deploy e promoção entre ambientes.

De forma geral, o resultado final que a automação deverá trazer é a possibilidade de realizar deploy de qualquer versão de qualquer micro serviço em qualquer ambiente.

Os sistemas de monitoramento devem contemplar todos os microsserviços.

A equipe de operações deverá garantir a escalabilidade dos serviços e também prover recursos como banco de dados, caches, tópicos, serviços de email e etc.

Cultura organizacional

As equipes desenvolvem, implantam e operam os microsserviços sob sua responsabilidade. Isto significa que as equipes devem ter autonomia com relação as suas atividades no dia a dia.

Esta abordagem traz mais responsabilidade e domínio de negócio para as equipes. Diferentemente da cultura tradicional onde temos uma série de processos burocráticos para cumprir e diferentes setores da organização dedicados a realizar apenas um tipo de tarefa.

A idéia é que a autonomia da equipe seja vertical, ou seja, vai do desenvolvimento até o acompanhamento pós produção do micro serviço.

Referências

 

2 comentários

  1. Gabriel Valente Prestes Responder

    Primeiramente por alguma razão no Chrome Versão 65.0.3325.181 (Versão oficial) 64 bits quando vou preencher um comentário os dizeres ‘E-mail’, ‘Nome’, ‘O que você está pensando’ estão ficando sobrepostos ao meu texto. Como se a função JS não funcionasse.

    Mas o ponto importante aqui é parabenizar pelo excelente texto. Um dos pontos que deixo como questionamento é: No texto é como um item obrigatório o uso de Docker e Orquestradores. Foi força do verbo ‘deve-se’ ou entendes que a utilização e administração correta de microsserviços só ocorrerá adequadamente com estes modelos(Docker/Orquestradores)?

    Corrigir no texto: autar – atuar

    • Inácio Klassmann Autor do postResponder

      Gabriel, obrigado por apontar os erros!
      O bug do texto sobreposto também está ocorrendo no meu browser (Firefox). Iremos verificar este problema.
      Com relação ao uso do Docker, a palavra ‘deve-se’ realmente é muito forte, acredito que ‘recomendado’ seja mais adequado.
      Podemos realizar a gestão de uma arquitetura de microsserviços sem a utlização de Docker, porém é muito custoso e gera trabalho manual pois perderíamos algumas das vantagens como por exemplo a escalabilidade, o deploy e o controle de recurso computacional.
      Vou atualizar o texto para adequar melhor ao seu questionamento.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *