RetroDash // SATURATION

GUIDESaturación de recursos: CPU, memoria, disco y red

Tema

Requisitos

Para métricas de saturación necesitas:

Notas de Compatibilidad

Variable $job_node

Todas las queries de node_cpu_seconds_total, node_memory_* y node_filesystem_* están filtradas por la variable de dashboard $job_node (por defecto: node-exporter). Si su node_exporter es recolectado bajo un nombre de job diferente, actualice la variable en Configuración del Dashboard → Variables.

Valores bajos de saturación en homelabs

Las métricas de saturación reflejan su carga de trabajo real. En un homelab típico con uso liviano, es completamente normal ver la CPU en 2–10%, la memoria en 30–50% y el I/O de disco cercano a cero. Los valores bajos no son señal de mala configuración — indican que su infraestructura tiene capacidad disponible. Los umbrales están calibrados para cargas de trabajo de producción; no dude en reducir los límites de advertencia/crítico para adaptarlos a la línea base de su homelab.

Mapa de Paneles

┌────────────────────────────────────────┐
│   SATURATION — RESOURCE EXHAUSTION    │
├────────────────────────────────────────┤
│  CPU %   │  Memory %  │  Disk %  │ Net │
│  (gauge) │  (gauge)   │  (gauge) │(gau)│
├────────────────────────────────────────┤
│  CPU + Memory Time Series [12 cols]   │
│  (evolución con thresholds)            │
├────────────────────────────────────────┤
│  Disk I/O [6 cols] │ Disk Free [6 col]│
│  (read/write ops)  │ (por mount)      │
├────────────────────────────────────────┤
│  Resource by Node [12 cols]            │
│  (tabla: CPU, mem, disco por host)     │
├────────────────────────────────────────┤
│  Requests vs Limits [12 cols]          │
│  (desglose de demanda actual vs límite)│
└────────────────────────────────────────┘

Personalización por Panel

CPU % Gauge

Porcentaje de CPU en uso (excluyendo idle).

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

Por instancia específica:

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

Excluir modos específicos (excluir iowait, steal):

100 - (avg(rate(node_cpu_seconds_total{mode=~"idle|iowait"}[5m])) * 100)

Thresholds recomendados: 70% yellow, 85% red

Memory % Gauge

Porcentaje de memoria en uso.

Usando available (recomendado):

100 * (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes))

Usando free (menos preciso):

100 * (1 - (node_memory_MemFree_bytes / node_memory_MemTotal_bytes))

Por nodo:

100 * (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) by (instance)

Thresholds: 80% yellow, 90% red (dejar buffer para caché)

Disk % Gauge

Porcentaje de disco utilizado (por mountpoint).

Default (root partition):

100 * (node_filesystem_used_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})

Excluir tmpfs y sistemas virtuales:

100 * (node_filesystem_used_bytes{fstype!~"tmpfs|devtmpfs|fuse.*",mountpoint!~"/sys.*|/proc.*"}
/ node_filesystem_size_bytes{fstype!~"tmpfs|devtmpfs|fuse.*"}) by (device)

Por mountpoint:

sum by (mountpoint) (100 * (node_filesystem_used_bytes / node_filesystem_size_bytes))

Thresholds: 80% yellow, 90% red

Network Saturation

Porcentaje de ancho de banda saturado.

Usando interface speed (si disponible):

100 * ((rate(node_network_transmit_bytes_total[5m]) * 8)
/ (node_network_speed_bytes * 1000000000))

Sin speed (normalizar por histórico):

rate(node_network_transmit_bytes_total[5m]) /
  avg_over_time(rate(node_network_transmit_bytes_total[5m])[1h:1m])

Por dirección (in/out):

sum by (device) (rate(node_network_receive_bytes_total[5m]))

CPU + Memory Time Series

Gráfico de línea con evolución de ambos recursos.

Query CPU:

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

Query Memory:

100 * (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes))

Per-node breakdown:

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

Añade líneas de threshold: En panel → Alerts → 70% (warning), 85% (critical)

Disk I/O

Operaciones de lectura/escritura por segundo.

Read ops/sec:

rate(node_disk_reads_completed_total{device="sda"}[5m])

Write ops/sec:

rate(node_disk_writes_completed_total{device="sda"}[5m])

Cambiar dispositivo: sdanvme0n1 (NVMe), vda (virtual), etc

Utilization %:

rate(node_disk_io_time_seconds_total{device="sda"}[5m]) * 100

Nota: > 30% I/O wait indica contención de disco

Disk Free by Mount

Espacio disponible por punto de montaje.

node_filesystem_avail_bytes{fstype!~"tmpfs|devtmpfs"} / 1024 / 1024 / 1024

Mostrar por mountpoint:

sum by (mountpoint) (node_filesystem_avail_bytes) / 1024 / 1024 / 1024

Porcentaje disponible:

100 * (node_filesystem_avail_bytes / node_filesystem_size_bytes) by (mountpoint)

Resource by Node (Tabla)

Tabla dinámica con CPU, memoria y disco por nodo.

Estructura JSON para tabla multi-métrica:

sum by (instance) (100 - (rate(node_cpu_seconds_total{mode="idle"}[5m]) * 100)) // CPU
sum by (instance) (100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) // Memory
sum by (instance, device) (100 * node_filesystem_used_bytes / node_filesystem_size_bytes) // Disk

Filtrar nodos de producción:

sum by (instance) (...) {instance=~"prod.*"}

Requests vs Limits

Comparativa de recursos pedidos vs límites en K8s.

CPU requests:

sum by (namespace, pod) (kube_pod_container_resource_requests_cpu_cores)

CPU limits:

sum by (namespace, pod) (kube_pod_container_resource_limits_cpu_cores)

Memory (en bytes):

sum by (namespace, pod) (kube_pod_container_resource_limits_memory_bytes) / 1024 / 1024

Filtrar por namespace:

sum by (namespace, pod) (...) {namespace!~"kube-system|kube-.*"}

Cambiar Tema de Color

Tema OK (<70%) Warning (70-85%) Critical (>85%)
GREEN #33FF00 #FFCC00 #FF4444
AMBER #FFB000 #FF8C00 #FF4500
BLUE #00BFFF #FFD700 #FF1493

Gauge thresholds en JSON:

"thresholds": {
  "mode": "absolute",
  "steps": [
    { "color": "green", "value": null },
    { "color": "yellow", "value": 70 },
    { "color": "red", "value": 85 }
  ]
}

Adaptar a tu Resolución

Tipo Stat Card Width Graph Height Table Height
Mobile 6 (stack vertical) 10 12
Tablet 10.9" 12 (full width) 12 14
iPad Pro 12.9" 12 (full width) 14 16
Desktop 1920×1080 6 (4 cols) 10 12

Importar en Grafana

  1. Exporta SATURATION dashboard como JSON
  2. Dashboards → Import
  3. Pega JSON
  4. Selecciona datasource Prometheus
  5. Verifica métricas de node_exporter disponibles
  6. Si faltan métricas, revisa que node_exporter esté ejecutándose con flags correctos
  7. Guarda y personaliza thresholds según tu infrastructure

Tips Avanzados

Detección de spike de CPU

rate(node_cpu_seconds_total{mode!="idle"}[5m]) >
  avg_over_time(rate(node_cpu_seconds_total{mode!="idle"}[5m])[1h:5m]) * 1.5

Alerta si CPU se eleva 50% por encima del promedio de 1h.

Memory pressure (usando swap)

(node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes) < 0.3

Alerta si se usa > 70% de swap (indicador de memory pressure severa).

Proyección de agotamiento de disco

predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[1h], 86400)

Predice espacio disponible en 24h. Si < 10GB, alerta proactivamente.

Correlacionar saturation con latency

histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) * 1000
+ (node_load1 / count(node_cpu_seconds_total{mode="idle"}) * 100)

Suaviza latencia por factor de load (muestra impacto de saturación).