user@luiscruz: ~/case-sre
home
user@luiscruz:~/case-sre$
$ cat 00-contexto.md

O cenário

Sexta-feira, 18h. Pico de tráfego, time reduzido, deploy recente: o momento clássico em que um incidente nasce.

A latência da API subiu de ~200ms para 5s. O Sentry começou a registrar timeouts em volume e clientes já reclamavam. O staging seguia normal, e havia um deploy às 17h30. O ambiente roda em Kubernetes (AKS) com C# e Python, instrumentado com Prometheus, Grafana e Loki; tracing distribuído ainda não estava pronto.

A pergunta de SRE não é "qual a causa raiz definitiva?", e sim: como reduzir impacto, organizar comunicação e preservar evidência. Primeiro restaurar, depois investigar.

$ cat 01-incidente.json # estado no pico, 17:45

O impacto, em números

Antes → depois do deploy. O serviço respondia health check enquanto a experiência real degradava.

Latência P95
220ms5.200ms
▲ ~24× acima do baseline
Latência P99
9.000ms
▲ cauda longa de timeouts
Taxa de erro
0,3%6,0%
▲ 20× · 5xx e timeouts
Error budget (99,5%)
3h36
▲ consumido de forma acelerada
Sinal que importa Disponibilidade HTTP sozinha não capturaria isto. O que conta é a experiência percebida: latência de cauda (P95/P99) e taxa de erro.
$ tail -f incident.log

Timeline do incidente

Correlação temporal forte com o deploy das 17h30: pista para reduzir o espaço de investigação.

17:20INFOBaseline saudável: P95 180ms, erro 0,2%
17:30DEPLOYNova versão publicada em produção
17:35WARNP95 sobe para 900ms, P99 para 1.800ms
17:36WARNPostgres registra queries > 2.600ms filtrando por account_id
17:40CRITP95 1.800ms, erros em 2,5%
17:45CRITPico: P95 5.200ms, P99 9.000ms, erros 6,0%
17:50CRITDegradação sustentada: P95 4.800ms, erro 5,5%
18:00ACTIONTratado como impacto em cliente: rollback/mitigação priorizados

Critério de rollback foi objetivo, não intuitivo: P95/P99 acima do SLO por duas janelas consecutivas, aumento de 5xx pós-deploy, clientes confirmando impacto, sem mitigação simples em 15 min, ou correlação temporal forte com o deploy.

$ cat 02-causa-raiz.sql

Causa raiz: N+1 + índice ausente

Para cada item processado, a aplicação disparava uma consulta adicional contra users. O log de slow queries mostrou o padrão:

-- repetida 1× por item, 2.500ms–5.100ms cada
SELECT * FROM users u WHERE u.account_id = $1;
-- sem índice em account_id → full scan sob carga real
A distinção que pega em entrevista O índice em account_id não resolve o N+1 sozinho. N+1 é problema de quantidade de consultas; o índice reduz o custo de cada consulta. A correção definitiva remove o padrão (batch, join ou eager loading); o índice entra como melhoria complementar.

Por que passou no staging? O ambiente não reproduzia volume, cardinalidade e concorrência de produção. A query parecia aceitável em baixa escala e degradou sob dados reais. Teste funcional passa, comportamento operacional falha.

$ cat 03-slo.yaml

SLIs, SLOs e error budget

Dois pilotos cobrem os dois tipos de experiência: resposta síncrona (API C#) e conclusão de trabalho assíncrono (Core Processor em Python).

SLIComo medirSLO inicial
Disponibilidade HTTPRequests não-5xx / total99,5% /mês
Latência P95Duração das requisições< 500ms (janela 5m)
Taxa de erro 5xx5xx / total de requests< 1% /mês
Backlog da fila jobsMensagens prontas na fila< 1.000 por >10min
Idade da mensagemEspera da msg mais antigaP95 < 5min
Taxa de ACKProcessadas com ACK / consumidas99% /mês
3h36budget / mês

Error budget = 0,5% de 720h

Um SLO de 99,5%/mês tolera ~3h36min de erro ou indisponibilidade. Não é permissão para falhar. É o limite que dispara decisão: se o consumo acelera, reduz-se risco de mudança (congelamento de deploys não críticos, rollback mais agressivo, priorização de confiabilidade).

Alertas multi-window, multi-burn-rate combinam janelas curtas e longas para o mesmo SLO, evitando tanto o alarme por pico isolado quanto a cegueira para degradação lenta:

SeveridadeJanelasSinalAção
Alta5m + 1hConsumo acelerado do budgetAcionar on-call
Média30m + 6hDegradação sustentadaInvestigar em horário comercial
Baixa24hTendência acima do esperadoRevisar capacidade / regressões

SLI de disponibilidade em PromQL (roda na stack via prometheus-net):

sum(rate(http_requests_received_total{job="csharp-api", code!~"5.."}[5m]))
/
sum(rate(http_requests_received_total{job="csharp-api"}[5m]))
$ cat 04-observabilidade.md

Estratégia de observabilidade

Maturar a base existente antes de adicionar ferramentas. Melhorar a qualidade do sinal antes da quantidade de dashboards.

O que manter

  • Prometheus para métricas operacionais e SLIs
  • Grafana como ponto central de visualização
  • Loki para logs estruturados (já via Promtail)
  • OpenTelemetry como padrão de instrumentação

O que melhorar

  • Padronizar labels e correlação request_id ↔ logs ↔ traces
  • Dashboards por serviço (4 sinais de ouro)
  • Alertas por burn rate, não por métrica técnica isolada
  • Controlar cardinalidade (cuidado com label path)
O gap do tracing O OTel Collector sobe e abre OTLP em 4317/4318, mas exporta apenas para debug, sem backend de traces nem datasource no Grafana. Existe base de instrumentação, falta capacidade de investigação ponta a ponta. Evolução em fases, começando por endpoints críticos e com sampling desde o início.
$ ./apm-recommendation.sh

APM & tracing: a decisão

OpenTelemetry como camada neutra reduz lock-in e permite trocar o backend sem reinstrumentar C# e Python.

OpçãoPontos fortesRiscos / limitações
DatadogExperiência operacional pronta, ótima correlaçãoCusto cresce rápido (hosts, ingestão, APM); exige governança
New RelicBoa cobertura de APM e dashboardsModelo de custo por usuário/ingestão; menos controle sem OTel
DynatraceForte em enterprise, automação de dependênciasPesado e caro para um estágio inicial
OSS: Tempo/Jaeger + OTelMenor lock-in, encaixe com Grafana existenteMais responsabilidade operacional (storage, retenção, escala)
Recomendação Manter OpenTelemetry como padrão obrigatório e rodar um piloto com Grafana Tempo (ou Grafana Cloud Traces): aproveita o que já existe, reduz mudança operacional e mantém liberdade de trocar de backend. Datadog entraria se a prioridade fosse velocidade de adoção, com limites de ingestão, retenção e sampling desde o primeiro mês.
$ cat 05-custo.csv # valores estimados

Análise de custo (FinOps)

Self-hosted no AKS. Premissas: ~50 req/s em pico, ~10 GB de logs/dia, ~50k séries ativas, sampling de traces 100% em erros e ~10% no tráfego normal.

ItemAtual (US$/mês)Proposto (US$/mês)
Compute do stack de monitoramento150180
Storage de métricas (Prometheus TSDB)2025
Storage de logs (Loki + object storage)3030
Backend de tracing (Tempo + storage)090
Rede egress e backup1520
TOTAL estimadoUS$ 215US$ 345
Delta: +US$ 130/mês (+60%) Quase todo o aumento é o backend de tracing, o item que falta para investigação ponta a ponta. Custo controlado por sampling.

Alavancas de redução sem perder visibilidade:

AlavancaImpactoComo controlar
Retenção por criticidadeMenos storage de logsDefinir quais eventos exigem retenção estendida
Sampling de tracesMenos ingestão100% em erros/lentidão; amostrar tráfego normal por serviço
Controle de cardinalidadeMenos séries de métricasDetalhe fino em logs/traces; métricas para agregados
Filtro de logs ruidososMenos ingestão e ruídoValidar filtros em piloto antes de produção
Alertas por SLOMenos toil e fadigaBurn rate aciona on-call; métrica técnica vira contexto
$ ls ./evidencias/

Evidências da validação local

A stack foi provisionada e validada localmente antes de qualquer recomendação. Clique para ampliar.

$ ls ./adrs/

Decisões arquiteturais (ADRs)

Decisões registradas com contexto, opções e consequências.

ADR-001

Alertas baseados em SLO e burn rate

Diferenciar sintoma com impacto real de sinal de diagnóstico. Métricas técnicas viram contexto em dashboard, não página.

Accepted
ADR-002

OpenTelemetry como padrão para APM e tracing

Camada neutra para trocar o backend sem reinstrumentar. Cuidado com sampling, atributos obrigatórios e governança de custo.

Accepted
ADR-003

Retenção de logs e controle de cardinalidade

Retenção curta para logs brutos; estendida só para eventos críticos. Controlar labels de alta cardinalidade no Loki.

Accepted
$ cat 06-prevencao.md

Prevenção de recorrência

A falha não foi de uma pessoa, e sim de lacunas no sistema de entrega. Tratar performance e observabilidade como parte do contrato de produção, não como validação posterior ao deploy.

Detecção mais cedo

Alertas baseados em SLO e burn rate para latência e erro da API.

Prevenção na entrega

Gate de performance na pipeline e revisão explícita de queries (risco de N+1) no checklist de PR.

Diagnóstico mais rápido

Tracing funcional com OpenTelemetry, correlacionando endpoint, chamada de banco e tempo por dependência.

Deploy mais seguro

Rollout progressivo (canary/blue-green) e feature flags para desligar comportamento novo sem rollback completo.

Staging representativo

Revisar massa de dados para refletir volume e cardinalidade reais.

$ open apresentacao-case-sre.pdf

Apresentação do case

Os mesmos pontos em formato de slides. Abrir em tela cheia

$ ls -la ./links
Nota de transparência: dados de slow query e de fila vêm dos logs/cenários fornecidos no desafio. As métricas do incidente (P95/P99, taxas de erro e a timeline minuto a minuto) são ilustrativas, coerentes com o cenário (latência de ~200ms para ~5s); os valores de custo são estimativas sobre premissas de volume, a calibrar com dados reais do ambiente.