Apresentando o curso e objetivos
Olá, pessoal.
Chegamos ao Curso 3, que tratará de observabilidade inteligente. Teremos mais 5 aulas especiais, nas quais não apenas aprofundaremos diversos temas que são base do mercado de trabalho, como também desenvolveremos um projeto para vocês, ainda que em ambiente local, para entender melhor como tudo o que veremos sobre observabilidade, ao longo deste Curso 3, se encaixa. Vamos trabalhar com Prometheus, Grafana e Docker, tudo em um ambiente local, que depois poderá ser testado na nuvem que desejarem, no sistema da empresa e em produção, entre outros contextos.
Hoje, na nossa primeira aula, abordaremos observabilidade moderna. Neste vídeo curto, veremos a evolução da observabilidade em ambientes modernos. Falaremos de conceitos-chave, como o monitoramento em black box (caixa-preta), que consiste em verificações externas, como PING (eco de rede) e estados HTTP (códigos de estado, como 200 — tudo certo; 300 — redirecionamento; 400 — geralmente erro do cliente ou problema de permissões; 500 — o conhecido internal server error), sem visibilidade interna. Em seguida, trataremos de observabilidade distribuída e instrumentação interna, que expõe o estado de cada componente. Além disso, discutiremos o contexto corporativo e metadados de negócio agregados à telemetria técnica, e retomaremos os pilares — já vistos em outro curso aqui na Alura — que são métricas, logs (registros) e traces (rastreamentos) como verticais complementares.
Preparando o ambiente e executando o script
Nesta primeira parte do curso — e este código também estará disponível para vocês — vamos explorar essas informações apresentadas. O que faremos? Vamos abrir o terminal e executar um script em Python. Lembrando que os pré-requisitos do curso serão enviados. É importante ter Docker instalado, Python instalado e Git, para que seja possível manejar a biblioteca e trabalhar da mesma forma que estamos demonstrando aqui.
Para colocar isso em prática, no terminal, executamos o script Python responsável por gerar os primeiros insights que discutiremos ao longo da aula:
python3 curso3-aula-01-observabilidade-moderna/video-1.1-evolucao-observabilidade/observability_evolution.py
Esse comando executa o script observability_evolution.py em ambiente local, permitindo observar, na prática, aspectos de monitoramento black box versus observabilidade moderna que iremos analisar em seguida.
Contrastando monitoramento black box e observabilidade moderna
Ao executarmos esse código em Python, já obteremos alguns dos insights que estamos discutindo hoje e com os quais trabalharemos ao longo do curso. Vamos falar sobre monitoramento em black box (caixa-preta) versus observabilidade moderna. No monitoramento em black box, que é externo, a equipe de operações realiza verificações HTTP externas. Geralmente fazemos um método GET (obter). O GET é utilizado quando lemos algum recurso em um back-end (camada de retaguarda), geralmente de APIs específicas, e essas APIs costumam expor uma rota para verificar a saúde da aplicação.
Essas rotas de verificação de saúde, como a rota /health, por exemplo, se a API tiver conexão com a base de dados, também devem se conectar a essa base. Não adianta enviar um PING a uma página estática, vazia, sem conexão com a base, quando a aplicação de fato depende dela. Em um cenário no qual o RDS (banco relacional) cai, pode parecer que a aplicação está funcionando porque a rota /health continua respondendo 200, mas, na realidade, trata-se de uma falsa sensação de 200 OK. Isso não reflete o estado verdadeiro da aplicação. Portanto, é uma boa prática fundamental que a página /health, que mostra de forma simplificada o estado da aplicação, verifique todas as dependências reais com as quais a aplicação trabalha — seja um RDS (banco de dados relacional), um banco de dados não relacional, um cache como o ElastiCache ou o Redis, entre outros — para sabermos se a aplicação está, de fato, saudável.
Nesse contexto, podemos observar vários componentes saudáveis: todos retornando healthy, o API Gateway saudável, o serviço de usuários também com health 200. Sabemos que está tudo saudável porque 200 é o código padrão que indica sucesso. Ao lermos sobre os códigos de estado HTTP, entendemos que, em geral, 2xx significa que a solicitação foi recebida, aceita e processada com sucesso (200 OK). Códigos 3xx indicam redirecionamento: o cliente precisa realizar ações adicionais para completar a solicitação. Códigos 4xx representam erros do cliente — alguma sintaxe incorreta (por exemplo, 404 para rota inexistente) ou problemas de permissão, como 403 (forbidden). Já os códigos 5xx indicam falhas internas do servidor, como o conhecido 500 internal server error.
Investigando sintomas e erros HTTP
Retomando o exemplo mencionado da rota /health ou da base de dados indisponível: esse cenário provavelmente resultará em um 500 internal server error. Em algumas situações, quando acessamos a página de index (página inicial), podemos ver um 504 bad gateway. Isso geralmente ocorre quando o index tenta acessar algo que falha com um erro 500. Ao tentar completar a solicitação e retornar 200, não consegue, pois ocorre um erro no meio do caminho, e o resultado final é 504 (bad gateway).
Voltando à nossa aplicação: durante um incidente, além do 504 bad gateway, também notamos aumento no tempo das solicitações. Quando tudo funciona, o tempo em milissegundos é muito menor. No incidente, provavelmente ocorre timeout (expiração). Observamos tempos próximos de 29 mil milissegundos (quase 30 mil) e 15 mil milissegundos, indicando que a solicitação ficou muito tempo tentando acessar algo que não estava funcionando. Possíveis causas incluem problemas na base de dados, falha no cache, alguma dependência relacionada a um serviço como o S3 (por exemplo, um bucket (repositório de objetos) com problema), ou ainda recursos estáticos, como CSS ou JavaScript, que não carregam. Nessas situações, a requisição atinge timeout e o sistema retorna como down (fora do ar).
Identificamos que o serviço de pagamento caiu. Em alguns momentos, o sistema de pagamentos fica fora do ar; o gateway de pagamento utilizado também apresentou indisponibilidade. O diagnóstico, no modelo de black box (caixa preta), indica serviços com problema: API Gateway, Card Service e Payment Service, todos sinalizados como indisponíveis, pois o tempo da solicitação ficou muito alto e provavelmente ocorreu um estouro de timeout (tempo limite).
Compreendendo timeouts e delimitando a investigação
O que é timeout (tempo limite), para quem não sabe? É o período máximo em que a solicitação permanecerá consultando o /health (ou qualquer outra rota que programarmos) para entender se o serviço está “on” ou “off”. Definimos um limite para evitar esperas indefinidas. Existem timeouts mais longos, pois, às vezes, é normal a aplicação demorar para iniciar. Há aplicações que ficam prontas em 15 segundos, mas outras aguardam que outra API inicie, esperam uma base de dados, um cache, JavaScript, entre outros, para que tudo esteja pronto. Em alguns casos, isso leva um minuto, um minuto e meio. Nesses cenários, o timeout da aplicação deve ser, por exemplo, de dois minutos. Se definirmos apenas um minuto, não é que a aplicação esteja com problema; ela estará “off” apenas porque não terminou de iniciar. É inadequado aplicar um timeout de um minuto quando a aplicação fica pronta em um minuto e meio. É mais adequado deixar uma margem e configurar dois minutos, por exemplo, para que a aplicação inicie confortavelmente. Além do tempo médio de um minuto e meio, adicionamos margem para variações e, ao mesmo tempo, não esperamos em excesso para confirmar se a aplicação está, de fato, falhando.
Neste momento, a causa é desconhecida. A base de dados parece saudável, pois realizamos uma consulta específica ao endpoint da base (por exemplo, RDS, Aurora, Postgres). O User Service e o Product Service também parecem saudáveis. Portanto, precisamos investigar manualmente cada serviço.
Aplicando observabilidade distribuída e correlacionando sinais
Vamos aplicar observabilidade distribuída. Precisamos coletar os logs e entender o que está acontecendo, porque apenas consultar um endpoint e verificar “on” ou “off” não é suficiente para realizar troubleshooting (diagnóstico de incidentes).
O que as sinais correlacionadas revelam? Realizamos um deploy (implantação) de um serviço. O connection pool (pool de conexões) já está em 95% na base de dados, e as conexões ativas chegam a 97% de 100%. Provavelmente estamos no limite de conexões, o que torna a base mais lenta e a aplicação também mais lenta. Precisamos agir: limpar conexões ociosas e entender por que a base está sendo tão demandada.
O User Service, em um GET, ainda está ok, retornando 200. Em seguida, realizamos um POST, enviando informações para o checkout. Como contexto, em e-commerce, o checkout (finalização de compra) é a etapa de pagamento. Nesse ponto, a parte do fluxo de pagamento foi abortada; algo durante a transação de pagamento falhou. No API Gateway, observamos uma taxa de erros elevada, com error rate (taxa de erro) de 0,68. A latency (latência) está muito alta, muito acima do SLO (objetivo de nível de serviço), que é inferior a 500 milissegundos; estamos em 30.000 milissegundos.
Diagnosticando a causa raiz e comparando abordagens
Qual foi o diagnóstico pela observabilidade? A causa raiz foi o deploy realizado: logo no primeiro serviço do fluxo, o User Service foi atualizado da versão 2.4.1 para 2.4.2. O autor, David Chin, introduziu uma consulta sem índice. Isso tornou as consultas mais lentas, saturou o connection pool e o time deixou de conseguir processar pagamentos e transações do checkout. Precisamos fazer rollback (retorno de versão) e adicionar o índice no próximo deploy. Com ferramentas automatizadas, levamos aproximadamente dois minutos para chegar a esse diagnóstico. Analisar logs manualmente costuma demorar muito mais.
Agora, vamos comparar o aspecto entre black box (caixa preta) e observabilidade distribuída:
- Visibilidade:
- Monitoramento black box (caixa preta): códigos de estado externos (por exemplo, 200, 404, 500).
- Observabilidade distribuída: estado interno de cada componente.
- Correlação:
- Monitoramento black box: nenhuma; alertas são isolados ao checar apenas o endpoint.
- Observabilidade distribuída: os traces (rastros) conectam o fluxo.
- Contexto de mudanças:
- Monitoramento black box: não existe, pois apenas consultamos os endpoints.
- Observabilidade distribuída: deploy detectado automaticamente.
- Causa raiz:
- Monitoramento black box: investigação manual.
- Observabilidade distribuída: identificamos muito mais rápido; com trace temos uma “história” coerente do que ocorreu.
- MTTR (tempo médio para reparo, do inglês Mean Time to Repair):
- Monitoramento manual: tende a ser maior; clientes percebem a demora.
- Observabilidade distribuída: resolvemos mais rápido, pois automação e leitura em fluxo/história aceleram a obtenção das informações.
Concluindo aprendizados e próximos passos
Conclusão: o monitoramento black box (caixa preta) responde apenas se o serviço está “up” ou “down” (200, 404, 500 etc.). A observabilidade moderna responde por que o serviço está se comportando assim. Obtemos essas respostas por meio de pequenas histórias, conectando métricas, logs e traces.
Na Aula 1.2, exploraremos como correlacionar métricas, logs e traces (rastros) de forma integrada para acelerar ainda mais o troubleshooting (diagnóstico de incidentes). Nos vemos na Aula 1.2 do nosso curso 3 de observabilidade inteligente.