Integração do OpenTelemetry à Arquitetura de Referência para Aplicações Modernas – Relatório de Progresso

NGINX | 08 de março de 2022

Quando apresentamos a Arquitetura de Referência para Aplicações Modernas da NGINX (MARA) no outono passado, durante o Sprint 2.0, enfatizamos que nossa intenção não era criar um “brinquedo”, como algumas arquiteturas, mas sim uma solução “robusta, testada e pronta para implantação em aplicações de produção executadas em ambientes Kubernetes”. Para um projeto como esse, as ferramentas de observabilidade são absolutamente essenciais. Todos os integrantes da equipe do MARA vivenciaram em primeira mão como a falta de visibilidade sobre o estado e o desempenho transforma o desenvolvimento e a entrega de aplicações em uma experiência frustrante. Chegamos imediatamente ao consenso de que o MARA precisava incluir instrumentação para depuração e rastreamento em um ambiente de produção.

Outro princípio norteador da MARA é a preferência por soluções de código aberto. Neste artigo, descrevemos como nossa busca por uma ferramenta de observabilidade multifuncional e de código aberto nos levou ao OpenTelemetry e, em seguida, detalhamos as concessões, decisões de projeto, técnicas e tecnologias que usamos para integrar o OpenTelemetry a uma aplicação de microsserviços desenvolvida com Python, Java e NGINX.

Esperamos que conhecer nossas experiências ajude você a evitar possíveis armadilhas e a acelerar sua própria adoção do OpenTelemetry. Observe que esta publicação é um relatório de progresso sujeito a mudanças com o tempo – prevemos que as tecnologias abordadas amadurecerão dentro de um ano. Além disso, embora apontemos as limitações atuais de alguns projetos, somos imensamente gratos por todo o trabalho de código aberto que está sendo realizado e estamos entusiasmados para acompanhar sua evolução.

Nossa aplicação

Como aplicação a ser integrada a uma solução de observabilidade, escolhemos o Bank of Sirius, nossa bifurcação do aplicativo de exemplo Bank of Anthos do Google. Trata-se de uma aplicação web com arquitetura de microsserviços que pode ser implantada por meio de infraestrutura como código. Há inúmeras maneiras de melhorar o desempenho e a confiabilidade dessa aplicação, mas ela é madura o suficiente para ser razoavelmente considerada uma aplicação brownfield. Por isso, acreditamos que ela seja um bom exemplo para mostrar como integrar o OpenTelemetry a uma aplicação, pois, em teoria, o rastreamento distribuído fornece informações valiosas sobre as deficiências da arquitetura de uma aplicação.

Como mostra o diagrama, os serviços que dão suporte à aplicação são relativamente simples.

Imagem cortesia do Google

Como escolhemos o OpenTelemetry

Nossa jornada até a escolha do OpenTelemetry foi bastante sinuosa e passou por várias etapas.

Criando uma lista de recursos desejados

Antes de avaliar as ferramentas de observabilidade de código aberto disponíveis, identificamos quais aspectos da observabilidade são importantes para nós. Com base em nossas experiências anteriores, elaboramos a lista a seguir.

  • Registro de logs – Da forma como usamos o termo, isso significa a geração, pelos aplicativos, de conjuntos clássicos de mensagens delimitadas por quebras de linha; o aplicativo Bank of Sirius estrutura seus logs no formato Bunyan
  • Rastreamento distribuído – Tempos e metadados de cada componente em toda a aplicação, semelhantes aos fornecidos por empresas de gerenciamento de desempenho de aplicações (APM)
  • Métricas – Medições coletadas ao longo de um período e representadas graficamente como dados de séries temporais
  • Agregação e notificação de exceções/erros – Uma coleção agregada das exceções e dos erros mais comuns, que deve permitir pesquisas para que possamos determinar quais erros de aplicação são mais frequentes
  • Verificações de integridade – Sondagens periódicas enviadas aos serviços para determinar se estão funcionando corretamente no aplicativo
  • Introspecção do estado de execução – Um conjunto de APIs visíveis apenas para administradores que retornam informações sobre o estado de execução da aplicação
  • Despejos de heap/core – Instantâneos abrangentes do estado de execução de um serviço; para nossos fins, o fator importante é a facilidade de obter esses despejos sob demanda ou quando um serviço falha

Comparando os recursos das ferramentas com a lista de requisitos

É claro que não esperávamos que uma única ferramenta ou abordagem de código aberto incluísse todos esses recursos, mas isso pelo menos nos deu uma base ideal para comparar as ferramentas disponíveis. Consultamos a documentação de cada ferramenta para descobrir quais dos sete recursos da nossa lista de desejos ela oferece. A tabela resume nossas conclusões.

Tecnologia Logs Rastreamento Distribuído Métricas Agregação de Erros Verificações de Integridade Introspecção em Tempo de Execução Dumps de Heap/CoreELK + Elastic APM ✅ ✅ ✅ ✅ ✅ ❌ ❌Grafana ✅ ✅ ✅ ✅ ✅ ❌ ❌Graylog ✅ ❌ ❌ ❌ ❌ ❌ ❌Jaeger ❌ ✅ ❌ ✅ ❌ ❌ ❌OpenCensus ❌ ❌ ✅ ❌ ❌ ❌ ❌OpenTelemetry Beta ✅ ✅ ✅ ✅ * ❌ ❌Prometheus ❌ ❌ ✅ ❌ ❌ ❌ ❌StatsD ❌ ❌ ✅ ❌ ❌ ❌ ❌Zipkin ❌ ✅ ❌ ✅ ❌ ❌ ❌

* Como uma extensão

Montar esta tabela foi um choque de realidade. As diversas ferramentas diferem tanto em seus recursos e finalidades que não foi possível considerá-las parte da mesma categoria — seria como comparar alhos com bugalhos!

Por exemplo, ELK (Elasticsearch-Logstash-Kibana, além do Filebeat) e o Zipkin fazem coisas tão fundamentalmente diferentes que tentar compará-los acaba gerando mais confusão do que esclarecimento. Infelizmente, a “ampliação do escopo” só torna tudo ainda mais nebuloso — sem dúvida em resposta às solicitações dos usuários, foram adicionados recursos secundários à finalidade principal de cada ferramenta, criando sobreposição com outras ferramentas. À primeira vista, o ELK armazena e visualiza logs, enquanto o Zipkin faz rastreamento distribuído. Mas, ao se aprofundar um pouco mais no portfólio de produtos da Elastic, você logo encontra o Elastic APM, que oferece suporte a rastreamento distribuído e é até compatível com o Jaeger.

Além da questão do desvio de escopo, muitas das ferramentas podem ser integradas entre si, resultando em diferentes combinações de coletores, agregadores, painéis e assim por diante. Algumas das tecnologias são compatíveis entre si, enquanto outras não.

Realizando uma investigação qualitativa

Sendo assim, essa tabela comparativa não nos forneceu uma visão precisa o suficiente para fundamentar nossa escolha. Precisávamos realizar uma investigação qualitativa dos objetivos, princípios orientadores e possíveis rumos futuros de cada projeto, partindo do pressuposto de que, quanto mais semelhantes fossem os valores de um projeto aos nossos, maior seria a probabilidade de continuarmos compatíveis ao longo do tempo. Ao visitar as páginas dos projetos, percebemos isso imediatamente na página do OpenCensus.

O OpenCensus e o OpenTracing se uniram para formar o OpenTelemetry, que representa a próxima versão principal do OpenCensus e do OpenTracing. O OpenTelemetry oferecerá compatibilidade retroativa com as integrações existentes do OpenCensus, e continuaremos a disponibilizar correções de segurança para as bibliotecas existentes do OpenCensus por dois anos.

Esse foi um dado fundamental para nós. Sabíamos que não podíamos garantir que nossa escolha continuaria adequada no futuro, mas queríamos ao menos ter certeza de que ela contaria com um forte apoio da comunidade dali em diante. Com essa informação, pudemos eliminar o OpenCensus da nossa lista de candidatos. Provavelmente também não seria uma boa ideia usar o Jaeger, pois ele é a implementação de referência do projeto OpenTracing, que agora está oficialmente obsoleto — a maior parte das novas contribuições será direcionada ao OpenTelemetry.

Então, fomos pesquisar mais sobre o OpenTelemetry Collector.

O OpenTelemetry Collector oferece uma implementação independente de fornecedor para receber, processar e exportar dados de telemetria. Além disso, elimina a necessidade de executar, operar e manter vários agentes/coletores para oferecer suporte a formatos de dados de telemetria de código aberto (por exemplo, Jaeger, Prometheus etc.) e enviá-los a vários back-ends comerciais ou de código aberto.

O OpenTelemetry Collector atua como um agregador que nos permite combinar diferentes métodos de coleta e instrumentação de observabilidade com diferentes backends. Basicamente, nossa aplicação pode coletar traces com o Zipkin e métricas do Prometheus, que podemos então enviar para um backend configurável e visualizar com o Grafana. Várias outras combinações desse design são possíveis, portanto podemos experimentar diferentes abordagens para descobrir quais tecnologias são mais adequadas ao nosso caso de uso.

Integração do OpenTelemetry como o caminho a seguir

Basicamente, o OpenTelemetry Collector nos conquistou porque, em teoria, permite alternar entre diferentes tecnologias de observabilidade. Apesar da relativa imaturidade do projeto, decidimos nos aventurar e usar o OpenTelemetry apenas com integrações de código aberto, pois a única maneira de entender esse cenário é usando as tecnologias.

No entanto, ainda faltam alguns componentes no OpenTelemetry Collector, por isso precisamos recorrer a outras tecnologias para obter essas funcionalidades. As seções a seguir resumem nossas escolhas e os motivos por trás delas.

Implementação de logs

O logging é uma parte aparentemente simples da observabilidade, mas que rapidamente leva a decisões complexas. É simples porque basta coletar a saída de logs dos seus contêineres, mas complexo porque, em seguida, é preciso decidir onde armazenar os dados, como transportá-los até esse local, como indexá-los para que sejam úteis e por quanto tempo mantê-los. Para que sejam úteis, os arquivos de log precisam permitir buscas fáceis com base em critérios variados o suficiente para atender às necessidades de diferentes usuários.

Analisamos o suporte a logs com o OpenTelemetry Collector e, no momento em que este texto foi escrito, ele ainda estava em uma fase beta bastante inicial. Decidimos usar o ELK para logs no curto prazo, enquanto continuamos avaliando outras opções.

Na ausência de qualquer motivo convincente para não fazê-lo, optamos por usar as ferramentas do Elasticsearch, o que nos permitiu dividir a implantação em nós de ingestão, coordenação, mestre e dados. Para facilitar a implantação, usamos um chart da Bitnami. Para transportar os dados, implantamos o Filebeat como parte de um DaemonSet do Kubernetes. Adicionamos a funcionalidade de pesquisa implantando o Kibana e aproveitando os índices, as pesquisas, as visualizações e os painéis pré-carregados.

Rapidamente ficou claro que, embora essa solução funcionasse, a configuração padrão consumia muitos recursos, o que dificultava sua execução em ambientes com menos recursos, como K3S ou Microk8s. A inclusão da possibilidade de ajustar o número de réplicas de cada componente resolveu esse problema, mas ocasionou algumas falhas possivelmente decorrentes do esgotamento de recursos ou de volumes excessivos de dados.

Longe de ficarmos decepcionados com isso, vemos a situação como uma oportunidade para avaliar o desempenho do nosso sistema de logs com diferentes configurações, além de investigar outras opções, como o Grafana Loki e o Graylog. É possível que descubramos que soluções de logs mais leves não oferecem o conjunto completo de recursos de que alguns usuários precisam e que podem obter com ferramentas que consomem mais recursos. Dada a natureza modular do MARA, provavelmente criaremos módulos adicionais para essas opções, oferecendo mais possibilidades de escolha aos usuários.

Implementação de rastreamento distribuído

Além de determinar qual ferramenta oferece a funcionalidade de rastreamento desejada, precisávamos considerar como implementar a solução e quais tecnologias deveriam ser integradas a ela.

Primeiro, queríamos garantir que nenhuma instrumentação afetasse negativamente a qualidade do serviço da própria aplicação. Todos nós já havíamos trabalhado com sistemas cujo desempenho caía de forma previsível uma vez por hora durante a exportação dos logs, e não queríamos reviver essa experiência. Nesse aspecto, a arquitetura do OpenTelemetry Collector nos pareceu muito interessante, pois permite executar uma instância por host. Cada coletor recebe dados de clientes e agentes de todas as diferentes aplicações em execução no host (em contêineres ou não). O coletor agrega e, possivelmente, compacta os dados antes de enviá-los a um backend de armazenamento, o que nos pareceu ideal.

Em seguida, avaliamos o suporte ao OpenTelemetry nas diferentes linguagens de programação e frameworks que usamos na aplicação. Nesse ponto, as coisas ficaram um pouco mais complicadas. Apesar de usarmos apenas as duas linguagens de programação e os respectivos frameworks apresentados na tabela, o nível de complexidade foi surpreendentemente alto.

Linguagem Framework Número de ServiçosJava Spring Boot 3Python Flask 3

Para adicionar o rastreamento no nível da linguagem, primeiro testamos os agentes de instrumentação automática do OpenTelemetry, mas achamos a saída deles poluída e confusa. Temos certeza de que isso melhorará à medida que as bibliotecas de instrumentação automática amadurecerem, mas, por enquanto, descartamos os agentes do OpenTelemetry e decidimos incorporar o rastreamento ao nosso código.

Antes de partir para uma implementação direta do rastreamento no código, primeiro configuramos o OpenTelemetry Collector para enviar todos os dados de rastreamento a uma instância do Jaeger em execução local, onde poderíamos visualizar a saída com mais facilidade. Isso foi bastante útil, pois pudemos experimentar diferentes formas de apresentação visual dos dados de rastreamento enquanto descobríamos como integrar totalmente o OpenTelemetry. Por exemplo, se percebêssemos que uma biblioteca cliente HTTP não incluía dados de rastreamento ao fazer chamadas para um serviço do qual dependia, adicionávamos imediatamente o problema à nossa lista de correções. O Jaeger oferece uma boa visualização de todos os diferentes spans em um único trace:

Rastreamento distribuído para Python

Adicionar rastreamento ao nosso código Python foi relativamente simples. Adicionamos dois arquivos-fonte Python que são referenciados por todos os nossos serviços e atualizamos os respectivos arquivos requirements.txt para incluir as dependências relevantes de opentelemetry-instrumentation-*. Com isso, pudemos usar a mesma configuração de rastreamento em todos os serviços Python, além de incluir o ID de rastreamento de cada solicitação nas mensagens de log e incorporá-lo às solicitações enviadas a serviços dependentes.

Rastreamento distribuído para Java

Em seguida, voltamos nossa atenção para os serviços Java. Usar as bibliotecas Java do OpenTelemetry diretamente em um projeto criado do zero é relativamente simples – basta importar as bibliotecas necessárias e usar diretamente a API de rastreamento. No entanto, se você usa o Spring, como nós, há outras decisões a tomar.

O Spring já conta com uma API de rastreamento distribuído, Spring Cloud Sleuth. Ela fornece uma fachada sobre a implementação subjacente de rastreamento distribuído que faz o seguinte, conforme descrito na documentação:

  • Adiciona IDs de trace e span ao MDC do Slf4J, permitindo extrair, em um agregador de logs, todos os logs de um determinado trace ou span.
  • Instrumenta pontos comuns de entrada e saída de aplicações Spring (filtro de servlet, RestTemplate, ações agendadas, canais de mensagens, cliente Feign).
  • Se o spring-cloud-sleuth-zipkin estiver disponível, … [gera e relata] rastreamentos compatíveis com o Zipkin via HTTP. Por padrão, ele os envia para um serviço coletor do Zipkin no localhost (porta 9411). Configure a localização do serviço usando spring.zipkin.baseUrl.

A API também nos permite adicionar rastreamentos a tarefas anotadas com @Scheduled.

Em outras palavras, usando apenas o Spring Cloud Sleuth, obtemos nativamente rastreamentos no nível dos endpoints do serviço HTTP, o que é uma boa vantagem. Como nosso projeto já usa o Spring, decidimos manter tudo dentro desse framework e utilizar os recursos oferecidos. No entanto, encontramos alguns problemas ao integrar tudo com o Maven:

  • O módulo Spring Cloud Sleuth Autoconfigure ainda está em uma versão de marco.
  • O módulo Spring Cloud Sleuth Autoconfigure depende de uma versão alfa desatualizada da opentelemetry-instrumentation-api. Atualmente, não há nenhuma versão 1.x recente e não alfa dessa biblioteca.
  • O projeto deve obter o modelo de objeto do projeto pai (POM) spring-cloud-build dos repositórios Spring Snapshot devido à forma como o Spring Cloud Sleuth codifica suas referências de dependência para versões de marco.

Isso tornou a definição do nosso projeto Maven um pouco mais complicada, pois tivemos que fazer com que o Maven obtivesse os artefatos tanto dos repositórios do Spring quanto do Maven Central, uma indicação clara de quão incipiente era o suporte ao OpenTelemetry no Spring Cloud. Mesmo assim, seguimos em frente e criamos um módulo comum de telemetria para configurar o rastreamento distribuído usando o Spring Cloud Sleuth e o OpenTelemetry, incluindo diversas funções auxiliares e extensões relacionadas à telemetria.

No módulo comum de telemetria, ampliamos a funcionalidade de rastreamento fornecida pelas bibliotecas Spring Cloud Sleuth e OpenTelemetry oferecendo:

Além disso, implementamos um cliente HTTP compatível com o Spring baseado no Apache HTTP Client, pois queríamos mais métricas e possibilidades de personalização ao fazer chamadas HTTP entre serviços. Nessa implementação, os identificadores de rastreamento e de span são enviados como cabeçalhos quando serviços dependentes são chamados, permitindo que sejam incluídos na saída de rastreamento. Além disso, essa implementação fornece métricas do pool de conexões HTTP que são agregadas pelo OpenTelemetry.

No fim das contas, foi trabalhoso integrar o rastreamento ao Spring Cloud Sleuth e ao OpenTelemetry, mas acreditamos que valeu a pena. Esperamos que este projeto e esta publicação ajudem a iluminar o caminho para outras pessoas que queiram seguir por essa direção.

Rastreamento distribuído para NGINX

Para obter rastreamentos que conectassem todos os serviços durante todo o ciclo de vida de uma solicitação, precisávamos integrar o OpenTelemetry ao NGINX. Para isso, usamos o módulo OpenTelemetry para NGINX (ainda em versão beta). Como prevíamos que poderia ser difícil obter binários funcionais do módulo que fossem compatíveis com todas as versões do NGINX, criamos um repositório no GitHub com imagens de contêiner que incorporam módulos do NGINX sem suporte oficial. Executamos compilações todas as noites e distribuímos o binário do módulo por meio de imagens do Docker fáceis de importar.

Ainda não integramos esse processo ao processo de compilação do NGINX Ingress Controller no projeto MARA, mas planejamos fazer isso em breve.

Implementando a coleta de métricas

Depois de concluir a integração do rastreamento com o OpenTelemetry, passamos a nos concentrar nas métricas. Não havia métricas para nossos aplicativos baseados em Python, e decidimos adiar sua adição por enquanto. Para os aplicativos Java, o código-fonte original do Bank of Anthos, que usa o Micrometer em conjunto com o Stackdriver do Google Cloud, oferece suporte a métricas. No entanto, removemos esse código do Bank of Sirius após criar uma bifurcação do Bank of Anthos, pois ele não nos permitia configurar um backend de métricas. Ainda assim, o fato de já existirem pontos de instrumentação para métricas evidenciava a necessidade de uma integração adequada de métricas.

Para chegar a uma solução configurável e pragmática, primeiro analisamos o suporte a métricas nas bibliotecas Java do OpenTelemetry e no Micrometer. Ao pesquisar comparações entre as tecnologias, encontramos vários resultados que enumeravam as limitações do OpenTelemetry quando usado como API de métricas na JVM, embora as métricas do OpenTelemetry ainda estivessem em fase alfa no momento da redação deste texto. O Micrometer é uma camada de fachada madura para métricas na JVM, semelhante ao slf4j por fornecer um wrapper de API comum que serve de interface para uma implementação de métricas configurável, em vez de ser uma implementação de métricas propriamente dita. Curiosamente, ele é a API de métricas padrão do Spring.

Nesse momento, estávamos ponderando os seguintes fatos:

  • O OpenTelemetry Collector pode consumir métricas de praticamente qualquer fonte, incluindo Prometheus, StatsD e o OpenTelemetry Protocol (OTLP) nativo
  • O Micrometer também oferece suporte a um grande número de backends de métricas, incluindo Prometheus e StatsD
  • O SDK de métricas do OpenTelemetry para a JVM permite o envio de métricas via OTLP

Após alguns experimentos, decidimos que a abordagem mais pragmática seria usar a fachada do Micrometer com uma implementação subjacente do Prometheus e configurar o OpenTelemetry Collector para usar a API do Prometheus a fim de coletar métricas da aplicação. Sabíamos, por meio de diversos artigos, que a ausência de alguns tipos de métricas no OpenTelemetry pode causar problemas, mas nossos casos de uso não precisam desses tipos, então essa solução de compromisso foi aceitável.

Descobrimos algo interessante sobre o OpenTelemetry Collector: embora o tivéssemos configurado para receber rastreamentos via OTLP e métricas via API do Prometheus, ele ainda pode ser configurado para enviar ambos os tipos de dados a um receptor de dados externo usando OTLP ou qualquer outro protocolo compatível. Isso nos permitiu testar facilmente nossa aplicação com a LightStep.

No geral, implementar métricas em Java foi relativamente simples, pois as escrevemos em conformidade com a API do Micrometer, que conta com inúmeros exemplos e tutoriais disponíveis. Provavelmente, o mais difícil, tanto para as métricas quanto para o rastreamento, foi configurar corretamente o grafo de dependências do Maven no arquivo pom.xml do telemetry-common.

Implementando a agregação de erros

O projeto OpenTelemetry não inclui, por si só, a agregação de erros em sua missão, nem oferece uma implementação de marcação de erros tão elegante quanto soluções como Sentry ou Honeybadger.io. Ainda assim, decidimos usar o OpenTelemetry para agregar erros no curto prazo, em vez de adicionar outra ferramenta. Com uma ferramenta como o Jaeger, podemos pesquisar por error=true para encontrar todos os rastreamentos que apresentam uma condição de erro. Isso pelo menos nos dá uma ideia dos problemas que ocorrem com mais frequência. No futuro, poderemos considerar adicionar uma integração com o Sentry.

Implementando verificações de integridade e introspecção em tempo de execução

No contexto da nossa aplicação, as verificações de integridade permitem que o Kubernetes saiba se um serviço está íntegro ou se concluiu sua fase de inicialização. Quando o serviço não está íntegro, o Kubernetes pode ser configurado para encerrar ou reiniciar instâncias. Em nossa aplicação, decidimos não usar as verificações de integridade do OpenTelemetry porque consideramos a documentação insuficiente.

Em vez disso, para os serviços JVM, usamos um projeto Spring chamado Spring Boot Actuator, que fornece não apenas endpoints de verificação de integridade, mas também endpoints de introspecção em tempo de execução e de despejo de heap. Para os serviços Python, usamos o módulo Flask Management Endpoints, que oferece um subconjunto dos recursos do Spring Boot Actuator. Atualmente, ele fornece apenas informações personalizáveis sobre a aplicação e verificações de integridade.

O Spring Boot Actuator integra-se à JVM e ao Spring para fornecer endpoints de introspecção, monitoramento e verificação de integridade. Além disso, ele oferece um framework para adicionar informações personalizadas aos dados padrão apresentados em seus endpoints. Os endpoints permitem a introspecção em tempo de execução de itens como o estado do cache, o ambiente de execução, as migrações de banco de dados, as verificações de integridade, as informações personalizáveis da aplicação, as métricas, as tarefas periódicas, o estado das sessões HTTP e os dumps de threads.

Os endpoints de verificação de integridade implementados pelo Spring Boot Actuator têm uma configuração modular, de modo que a integridade de um serviço pode ser composta por várias verificações individuais, categorizadas como vivacidade ou prontidão. Também está disponível uma verificação de integridade completa, que exibe todos os módulos de verificação e normalmente se parece com isto.

Os endpoints informativos são definidos em um documento JSON como um único objeto JSON de alto nível e uma série de chaves e valores hierárquicos. Normalmente, o documento especifica o nome e a versão do serviço, a arquitetura, o nome do host, as informações do sistema operacional, o ID do processo, o nome do executável e detalhes sobre o host, como um ID da máquina ou um ID exclusivo do serviço.

Implementação de dumps de heap e de núcleo

Talvez você se lembre da tabela em Comparação dos recursos das ferramentas com a lista de requisitos de que nenhuma das ferramentas oferece suporte à introspecção em tempo de execução nem a dumps de heap/core. No entanto, o Spring, nosso framework subjacente, oferece suporte a ambos — embora tenha sido necessário algum trabalho para integrar os recursos de observabilidade ao aplicativo. Conforme detalhado na seção anterior, para a introspecção em tempo de execução, usamos um módulo Python em conjunto com o Spring Boot Actuator.

Da mesma forma, para os dumps de heap, usamos os endpoints de dump de threads fornecidos pelo Spring Boot Actuator para implementar parte dos recursos que queríamos. Não conseguimos obter dumps de núcleo sob demanda nem dumps de heap da JVM com o nível de granularidade ideal, mas conseguimos parte da funcionalidade desejada com pouco esforço adicional. Infelizmente, os dumps de núcleo dos serviços Python exigirão uma quantidade considerável de trabalho adicional, que adiamos para uma data futura.

Resumo

Depois de muito chorar e questionar nossas escolhas de vida, chegamos a um consenso sobre o uso das seguintes tecnologias para observabilidade no MARA (a seguir, OTel significa OpenTelemetry):

  • Registro de logs (para todos os contêineres) – Filebeat → Elasticsearch / Kibana
  • Rastreamento distribuído
    • Java – Spring Cloud Sleuth → exportador do Spring Cloud Sleuth para OTel → OTel Collector → exportadores conectáveis, como Jaeger, Lightstep, Splunk etc.
    • Python – Bibliotecas Python do OTel → OTel Collector → armazenamento conectável
    • NGINX e NGINX Plus (o NGINX Ingress Controller ainda não é compatível) – módulo OTel do NGINX → OTel Collector → exportador configurável
  • Coleta de métricas
    • Java – Micrometer via Spring → exportador do Prometheus → OTel Collector
    • Python – Ainda não há implementação
    • Python WSGI – GUnicorn StatsD → Prometheus (via StatsD / ServiceMonitor)
    • NGINX – endpoint do Prometheus → Prometheus (via ServiceMonitor)
  • Agregação de erros – rastreamentos distribuídos do OTel → exportador configurável → funcionalidade de pesquisa do exportador para localizar rastreamentos marcados com erro
  • Verificações de integridade
    • Java – Spring Boot Actuator → Kubernetes
    • Python – módulo Flask Management Endpoints → Kubernetes
  • Introspecção em tempo de execução
    • Java – Spring Boot Actuator
    • Python – módulo Flask Management Endpoints
  • Dumps de heap/core
    • Java – Suporte do Spring Boot Actuator para dumps de threads
    • Python – Ainda não há suporte

Esta implementação representa um retrato do momento atual. Ela certamente mudará e evoluirá à medida que o desenvolvimento avançar. Em breve, submeteremos a aplicação a testes de carga abrangentes. Esperamos aprender muito sobre as limitações da nossa abordagem de observabilidade e adicionar novos recursos de observabilidade.

Experimente a Arquitetura de Referência para Aplicativos Modernos e o aplicativo de exemplo (Bank of Sirius). Se você tiver ideias de como podemos melhorar, suas contribuições serão bem-vindas em nosso repositório no GitHub!

Posts relacionados

Este post faz parte de uma série. À medida que adicionamos novos recursos ao MARA, publicamos os detalhes no blog:


Compartilhar

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
NGINX | 10/10/2024

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade

Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
NGINX | 17/06/2024

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa

Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
NGINX | 14/07/2021

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor

Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
NGINX | 02/04/2019

Distribuição segura de chaves privadas SSL com o NGINX

Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
NGINX | 24/05/2018

Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX

O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
NGINX | 19/04/2016

Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus

Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.