Pular para o conteúdo
iauaiiauai — portal de tecnologia, IA e Cloud
CloudIntermediário

Monitoramento com Prometheus e Grafana

4 métricas (counter, gauge, histogram, summary). Instrumentar, PromQL prático, 4 sinais dourados, alertas sem ruído, SLI/SLO, cardinalidade controlada.

Por Equipe iauai · 3 de agosto de 2026 · 12 min de leitura

Nesta página

O problema real

Seu cluster rodando 10 microsserviços. Um deles começa lento. Você não sabe qual — avisa pelo Slack que "aplicação tá lenta", mas ninguém responde rápido. 30 minutos depois, descobre que é Rate Limit da API terceira. Se tivesse observabilidade, um gráfico apontaria: "requisições pra API X estão falhando 5%", e você resolveria em 2 minutos.

Realidade: aplicação rápida demanda não é "está tudo bem", é "temos dados de que está bem". Sem Prometheus + Grafana, você só vê crash no NewRelic quando é tarde demais.

Os 4 tipos de métrica

Prometheus coleta números. Cada número é de um tipo:

Counter: apenas aumenta

# Contador: requisições totais
requests_total = Counter(
    'http_requests_total',
    'Total de requisições HTTP',
    ['method', 'endpoint', 'status']
)

# Incrementa quando request completa
requests_total.labels(method='GET', endpoint='/users', status=200).inc()
requests_total.labels(method='POST', endpoint='/users', status=201).inc()
requests_total.labels(method='GET', endpoint='/users', status=500).inc()

Uso: requisições, erros, logs, mensagens processadas. Não use para: temperatura da sala, memória (ela desce).

Gauge: sobe e desce

# Gauge: memória em uso (varia)
memory_usage = Gauge(
    'process_memory_bytes',
    'Memória do processo em bytes'
)

memory_usage.set(1024 * 1024 * 256)  # 256 MB
memory_usage.set(1024 * 1024 * 512)  # depois 512 MB
memory_usage.set(1024 * 1024 * 128)  # depois 128 MB

Uso: memória, CPU, tamanho de fila, número de conexões.

Histogram: distribuição de valores

# Histograma: latência de requisição
request_duration = Histogram(
    'http_request_duration_seconds',
    'Latência das requisições em segundos',
    buckets=(0.001, 0.01, 0.1, 0.5, 1.0)
)

import time

@app.route('/api/users')
def get_users():
    start = time.time()
    # ... lógica
    duration = time.time() - start
    request_duration.observe(duration)

Prometheus calcula automaticamente:

  • Soma de todas latências
  • Contagem de requisições
  • Percentis (p50, p95, p99)

Uso: latência, tamanho de arquivo, tempo de processamento.

Summary: percentil direto

Similar a Histogram, mas calcula percentil no cliente (mais barato):

# Summary: latência com percentil automático
response_time = Summary(
    'response_time_seconds',
    'Tempo de resposta em segundos'
)

@app.route('/api')
def api():
    with response_time.time():
        # ... lógica
        pass

Diferença Histogram vs Summary:

  • Histogram: preciso de percentil? Use isso. Calcula no Prometheus (query lenta).
  • Summary: aplicação calcula percentil (query rápida, mas menos flexível).

Instrumentar uma aplicação de verdade

Setup Prometheus + Grafana em Docker:

# docker-compose.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin
    volumes:
      - grafana_data:/var/lib/grafana

  app:
    build: .
    ports:
      - "5000:5000"
    depends_on:
      - prometheus

volumes:
  prometheus_data:
  grafana_data:

prometheus.yml:

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'app'
    static_configs:
      - targets: ['localhost:5000']

Aplicação Flask instrumentada:

from flask import Flask
from prometheus_client import Counter, Gauge, Histogram, generate_latest
import time

app = Flask(__name__)

# Métricas
requests_total = Counter(
    'http_requests_total',
    'Total requisições',
    ['method', 'endpoint', 'status']
)

request_duration = Histogram(
    'http_request_duration_seconds',
    'Latência em segundos',
    buckets=(0.01, 0.025, 0.05, 0.1, 0.5, 1.0)
)

active_connections = Gauge(
    'active_connections',
    'Conexões ativas'
)

# Middleware: registra cada requisição
@app.before_request
def before_request():
    request.start_time = time.time()
    active_connections.inc()

@app.after_request
def after_request(response):
    duration = time.time() - request.start_time
    request_duration.observe(duration)
    
    requests_total.labels(
        method=request.method,
        endpoint=request.path,
        status=response.status_code
    ).inc()
    
    active_connections.dec()
    return response

@app.route('/metrics')
def metrics():
    return generate_latest()

@app.route('/users')
def get_users():
    time.sleep(0.05)  # simula delay
    return {'users': ['alice', 'bob']}

if __name__ == '__main__':
    app.run(port=5000)

Rode: curl localhost:5000/metrics e vê as métricas em formato Prometheus.

PromQL prático: a linguagem de queries

Acesse http://localhost:9090, clique em "Graph", escreva queries:

Taxa de requisições por segundo

# rate() calcula mudança ao longo do tempo
rate(http_requests_total[5m])

# Resultado: requisições por segundo nos últimos 5 minutos
# Exemplo: 10 requisições

Taxa de erro

# Requisições com erro (status >= 400)
rate(http_requests_total{status=~"4..|5.."}[5m])

# Percentual de erro
(
  rate(http_requests_total{status=~"4..|5.."}[5m]) 
  / 
  rate(http_requests_total[5m])
) * 100

# Resultado: 2.5% (2.5 em cada 100 requisições falham)

Percentil de latência

# P95 (95% das requisições mais rápidas)
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# Resultado: 0.234 segundos (p95 é 234 ms)

# P99 (99% mais rápidas)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# Resultado: 0.512 segundos

Por que média engana:

Latências: 10ms, 10ms, 10ms, 10ms, 10.000ms

Média = (10+10+10+10+10000) / 5 = 2.008 segundos (engana!)
P95 = 10ms (verdade — 95% dos usuários vê 10ms)

Memória em MB

# Gauge em bytes, divide por 1 milhão pra MB
process_memory_bytes / 1024 / 1024

# Resultado: 256 (256 MB)

Os 4 sinais dourados

Google SRE recomenda monitorar esses 4 sinais:

1. Latência (tempo de resposta)

histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

Alarme: p95 > 500ms.

2. Tráfego (carga)

rate(http_requests_total[5m])

Alarme: > 10.000 requisições/segundo (ajuste por sua aplicação).

3. Erros (taxa de falha)

rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])

Alarme: > 1% de erro (5xx).

4. Saturação (recursos no limite)

# CPU
node_cpu_seconds_total

# Memória
process_resident_memory_bytes / 1024 / 1024

# Disk I/O
node_disk_io_time_seconds_total

Alarme: > 80% de utilização.

Alertas que não viram ruído

❌ Alertas ruins (viram ruído):

- alert: HighMemory
  expr: process_memory_bytes > 512*1024*1024  # > 512 MB
  # Problema: memória natural sobe, você ignora 100 alerts/dia

✓ Alertas bons (sintoma, não causa):

- alert: ErrorRateHigh
  expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.01
  for: 5m  # apenas se persistir por 5 minutos
  
  - alert: LatencyHighp95
    expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1.0
    for: 10m

- alert: ContainerCrashLoop
  expr: rate(container_last_seen[5m]) == 0
  # Sintoma: container não responde. Causa é desconhecida.

Regra: alerta em sintoma (usuário sofre), não em causa (memória sobe).

SLI, SLO, SLA com número concreto

SLI (Service Level Indicator): métrica mensurável.

# SLI: requisições bem-sucedidas (< 500ms)
(
  sum(rate(http_requests_total{status=~"2.."}[30d])[30d:]) 
  / 
  sum(rate(http_requests_total[30d])[30d:])
) * 100

SLO (Service Level Objective): meta de SLI.

Objetivo: 99.5% de requisições respondem em < 500ms
(número que você publica internamente)

SLA (Service Level Agreement): contrato, penalidade se falhar.

Se SLI < SLO por mais de 1 dia, cliente ganha crédito 5%
(contrato legal — envolve dinheio)

Exemplo real:

App: API de usuários
SLI: (requisições 2xx) / (todas) = 99.2%
SLO: >= 99.5%
SLA: se < 99.5%, cliente ganha $500 crédito

Resultado: 30 dias com 99.2% (abaixo SLO) = cliente recebe $500

Cardinalidade: o erro que derruba Prometheus

Nunca use valores dinâmicas como rótulo:

# ❌ ERRADO: user_id é dinâmico (milhões de valores)
# Cada usuário = nova série = Prometheus explode
requests_by_user = Counter(
    'requests_by_user_total',
    'Requisições por usuário',
    ['user_id']
)

requests_by_user.labels(user_id=request.user_id).inc()
# 1 milhão de usuários = 1 milhão de séries!

Prometheus fica lento (memória cresce), queries demoram 10 segundos:

ERRO: cardinality explosion
Series: 5,000,000
Memory: 8 GB (esperava 200 MB)

✓ CORRETO: rótulos com baixa cardinalidade

# Bom: endpoint é ~50 valores
requests_total = Counter(
    'http_requests_total',
    'Total requisições',
    ['method', 'endpoint', 'status']  # ~6 * 4 * 10 = 240 séries
)

requests_total.labels(
    method='GET',
    endpoint='/users',
    status=200
).inc()

Regra: cardinalidade = (labels[0] valores) * (labels[1] valores) * ...

Se > 100.000 séries, Prometheus sofre. Limite!

Armadilhas comuns

1. Prometheus sem retenção (disco cheio):

--storage.tsdb.retention.time=30d  # manter 30 dias

2. Scrape interval muito curto:

scrape_interval: 1s  # ❌ Prometheus coleta a cada 1 segundo, fica lento
scrape_interval: 15s  # ✓ Padrão, suficiente pra maioria

3. Alertas sem runbook:

- alert: HighErrorRate
  expr: error_rate > 0.05
  # "O que fazer agora?" — ninguém sabe

Bom:

- alert: HighErrorRate
  expr: error_rate > 0.05
  annotations:
    runbook_url: https://wiki.company.com/alerts/high_error_rate
    summary: "Taxa de erro acima de 5%"

Quando NÃO usar Prometheus

Métrica com mudança a cada nanosegundo: Prometheus coleta a cada 15 segundos. Se precisa tempo real, use InfluxDB.

Logs estruturados: Prometheus é pra métricas. Use ELK/Loki para logs.

Forecasting/ML: Prometheus não prevê. Use M3/Graphite se precisa predição.

Próximos passos

Correlacione métricas com erros em aplicações IA: Observabilidade em aplicações com LLM — inclui setup completo de logging + métricas.

Deploy Prometheus em produção: Terraform na prática: sua primeira infra versionada — provisiona com IaC.

Teste: rode o docker-compose acima, acessa http://localhost:3000 (Grafana), cria dashboard com 4 gráficos (latência, taxa de erro, tráfego, saturação). Gera carga: ab -n 1000 -c 10 http://localhost:5000/users. Vê em tempo real as métricas subindo em Grafana. Isso é ouro puro.

Aprenda jogando

Datacenter

Percorra o corredor de racks e resolva falhas antes que o uptime despenque.

Jogar Datacenter

Continue lendo