Rastreamento e monitoramento Istio: microsserviços e o princípio da incerteza

O princípio da incerteza de Heisenberg afirma que é impossível medir simultaneamente a posição de um objeto e sua velocidade. Se um objeto se mover, ele não terá um local. E se a localização é, isso significa que ele não tem velocidade.



Quanto aos microsserviços na plataforma Red Hat OpenShift (e executando o Kubernetes), graças ao software de código aberto correspondente, eles podem relatar simultaneamente seu desempenho e integridade. Obviamente, isso não refuta o antigo Heisenberg, mas elimina a incerteza ao trabalhar com aplicativos em nuvem. O Istio facilita a organização de rastreamento (rastreamento) e monitoramento desses aplicativos para manter tudo sob controle.

Definir terminologia


Rastreando , entendemos a atividade do sistema de registro. Parece bastante geral, mas na verdade uma das principais regras aqui é despejar dados de rastreamento no armazenamento apropriado sem se preocupar em formatá-los. E todo o trabalho de busca e análise de dados é confiado ao consumidor. O Istio usa o sistema de rastreamento Jaeger, que implementa o modelo de dados OpenTracing.

Por traços (Traços, e a palavra "traços" é usada aqui no significado de "traços", como, por exemplo, em um exame balístico), queremos dizer dados que descrevem completamente a passagem de uma solicitação ou unidade de trabalho, como se costuma dizer, "de e para". Por exemplo, tudo o que acontece desde o momento em que o usuário pressiona um botão em uma página da Web até o momento em que os dados são retornados, incluindo todos os microsserviços envolvidos nisso. Podemos dizer que um rastreio descreve completamente (ou simula) a passagem da solicitação para frente e para trás. Na interface do Jaeger, as trilhas são decompostas em componentes ao longo do eixo do tempo, como a forma como uma cadeia pode ser decomposta em links separados. Somente em vez de links, a trilha consiste nos chamados vãos.

Span é o intervalo desde o início de uma unidade de trabalho até sua conclusão. Continuando a analogia, podemos dizer que cada período é um elo separado na cadeia. Um período pode ou não ter um ou mais períodos filhos. Como resultado, o período de nível superior (período raiz) terá a mesma duração total que o rastreamento ao qual ele pertence.

O monitoramento é, de fato, a própria observação do seu sistema - através dos olhos, através de uma interface do usuário ou por meio de automação. O monitoramento é baseado em dados de rastreamento. No Istio, o monitoramento é implementado usando as ferramentas do Prometheus e possui uma interface de usuário correspondente. O Prometheus suporta o monitoramento automático usando alertas de alertas e gerenciadores de alerta.

Deixe os cortes


Para que o rastreamento seja possível, o aplicativo deve criar uma coleção de extensões. Em seguida, eles devem ser exportados para Jaeger, para que ele, por sua vez, crie uma representação visual do rastreamento. Entre outras coisas, esses períodos marcam o nome da operação, bem como os registros de data e hora de seu início e fim. Os spans são enviados encaminhando cabeçalhos de solicitação HTTP específicos do Jaeger de solicitações recebidas para solicitações de saída. Dependendo da linguagem de programação usada, isso pode exigir uma pequena modificação no código fonte do aplicativo. A seguir, é apresentado um exemplo de código Java (ao usar a estrutura Spring Boot) que adiciona cabeçalhos B3 (estilo Zipkin) à sua solicitação na classe de configuração Spring:


As seguintes configurações de cabeçalho são usadas:


Se você usa Java, pode deixar o código intocado, basta adicionar algumas linhas ao arquivo POM do Maven e definir variáveis ​​de ambiente. Aqui estão as linhas que você precisa adicionar ao arquivo POM.XML para implementar o Jaeger Tracer Resolver:


E as variáveis ​​de ambiente correspondentes são definidas no Dockerfile:


É isso, agora está tudo configurado e nossos microsserviços começarão a gerar dados de rastreamento.

Nós olhamos em termos gerais


O Istio inclui um painel de controle simples baseado no Grafana. Quando tudo está configurado e em execução na plataforma Red Hat OpenShift PaaS (em nosso exemplo, o Red Hat OpenShift e o Kubernetes são implementados no minishift), esse painel é iniciado com o seguinte comando:

open "$(minishift openshift service grafana -u)/d/1/istio-dashboard?refresh=5⩝Id=1" 

O painel Grafana permite avaliar rapidamente o sistema. Um fragmento deste painel é mostrado na figura abaixo:


Aqui você pode ver que o cliente de microsserviço chama a preferência de microsserviço v1 e, por sua vez, chama a recomendação de microsserviços v1 e v2. O painel Grafana possui um bloco Dashboard Row para métricas de alto nível, como o número total de solicitações (volume global de solicitações), porcentagem de solicitações bem-sucedidas (taxas de êxito) e erros 4xx. Além disso, há uma exibição de malha do servidor com gráficos para cada serviço e um bloco de linha de serviços para exibir informações detalhadas de cada contêiner para cada serviço.

Agora cavar mais fundo


Com um rastreamento configurado corretamente, o Istio, como eles dizem, logo após a instalação permite que você mergulhe na análise do desempenho do sistema. Na interface do usuário do Jaeger, é possível visualizar os rastreamentos e ver até que ponto eles são profundos, além de localizar visualmente gargalos de desempenho. Ao usar o Red Hat OpenShift na plataforma minishift, inicie a Jaeger UI usando o seguinte comando:

 minishift openshift service jaeger-query --in-browser 


O que pode ser dito sobre o rastreamento nesta tela:

  • É dividido em 7 extensões.
  • O tempo total de execução é 6,99 ms.
  • A recomendação de microsserviço, que é a última da cadeia, leva 0,69 ms.

Diagramas desse tipo permitem descobrir rapidamente uma situação em que o desempenho de todo o sistema é prejudicado devido a um único serviço com mau funcionamento.

Agora vamos complicar a tarefa e ativar duas instâncias do microsserviço de recomendação: v2 com o comando oc scale --replicas = 2 deployment / recomendação-v2. Aqui estão os pods que teremos depois disso:


Se agora voltarmos para Jaeger e implantarmos a extensão do serviço de recomendação, veremos para quais solicitações de pod são roteadas. Assim, podemos localizar facilmente os freios no nível específico do pod. Você deve olhar para o campo node_id:


Onde e como tudo vai


Agora vamos para a interface do Prometheus e esperamos ver que as solicitações entre a segunda e a primeira versão do serviço de recomendação são divididas em uma proporção de 2: 1, estritamente pelo número de pods em funcionamento. Além disso, este gráfico será alterado dinamicamente ao dimensionar os pods para cima e para baixo, o que será especialmente útil com o Canary Deployment (examinaremos esse esquema de implantação com mais detalhes na próxima vez).


É só o começo


De fato, hoje, como eles dizem, tocamos apenas um depósito de informações úteis sobre Jaeger, Grafana e Prometeu. Em geral, esse era o nosso objetivo - guiá-lo na direção certa e abrir as perspectivas do Istio.

E lembre-se, tudo isso já está embutido no Istio. Ao usar determinadas linguagens de programação (por exemplo, Java) e estruturas (por exemplo, Spring Boot), tudo isso pode ser realizado sem tocar completamente no próprio código do aplicativo. Sim, o código precisará ser ligeiramente modificado se você usar outros idiomas, principalmente Nodejs ou C #. Mas como a rastreabilidade (leitura, “rastreamento”) é um dos pré-requisitos para a criação de sistemas em nuvem confiáveis, em qualquer caso, você precisará editar o código, independentemente de possuir ou não o Istio. Então, por que não gastar o esforço com mais lucro?

Pelo menos, para sempre responder às perguntas “onde?” E “com que rapidez?” Com 100% de certeza.

Engenharia do caos no Istio: foi concebida


A capacidade de quebrar as coisas ajuda a garantir que elas não quebrem


O teste de software não é apenas uma coisa complicada, mas também importante. Ao mesmo tempo, testar a correção (por exemplo, se uma função retorna o resultado correto) é uma coisa, e testar em uma rede não confiável é uma tarefa completamente diferente (acredita-se frequentemente que a rede sempre funcione sem falhas, e esse é o primeiro dos oito conceitos errôneos sobre distribuição computação). Uma das dificuldades na solução desse problema é como simular falhas no sistema ou apresentá-las intencionalmente, executando a chamada injeção de falha. Isso pode ser feito modificando o código fonte do próprio aplicativo. Mas você não testará seu código original, mas sua versão, que simula especificamente falhas. Como resultado, você corre o risco de entrar em um abraço fatal da injeção de falhas e colidir com os heisenbags - falhas que desaparecem quando você tenta detectá-los.

E agora mostraremos como o Istio ajuda a lidar com essas dificuldades individualmente.

Como fica quando está tudo bem


Considere o seguinte cenário: temos dois pods para o nosso microsserviço de recomendação, retirados do tutorial do Istio. Um pod é marcado como v1 e o outro como v2. Como você pode ver, enquanto tudo funciona bem:


(A propósito, o número à direita é apenas um contador de chamadas para cada pod)

Mas não precisamos disso, não é? Bem, vamos tentar quebrar tudo sem tocar no código fonte.

Organizamos interrupções no trabalho do microsserviço


Abaixo está o arquivo yaml da regra de roteamento Istio, que pela metade dos casos falhará (erro 503 do servidor):


Observe que prescrevemos explicitamente que na metade dos casos o erro 503 deve ser retornado.

E aqui está uma captura de tela do comando curl lançado no loop depois que ativamos essa regra para simular falhas. Como você pode ver, metade das solicitações retorna o erro 503 e, independentemente de qual pod - v1 ou v2 - elas acessam:


Para restaurar a operação normal, basta remover esta regra; no nosso caso, o comando istioctl delete routerule recommend-503 -n tutorial. Aqui Tutorial é o nome do projeto Red Hat OpenShift que executa o tutorial do Istio.

Fazendo atrasos artificiais


Os erros artificiais 503 ajudam a testar a tolerância a falhas do sistema, mas a capacidade de prever e lidar com atrasos deve impressioná-lo ainda mais. E atrasos na vida real acontecem com mais frequência do que falhas. Um microsserviço de execução lenta é o veneno de que todo o sistema sofre. Graças ao Istio, você pode testar o código relacionado ao atraso no processamento sem alterá-lo. Para começar, mostraremos como fazer isso no caso de atrasos de rede introduzidos artificialmente.

Observe que, após esse teste, você pode precisar (ou querer) refinar seu código. A boa notícia é que, neste caso, você agirá proativamente, não reativamente. É assim que o ciclo de desenvolvimento deve ser construído: coding-testing-feedback-coding-testing ...

É assim que a regra se parece ... Embora você saiba o que? O Istio é tão simples, e esse arquivo yaml é tão claro que tudo neste exemplo fala por si só, basta dar uma olhada:


Na metade dos casos, teremos um atraso de 7 segundos. E isso não é o mesmo, como se inseríssemos o comando sleep no código-fonte, pois o Istio realmente atrasa a solicitação por 7 segundos. Como o Istio suporta o rastreamento de Jaeger, esse atraso é excelente na interface do usuário distorcida de Jaeger, como mostra a captura de tela abaixo. Preste atenção à solicitação longa no canto superior direito do diagrama - sua duração é de 7.02 segundos:


Este cenário permite testar o código em condições de latência da rede. E é claro que, ao remover esta regra, removeremos o atraso artificial. Repetimos, mas novamente fizemos tudo isso sem tocar no código fonte.

Não recue e não desista


Outro recurso do Istio que é útil para a engenharia do caos são as chamadas repetidas para o serviço um número especificado de vezes. O ponto aqui é não parar de tentar, quando a primeira solicitação terminar com o erro 503 - e, talvez, pela décima primeira vez que tivermos sorte. Talvez o serviço seja suspenso por um curto período de tempo por um motivo ou outro. Sim, esse motivo deve ser desenterrado e eliminado. Mas isso é mais tarde, mas por enquanto vamos tentar fazer o sistema continuar funcionando.

Portanto, queremos que o serviço cometa um erro 503 de tempos em tempos, e depois disso o Istio tentará entrar em contato com ele novamente. E aqui claramente precisamos de uma maneira de gerar o erro 503, sem tocar no próprio código ...

Pare de esperar! Nós apenas fizemos isso.

Este arquivo fará com que o serviço recomendação-v2 gere um erro 503 na metade do caso:


Obviamente, parte dos pedidos falhará:


E agora vamos usar a função Repetir Istio:


Essa regra de roteamento realiza três tentativas com um intervalo de dois segundos e deve reduzir (e, idealmente, remover completamente do radar) os erros 503:


Resumimos: fizemos isso para que o Istio, em primeiro lugar, gerasse um erro 503 para metade das solicitações. Além disso, o mesmo Istio faz três tentativas de reconectar-se ao serviço se ocorrer um erro 503. Como resultado, tudo funciona bem. Assim, usando a função Repetir, cumprimos nossa promessa de não desistir e desistir.

E sim, fizemos novamente sem tocar no código. Tudo o que precisávamos eram duas regras de roteamento do Istio:


Como não decepcionar um usuário ou sete, não espere


E agora reviramos a situação e consideramos o cenário em que você não precisa recuar e desistir apenas de um tempo fixo. E então você só precisa parar de tentar processar a solicitação para não forçar todo mundo a esperar por um serviço de frenagem. Em outras palavras, não protegeremos a posição perdida, mas passaremos para a linha de reserva para não decepcionar o usuário do site e não forçá-lo a definhar na ignorância.

No Istio, você pode definir o tempo limite da solicitação. Se o serviço exceder esse tempo limite, o erro 504 (Tempo limite do gateway) é retornado - novamente, tudo isso é feito através da configuração do Istio. Mas teremos que adicionar o comando sleep ao código fonte do serviço (e, é claro, executar a reconstrução e a reimplantação) para simular a operação lenta do serviço. Infelizmente, não funcionará de outra maneira.

Portanto, inserimos um sono de três segundos no código de serviço da recomendação v2, reconstruímos a imagem correspondente e fizemos um modo de contêiner novamente e agora adicionaremos um tempo limite usando a seguinte regra de roteamento do Istio:


A captura de tela acima mostra que estamos tentando entrar em contato com o serviço de recomendação se não recebermos uma resposta dentro de um segundo, ou seja, antes da ocorrência do erro 504. Após aplicar esta regra de roteamento (e adicionar um período de suspensão de três segundos ao código do serviço de recomendação) : v2), obtemos o seguinte:


Repetimos novamente, mas o tempo limite pode ser definido sem tocar no código fonte. E o bônus adicional aqui é que agora você pode modificar seu código para responder a um tempo limite e é fácil testar essas melhorias usando o Istio.

E agora todos juntos


Fazer um pouco de caos com o Istio é uma ótima maneira de testar seu código e a confiabilidade do seu sistema como um todo. Padrões de fallback, anteparos e disjuntores, mecanismos de falhas e atrasos artificiais e também chamadas e tempos limite repetidos serão muito úteis ao criar sistemas em nuvem tolerantes a falhas. Combinadas com o Kubernetes e o Red Hat OpenShift, essas ferramentas ajudam você a enfrentar o futuro com confiança.

Source: https://habr.com/ru/post/pt485136/


All Articles