Pular para o conteúdo

Prometheus e PromQL

Intermediário24 min de leituraobservabilidade
Antes disto:

Prometheus guarda séries temporais numéricas e as consulta com PromQL. Ele puxa as métricas de alvos que expõem um endpoint HTTP — normalmente /metrics — em vez de esperar que a aplicação envie. Isso torna a coleta observável por si só: se o alvo sumiu, o Prometheus sabe.

Uma série é identificada pelo nome da métrica mais o conjunto de labels. Trocar um label cria outra série; por isso label instável é problema de custo, e não de estilo.

http_requests_total{job="loja", instance="10.0.1.7:8080", route="/checkout", status="500"}

Em Kubernetes você quase nunca lista alvos à mão: a descoberta encontra os Pods pelos labels e o relabeling decide o que coletar.

scrape_configs:
- job_name: aplicacoes
kubernetes_sd_configs: [{ role: pod }]
relabel_configs:
# só coleta Pod anotado com prometheus.io/scrape: "true"
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
Janela do terminal
# alvos com falha de coleta, direto da API — mais rápido que a interface
curl -s localhost:9090/api/v1/targets | jq -r '.data.activeTargets[]
| select(.health!="up") | "\(.labels.job) \(.scrapeUrl) \(.lastError)"'
  • Counter — só cresce (requisições, erros, bytes). Nunca leia o valor bruto; leia a taxa com rate(). Reinício do processo zera o counter, e o rate() já corrige isso.
  • Gauge — sobe e desce (memória em uso, fila, réplicas). Aqui o valor bruto faz sentido.
  • Histogram — distribui observações em baldes (_bucket, _sum, _count). É o que permite percentil agregável entre instâncias.
  • Summary — calcula quantis no cliente. Não é agregável entre instâncias; prefira histogram salvo quando você mede uma única instância.
# p95 de latência a partir de um histogram, agregado por rota
histogram_quantile(0.95,
sum by (le, route) (rate(http_request_duration_seconds_bucket[5m])))
up{job="loja"} # 1 ou 0 por alvo
rate(http_requests_total[5m]) # requisições por segundo, por série
sum by (route) (rate(http_requests_total[5m])) # some as instâncias, mantenha a rota
topk(5, sum by (pod) (rate(container_cpu_usage_seconds_total[5m])))
# disponibilidade: proporção de sucesso — cuidado com divisão por zero
sum(rate(http_requests_total{status!~"5.."}[5m]))
/ sum(rate(http_requests_total[5m]))
# uso de memória contra o limite do container
sum by (pod) (container_memory_working_set_bytes{namespace="loja"})
/ sum by (pod) (kube_pod_container_resource_limits{namespace="loja", resource="memory"})

A regra de ouro da agregação: agregue depois de calcular a taxa, nunca antes. sum(rate(x[5m])) está certo; rate(sum(x)[5m:]) mente quando um alvo reinicia.

rate() calcula a taxa média na janela e é o que você quer em alerta e painel. irate() usa os dois últimos pontos e serve só para gráfico de curta duração — em alerta, ele oscila e dispara sozinho.

A janela precisa conter pelo menos quatro amostras: com scrape_interval de 30s, use [2m] ou mais. Janela curta demais produz buracos no gráfico; longa demais atrasa a detecção. Para counters que podem sumir (Pod que morreu), lembre que a série desaparece — absent() e alertas sobre ausência existem por isso.

Consulta cara repetida em painel e alerta deve virar série pré-calculada. Ganha-se tempo de resposta e consistência: todo mundo passa a olhar o mesmo número.

groups:
- name: loja-slo
interval: 30s
rules:
- record: job:http_requests:rate5m
expr: sum by (job, route) (rate(http_requests_total[5m]))
- record: job:http_errors:ratio_rate5m
expr: |
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by (job) (rate(http_requests_total[5m]))
Janela do terminal
promtool check rules regras.yaml # rode no CI, antes do merge
promtool check config prometheus.yml

Um Prometheus é um processo único com disco local; ele não replica. Para histórico longo e visão global, envie por remote_write para Thanos, Mimir ou um serviço gerenciado, e mantenha a retenção local curta (15 a 30 dias) para consulta rápida.

Antes de crescer o hardware, meça: prometheus_tsdb_head_series mostra quantas séries você mantém, e quase sempre o problema é um label de alta cardinalidade recém-adicionado, não falta de memória.

Próximo passo: transforme essas consultas em algo que alguém use em Grafana: painéis que alguém usa. Para a sintaxe no dia a dia, veja a referência de PromQL.