404 Not Found

404 Not Found


nginx

Observabilidade

Observabilidade são os olhos das operações em produção — métricas revelam tendências, logs apontam causas e dados de trace identificam as causas raiz. Esses três pilares são todos indispensáveis.

1. O Que Você Vai Aprender


2. Uma História Real de um Engenheiro SRE

(1) Dor: Troubleshooting de Problemas Online como Caixa Preta

Quando o OrderFlow encontra um erro em produção, Bob fica peneirando um mar de logs de aplicação: Qual API está lenta? Qual serviço está com problemas? Por quais microsserviços a requisição passou? Ele não tem ideia. Alice e Bob frequentemente gastam quatro horas solucionando um único problema de produção, três das quais são gastas "adivinhando" onde está o problema.

(2) Abordagens para os Três Pilares da Observabilidade

100%
graph LR
    A["Observabilidade<br/>Três Pilares"] --> B["Métricas<br/>O que aconteceu?<br/>Prometheus"]
    A --> C["Logs<br/>Por que aconteceu?<br/>ELK / Loki"]
    A --> D["Traces<br/>Onde aconteceu?<br/>Jaeger / Zipkin"]

Identificar problemas usando métricas, analisar logs para determinar a causa e usar análise de trace para localizar a causa raiz.

(3) Resultado

Depois que Bob estabeleceu o sistema de observabilidade, os dashboards do Grafana começaram a exibir latência P99 e taxas de erro em tempo real, os alertas do Prometheus dispararam notificações automáticas e os dados de trace do OpenTelemetry localizaram a causa raiz dos problemas em 30 segundos. O tempo médio de resolução de problemas caiu de 4 horas para 15 minutos.


3. Coleta de Dados com Micrometer

(1) Quatro Tipos de Métricas

Tipo Significado Incrementa Apenas Cenários Típicos
Counter Contador (Apenas Incrementa) Sim Total de requisições, número de pedidos criados
Gauge Valor Atual (Pode Aumentar ou Diminuir) Não Número Atual de Conexões, Comprimento da Fila
Timer Distribuição de Duração Não Tempo de Resposta da Requisição
DistributionSummary Estatísticas de Distribuição Não Distribuição do Tamanho do Corpo da Requisição

(1) ▶ Exemplo: Métricas de Negócio Personalizadas

JAVA
@Service
public class OrderMetrics {

    private final Counter orderCreatedCounter;
    private final Counter orderCancelledCounter;
    private final Timer orderCreationTimer;
    private final Gauge pendingOrdersGauge;

    public OrderMetrics(MeterRegistry registry, OrderRepository orderRepo) {
        this.orderCreatedCounter = Counter.builder("orderflow.orders.created")
            .description("Total orders created")
            .tag("service", "orderflow")
            .register(registry);

        this.orderCancelledCounter = Counter.builder("orderflow.orders.cancelled")
            .description("Total orders cancelled")
            .register(registry);

        this.orderCreationTimer = Timer.builder("orderflow.orders.creation.duration")
            .description("Order creation duration")
            .publishPercentiles(0.5, 0.95, 0.99)
            .publishPercentileHistogram()
            .register(registry);

        this.pendingOrdersGauge = Gauge.builder("orderflow.orders.pending",
                orderRepo, repo -> repo.countByStatus("PENDING"))
            .description("Current pending orders count")
            .register(registry);
    }

    public void recordOrderCreated() {
        orderCreatedCounter.increment();
    }

    public Timer.Sample startCreationTimer() {
        return Timer.start(orderCreationTimer);
    }

    public void recordCreationComplete(Timer.Sample sample) {
        sample.stop(orderCreationTimer);
    }
}

Saída:

TEXT
// Execução bem-sucedida

(2) ▶ Exemplo: Usando Métricas em um Service

JAVA
@Service
public class OrderServiceImpl implements OrderService {

    private final OrderMetrics metrics;

    @Override
    @Transactional
    public Order createOrder(CreateOrderRequest request) {
        Timer.Sample sample = metrics.startCreationTimer();
        try {
            Order order = doCreateOrder(request);
            metrics.recordOrderCreated();
            return order;
        } finally {
            metrics.recordCreationComplete(sample);
        }
    }
}

Saída:

TEXT
// Execução bem-sucedida

4. Integração com Prometheus

(1) ▶ Exemplo: Dependências e Configuração do Prometheus

XML
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Saída:

TEXT
// Execução bem-sucedida
YAML
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,prometheus,metrics
  metrics:
    tags:
      application: ${spring.application.name}
    export:
      prometheus:
        enabled: true

(2) ▶ Exemplo: Configuração de Scrape do Prometheus

YAML
# prometheus.yml
scrape_configs:
  - job_name: 'orderflow'
    metrics_path: '/actuator/prometheus'
    scrape_interval: 15s
    static_configs:
      - targets: ['orderflow:8080']

Saída:

TEXT
Monitoring config loaded
Prometheus targets: 3 active
Grafana dashboard: ready

(3) ▶ Exemplo: Consultas PromQL e Alertas

YAML
# Consultas PromQL
# Latência P99 para API de pedidos
histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{uri=~"/api/v1/orders.*"}[5m])) by (le, uri))

# Taxa de erro (respostas 5xx)
sum(rate(http_server_requests_seconds_total{status=~"5.."}[5m]))
/
sum(rate(http_server_requests_seconds_total[5m]))

# Pedidos por minuto
rate(orderflow_orders_created_total[1m]) * 60

Saída:

TEXT
Configuração aplicada com sucesso
YAML
# alert_rules.yml
groups:
- name: orderflow
  rules:
  - alert: HighErrorRate
    expr: |
      sum(rate(http_server_requests_seconds_total{status=~"5.."}[5m]))
      / sum(rate(http_server_requests_seconds_total[5m])) > 0.001
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "OrderFlow taxa de erro excede 0,1%"

  - alert: HighP99Latency
    expr: |
      histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[5m])) by (le)) > 0.1
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "OrderFlow latência P99 excede 100ms"

5. Dashboard Grafana

(1) Métricas Chave do Kanban

Dashboard Métrica PromQL
Taxa de Requisição QPS sum(rate(http_server_requests_seconds_total[5m]))
Latência P50/P95/P99 Distribuição do Tempo de Resposta histogram_quantile(0.99, ...)
Taxa de Erro Proporção 5xx rate(...{status=~"5.."})/rate(...)
Memória Heap JVM Uso de Memória jvm_memory_used_bytes{area="heap"}
Pausa GC Duração do GC rate(jvm_gc_pause_seconds_sum[5m])
Conexões Ativas HikariCP Uso do Pool de Conexões hikaricp_connections_active
Taxa de Criação de Pedidos Métrica de Negócio rate(orderflow_orders_created_total[1m])

(1) ▶ Exemplo: Trecho JSON do Dashboard Grafana

JSON
{
  "dashboard": {
    "title": "OrderFlow Observability",
    "panels": [
      {
        "title": "Request Rate (QPS)",
        "type": "timeseries",
        "targets": [{
          "expr": "sum(rate(http_server_requests_seconds_total{application=\"orderflow-service\"}[5m]))"
        }]
      },
      {
        "title": "P99 Latency",
        "type": "timeseries",
        "targets": [{
          "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{application=\"orderflow-service\"}[5m])) by (le))"
        }]
      },
      {
        "title": "Error Rate",
        "type": "gauge",
        "targets": [{
          "expr": "sum(rate(http_server_requests_seconds_total{application=\"orderflow-service\",status=~\"5..\"}[5m])) / sum(rate(http_server_requests_seconds_total{application=\"orderflow-service\"}[5m]))"
        }],
        "fieldConfig": {
          "defaults": {
            "thresholds": {
              "steps": [
                {"value": 0, "color": "green"},
                {"value": 0.001, "color": "red"}
              ]
            }
          }
        }
      }
    ]
  }
}

Saída:

JSON
{
  "dashboard": {
    "title": "OrderFlow Observability",
    "panels": [
      {
        "title": "Request Rate (QPS)",
        "type": "timeseries",
        "targets": [
          {
            "expr": "sum(rate(http_server_requests_seconds_total{application=\"orderflow-service\"}[5m]))"
          }
        ]
      },
      {
        "title": "P99 Latency",
        "type": "timeseries",
        "targets": [
          {
            "expr": "histogram_quantile(0.99, sum(rate(http_server_request

6. Trace com OpenTelemetry

(1) O Conceito de Distributed Tracing

100%
graph LR
    A["Client"] --> B["API Gateway<br/>Trace: abc123<br/>Span 1"]
    B --> C["Order Service<br/>Span 2<br/>parent: Span 1"]
    C --> D["Product Service<br/>Span 3<br/>parent: Span 2"]
    C --> E["Database<br/>Span 4<br/>parent: Span 2"]
Conceito Significado
Trace Caminho completo de uma única requisição
Span Uma operação na cadeia
Context Contexto de trace passado entre spans
SpanId Identificador único do span atual
TraceId Identificador único do trace inteiro

(1) ▶ Exemplo: Dependência OpenTelemetry

XML
<dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-spring-boot-starter</artifactId>
</dependency>

Saída:

TEXT
// Execução bem-sucedida
YAML
# application.yml
otel:
  exporter:
    otlp:
      endpoint: http://otel-collector:4317
  resource:
    attributes:
      service.name: orderflow-service
  traces:
    exporter: otlp

(2) ▶ Exemplo: Span Personalizado

JAVA
@Service
public class OrderService {

    private final Tracer tracer;

    public OrderService(Tracer tracer) {
        this.tracer = tracer;
    }

    public Order createOrder(CreateOrderRequest request) {
        Span span = tracer.spanBuilder("create-order")
            .setAttribute("product.id", request.productId())
            .setAttribute("quantity", request.quantity())
            .startSpan();

        try (Scope scope = span.makeCurrent()) {
            Order order = doCreateOrder(request);
            span.setAttribute("order.id", order.getId());
            return order;
        } catch (Exception e) {
            span.recordException(e);
            span.setStatus(StatusCode.ERROR, e.getMessage());
            throw e;
        } finally {
            span.end();
        }
    }
}

Saída:

TEXT
// Execução bem-sucedida

7. Exemplo Completo: Dashboard SLO do OrderFlow

YAML
# docker-compose.observability.yml
version: "3.9"
services:
  prometheus:
    image: prom/prometheus:latest
    ports: ["9090:9090"]
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./alert_rules.yml:/etc/prometheus/alert_rules.yml

  grafana:
    image: grafana/grafana:latest
    ports: ["3000:3000"]
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin
    volumes:
      - grafana-data:/var/lib/grafana

  otel-collector:
    image: otel/opentelemetry-collector:latest
    ports: ["4317:4317", "4318:4318"]
    volumes:
      - ./otel-collector-config.yml:/etc/otelcol/config.yaml

  jaeger:
    image: jaegertracing/all-in-one:latest
    ports: ["16686:16686"]

  app:
    build: .
    ports: ["8080:8080"]
    environment:
      OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
      OTEL_SERVICE_NAME: orderflow-service
      MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: health,prometheus,metrics
Métrica SLO Alvo Limite de Alerta PromQL
Latência P99 < 100 ms > 100 ms por 5 minutos histogram_quantile(0.99, ...)
Taxa de Erro < 0,1% > 0,1% por 5 minutos rate(5xx)/rate(all)
Disponibilidade > 99,9% < 99,9% por 5 minutos 1 - rate(5xx)/rate(all)
Throughput de Pedidos > 1.000/min < 500/min por 10 minutos rate(orders_created)[1m]*60

❓ Perguntas Frequentes

P Qual a diferença entre Métricas e Logs?
R Métricas são valores agregados (contadores, histogramas) e são adequados para monitorar tendências e disparar alertas. Logs são registros de eventos discretos e são adequados para analisar causas específicas. Use Métricas para identificar problemas e Logs para analisar suas causas.
P Quais são os respectivos papéis do Prometheus e do Grafana?
R O Prometheus cuida da coleta e armazenamento de dados (banco de dados time-series) além de regras de alerta. O Grafana cuida da visualização (dashboards). Quando usados juntos, o Prometheus serve como fonte de dados e o Grafana como camada de apresentação.
P Qual a relação entre OpenTelemetry e Jaeger?
R OpenTelemetry é o padrão de "coleta" (SDK + API), enquanto Jaeger é o backend de "armazenamento e visualização". Aplicações usam o SDK OTel para coletar dados de trace e enviá-los ao Jaeger para armazenamento e consulta.
P Qual a diferença entre publishPercentiles e histogram_quantile?
R publishPercentiles calcula percentis no lado da aplicação (economizando armazenamento no Prometheus, mas menos preciso entre múltiplas instâncias). histogram_quantile calcula percentis no lado do Prometheus (suporta agregação multi-instância e é mais preciso). Recomendamos calcular no lado do Prometheus em ambientes de produção.
P Qual a diferença entre SLO e SLA?
R Um SLO (Service Level Objective) é uma meta interna, como P99 < 100 ms. Um SLA (Service Level Agreement) é um compromisso com clientes que inclui compensação por violações. Um SLO forma a base de um SLA.
P Como escolher um backend de logs?
R ELK (Elasticsearch + Logstash + Kibana) é poderoso mas consome muitos recursos; Loki (parte do ecossistema Grafana) é leve mas tem capacidades de consulta limitadas. Recomendamos Loki para projetos de pequeno e médio porte e ELK para projetos grandes.

📖 Resumo


📝 Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Configure Micrometer + Prometheus para o OrderFlow, exponha o endpoint /actuator/prometheus e defina três métricas de negócio personalizadas (contagem de pedidos criados, tempo de processamento de pedidos e número de pedidos pendentes).

  2. Exercício Avançado (Dificuldade: ⭐⭐): Configure o Prometheus para coletar dados e configure um dashboard Grafana para exibir HTTP QPS, latência P99, taxa de erro e memória heap JVM. Escreva duas regras de alerta do Prometheus (para taxa de erro alta e latência alta).

  3. Desafio (Dificuldade: ⭐⭐⭐): Integre OpenTelemetry e Jaeger para implementar distributed tracing. Adicione um span personalizado ao OrderService para rastrear todo o fluxo de realização de pedidos (Controller → Service → Repository) e visualize os detalhes do trace na UI do Jaeger.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%