Skip to main content

Microsserviço 10

· 11 min read
Leandro Andrade
Leandro Andrade
Software Developer

Dividir os nossos sistemas em microsserviços menores e mais especializados possui diversas vantagens. Entretanto, novas fontes de complexidade, principalmente no que tange ao comportamento dos sistemas no ambiente de produção.

A partir desse momento, temos vários servidores para monitorar, vários logs para filtrar e vários pontos em que a latência pode causar problemas. Considerando esse contexto, a primeira coisa que precisamos é monitorar pequenas partes e disponibilizar um recurso de agregação que permita ver o quadro geral e também permita fazer uma análise minunciosa dos dados obtidos.

Tendo um único microsserviço e um único servidor, vamos querer informações host como CPU e memória. Além disso, queremos logs da instância do microsserviço, monitorar a própria aplicação - observando-a de fora - por exemplo, os tempos de respostas.

Tendo um único microsserviço e vários servidores, temos mais complexidade. Queremos continuar monitorando tudo o que monitorávamos antes, mas deve ser possível isolar o problema. As métricas de cada host devem ser obtidas e agregadas, entretanto deve ser possível analisá-las de forma isolada. Além disso, métricas do balanceador de carga também precisam ser obtidas para que seja possível monitorar os tempos de respostas aos serviços downstream e assim ser possível evidenciar um possível gargalo do balanceador.

Tendo vários serviços, vários servidores, a agregação de métricas e logs possui um papel fundamental para um possível throubleshotting.

No fim do dia, o que precisamos é que todas as informações disponíveis em todos os hosts e serviços devem ser enviadas para uma ferramenta de agregação que permita, além de ver o todo, analisar cada caso individualmente.

observabilidade de monitoramento

Considerando essas informações, precisamos entender a diferença entre observabilidade de monitoramento. Quando falamos de observabilidade, estamos falando de compreender o estado interno do microsserviço a partir de suas saidas externas - quanto mais observável é um sistema, mais fácil será o entendimento de um problemas quando houver. Já o monitoramento, é algo que nós fazemos, uma atividade, e devemos pensar no que queremos alcançar com essa atividade.

Assim:

  • obervabilidade: o sistema tem, uma propriedade do sistema;
  • monitoração: o sistema faz, uma atividade que fazemos;

Ainda na observabilidade, algumas pessoas a definem a partir de 3 pilares na forma de métricas, logging e tracing distribuído, que basicamente ajudam a deixar o sistema observável. Quando se trata de deixar o sistema observável, precisamos pensar nas saídas que precisam ser coletadas para que seja possível interrogá-las. Quando acontecer um problema, queremos saber antes que os usuários descubram sozinhos. Assim, podemos seguir alguns passos que podem ajudar a melhorar a observabilidade da arquitetura como um todo.

agregação de logs

coletar informações de vários microsserviços e disponibilizá-las de forma centralizada.

Basicamente, os microsserviços registram os logs e um daemon coleta esses logs e os encaminham para um repositório. Podemos dizer que a agregação de logs é o mínimo que se precisa ter em uma arquitetura de microsserviços.

Com a ferramenta de agregação em operação, o próximo passo é padronizar o formato de envio de logs. Por exemplo, o JSON acaba sendo um formato que permite estruturas o log com diferentes informações e torná-las pesquisáveis. Além disso, podemos adicionar o correlation id no log para que seja possível pesquisar uma cadeia de chamadas que foram geradas a partir de um serviço, correlacionar todas as chamadas subsequentes relacionadas à requisição. Evidentemente que cada serviço pertencente à cadeia de chamadas deve ser capaz de "passar adiante" o ID de correlação.

Um exemplo desse tipo de ferramenta para agregação e visualização de logs é o elasticsearch e kibana.

agregação de métricas

capturar números dos microsserviços e da infraestrutura subjacente para ajudar a detectar problemas e apoiar no planejamento de capacidade.

O primeiro passo é coletar métricas sobre o comportamento do sistema durante um período suficientemente longo, a ponto de surgirem padrões claros. A partir do momento que conhecermos os padrões de uso, fica claro identificar se teremos infraestrutura suficiente para atender às nossas necessidades.

Saber o que é bom vai depender muito das métricas obtidas, por exemplo, cargas de CPU e códigos de erros HTTP. Além disso, quanto maior o sistema, mais detalhadas deverão ser as métricas, somado a ferramentas que permitam analisar minunciosamente esses dados.

tracing distribuído

o objetivo é rastrear o fluxo de chamadas.

Como microsserviços são um conjunto de processos que atuam em colaboração a fim de executar algum tipo de tarefa, queremos ser capazes de visualizar o relacionamento entre os microsserviços.

A implementação é dividida em 3 partes:

  1. capturar as informações de span nos microsserviços;
  2. enviar as informações capturadas para um coletor. É comum agentes locais encaminharem os dados;
  3. o coletor recebe as informações e as interpreta;

Exemplos de ferramentas são: Jaeger, Lightstep, Honeycomb.

como estamos

olhar para error budgets, SLA, SLO. O desafio é saber se os sistemas estão funcionando de forma esperada.

Quando estamos no monolítito, a tarefa torna-se mais simples já que tudo é um único processo. Já em sistemas distribuídos, precisamos olhar para o todo e identificar o que seria um comportamento aceitável.

Alguns conceitos balizadores são:

  • SLA (service-level agreement): no nível de empresa, acordo entre pessoas que criam sistemas e pessoas que os utilizam. Descreve não só o que os usuários podem esperar, mas também o que acontece se o sistema não atingir o nível de comportamento aceitável;
  • SLO (service-level objectives): no nível de equipe, diz o que a equipe se compromete a oferecer. O SLO de todas as equipes poderá satisfazer o SLA da empresa, mas claro que também existem SLOs que não tem relaçãa direta com o SLA da empresa, podendo ser metas de caráter interno. Exemplos de SLO são uptime esperado ou tempos de resposta aceitáveis;
  • SLI (service-level indicators): são indicadores de algo que nosso software faz, coletados a partir de dados reais. Exemplos são tempos de resposta de um processo, um cliente sendo cadastrado, um pedido feito, etc.

Assim:

  • SLA: empresa;
  • SLO: equipe;
  • SLI: produto;

Error Budget é um forma de deixar claro a quantidade de erros que é aceitável em um sistema. Por exemplo, o uptime do serviço deve ser 99,9% por trimestre, 24x7. Isso significa que o sistema poderia ficar inativo por 2h11 por trimestre. Se estiver abaixo do error budget esperado para o trimestre, pode ser interessante adiar o rollout daquele microsserviço escrito em uma nova linguagem de programação e focar na melhoria da confiabilidade do sistema.

Basicamente, error budget é sobre dar espaço de manobra para que as equipes possam tentar algo novo.

alertas

verificar o que deve gerar alertas.

Ocasionalmente, algo acontecerá nos sistemas e exigirá que alguém intervenha para tomar alguma atitude. O desafio em microsserviços é descobrir que tipos de problemas devem fazer com que uma pessoa seja informada e como deve ser informada.

O ponto é, à medida que as causas de possíveis problemas aumentarem, será necessário priorizar os tipos de ocorrências que geram determinados tipos de alertas, para que tenhamos a capacidade de separar o trivial do urgente.

O que devemos evitar é uma sobrecarga de alertas. Deve ser clara a separação entre trival, urgente e prioritário. Quando geramos alertas demais, não permitimos que os operadores foquem nos alertas prioritários. O propósito é direcionar a atenção do operador para os aspectos significativos da operação e do equipamento que exijam atenção imediata.

Um bom alerta pode ser:

  • relevante;
  • único;
  • na hora certa: receber o alerta com rapidez;
  • priorizado: dê informações suficientes ao operador;
  • compreensível: claro e legível;
  • deixa claro o que há de errado;
  • apresenta orientações;
  • foco: chame a atenção para os problemas mais importantes;

monitoração semântica

pensar de modo diferente na saúde dos nossos sistemas.

Verificar quais a propriedades o nosso sistema deve ter para considerarmos que está funcionando como esperado. Ao invés de analisar a presença de erros, devemos pensar se o sistema está se comportando do modo esperado a partir de modelos previamente definidos. Podemos definir modelos como:

  • clientes estão conseguindo se cadastrar;
  • os emails estão sendo enviados;
  • o saldo está sendo atualizado;

A ideia não é ter um pensamento low-level, mas sim afirmações em alto nível sobre o comportamento do sistema, já que muitas dessas afirmações serão e deverão ser definidas pelo P.O. O consolidado dessas afirmações será o modelo a ser seguido de comportamento esperado do sistema.

Com o modelo definido, temos duas maneiras de validar se o comportamento do sistema está conforme o modelo:

  • monitoração de usuários reais: observamos o que realmente acontece em nosso sistema de produção e comparamos isso o modelo semântico. O ponto é que, como teremos informações sobre algo que já aconteceu, a consequência é que um problema só será identificado depois de já ter ocorrido.
  • transações sintéticas: inserimos comportamento de um usuário simulado no sistema em produção com entradas conhecidas e saídas esperadas. Essas transações seriam disparadas regularmente para que problemas sejam identificados o mais rápido possível.

testes em produção

ver o todo em execução, todas as partes envolvidas.

Pode ser algo muito conveniente e seguro a ponto de identificar problemas antes dos usuário chegarem a perceber, mas precisamos garantir que efeitos colaterais não sejam gerados acidentalmente. Podemos usar:

  • testes A/B: implantamos duas versões diferentes da mesma funcionalidade, com os usuários vendo a funcionalidade "A" ou "B". Assim, podemos ver qual funcionalidade tem o melhor desempenho e decidir entre duas abordagens diferentes para fazer algo;
  • canary release: uma parcela dos usuários enxergam uma nova funcionalidade. Se essa nova funcionalidade se comportar bem, aumentamos a parcela de usuários que também enxergarão a nova funcionalidade, até o ponto em que a nova funcionalidade será enxergada por todos os usuários. Agora, caso a nova funcionalidade não se comporte como esperado, o impacto será em uma pequena parcela de usuários;
  • execução paralela: executamos duas implementações equivalentes da mesma funcionalidade, lado a lado. As requisições dos usuários serão encaminhadas para as duas versões que terão os resultados comparados;
  • smoke test: após o sistema ter sido implantado em produção, mas antes de ser lançado, são executados testes para garantir que o software está funcionando como esperado;
  • transações sintéticas: uma interação completa de um usuário simulado é introduzida no sistema;
  • engenharia do caos: inserção de falhas no ambiente de produção a fim de garantir que o serviço seja capaz de lidar com os problemas imprevistos. Exemplo de ferramenta e o Chaos Monkey;

Considerando todos esses blocos de construção da monitoração e observabilidade, faz-se necessário criar a padronização, por exemplo, escrever logs em um formato padrão, agregar logs em um só lugar, labels pré-definidas para as métricas. Deve ser fácil fazer o certo.

Ao escolher ferramentas para apoiar essa padronização, alguns critérios importantes precisam ser observados:

  • precisam ser democráticas: considere as necessidades de todas as pessoas que as utilizarão, já que terá de ser utilizável por todos da equipe. Garantir que seja utilizada não só em produção, mas também em desenvolvimento e testes. Isso contribuirá bastante;
  • devem ser fácil de integrar: escolher ferramentas que aceitem padrões abertos facilitará o trabalho de integração e de uma possível mudança de fornecedor mais tarde;
  • devem fornecer o máximo de contexto: temporal, relativo, relacional, proporcional (quem será impactado?);
  • devem fornecer acesso as informações: o mais rápido possível a ponto de ter a chance de identificar um problema antes que o usuário perceba, além de ter as informações à disposição quando alguém reclamar;
  • devem considerar o seu contexto e sua escala: caso sua escala aumente, o ideial é que a ferramenta acompanhe;

Comece por aqui

Assim, como primeiro passo podemos seguir:

  • obter taxa de CPU, E/S, memória;
  • obter o response time de cada serviço com correlation id registrado nos logs;
  • caso esteja em uma escala maior, tracing distribuído;
  • transações sintéticas para operações essenciais;
  • dizer com confiança: o sistema está funcionando de modo adequado?

Assim, o entendimento no contexto de sistemas distribuídos está relacionado ao quão observável o ecossistema está, já que sem isso, resolver problemas no ambiente de produção pode se tornar algo extremamente difícil. O primeiro passo deve ser agregação de logs com correlation id deste do início. O tracing distribuído pode vir depois. Não deixe que cada pequeno problema gere um alerta.