Saltar a contenido

Consultas PromQL

PromQL, abreviatura de Prometheus Query Language, es el lenguaje utilizado para consultar, seleccionar, transformar y agregar métricas almacenadas en Prometheus.

Durante el curso se utilizará PromQL para analizar métricas de Node Exporter y construir paneles operativos en Grafana. Las consultas permitirán responder preguntas como:

  • ¿Está disponible un servicio?
  • ¿Qué porcentaje de CPU está utilizando el equipo?
  • ¿Cuánta memoria queda disponible?
  • ¿Qué espacio libre existe en el sistema de archivos?
  • ¿Cuál es el tráfico de red?
  • ¿Qué targets están caídos?
  • ¿Cómo ha evolucionado una métrica durante los últimos minutos?

Objetivos

Al finalizar esta sesión, el alumno podrá:

  • Comprender la estructura de una métrica de Prometheus.
  • Ejecutar consultas instantáneas en la interfaz web de Prometheus.
  • Utilizar selectores de métricas y etiquetas.
  • Diferenciar entre vectores instantáneos y vectores de rango.
  • Utilizar operadores aritméticos, de comparación y lógicos.
  • Calcular porcentajes de CPU, memoria y almacenamiento.
  • Utilizar funciones como rate, irate, increase, avg_over_time y max_over_time.
  • Agrupar resultados mediante sum, avg, min, max y count.
  • Filtrar resultados con etiquetas.
  • Detectar targets disponibles y no disponibles.
  • Integrar consultas PromQL en Grafana.
  • Crear consultas reutilizables para dashboards y alertas.
  • Diagnosticar errores habituales de sintaxis y de interpretación.

Introducción

Prometheus almacena datos como series temporales. Cada serie está formada por:

  • Un nombre de métrica.
  • Un conjunto de etiquetas.
  • Una secuencia de valores asociados a marcas de tiempo.

Una serie temporal puede representarse conceptualmente así:

nombre_de_metrica{etiqueta="valor"} valor

Ejemplo:

up{job="node_exporter", instance="localhost:9100"} 1

En este ejemplo:

  • up es el nombre de la métrica.
  • job e instance son etiquetas.
  • node_exporter y localhost:9100 son valores de etiquetas.
  • 1 indica que el target está disponible.

Si el target no está disponible, Prometheus normalmente mostrará:

up{job="node_exporter", instance="localhost:9100"} 0

Acceso a la interfaz de Prometheus

La interfaz web de Prometheus suele estar disponible en:

http://localhost:9090

Para ejecutar una consulta:

  1. Abre Prometheus en el navegador.
  2. Accede a la sección Query o Graph.
  3. Escribe una consulta en el campo de expresión.
  4. Ejecuta la consulta.
  5. Selecciona la vista de tabla o gráfico.
  6. Revisa las etiquetas y los valores devueltos.

Comprobar que Prometheus está disponible

Desde la terminal:

curl http://localhost:9090/-/healthy

Resultado esperado:

Prometheus is Healthy.

Ejecutar una consulta mediante la API

La API HTTP de Prometheus permite ejecutar consultas desde la terminal.

curl -sG http://localhost:9090/api/v1/query \
  --data-urlencode 'query=up'

Si jq está instalado:

curl -sG http://localhost:9090/api/v1/query \
  --data-urlencode 'query=up' \
  | jq

Estructura de una métrica

Nombre de métrica

Una consulta sencilla puede contener únicamente el nombre de una métrica:

up

Esta consulta devuelve el estado de todos los targets conocidos por Prometheus.

Otros ejemplos:

node_memory_MemAvailable_bytes
node_filesystem_avail_bytes
node_load1

Etiquetas

Las etiquetas permiten diferenciar distintas series que comparten el mismo nombre de métrica.

Ejemplo:

up{job="node_exporter"}

Esta consulta devuelve únicamente las series cuyo valor de job sea node_exporter.

Otro ejemplo:

node_memory_MemAvailable_bytes{instance="localhost:9100"}

Selector exacto

El operador = selecciona etiquetas con un valor exacto:

up{job="node_exporter"}

Selector distinto

El operador != excluye las series cuyo valor coincide:

up{job!="node_exporter"}

Expresión regular positiva

El operador =~ selecciona valores que coinciden con una expresión regular:

up{job=~"node_exporter|prometheus"}

Seleccionar varias instancias:

up{instance=~"server01:9100|server02:9100"}

Expresión regular negativa

El operador !~ excluye los valores que coinciden con una expresión regular:

up{job!~"pushgateway|blackbox"}

Combinar varias etiquetas

up{
  job="node_exporter",
  instance="localhost:9100"
}

Las etiquetas dentro de un selector se separan mediante comas.

Tipos de datos de PromQL

PromQL trabaja con varios tipos de datos principales.

Vector instantáneo

Un vector instantáneo contiene una muestra por cada serie seleccionada en un momento concreto.

Ejemplo:

up

También:

node_load1

Vector de rango

Un vector de rango contiene las muestras de una serie durante un intervalo de tiempo.

Se indica entre corchetes:

node_cpu_seconds_total[5m]

Las unidades de tiempo más utilizadas son:

Unidad Significado
s Segundos
m Minutos
h Horas
d Días
w Semanas
y Años

Ejemplos:

up[10m]
node_network_receive_bytes_total[1h]

Escalar

Un escalar es un valor numérico sin etiquetas.

Ejemplo:

100

También puede obtenerse mediante funciones:

scalar(count(up))

Cadena

PromQL admite cadenas en contextos concretos, aunque las consultas operativas habituales utilizan principalmente vectores y escalares.

Consultas básicas

Consultar todos los targets

up

Consultar Node Exporter

up{job="node_exporter"}

Consultar una métrica concreta

node_load1

Consultar la memoria disponible

node_memory_MemAvailable_bytes

Consultar la memoria total

node_memory_MemTotal_bytes

Consultar el espacio disponible

node_filesystem_avail_bytes

Consultar el tamaño total del sistema de archivos

node_filesystem_size_bytes

Consultar el tiempo de actividad

node_time_seconds - node_boot_time_seconds

Consultar información de la máquina

node_uname_info

Operadores aritméticos

PromQL permite utilizar operadores matemáticos.

Operador Operación
+ Suma
- Resta
* Multiplicación
/ División
% Módulo
^ Potencia

Convertir bytes a gigabytes

node_memory_MemTotal_bytes / 1024 / 1024 / 1024

También puedes utilizar una aproximación decimal:

node_memory_MemTotal_bytes / 1e9

Calcular memoria utilizada

node_memory_MemTotal_bytes
-
node_memory_MemAvailable_bytes

Calcular memoria utilizada en porcentaje

(
  1 -
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
) * 100

Calcular memoria disponible en porcentaje

(
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
) * 100

Convertir bytes por segundo a megabytes por segundo

rate(node_network_receive_bytes_total[5m])
/ 1024 / 1024

Operadores de comparación

Los operadores de comparación permiten filtrar o evaluar valores.

Operador Significado
== Igual
!= Distinto
> Mayor que
< Menor que
>= Mayor o igual que
<= Menor o igual que

Targets caídos

up == 0

Targets disponibles

up == 1

Memoria disponible inferior al 20 %

(
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
) * 100 < 20

Sistemas de archivos con menos del 15 % libre

(
  node_filesystem_avail_bytes
  /
  node_filesystem_size_bytes
) * 100 < 15

CPU con carga elevada

node_load1 > 2

El valor adecuado depende del número de CPU y de las características del equipo. Un umbral fijo no debe interpretarse sin contexto.

Operadores lógicos

Operador and

Devuelve las series que cumplen ambas condiciones:

up == 0 and up{job="node_exporter"}

Operador or

Devuelve las series que cumplen una condición u otra:

up{job="node_exporter"} or up{job="prometheus"}

Operador unless

Devuelve las series de la primera expresión que no tengan correspondencia en la segunda:

up unless up{job="node_exporter"}

Métricas de disponibilidad

Métrica up

La métrica up es una de las métricas más importantes de Prometheus.

up

Interpretación:

Valor Significado
1 El scraping ha funcionado
0 El scraping ha fallado

Comprobar Node Exporter

up{job="node_exporter"}

Contar targets disponibles

count(up == 1)

Contar targets caídos

count(up == 0)

Calcular el porcentaje de targets disponibles

100 * sum(up) / count(up)

Calcular la disponibilidad de Node Exporter

100 *
sum(up{job="node_exporter"})
/
count(up{job="node_exporter"})

Mostrar únicamente targets caídos

up{job="node_exporter"} == 0

Consultar el último error de scraping

La información detallada del último error se consulta normalmente mediante la interfaz de targets o la API de Prometheus:

curl -s http://localhost:9090/api/v1/targets | jq

Métricas de CPU

Node Exporter expone la métrica:

node_cpu_seconds_total

Esta métrica es un contador acumulativo. Por ese motivo, normalmente se consulta mediante rate o irate.

CPU por modo

rate(node_cpu_seconds_total[5m])

La consulta devuelve series diferenciadas por etiquetas como:

cpu
mode
instance
job

CPU en modo idle

rate(
  node_cpu_seconds_total{
    mode="idle"
  }[5m]
)

Porcentaje de CPU utilizada

Una consulta habitual es:

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

La consulta:

  1. Calcula la tasa de tiempo en modo idle.
  2. Obtiene la media entre las CPU.
  3. Resta el resultado a 1.
  4. Multiplica por 100.

CPU utilizada por instancia

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

CPU utilizada por núcleo

100 * (
  1 -
  rate(
    node_cpu_seconds_total{
      mode="idle"
    }[5m]
  )
)

CPU utilizada por modo

100 *
sum by (instance, mode) (
  rate(node_cpu_seconds_total[5m])
)

Uso de CPU durante un intervalo corto

100 * (
  1 -
  avg by (instance) (
    irate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

irate reacciona más rápidamente a cambios recientes, pero puede ser más inestable que rate. Para dashboards operativos suele ser preferible rate.

Métricas de memoria

Memoria total

node_memory_MemTotal_bytes

Memoria disponible

node_memory_MemAvailable_bytes

Memoria libre

node_memory_MemFree_bytes

MemFree y MemAvailable no significan exactamente lo mismo. Para estimar la memoria utilizable por el sistema suele ser más adecuado utilizar MemAvailable.

Memoria utilizada

node_memory_MemTotal_bytes
-
node_memory_MemAvailable_bytes

Memoria utilizada en porcentaje

100 * (
  1 -
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
)

Memoria disponible en porcentaje

100 *
node_memory_MemAvailable_bytes
/
node_memory_MemTotal_bytes

Memoria utilizada en gigabytes

(
  node_memory_MemTotal_bytes
  -
  node_memory_MemAvailable_bytes
) / 1024 / 1024 / 1024

Memoria disponible en gigabytes

node_memory_MemAvailable_bytes
/ 1024 / 1024 / 1024

Métricas de almacenamiento

Node Exporter proporciona métricas de sistemas de archivos.

Espacio disponible

node_filesystem_avail_bytes

Espacio libre para usuarios no privilegiados

node_filesystem_avail_bytes

Tamaño total del sistema de archivos

node_filesystem_size_bytes

Espacio utilizado

node_filesystem_size_bytes
-
node_filesystem_avail_bytes

Porcentaje utilizado

100 * (
  1 -
  node_filesystem_avail_bytes
  /
  node_filesystem_size_bytes
)

Porcentaje libre

100 *
node_filesystem_avail_bytes
/
node_filesystem_size_bytes

Filtrar un punto de montaje

node_filesystem_avail_bytes{
  mountpoint="/"
}

Filtrar por sistema de archivos

node_filesystem_avail_bytes{
  fstype="ext4"
}

Excluir sistemas de archivos virtuales

node_filesystem_avail_bytes{
  fstype!~"tmpfs|overlay|squashfs"
}

Excluir dispositivos temporales

node_filesystem_avail_bytes{
  device!~"rootfs|tmpfs"
}

Porcentaje utilizado de la raíz

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
)

Filtrar valores no válidos

En algunos sistemas aparecen sistemas de archivos con tamaño cero. Para evitar divisiones problemáticas:

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/"
  }
)
and
node_filesystem_size_bytes{
  mountpoint="/"
} > 0

Métricas de red

Las métricas de tráfico de red suelen ser contadores acumulativos.

Bytes recibidos

node_network_receive_bytes_total

Bytes transmitidos

node_network_transmit_bytes_total

Tráfico recibido por segundo

rate(node_network_receive_bytes_total[5m])

Tráfico transmitido por segundo

rate(node_network_transmit_bytes_total[5m])

Tráfico recibido en megabytes por segundo

rate(node_network_receive_bytes_total[5m])
/ 1024 / 1024

Filtrar una interfaz

rate(
  node_network_receive_bytes_total{
    device="eth0"
  }[5m]
)

En algunos entornos la interfaz puede llamarse:

ens33
enp0s3
eth0
wlan0

Consultar las interfaces disponibles:

node_network_receive_bytes_total

Excluir interfaces virtuales

rate(
  node_network_receive_bytes_total{
    device!~"lo|docker.*|veth.*|br-.*"
  }[5m]
)

Errores de recepción

rate(node_network_receive_errs_total[5m])

Paquetes descartados

rate(node_network_receive_drop_total[5m])

Métricas de carga

Carga de un minuto

node_load1

Carga de cinco minutos

node_load5

Carga de quince minutos

node_load15

Comparar carga con el número de CPU

node_load1
/
count by (instance) (
  node_cpu_seconds_total{
    mode="idle"
  }
)

Una carga superior al número de CPU puede indicar una presión importante, aunque debe interpretarse junto con el uso de CPU, la memoria y la espera de disco.

Métricas de tiempo y actividad

Tiempo actual del sistema

node_time_seconds

Momento de arranque

node_boot_time_seconds

Tiempo de actividad

node_time_seconds - node_boot_time_seconds

Tiempo de actividad en horas

(
  node_time_seconds
  -
  node_boot_time_seconds
) / 3600

Tiempo de actividad en días

(
  node_time_seconds
  -
  node_boot_time_seconds
) / 86400

Funciones de PromQL

rate

Calcula la tasa media por segundo de un contador durante un intervalo.

rate(
  node_cpu_seconds_total[5m]
)

Es adecuada para:

  • Uso de CPU.
  • Tráfico de red.
  • Operaciones de disco.
  • Errores acumulativos.
  • Peticiones por segundo.

irate

Calcula una tasa basada principalmente en las muestras más recientes:

irate(
  node_cpu_seconds_total[5m]
)

Es más sensible a cambios rápidos y puede mostrar más variaciones.

increase

Calcula cuánto ha aumentado un contador durante un intervalo:

increase(
  node_network_receive_bytes_total[1h]
)

La consulta indica cuántos bytes se han recibido aproximadamente durante la última hora.

delta

Calcula la diferencia entre el primer y el último valor de una métrica de tipo gauge:

delta(
  node_load1[15m]
)

avg_over_time

Calcula la media de una métrica durante un intervalo:

avg_over_time(
  node_load1[15m]
)

min_over_time

Obtiene el valor mínimo:

min_over_time(
  node_load1[1h]
)

max_over_time

Obtiene el valor máximo:

max_over_time(
  node_load1[1h]
)

last_over_time

Obtiene la última muestra disponible dentro de un intervalo:

last_over_time(
  node_load1[15m]
)

count_over_time

Cuenta las muestras existentes durante un intervalo:

count_over_time(
  node_load1[1h]
)

Agregaciones

Las agregaciones permiten resumir varias series.

sum

Suma los valores:

sum(up)

avg

Calcula la media:

avg(node_load1)

min

Obtiene el valor mínimo:

min(node_load1)

max

Obtiene el valor máximo:

max(node_load1)

count

Cuenta las series:

count(up)

count_values

Cuenta cuántas series tienen cada valor:

count_values("estado", up)

Agrupar mediante by

Calcular la disponibilidad por trabajo:

sum by (job) (up)

Contar targets por trabajo:

count by (job) (up)

Calcular la media de carga por instancia:

avg by (instance) (node_load1)

Agrupar mediante without

Excluir determinadas etiquetas de la agrupación:

sum without (cpu, mode) (
  rate(node_cpu_seconds_total[5m])
)

Operadores vectoriales y coincidencia de etiquetas

PromQL debe saber cómo relacionar las series cuando se combinan dos expresiones.

Comparar expresiones con etiquetas compatibles

node_memory_MemAvailable_bytes
/
node_memory_MemTotal_bytes

Si ambas métricas comparten las mismas etiquetas relevantes, Prometheus puede relacionarlas automáticamente.

Utilizar on

Indicar las etiquetas utilizadas para hacer coincidir las series:

rate(node_cpu_seconds_total[5m])
  / on (instance)
count by (instance) (
  node_cpu_seconds_total{
    mode="idle"
  }
)

Utilizar ignoring

Ignorar determinadas etiquetas al hacer la coincidencia:

rate(node_cpu_seconds_total[5m])
  / ignoring (cpu, mode)
node_cpu_seconds_total

Debe utilizarse con cuidado. Una coincidencia incorrecta puede producir resultados vacíos o combinaciones inesperadas.

Utilizar group_left

Permite conservar etiquetas adicionales de la expresión derecha cuando existe una relación de uno a muchos.

Ejemplo conceptual:

metric_a
  * on (instance)
  group_left(label_extra)
metric_b

No es necesario utilizar group_left en las consultas básicas del curso, pero resulta útil en métricas con metadatos adicionales.

Funciones de etiquetas

label_replace

Permite crear o modificar etiquetas a partir de otras etiquetas.

Ejemplo:

label_replace(
  up,
  "servidor",
  "$1",
  "instance",
  "([^:]+):.*"
)

Esta consulta crea una etiqueta servidor a partir del nombre anterior a los dos puntos de instance.

label_join

Combina varias etiquetas en una nueva etiqueta:

label_join(
  up,
  "destino",
  ":",
  "job",
  "instance"
)

Estas funciones son útiles para adaptar las etiquetas a una visualización o a una convención de nombres.

Consultas para dashboards

Panel de disponibilidad

up

Unidad recomendada:

none

Valores posibles:

0 = DOWN
1 = UP

Panel de CPU

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

Unidad recomendada:

percent (0-100)

Panel de memoria utilizada

100 * (
  1 -
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
)

Unidad recomendada:

percent (0-100)

Panel de memoria disponible

node_memory_MemAvailable_bytes

Unidad recomendada:

bytes

Panel de almacenamiento utilizado

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
)

Unidad recomendada:

percent (0-100)

Panel de carga del sistema

node_load1

Unidad recomendada:

none

Panel de tráfico recibido

rate(
  node_network_receive_bytes_total{
    device!~"lo|docker.*|veth.*|br-.*"
  }[5m]
)

Unidad recomendada:

bytes/sec

Panel de tráfico transmitido

rate(
  node_network_transmit_bytes_total{
    device!~"lo|docker.*|veth.*|br-.*"
  }[5m]
)

Unidad recomendada:

bytes/sec

Variables de Grafana

Las variables permiten reutilizar un dashboard para varias instancias, trabajos o dispositivos.

Variable de instancias

En Grafana, una consulta habitual para una variable de instancia es:

label_values(up, instance)

En versiones recientes de Grafana también puede utilizarse una consulta basada en Prometheus:

query_result(up)

La sintaxis disponible depende de la versión y del editor de variables.

Variable de trabajos

label_values(up, job)

Variable de dispositivos

label_values(node_network_receive_bytes_total, device)

Utilizar una variable en una consulta

Si la variable se llama instance:

up{instance="$instance"}

Si permite selección múltiple:

up{instance=~"$instance"}

Para una variable de trabajo:

up{job=~"$job"}

Consulta de CPU con variables

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle",
        instance=~"$instance"
      }[5m]
    )
  )
)

Consultas para alertas

Target no disponible

up{job="node_exporter"} == 0

Memoria disponible baja

(
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
) * 100 < 20

Almacenamiento casi lleno

(
  node_filesystem_avail_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
) * 100 < 15

CPU elevada durante varios minutos

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
) > 80

El tiempo durante el cual debe mantenerse la condición se configura en la regla de alerta, no necesariamente dentro de la consulta.

Carga elevada respecto al número de CPU

node_load1
>
count by (instance) (
  node_cpu_seconds_total{
    mode="idle"
  }
)

Esta consulta es orientativa. La interpretación de la carga debe considerar el tipo de sistema y la actividad que está realizando.

Diferencia entre métricas gauge y counter

Gauge

Un gauge puede subir o bajar.

Ejemplos:

node_load1
node_memory_MemAvailable_bytes
node_filesystem_avail_bytes

Los gauges suelen consultarse directamente:

node_load1

Counter

Un counter aumenta de forma acumulativa y puede reiniciarse cuando se reinicia el proceso.

Ejemplos:

node_cpu_seconds_total
node_network_receive_bytes_total
node_network_transmit_bytes_total

Los counters suelen analizarse mediante:

rate(metric[5m])

o:

increase(metric[1h])

No es recomendable interpretar directamente el valor acumulado de un counter como una tasa actual.

Consultas de diagnóstico

Verificar si existe una métrica

node_memory_MemAvailable_bytes

Si no devuelve resultados:

  • Node Exporter puede no estar disponible.
  • La métrica puede tener otro nombre.
  • Prometheus puede no estar realizando scraping.
  • El target puede estar configurado con otro job.
  • La métrica puede no estar expuesta por la versión instalada.

Consultar todas las métricas de Node Exporter

Desde la terminal:

curl -s http://localhost:9100/metrics

Buscar nombres relacionados con memoria:

curl -s http://localhost:9100/metrics \
  | grep "^node_memory_" \
  | head -30

Buscar nombres relacionados con disco:

curl -s http://localhost:9100/metrics \
  | grep "^node_filesystem_" \
  | head -30

Comprobar los nombres de las métricas en Prometheus

En la interfaz de Prometheus puedes utilizar el explorador de métricas para consultar los nombres disponibles.

También puedes obtener las etiquetas y series mediante la API:

curl -s http://localhost:9090/api/v1/label/__name__/values \
  | jq

Consultar las etiquetas de una métrica

curl -sG http://localhost:9090/api/v1/series \
  --data-urlencode 'match[]=node_load1' \
  | jq

Consultar los targets activos

curl -s http://localhost:9090/api/v1/targets \
  | jq '.data.activeTargets'

Errores habituales

Utilizar una métrica que no existe

Consulta:

node_memory_available_bytes

Si la métrica no existe, revisa el nombre real:

node_memory_MemAvailable_bytes

Los nombres de las métricas distinguen mayúsculas y minúsculas.

Olvidar el intervalo en rate

Incorrecto:

rate(node_cpu_seconds_total)

Correcto:

rate(node_cpu_seconds_total[5m])

Aplicar rate a un gauge

No suele ser correcto aplicar rate directamente a:

node_memory_MemAvailable_bytes

Esta métrica es un gauge y debe consultarse directamente o mediante una función temporal apropiada.

Dividir series incompatibles

Una consulta puede devolver resultados vacíos si las etiquetas de las métricas no coinciden.

Comprueba primero cada parte:

node_memory_MemAvailable_bytes
node_memory_MemTotal_bytes

Después combina ambas:

node_memory_MemAvailable_bytes
/
node_memory_MemTotal_bytes

No filtrar sistemas de archivos

Una consulta general puede incluir tmpfs, overlay u otros sistemas virtuales:

node_filesystem_size_bytes

Es preferible filtrar los sistemas relevantes:

node_filesystem_size_bytes{
  mountpoint="/",
  fstype!~"tmpfs|overlay|squashfs"
}

Utilizar un intervalo demasiado corto

Una consulta como esta puede resultar inestable:

rate(node_cpu_seconds_total[30s])

En muchos entornos es preferible:

rate(node_cpu_seconds_total[5m])

Confundir valor instantáneo con histórico

La vista de tabla muestra el valor en un instante. La vista de gráfico muestra la evolución de la consulta durante un intervalo de tiempo.

Buenas prácticas para escribir consultas

  • Utiliza nombres de métricas exactos.
  • Comprueba primero la métrica sin filtros.
  • Añade etiquetas progresivamente.
  • Usa nombres de etiquetas coherentes.
  • Aplica rate a counters.
  • Usa ventanas de tiempo razonables.
  • Filtra sistemas de archivos virtuales.
  • Comprueba las unidades del resultado.
  • Utiliza by para conservar las etiquetas necesarias.
  • Evita conservar cardinalidad innecesaria.
  • Divide las consultas complejas en partes durante el diagnóstico.
  • Comprueba que el resultado no esté vacío.
  • Documenta los umbrales utilizados.
  • Valida las consultas en Prometheus antes de incorporarlas a Grafana.
  • No asumas que una métrica existe en todas las instalaciones.
  • Comprueba la versión de Node Exporter si faltan métricas.

Sesión práctica 1: comprobar la disponibilidad

En esta sesión se comprobará el estado de los targets configurados.

Objetivo

Ejecutar consultas básicas sobre la métrica up.

Consultar todos los targets

up

Filtrar Node Exporter

up{job="node_exporter"}

Contar targets

count(up)

Contar targets disponibles

count(up == 1)

Contar targets caídos

count(up == 0)

Calcular el porcentaje de disponibilidad

100 * sum(up) / count(up)

Actividad controlada

En el entorno de laboratorio:

  1. Ejecuta up{job="node_exporter"}.
  2. Anota el valor inicial.
  3. Detén Node Exporter:
sudo systemctl stop node_exporter
  1. Espera varios intervalos de scraping.
  2. Ejecuta de nuevo:
up{job="node_exporter"}
  1. Comprueba que el valor cambia a 0.
  2. Inicia el servicio:
sudo systemctl start node_exporter
  1. Espera a que Prometheus vuelva a realizar scraping.
  2. Comprueba que el valor vuelve a 1.

Preguntas de análisis

  • ¿Qué valor tenía el target inicialmente?
  • ¿Cuánto tardó en pasar a 0?
  • ¿Cuánto tardó en volver a 1?
  • ¿Qué relación existe entre el intervalo de scraping y el tiempo observado?
  • ¿Qué mensaje aparece en la página de targets de Prometheus?

Sesión práctica 2: analizar CPU

Objetivo

Construir una consulta para medir el porcentaje de CPU utilizada.

Consultar la métrica base

node_cpu_seconds_total

Consultar únicamente el modo idle

node_cpu_seconds_total{
  mode="idle"
}

Calcular la tasa del modo idle

rate(
  node_cpu_seconds_total{
    mode="idle"
  }[5m]
)

Calcular el porcentaje utilizado

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

Actividad de generación de carga

En el laboratorio, abre una segunda terminal y ejecuta durante unos segundos:

yes > /dev/null

En otra terminal, observa el dashboard o ejecuta la consulta de CPU.

Detén la carga con:

Ctrl + C

Preguntas de análisis

  • ¿Qué ocurre con el porcentaje de CPU mientras se ejecuta yes?
  • ¿Qué ocurre después de detenerlo?
  • ¿Qué diferencia existe entre rate e irate?
  • ¿Qué ventana temporal produce un gráfico más estable?
  • ¿Qué valor devuelve la consulta cuando el equipo está en reposo?

Sesión práctica 3: analizar memoria

Objetivo

Calcular la memoria total, disponible y utilizada.

Consultar la memoria total

node_memory_MemTotal_bytes

Consultar la memoria disponible

node_memory_MemAvailable_bytes

Calcular la memoria utilizada

node_memory_MemTotal_bytes
-
node_memory_MemAvailable_bytes

Calcular el porcentaje utilizado

100 * (
  1 -
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
)

Calcular el porcentaje disponible

100 *
node_memory_MemAvailable_bytes
/
node_memory_MemTotal_bytes

Convertir la memoria utilizada a gigabytes

(
  node_memory_MemTotal_bytes
  -
  node_memory_MemAvailable_bytes
) / 1024 / 1024 / 1024

Comparar con Ubuntu

Desde la terminal:

free -h

Compara los resultados con las consultas de Prometheus.

Preguntas de análisis

  • ¿La memoria total de Prometheus coincide aproximadamente con free -h?
  • ¿Por qué puede existir una pequeña diferencia?
  • ¿Qué métrica es más adecuada para estimar la memoria disponible?
  • ¿Cuál es el porcentaje actual de memoria utilizada?

Sesión práctica 4: analizar almacenamiento

Objetivo

Calcular el espacio utilizado y disponible en el sistema de archivos raíz.

Consultar los sistemas de archivos

node_filesystem_size_bytes

Consultar la raíz

node_filesystem_size_bytes{
  mountpoint="/"
}

Consultar el espacio disponible

node_filesystem_avail_bytes{
  mountpoint="/"
}

Calcular el porcentaje utilizado

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/"
  }
)

Excluir sistemas virtuales

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
)

Comparar con Ubuntu

Desde la terminal:

df -h /

Crear una condición de alerta

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
) > 80

Preguntas de análisis

  • ¿Qué sistema de archivos corresponde a /?
  • ¿Qué valor devuelve df -h /?
  • ¿Qué sistemas virtuales aparecen en Node Exporter?
  • ¿Por qué conviene excluirlos?
  • ¿Qué umbral utilizarías para una alerta de almacenamiento?

Sesión práctica 5: analizar tráfico de red

Objetivo

Medir el tráfico recibido y transmitido por una interfaz.

Consultar las interfaces

node_network_receive_bytes_total

Identificar una interfaz concreta

node_network_receive_bytes_total{
  device="eth0"
}

Sustituye eth0 por el nombre real de la interfaz.

Calcular tráfico recibido

rate(
  node_network_receive_bytes_total[5m]
)

Calcular tráfico transmitido

rate(
  node_network_transmit_bytes_total[5m]
)

Excluir interfaces virtuales

sum by (instance) (
  rate(
    node_network_receive_bytes_total{
      device!~"lo|docker.*|veth.*|br-.*"
    }[5m]
  )
)

Convertir a megabytes por segundo

sum by (instance) (
  rate(
    node_network_receive_bytes_total{
      device!~"lo|docker.*|veth.*|br-.*"
    }[5m]
  )
) / 1024 / 1024

Generar tráfico de prueba

Desde otra terminal puedes realizar una petición al endpoint de métricas:

for i in {1..100}; do
  curl -s http://localhost:9100/metrics > /dev/null
done

Observa el gráfico de tráfico de red y comprueba si aparece alguna variación.

Preguntas de análisis

  • ¿Qué interfaces existen?
  • ¿Cuál es la interfaz principal?
  • ¿Qué diferencia existe entre bytes recibidos y transmitidos?
  • ¿Por qué se utiliza rate?
  • ¿Qué interfaces conviene excluir del dashboard?

Sesión práctica 6: crear un dashboard operativo

Objetivo

Construir un dashboard en Grafana utilizando consultas PromQL verificadas.

Panel de disponibilidad

Consulta:

up{job="node_exporter"}

Configuración recomendada:

Tipo de panel: Stat
Unidad: none
Valor mínimo: 0
Valor máximo: 1

Panel de CPU

Consulta:

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

Configuración recomendada:

Tipo de panel: Time series o Gauge
Unidad: percent (0-100)

Panel de memoria

Consulta:

100 * (
  1 -
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
)

Configuración recomendada:

Tipo de panel: Gauge
Unidad: percent (0-100)

Panel de almacenamiento

Consulta:

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
)

Configuración recomendada:

Tipo de panel: Gauge
Unidad: percent (0-100)

Panel de carga

Consulta:

node_load1

Configuración recomendada:

Tipo de panel: Time series
Unidad: none

Validación del dashboard

Comprueba que:

  • Los paneles muestran datos.
  • Las unidades son correctas.
  • Las etiquetas identifican la instancia.
  • Los valores se actualizan.
  • Los umbrales están documentados.
  • No aparecen sistemas de archivos irrelevantes.
  • La consulta sigue funcionando con el intervalo temporal seleccionado.

Sesión práctica 7: construir una consulta compleja paso a paso

Objetivo

Construir una consulta de porcentaje de CPU sin escribirla completa desde el principio.

Paso 1: localizar la métrica

node_cpu_seconds_total

Paso 2: seleccionar el modo idle

node_cpu_seconds_total{
  mode="idle"
}

Paso 3: calcular la tasa

rate(
  node_cpu_seconds_total{
    mode="idle"
  }[5m]
)

Paso 4: agrupar por instancia

avg by (instance) (
  rate(
    node_cpu_seconds_total{
      mode="idle"
    }[5m]
  )
)

Paso 5: calcular la parte utilizada

1 -
avg by (instance) (
  rate(
    node_cpu_seconds_total{
      mode="idle"
    }[5m]
  )
)

Paso 6: convertir a porcentaje

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

Preguntas de análisis

  • ¿Qué devuelve cada paso?
  • ¿Qué etiquetas se conservan después de avg by (instance)?
  • ¿Por qué se resta el porcentaje idle a 1?
  • ¿Por qué se multiplica por 100?
  • ¿Qué sucedería si se utilizara sum en lugar de avg?

Sesión práctica 8: crear consultas para alertas

Objetivo

Preparar consultas que puedan utilizarse como condiciones de alerta.

Alerta de Node Exporter caído

up{job="node_exporter"} == 0

Alerta de CPU elevada

100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
) > 80

Alerta de memoria baja

100 * (
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
) < 20

Alerta de almacenamiento elevado

100 * (
  1 -
  node_filesystem_avail_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    mountpoint="/",
    fstype!~"tmpfs|overlay|squashfs"
  }
) > 80

Procedimiento

  1. Ejecuta la consulta en Prometheus.
  2. Comprueba que devuelve datos.
  3. Comprueba la unidad del resultado.
  4. Define el umbral.
  5. Configura el tiempo de permanencia.
  6. Añade etiquetas de severidad.
  7. Añade una descripción.
  8. Prueba la condición en el laboratorio.
  9. Documenta el resultado.

Catálogo de consultas

Disponibilidad

up
up{job="node_exporter"}
up == 0
100 * sum(up) / count(up)

CPU

node_cpu_seconds_total
rate(node_cpu_seconds_total[5m])
100 * (
  1 -
  avg by (instance) (
    rate(
      node_cpu_seconds_total{
        mode="idle"
      }[5m]
    )
  )
)

Memoria

node_memory_MemTotal_bytes
node_memory_MemAvailable_bytes
100 * (
  1 -
  node_memory_MemAvailable_bytes
  /
  node_memory_MemTotal_bytes
)

Almacenamiento

node_filesystem_size_bytes{mountpoint="/"}
node_filesystem_avail_bytes{mountpoint="/"}
100 * (
  1 -
  node_filesystem_avail_bytes{mountpoint="/"}
  /
  node_filesystem_size_bytes{mountpoint="/"}
)

Red

rate(node_network_receive_bytes_total[5m])
rate(node_network_transmit_bytes_total[5m])

Carga

node_load1
node_load5
node_load15

Actividad

node_time_seconds - node_boot_time_seconds
(
  node_time_seconds
  -
  node_boot_time_seconds
) / 3600

Puntos clave

  • PromQL es el lenguaje de consulta de Prometheus.
  • Una serie temporal está formada por una métrica, etiquetas, valores y marcas temporales.
  • up permite comprobar la disponibilidad de un target.
  • El valor 1 indica normalmente que el scraping ha funcionado.
  • El valor 0 indica que el scraping ha fallado.
  • Las etiquetas permiten filtrar y distinguir series.
  • = selecciona una etiqueta con coincidencia exacta.
  • =~ utiliza expresiones regulares.
  • Un vector instantáneo representa valores en un momento concreto.
  • Un vector de rango representa valores durante un intervalo.
  • rate se utiliza principalmente con counters.
  • irate reacciona más rápidamente, pero puede ser más inestable.
  • Los gauges suelen consultarse directamente.
  • sum, avg, min, max y count permiten agregar series.
  • by conserva las etiquetas indicadas en una agregación.
  • Las consultas deben validarse en Prometheus antes de utilizarse en Grafana.
  • Las unidades del panel deben corresponder al resultado de la consulta.
  • Los sistemas de archivos virtuales deben filtrarse en las consultas de almacenamiento.
  • Las consultas complejas deben construirse y validarse paso a paso.
  • Los umbrales de alerta deben documentarse y justificarse.

Preguntas de comprobación

  1. ¿Qué significa la métrica up?
  2. ¿Qué diferencia existe entre los valores 0 y 1 de up?
  3. ¿Qué función cumplen las etiquetas de una métrica?
  4. ¿Qué diferencia existe entre {job="node_exporter"} y {job=~"node_.*"}?
  5. ¿Qué es un vector instantáneo?
  6. ¿Qué es un vector de rango?
  7. ¿Qué unidades de tiempo pueden utilizarse en un selector de rango?
  8. ¿Por qué se aplica rate a node_cpu_seconds_total?
  9. ¿Por qué no se debe aplicar normalmente rate a node_memory_MemAvailable_bytes?
  10. ¿Qué diferencia existe entre rate e irate?
  11. ¿Qué consulta permite calcular la memoria utilizada en porcentaje?
  12. ¿Qué consulta permite calcular el porcentaje de CPU utilizado?
  13. ¿Por qué se deben excluir algunos sistemas de archivos en una consulta de almacenamiento?
  14. ¿Qué función cumple sum by (instance)?
  15. ¿Qué diferencia existe entre by y without?
  16. ¿Qué ocurre si una consulta utiliza una métrica inexistente?
  17. ¿Cómo comprobarías si Node Exporter expone una métrica concreta?
  18. ¿Qué consulta permite mostrar targets caídos?
  19. ¿Qué factores deben tenerse en cuenta al elegir una ventana para rate?
  20. ¿Qué pasos seguirías para validar una consulta antes de incorporarla a Grafana?