Stack de monitorização: Prometheus, Grafana, DCGM e Loki para servidores de IA

Um servidor de IA que ninguém está a vigiar é um servidor que faz throttling em silêncio, que perde VRAM, que acumula erros ECC ou que é morto pelo OOM killer às 03:00 — e só se dá conta três dias depois, quando alguém pergunta porque é que o fine-tune produziu lixo. A maioria dos piores modos de falha numa máquina com GPU é invisível do lado da aplicação: o throttling térmico não escreve para o stderr, as correções ECC não fazem rebentar nada de imediato, o OOM killer come um processo e o orquestrador reinicia-o sem alarde. Sem métricas do próprio hardware, nada disto é visível até já ter custado uma semana.

O conjunto habitual de ferramentas de sysadmin (htop, df, uptime, syslog) não chega. A GPU é o componente mais caro do chassis e o mais propenso a falhar, e tem uma stack de telemetria própria que exige ligações explícitas. Este artigo é a proposta assumida para essa stack — Prometheus, Grafana, DCGM-exporter, node_exporter, Loki e Alertmanager — empacotada numa única implementação docker-compose que corremos em todos os servidores de IA Kentino que expedimos.

O público é quem está a pôr de pé um servidor de IA de 4 ou 8 GPU, sabe escrever um ficheiro docker-compose e quer a resposta a "o que devo realmente monitorizar e a partir de que limiar devo gerar alarme."

A stack padrão em 2026

Cinco componentes fazem quase todo o trabalho. Tudo o resto é acessório.

Componente Função Consumo em repouso
Prometheus Base de dados de séries temporais + orquestrador de recolha ~150 MB RAM, ~3 MB/s
Grafana Dashboards, interface de alertas ~120 MB RAM
DCGM-exporter Métricas da GPU (temperatura, utilização, consumo, memória, ECC, XID) ~30 MB RAM, <0.1% CPU
node_exporter Métricas do sistema (CPU, RAM, disco, rede, hwmon) ~15 MB RAM
Loki + Promtail Agregação de registos e respetivo expedidor ~100 MB RAM
Alertmanager Encaminhamento de alertas (e-mail, Slack, PagerDuty, webhook) ~25 MB RAM

No total, bem abaixo de 0.5% de um núcleo de CPU num EPYC de 96 núcleos e cerca de 700 MB de RAM. Num servidor de 256 GB com 8 GPU, isto é um erro de arredondamento. O argumento de que "a monitorização rouba ciclos ao treino" deixou de ser verdade por volta de 2019.

A única decisão de arquitetura que vale a pena tomar à partida: coloque a stack numa VM de gestão separada ou numa máquina pequena, e não no próprio servidor de GPU. Um mini-PC dedicado, um NUC, um nó de serviço EPYC ou uma VM no hipervisor do laboratório — qualquer coisa que não seja a máquina com as GPU. Por duas razões: quando o servidor de GPU vai abaixo (kernel panic por falta de memória, disparo da fonte de alimentação, encerramento térmico) continua a querer o histórico de métricas para diagnosticar o que aconteceu, e não quer um treino descontrolado a competir pela memória com o Prometheus e a disparar o alerta do próprio. O DCGM-exporter e o node_exporter correm no anfitrião com GPU (têm de correr — leem dispositivos locais); o Prometheus, o Grafana, o Loki e o Alertmanager correm na VM de gestão e recolhem para dentro.

DCGM-exporter — a peça que não se pode dispensar

O Data Center GPU Manager (DCGM) da NVIDIA é a fonte suportada e autoritativa de telemetria da GPU. O contentor dcgm-exporter expõe as métricas do DCGM em formato Prometheus na porta 9400. É o componente mais importante de toda a stack e é aquilo que fazer polling com nvidia-smi nunca irá substituir.

Instale a partir do contentor NGC (nvcr.io/nvidia/k8s/dcgm-exporter, atualmente na versão 4.x em meados de 2026) ou do Helm chart oficial para Kubernetes. Em Docker simples, basta um docker run --gpus all --rm; o daemon passa então a publicar ~80 métricas em :9400/metrics. As que realmente importam, por ordem da frequência com que apanham problemas reais:

Métrica O que indica Limiar de alarme
DCGM_FI_DEV_GPU_TEMP Temperatura do núcleo da GPU (°C) > 80 °C aviso, 87 °C crítico
DCGM_FI_DEV_MEMORY_TEMP Temperatura da VRAM / junção de memória (°C) > 95 °C aviso, 105 °C crítico
DCGM_FI_DEV_GPU_UTIL Utilização de cálculo dos SM (%) < 5% com VRAM alocada → processo bloqueado
DCGM_FI_DEV_FB_USED Frame buffer (VRAM) utilizado, em MiB > 95% do total
DCGM_FI_DEV_POWER_USAGE Consumo atual (W) > TDP × 0.98 de forma sustentada
DCGM_FI_DEV_PCIE_TX_THROUGHPUT Largura de banda PCIe TX (KiB/s) teto sustentado = regressão de riser/pistas
DCGM_FI_DEV_ECC_SBE_VOL_TOTAL Contagem de erros ECC corrigíveis aumento da taxa > 10× face à linha de base
DCGM_FI_DEV_ECC_DBE_VOL_TOTAL Contagem de erros ECC não corrigíveis qualquer
DCGM_FI_DEV_THERMAL_VIOLATION ns acumulados em throttling térmico taxa > 0
DCGM_FI_DEV_POWER_VIOLATION ns acumulados em throttling por consumo taxa > 0
DCGM_FI_DEV_XID_ERRORS Contagem de erros XID (falhas de driver / hardware) qualquer

Os contadores de throttling são a funcionalidade decisiva. DCGM_FI_DEV_THERMAL_VIOLATION é um contador monotónico dos nanossegundos que a GPU passou em throttling. Calcule a sua taxa numa janela de 5 minutos e tem a resposta exata a "o meu servidor está neste momento limitado termicamente." Sem isso, está a adivinhar apenas pela temperatura, que engana — uma 4090 entra em throttling aos 83 °C numa carga sustentada, independentemente do que o painel de temperatura mostre.

Duas particularidades conhecidas do DCGM-exporter a ter em conta em 2026: alguns códigos XID (nomeadamente o XID 62) nem sempre aparecem através de DCGM_FI_DEV_XID_ERRORS e a métrica é um gauge do último XID observado — pelo que pode não voltar a zero após uma recuperação sem reiniciar o exporter. A mitigação é vigiar também o kernel ring buffer através do Loki, à procura da string literal NVRM: Xid (mais sobre isto abaixo). Cinto e suspensórios.

Em placas puramente de consumo (RTX 4090, 5090) algumas funcionalidades de centro de dados do DCGM só funcionam em parte — não existe MIG, o NVLink está ausente nos modelos Blackwell de consumo e certos contadores ECC devolvem zero. O DCGM continua a funcionar e reporta o que está exposto; a alternativa leve da comunidade, nvidia_gpu_exporter (que faz scraping de nvidia-smi), é uma solução de recurso viável se não quiser a cadeia de dependências do DCGM. Para as Pro 6000 Blackwell, L40 e L4 — tudo o que seja da linha de centro de dados / pro — use o DCGM e não o wrapper.

node_exporter — a metade do sistema

As métricas da GPU contam apenas metade da história. O node_exporter cobre o resto:

Família de métricas Porque importa numa máquina de IA
node_cpu_seconds_total Saturação do CPU — os tokenizers e dataloaders do vLLM adoram CPU
node_memory_MemAvailable_bytes RAM do sistema — os fluxos de treino e de inferência têm fugas
node_disk_io_time_seconds_total Saturação do NVMe — carregamento de datasets, escrita de checkpoints
node_filesystem_avail_bytes Espaço em disco — os pesos dos modelos ocupam 50–150 GB cada (ver também L04)
node_network_receive_bytes_total Débito de rede — treino multinó, clientes de inferência
node_load_average Indicador rápido do estado de saúde
node_hwmon_temp_celsius Temperaturas do CPU e do chipset e, em algumas placas, da fonte de alimentação
node_vmstat_oom_kill O OOM killer disparou — o alerta mais esquecido em qualquer implementação

O modo de falha "RAM do sistema esgotada, o OOM killer leva o vLLM, o contentor reinicia sem alarde" é apanhado aqui, e não pelo DCGM. Vigie node_memory_MemAvailable_bytes e gere alarme quando descer abaixo de 5% do total. Em Linux, o killer dispara perto dos 0% por predefinição, mas a essa altura o processo já morreu.

Prometheus — configuração, retenção, dimensionamento

O Prometheus é a base de dados de séries temporais e o orquestrador de recolha. As predefinições são razoáveis; as duas definições que vale a pena mudar logo no primeiro dia são o intervalo de recolha e a retenção.

Um intervalo de recolha de 15 segundos é o ponto de partida certo para um servidor de IA: rápido o suficiente para apanhar um pico térmico antes de se tornar um throttling sustentado, lento o suficiente para o custo das séries temporais se manter contido. A retenção está predefinida em 15 dias; 30 dias é um número melhor num contexto de guia de construção, em que pode querer comparar o comportamento de hoje com uma afinação do mês passado.

Orçamento de armazenamento com recolha a 15 s, ~80 métricas DCGM × N GPU + ~400 métricas do node_exporter + ~50 métricas do vLLM: cerca de 1.5–2 GB por semana, ou seja, 30 dias ficam em 6–10 GB numa máquina de 8 GPU. Defina a retenção por tempo e por tamanho, como salvaguarda:

command:
  - "--storage.tsdb.retention.time=30d"
  - "--storage.tsdb.retention.size=20GB"

Qualquer um dos limites desencadeia a compactação; vence o que for atingido primeiro. Uma alocação de 100 GB dá-lhe mais de um ano de folga sem ter de pensar no assunto.

Dashboards do Grafana — comece pelos já feitos

Não construa dashboards de raiz. A comunidade já o fez.

Dashboard ID em Grafana.com O que cobre
NVIDIA DCGM Exporter Dashboard 12239 O oficial da NVIDIA — todas as métricas da GPU
Node Exporter Full 1860 CPU / RAM / disco / rede
Registos Loki / Promtail 13639 Pesquisa e exploração de registos
Serviço vLLM (comunidade) varia TTFT, TPOT, profundidade da fila, cache KV

Importe primeiro o 12239 e o 1860. Cobrem ~90% daquilo que realmente quer ver e foram refinados ao longo de anos. Construa os seus próprios só ao fim de um mês, quando já souber que painéis abre de facto. As pequenas alterações que vale a pena fazer para o hardware de IA Kentino são: ajustar os painéis de limiar de temperatura da GPU para intervalos adequados ao Blackwell (a 5090 entra em throttling perto dos 87 °C, a RTX Pro 6000 mais perto dos 90 °C) e acrescentar um painel por slot PCIe a mostrar DCGM_FI_DEV_PCIE_LINK_GEN e DCGM_FI_DEV_PCIE_LINK_WIDTH para ver num relance se um riser desceu de x16 para x8.

Loki — registos que explicam o que as métricas mostram

As métricas dizem-lhe o que mudou; os registos dizem-lhe porquê. O Loki é a base de dados de registos do Grafana; o Promtail é o expedidor que segue os ficheiros e os envia. Aponte o Promtail para:

  • /var/log/syslog e journalctl -k — mensagens OOM do kernel, queixas do driver NVIDIA, dumps de XID
  • /var/log/nvidia-installer.log — estado da instalação do driver
  • stdout do contentor vLLM (através do log driver JSON do Docker)
  • Registos de aplicação de tudo o que o cliente executar

A consulta mais valiosa de todas no separador Explore do Grafana é:

{job="syslog"} |= "NVRM:"

Isto traz à superfície todas as mensagens do driver NVIDIA no kernel ring buffer — erros XID, falhas de ventoinha, eventos de placa caída do barramento, timeouts de RPC do GSP. Combine-a com o alerta Prometheus DCGM_FI_DEV_XID_ERRORS e tem a métrica estruturada e o detalhe não estruturado no mesmo painel.

Por predefinição, não enviamos os registos para fora do anfitrião. O Loki guarda-os localmente com retenção de 30 dias; quem está de piquete abre um túnel SSH para o Grafana quando é preciso. Os clientes que queiram registos centralizados de vários servidores podem apontar o Loki para S3 ou correr uma instância regional — isso é uma questão de implementação, não de arquitetura.

Métricas do vLLM e do SGLang — instrumente a aplicação, não apenas o metal

O DCGM diz-lhe que a GPU está ocupada. Não lhe diz se os pedidos de inferência respondem em 200 ms ou em 2 s. Para isso, instrumenta-se a camada de serviço.

O vLLM expõe /metrics nativamente na mesma porta da API OpenAI. Com as definições predefinidas, o endpoint em :8000/metrics publica métricas Prometheus com o prefixo vllm: (que passa a vllm_ após a recolha do Prometheus). As que vale a pena recolher:

Métrica do vLLM Significado
vllm:e2e_request_latency_seconds Latência ponta a ponta do pedido (histograma)
vllm:time_to_first_token_seconds TTFT — o número que os utilizadores realmente sentem
vllm:time_per_output_token_seconds Velocidade de geração de tokens (histograma)
vllm:num_requests_running Pedidos ativos em curso
vllm:num_requests_waiting Profundidade da fila
vllm:gpu_cache_usage_perc Utilização da cache KV (0–1)
vllm:request_prompt_tokens Distribuição do comprimento do prompt

A combinação vllm:num_requests_waiting > 0 e DCGM_FI_DEV_GPU_UTIL < 90% significa que a fila está a acumular enquanto a GPU está parada — normalmente um estrangulamento do tokenizer ou do escalonador, não de cálculo. Só se vê isso com ambas as métricas no mesmo dashboard, que é precisamente a razão de unificar a telemetria da aplicação e do hardware num só Prometheus.

O NVIDIA NIM expõe as mesmas métricas do vLLM em /v1/metrics sem lhes mudar o nome, pelo que os seus dashboards e regras de alerta de vLLM passam sem alterações para uma implementação servida por NIM. O SGLang publica um conjunto semelhante na sua própria porta (30000 por predefinição); o servidor HTTP do llama.cpp expõe um subconjunto mais pequeno. O Triton publica a sua própria taxonomia. Seja qual for o que servir, faça scraping da aplicação — e não apenas do hardware.

Regras do Alertmanager — as que realmente expedimos

Os dashboards são bonitos. Os alertas são úteis. As regras abaixo são as que apanharam problemas reais em hardware real de clientes.

groups:
  - name: gpu
    interval: 30s
    rules:
      - alert: GPUTempCritical
        expr: DCGM_FI_DEV_GPU_TEMP > 87
        for: 30s
        labels: { severity: critical }
        annotations:
          summary: "GPU {{ $labels.gpu }} thermal critical ({{ $value }} °C)"

      - alert: GPUThermalThrottling
        expr: rate(DCGM_FI_DEV_THERMAL_VIOLATION[5m]) > 0
        for: 1m
        labels: { severity: warning }

      - alert: GPUECCUncorrectable
        expr: increase(DCGM_FI_DEV_ECC_DBE_VOL_TOTAL[10m]) > 0
        labels: { severity: critical }
        annotations:
          summary: "GPU {{ $labels.gpu }} uncorrectable ECC — schedule replacement"

      - alert: GPUXIDError
        expr: increase(DCGM_FI_DEV_XID_ERRORS[5m]) > 0
        labels: { severity: critical }

      - alert: GPUPowerEnvelopeExceeded
        expr: DCGM_FI_DEV_POWER_USAGE > 590  # 5090 nominal 575 W; alarm above sustained ceiling
        for: 5m
        labels: { severity: warning }

      - alert: GPUIdleDuringWork
        expr: DCGM_FI_DEV_GPU_UTIL < 5 and DCGM_FI_DEV_FB_USED > 1024
        for: 10m
        labels: { severity: warning }
        annotations:
          summary: "GPU {{ $labels.gpu }} idle with VRAM allocated — likely hung"

  - name: system
    interval: 30s
    rules:
      - alert: HostMemoryLow
        expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) < 0.05
        for: 2m
        labels: { severity: critical }

      - alert: OOMKillerFired
        expr: increase(node_vmstat_oom_kill[5m]) > 0
        labels: { severity: critical }

      - alert: ContainerRestartLoop
        expr: rate(container_start_time_seconds[15m]) > 3
        for: 10m
        labels: { severity: warning }

  - name: serving
    interval: 30s
    rules:
      - alert: vLLMQueueBacklog
        expr: vllm:num_requests_waiting > 10
        for: 5m
        labels: { severity: warning }

      - alert: vLLMHighLatency
        expr: histogram_quantile(0.95, rate(vllm:e2e_request_latency_seconds_bucket[5m])) > 10
        for: 5m
        labels: { severity: warning }

Decisões assumidas nessas regras:

  • 87 °C como crítico para a temperatura da GPU. Na maioria das placas, uma 5090 entra em throttling na casa dos 80 e muitos graus. Se a sua sala não consegue manter as placas abaixo dos 80 °C em carga sustentada, tem um problema de AVAC e não de software.
  • Qualquer ECC não corrigível chama quem está de piquete. Um único evento ECC de duplo bit invalida o que estiver nessa página de VRAM — um passo de treino fica errado, um resultado de inferência fica errado. A placa precisa de substituição, não de reinício.
  • GPUIdleDuringWork é o detetor de deadlock. > 1 GiB alocado e < 5% de utilização durante 10 minutos significa que alguma coisa está presa. Apanha bloqueios do lado do CUDA que a aplicação ignora alegremente.
  • O alerta do OOM killer é a regra mais esquecida em qualquer implementação. O Linux a matar o seu treino em silêncio e o Docker a reiniciá-lo sem alarde é o modo de falha que mais horas de engenharia desperdiça por ano. Torne-o bem audível.
  • O ciclo de reinícios do contentor apanha ciclos de reinício do NIM e do vLLM que parecem saudáveis vistos de fora (o contentor está "a correr") mas que na realidade rebentam a cada carregamento do modelo.

Chassis e armazenamento — IPMI e SMART

O DCGM fica-se pela GPU. O node_exporter fica-se pelo sistema operativo. O resto do chassis — ventoinhas, fontes de alimentação, temperatura ambiente, saúde do armazenamento — exige mais dois exporters.

ipmi_exporter (prometheus-community) fala com o BMC através de IPMI/RMCP e expõe telemetria ao nível do chassis: RPM de cada ventoinha, tensão e corrente de entrada da fonte de alimentação, entradas do registo de eventos do sistema, temperatura ambiente à entrada, estado do watchdog do BMC. Num chassis Supermicro ou Bone64c com um BMC funcional, isto é meio dia de trabalho e apanha coisas que o DCGM literalmente não consegue ver — uma fonte de alimentação a falhar na configuração de 8 GPU com fonte dupla aparece como uma quebra de tensão nos dados dos sensores ipmi minutos antes de a GPU saltar para o XID 79. Corra-o no anfitrião (precisa de /dev/ipmi0) ou remotamente, com credenciais do BMC guardadas, segundo o padrão de exporter multi-alvo.

smartctl_exporter (ou o mais antigo smart_exporter) lê os atributos SMART de NVMe e SATA: indicador de desgaste do suporte, reserva disponível, temperatura, contagem de erros. As cargas de trabalho de IA são brutais para o NVMe — carregadores de datasets, escrita de checkpoints e caches do HuggingFace esgotam em meses os objetivos de desgaste empresariais em discos de gama de consumo. A métrica para alarme é nvme_available_spare a descer abaixo de 20% e nvme_percentage_used (o indicador de desgaste) a subir acima de 80%. A falha de disco é a segunda avaria de hardware mais comum num servidor de IA em carga, logo a seguir à categoria riser/fonte de alimentação.

Uma implementação completa de monitorização de IA da Kentino inclui ambos. O custo marginal é de minutos; o valor, da primeira vez que uma ventoinha falha em silêncio ou que um Samsung 990 Pro chega ao seu teto de DWPD, é de horas.

Um docker-compose real para a VM de gestão

O que realmente implementamos na máquina de gestão. Ajuste host.docker.internal (ou use o hostname/IP do servidor de GPU) para apontar o Prometheus às portas dos exporters do anfitrião com GPU.

version: "3.8"

networks:
  monitoring: { driver: bridge }

volumes:
  prometheus_data:
  grafana_data:
  loki_data:

services:
  prometheus:
    image: prom/prometheus:v3.0.0
    restart: unless-stopped
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./rules:/etc/prometheus/rules:ro
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--storage.tsdb.retention.time=30d"
      - "--storage.tsdb.retention.size=20GB"
      - "--web.enable-lifecycle"
    ports: ["9090:9090"]
    networks: [monitoring]

  grafana:
    image: grafana/grafana:11.4.0
    restart: unless-stopped
    environment:
      - GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/grafana_pw
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
    secrets: [grafana_pw]
    ports: ["3000:3000"]
    networks: [monitoring]

  alertmanager:
    image: prom/alertmanager:v0.28.0
    restart: unless-stopped
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
    ports: ["9093:9093"]
    networks: [monitoring]

  loki:
    image: grafana/loki:3.3.0
    restart: unless-stopped
    command: -config.file=/etc/loki/loki.yml
    volumes:
      - ./loki.yml:/etc/loki/loki.yml:ro
      - loki_data:/loki
    ports: ["3100:3100"]
    networks: [monitoring]

secrets:
  grafana_pw: { file: ./secrets/grafana_pw.txt }

No próprio anfitrião com GPU (compose separado, no servidor de GPU):

services:
  dcgm-exporter:
    image: nvcr.io/nvidia/k8s/dcgm-exporter:4.5.1-4.8.0-ubuntu22.04
    restart: unless-stopped
    runtime: nvidia
    environment: [NVIDIA_VISIBLE_DEVICES=all]
    cap_add: [SYS_ADMIN]
    ports: ["9400:9400"]

  node-exporter:
    image: prom/node-exporter:v1.9.0
    restart: unless-stopped
    pid: host
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - "--path.procfs=/host/proc"
      - "--path.sysfs=/host/sys"
      - "--path.rootfs=/rootfs"
    ports: ["9100:9100"]

  ipmi-exporter:
    image: prometheuscommunity/ipmi-exporter:v1.10.0
    restart: unless-stopped
    privileged: true
    volumes: ["/dev/ipmi0:/dev/ipmi0"]
    ports: ["9290:9290"]

  smartctl-exporter:
    image: prometheuscommunity/smartctl-exporter:v0.13.0
    restart: unless-stopped
    privileged: true
    ports: ["9633:9633"]

  promtail:
    image: grafana/promtail:3.3.0
    restart: unless-stopped
    volumes:
      - /var/log:/var/log:ro
      - ./promtail.yml:/etc/promtail/promtail.yml:ro
    command: -config.file=/etc/promtail/promtail.yml

A configuração de recolha do Prometheus na VM de gestão:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - /etc/prometheus/rules/*.yml

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

scrape_configs:
  - job_name: dcgm
    static_configs:
      - targets: ["k-ai-01.lan:9400", "k-ai-02.lan:9400"]

  - job_name: node
    static_configs:
      - targets: ["k-ai-01.lan:9100", "k-ai-02.lan:9100"]

  - job_name: ipmi
    static_configs:
      - targets: ["k-ai-01.lan:9290", "k-ai-02.lan:9290"]

  - job_name: smart
    static_configs:
      - targets: ["k-ai-01.lan:9633", "k-ai-02.lan:9633"]

  - job_name: vllm
    metrics_path: /metrics
    static_configs:
      - targets: ["k-ai-01.lan:8000"]

Esta é uma stack funcional para um laboratório de um a três servidores. A partir de quatro ou cinco servidores, mude a configuração de recolha do Prometheus para service discovery baseado em ficheiros ou — se estiver em Kubernetes — para o Helm chart do DCGM-exporter incluído no GPU Operator e para os CRD ServiceMonitor do Prometheus Operator.

OpenTelemetry, Pixie, eBPF — o panorama em 2026

Uma nota sobre as peças em movimento, porque a pergunta surge sempre.

OpenTelemetry é a norma da CNCF para instrumentação de observabilidade e, desde o início de 2026, os três tipos de sinal (métricas, traces, registos) estão estáveis. O pipeline do OTel Collector está a substituir agentes específicos de fabricante em muitas organizações, como router universal de telemetria. Para um servidor de IA, a resposta pragmática em 2026 é: manter o Prometheus para métricas (o DCGM-exporter e o node_exporter falam Prometheus nativamente, e as suas regras de alerta estão escritas em PromQL) e acrescentar um OTel Collector se e quando precisar de tracing distribuído ao longo de um grafo de serviço de inferência (pedido → gateway de API → vLLM → chamada de ferramenta → base de dados vetorial → resposta). Numa instalação de servidor único com um modelo por trás do nginx, o OTel acrescenta custo sem valor. Os 71% de organizações que "usam ambos" usam o Prometheus para o metal e o OTel para traces de aplicação — uma divisão sensata.

O Pixie é uma ferramenta de observabilidade nativa de Kubernetes que usa eBPF para recolher métricas, traces e registos ao nível do kernel sem alterações de código. O desenvolvimento de 2026 que vale a pena acompanhar é o trabalho de eBPF-on-GPU (bpftime, eGPU, módulos de kernel abertos da NVIDIA) que estende a instrumentação eBPF aos kernels de GPU via injeção de PTX em tempo de execução. Hoje está ao nível de investigação e não faz parte de nenhuma stack de produção que expedimos. Por agora, o DCGM é a resposta suportada.

O profiling contínuo (Grafana Phlare, Pyroscope) é um terceiro acessório que vale a pena conhecer. Em cargas de inferência em que controla o código da framework (patches próprios ao vLLM, otimizações de tokenizer), diz-lhe que funções consomem o CPU. Para puro serviço de modelos com contentores de origem, é exagero.

O que corre mal (edição monitorização)

Modos de falha previsíveis da própria stack, por ordem da frequência com que incomodam:

  • O disco do Prometheus enche. A retenção predefinida é de 15 dias; nós definimos 30 com um teto de 20 GB. Acima de 60 dias numa máquina em carga, conte com dezenas de GB. Defina a retenção por tempo e por tamanho.
  • O DCGM-exporter perde as GPU depois de uma atualização do driver. Sintoma: todos os painéis de GPU ficam em branco. Solução: reiniciar o contentor; voltar a correr nvidia-ctk runtime configure se o runtime mudou de sítio.
  • Alertmanager não configurado para o recetor que realmente usa. As pessoas põem o Prometheus e o Grafana de pé, esquecem-se de apontar o Alertmanager para o e-mail ou o Slack e descobrem seis meses depois que nunca disparou um único alerta. Teste disparando de propósito GPUTempCritical com uma carga de stress, ou use amtool alert add para gerar um alerta sintético logo no primeiro dia.
  • Explosão de cardinalidade por causa de etiquetas por pedido. Não etiquete as métricas do vLLM com user_id nem request_id. O Prometheus não foi concebido para isso — vai esgotar a memória da base de dados.
  • Fuga da palavra-passe do Grafana pelo env do compose. Use secrets do Docker e não GF_SECURITY_ADMIN_PASSWORD no bloco environment. O docker inspect e os registos expõem os valores de ambiente.
  • Gauge de XID que não volta a zero. Como referido, o gauge de XID do DCGM-exporter pode ficar preso no último valor observado após uma recuperação. Combine a métrica com a leitura contínua do syslog no Loki por NVRM: para evitar falsa confiança.

A opinião honesta

A maioria dos laboratórios instala o Grafana uma vez, constrói um dashboard que a equipa admira durante uma semana e nunca mais lhe olha. O dashboard é um artefacto gratificante; não é o que apanha os seus problemas. São os alertas que apanham os seus problemas. Configure o Alertmanager com um recetor a sério (e-mail, Slack, PagerDuty) e um pequeno conjunto de regras de alta precisão — temperatura da GPU, ECC de duplo bit, XID, OOM killer, ciclo de reinícios do contentor — e afine-as até só dispararem quando algo está mesmo mal. Faça isto primeiro. Só depois construa dashboards para a história do diagnóstico pós-incidente.

A outra metade da opinião honesta: à escala Kentino de um único servidor, esta stack dar-lhe-á talvez um alerta por mês e, na maioria dos meses, será um falso positivo que acaba por ignorar. É o sistema a funcionar. O valor está no alerta que dispara no dia em que um riser começa a cozer, dois dias antes de a placa saltar para o XID 79, quando ainda há tempo de voltar a encaixar um cabo em vez de enviar uma GPU para RMA. Esse único acontecimento paga todo o esforço de monitorização, e paga-o muitas vezes.

O que fazer a seguir

Para um servidor construído pela Kentino que entra em produção esta semana:

  1. Ponha de pé a VM de gestão ou o nó de serviço. Uma máquina de 4 núcleos / 8 GB é mais do que suficiente. Instale o Docker. Aplique o compose prometheus + grafana + alertmanager + loki acima.
  2. No anfitrião com GPU, instale o nvidia-container-toolkit (conforme L02) e confirme que docker run --rm --gpus all nvidia/cuda:13.0.0-base-ubuntu24.04 nvidia-smi funciona.
  3. Instale dcgm-exporter, node-exporter, ipmi-exporter, smartctl-exporter e promtail no anfitrião com GPU. Confirme que cada endpoint /metrics devolve dados.
  4. Aponte o Prometheus aos cinco alvos de exporter e ainda ao endpoint /metrics do seu vLLM. Recarregue (curl -X POST :9090/-/reload).
  5. Importe os dashboards 12239 e 1860 do Grafana. Confirme que os painéis de GPU e de sistema se preenchem.
  6. Ligue o Alertmanager ao seu recetor de e-mail ou Slack. Dispare um alerta sintético com amtool. Se o alerta de teste não chegar, nenhum alerta real chegará.
  7. Corra uma carga de stress (gpu-burn durante uma hora, ou um treino a sério) e acompanhe os dashboards. É aqui que descobre que a sua sala não consegue manter as GPU abaixo dos 80 °C, que o NVMe é o estrangulamento ou que a cache KV está subdimensionada — tudo coisas mais fáceis de corrigir no primeiro dia do que na terceira semana.

Artigos complementares: L01 sobre fixação de versões de driver, L02 sobre CUDA e o runtime de contentores, L03 sobre afinação do kernel, L04 sobre a escolha do sistema de ficheiros.

Monitorizar primeiro. Afinar depois. Tudo o resto é adivinhar.


Este artigo faz parte da Kentino Wiki, uma série de referência sobre computação de IA, robótica e os sistemas que as ligam. Comentários e correções são bem-vindos em info@kentino.com.