Módulo 15 — Monitorización y rendimiento
Introducción
«El servidor va lento» es el ticket más frecuente en cualquier equipo de operaciones. La respuesta típica —abrir top, ver la CPU al 90% y matar el proceso más pesado— es la forma más rápida de no resolver el problema real.
El rendimiento de un sistema es el resultado de cuatro recursos interactuando: CPU, memoria, disco y red. El cuello de botella puede estar en cualquiera de ellos, puede ser latencia o ancho de banda, puede ser del kernel o de la aplicación. Probar comandos al azar sin un modelo mental es ineficiente y a menudo contraproducente.
Este módulo enseña primero la metodología (el modelo mental), luego las herramientas para cada recurso, y termina con la observabilidad continua que permite detectar problemas antes de que los usuarios los reporten.
Los módulos anteriores proveen el contexto: procesos y señales en el Módulo 09, almacenamiento en el Módulo 12, parámetros del kernel en el Módulo 13.
Objetivos de aprendizaje
Al finalizar este módulo, serás capaz de:
- ✅ Aplicar el método USE para diagnosticar cualquier recurso de forma sistemática
- ✅ Interpretar correctamente
load average,top,vmstatyiostat - ✅ Identificar cuellos de botella de CPU, memoria, E/S de disco y red
- ✅ Trazar syscalls con
stracey perfilar conperf record+ flame graphs - ✅ Usar
eBPF/bpftracepara observabilidad a nivel de kernel sin parchear el sistema - ✅ Configurar
sysstat/atoppara históricos post-mortem - ✅ Gestionar logs con
journald,rsyslogylogrotate - ✅ Desplegar Prometheus + node_exporter + Grafana para monitorización continua
15.1 — Metodología de análisis de rendimiento
El método USE
El método USE (Utilization, Saturation, Errors), desarrollado por Brendan Gregg, propone analizar cada recurso del sistema en tres dimensiones antes de sacar conclusiones:
Para cada recurso (CPU, memoria, discos, interfaces de red):
UTILIZACIÓN ¿Qué fracción del tiempo útil está ocupada?
Un recurso al 100% de utilización está saturado.
Ejemplo: CPU a 95% us → cuello de botella en CPU de usuario
SATURACIÓN ¿Hay trabajo que no puede atenderse y queda en cola?
Un recurso puede estar al 70% de utilización pero
tener una cola creciente → problema de latencia.
Ejemplo: load average > número de CPUs → run queue saturada
ERRORES ¿Hay eventos de error? Los errores consumen recursos
y pueden enmascarar el problema real.
Ejemplo: errores de NIC → retransmisiones → CPU y latencia
Aplicación práctica:
1. Listar todos los recursos del sistema
2. Para cada uno: verificar U, S y E con las herramientas adecuadas
3. El primer recurso con indicadores fuera de rango = cuello de botella
4. Investigar la causa raíz (no el síntoma)
Los primeros 60 segundos en un sistema nuevo
Cuando conectas a un servidor con problemas de rendimiento sin contexto previo, estos comandos dan una imagen completa en menos de un minuto:
# 1. uptime: load average y tiempo encendido
uptime
# 11:52:03 up 45 days, 3:12, 2 users, load average: 2.14, 3.02, 2.89
# Los tres números: promedios de los últimos 1, 5 y 15 minutos
# INTERPRETAR: comparar siempre con el número de CPUs (nproc)
# Si load average > nproc → el sistema tiene más trabajo del que puede procesar
# 2. dmesg: errores recientes del kernel
dmesg -T | tail -20
dmesg -T -l err,crit,alert,emerg # Solo errores (módulo 13)
# 3. vmstat 1: panorama completo cada segundo
vmstat 1 5 # 5 muestras, una por segundo
# procs: r=run queue b=bloqueados en E/S
# swap: si=swap in so=swap out (si so>0 continuamente: problema grave)
# cpu: us=user sy=system id=idle wa=iowait st=stolen por hypervisor
# 4. mpstat: CPU por núcleo
mpstat -P ALL 1 3
# 5. free: memoria
free -h
# 6. iostat: estado de los discos
iostat -x 1 3
# 7. ss -s: resumen de sockets
ss -s
# 8. sar -n DEV 1: tráfico de red
sar -n DEV 1 3 # (requiere sysstat instalado)
# Todo-en-uno para un primer vistazo rápido:
sudo apt install glances
glances # CPU, RAM, red, disco en una sola pantalla interactiva
Load average: la interpretación correcta
Load average en Linux incluye:
• Procesos en la run queue (esperando CPU)
• Procesos en estado D (espera de E/S ininterrumpible)
Por tanto, load average alto puede significar:
a) CPU saturada (muchos procesos queriendo CPU)
b) E/S saturada (muchos procesos esperando disco/red)
c) Ambas → desambiguar con vmstat (r vs b) e iostat
ESCALA POR NÚMERO DE CPUs:
• 1 CPU: load 1.0 = saturado load 0.5 = al 50%
• 8 CPUs: load 8.0 = saturado load 2.0 = al 25%
• 32 CPUs: load 10.0 = tranquilo load 32.0 = saturado
TENDENCIA más importante que el valor absoluto:
load(1min) >> load(15min) → problema RECIENTE, empeorando
load(1min) << load(15min) → problema reciente que ya MEJORÓ
15.2 — CPU
top y htop en profundidad
# Líneas de CPU en top (interpretar con método USE):
# %Cpu(s): 2.3 us, 0.5 sy, 0.0 ni, 96.8 id, 0.3 wa, 0.0 hi, 0.1 si, 0.0 st
#
# us (user): tiempo en código de usuario. Alto → la app consume CPU
# sy (system): tiempo en llamadas al sistema. Alto → mucho I/O o syscalls
# ni (nice): tiempo en procesos con prioridad nice modificada
# id (idle): tiempo libre
# wa (iowait): esperando E/S de disco. Alto → cuello de botella en I/O
# hi (hw irq): interrupciones hardware. Alto → problema de dispositivo
# si (sw irq): interrupciones software (red). Alto → saturación de paquetes
# st (stolen): robado por el hypervisor. Alto en VMs → infraestructura sobrevendida
# Diagnóstico por síntoma:
# wa alto (>20%) → problema de disco (ver §15.4)
# us+sy (>90%) → CPU saturada
# si alto (>5%) → problema de red (muchos paquetes/segundo)
# st alto (>5%) → mala vecindad en el hipervisor (ver módulo 16)
# Atajos dentro de top:
# 1 → mostrar todos los cores individualmente
# M → ordenar por memoria
# P → ordenar por CPU (por defecto)
# c → mostrar la línea de comandos completa
# u → filtrar por usuario
# k → matar un proceso (introduce el PID)
# mpstat: CPU por núcleo (detect. de desequilibrio entre cores)
sudo apt install sysstat
mpstat -P ALL 1 # Todos los núcleos, cada segundo
# Si un core está al 100% y los demás al 5% → app single-threaded: no escala
# Si todos están al 100% → carga masiva o bug de sincronización
# pidstat: CPU por proceso en tiempo real
pidstat 1 # Todos los procesos, actualización cada segundo
pidstat -p 1234 1 # Solo el proceso 1234
pidstat -u -t 1 # Incluir hilos (threads) individuales
# Procesos en estado D (esperando I/O — contribuyen al load average)
ps aux | awk '$8 == "D" {print}'
# Si hay muchos en estado D → saturación de I/O (ver §15.4)
Gobernadores de CPU y frecuencia
# Ver el gobernador de CPU actual
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# powersave: mínima frecuencia → menor consumo (laptops en batería)
# performance: máxima frecuencia siempre → máximo rendimiento
# schedutil: integrado con el planificador CFS (moderno, recomendado)
# ondemand: sube la frecuencia bajo carga (Linux por defecto históricamente)
# Cambiar el gobernador
sudo apt install linux-tools-$(uname -r) 2>/dev/null || sudo apt install linux-tools-generic
sudo cpupower frequency-set -g performance # Para todos los cores
sudo cpupower frequency-info # Ver estado y frecuencias disponibles
# Ver la frecuencia actual
cat /proc/cpuinfo | grep "cpu MHz"
# turbostat (requiere permisos root y módulo msr)
sudo turbostat --quiet --show Pkg_J,Cor,CPU,Busy%,Bzy_MHz 2>/dev/null
15.3 — Memoria
El mito de la «memoria llena»
Linux usa toda la RAM libre como caché de páginas del disco.
Esta caché acelera el sistema (evita leer el disco si la página ya está en RAM).
La caché se libera AUTOMÁTICAMENTE cuando una aplicación necesita más memoria.
free -h bien interpretado:
total used free shared buff/cache available
Mem: 31Gi 8.2Gi 1.1Gi 456Mi 22Gi 22Gi
Swap: 2Gi 0Bi 2Gi
• "used" (8.2G): memoria en uso real por procesos de usuario
• "buff/cache" (22G): usada por el KERNEL como caché (NO es memoria "perdida")
• "available" (22G): estimación de cuánta puede pedir una app nueva
(libre + caché que se puede liberar)
• "free" (1.1G): literalmente sin usar para nada
ALARMA REAL: "available" cercano a 0 + vmstat muestra "so" (swap out) > 0
NO ES ALARMA: "free" = 100M pero "available" = 20G → el kernel usa la RAM bien
# vmstat: análisis de memoria y swap
vmstat 1
# Columnas de memoria:
# swpd: memoria actualmente en swap (si >0: ha habido presión de memoria)
# free: memoria libre
# buff: buffers del kernel (metadatos de dispositivos de bloque)
# cache: caché de páginas
# Columnas CRÍTICAS de swap (método USE — saturación):
# si (swap in): páginas leídas DESDE swap. Si >0 continuamente: problema grave
# so (swap out): páginas escritas A swap. Si >0 continuamente: problema grave
# /proc/meminfo: información exhaustiva del subsistema de memoria
cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Cached:|Dirty:|SwapUsed"
# smem: uso de memoria real por proceso (descuenta la compartida)
sudo apt install smem
smem -s pss -r -n | head -15 # PSS (Proportional Set Size): el más justo
smem -s rss -r -n | head -15 # RSS (Resident Set Size): incluye toda la compartida
# PSS divide la memoria compartida entre los procesos que la usan
# RSS sobreestima el uso cuando hay bibliotecas compartidas
OOM Killer: cuándo y cómo actúa
# OOM (Out Of Memory) Killer: cuando el sistema se queda sin memoria,
# el kernel elige y mata procesos para evitar un kernel panic total.
# Detectar si el OOM Killer ha actuado
dmesg | grep -i "oom\|out of memory\|killed process"
journalctl -k | grep -i "oom\|killed process"
# Ejemplo de mensaje en dmesg:
# Out of memory: Kill process 12345 (java) score 852 or sacrifice child
# Killed process 12345 (java) total-vm:4194304kB, anon-rss:3145728kB
# OOM Score: valor 0-1000; el OOM Killer mata el proceso con score más alto
cat /proc/1234/oom_score # Score actual calculado por el kernel
cat /proc/1234/oom_score_adj # Ajuste manual configurado por el admin (-1000 a 1000)
# Proteger un proceso crítico del OOM Killer
echo -500 | sudo tee /proc/$(pgrep -f postgresql | head -1)/oom_score_adj
# -1000 = inmunidad total (solo para procesos del sistema como init)
# Hacer un proceso candidato prioritario para ser matado
echo 500 | sudo tee /proc/$(pgrep java | head -1)/oom_score_adj
# Configuración permanente vía systemd (módulo 09):
# En la unit .service añadir:
# [Service]
# OOMScoreAdjust=-500
15.4 — Disco y E/S
iostat -x: la herramienta central
sudo apt install sysstat
iostat -x 1 5 # Extended, una muestra por segundo, 5 iteraciones
# Columnas clave (método USE aplicado a disco):
#
# %util: porcentaje de tiempo que el dispositivo está ocupado
# 100% → disco utilizado al máximo (UTILIZACIÓN)
# Pero 100% en NVMe puede no ser problema si la cola fluye bien
#
# avgqu-sz: longitud media de la cola de peticiones pendientes
# > 1 en HDD → saturación (más trabajo del que puede despachar)
# En NVMe puede ser mayor sin ser problema (alta concurrencia interna)
#
# await: latencia media total en milisegundos (espera en cola + tiempo de servicio)
# < 1ms: NVMe excelente
# 1-5ms: SSD SATA bueno
# 5-20ms: HDD normal bajo carga moderada
# > 50ms: disco saturado o con problemas mecánicos
#
# r/s w/s: lecturas/escrituras por segundo (IOPS)
# rkB/s wkB/s: throughput en KB/s
# Ejemplo de disco SATURADO:
# Device r/s w/s await %util avgqu-sz
# sda 0.0 220 185.3 100.0 42.5
# → %util=100%, await=185ms, queue=42 → severamente saturado
iotop: quién escribe
sudo apt install iotop
sudo iotop # Todos los procesos con su I/O
sudo iotop -o # Solo procesos con E/S activa en este momento
sudo iotop -b -n 5 # Batch mode, 5 iteraciones (para scripts/logs)
sudo iotop -p 1234 # Solo el proceso 1234
# Columnas:
# IO: E/S total actual (lectura + escritura)
# PRIO: prioridad de I/O del proceso (be=best-effort, rt=realtime, idle)
Benchmarks de disco: fio
sudo apt install fio
# Test de escritura SECUENCIAL (ancho de banda — backups, logs, video)
fio --name=write-seq --rw=write --bs=1M --size=1G \
--filename=/tmp/fio-test --ioengine=libaio --direct=1
# Test de escritura ALEATORIA 4K (IOPS — bases de datos, VMs)
fio --name=randwrite-4k --rw=randwrite --bs=4k --size=512M \
--filename=/tmp/fio-test --ioengine=libaio --direct=1 --iodepth=32
# Test de lectura ALEATORIA (IOPS de lectura — base de datos caliente)
fio --name=randread-4k --rw=randread --bs=4k --size=512M \
--filename=/tmp/fio-test --ioengine=libaio --direct=1 --iodepth=32
rm -f /tmp/fio-test
# ¿Por qué NO usar dd para benchmarks de disco?
# dd sin oflag=direct mide la velocidad del caché de escritura del kernel,
# NO la velocidad real del hardware de almacenamiento.
# Siempre usar --direct=1 (O_DIRECT) en fio para evitar el caché.
Schedulers de E/S
# Ver el scheduler activo para cada dispositivo
cat /sys/block/sda/queue/scheduler
# [mq-deadline] none kyber bfq → mq-deadline es el activo
# Schedulers disponibles:
# none/noop: sin reordenación — ideal para NVMe y SSDs rápidos
# mq-deadline: buen equilibrio entre latencia y throughput — bueno para HDD y SSD SATA
# bfq: Budget Fair Queueing — latencia baja, ideal para escritorio interactivo
# kyber: latencias controladas — diseñado para SSDs y storage rápido
# Cambiar el scheduler en caliente
echo none | sudo tee /sys/block/nvme0n1/queue/scheduler # Para NVMe
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler # Para HDD/SSD SATA
# Cambio permanente vía udev (módulo 13):
# /etc/udev/rules.d/60-scheduler.rules:
# ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"
# ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="mq-deadline"
15.5 — Red (rendimiento)
# ss: estadísticas de sockets (módulo 11 — aquí enfoque rendimiento)
ss -s # Resumen: TCP en ESTABLISHED, LISTEN, TIME_WAIT...
ss -tn state time-wait | wc -l # Número de TIME_WAIT (problema si son miles: backlog)
# nstat: contadores de protocolo del kernel (sustituto moderno de netstat -s)
nstat # Todos los contadores desde el arranque
nstat -z # Incluyendo los que son cero (para completitud)
# Contadores importantes para rendimiento:
# TcpRetransSegs: retransmisiones TCP → pérdida de paquetes o red sobrecargada
# TcpAttemptFails: conexiones TCP fallidas
# IpInDiscards: paquetes IP descartados → colas de red llenas
# ethtool: estadísticas del driver de la NIC (errores de hardware)
sudo ethtool -S eth0 | grep -E "error|drop|miss|overrun"
# rx_errors, tx_errors → errores de la tarjeta de red
# rx_missed_errors → paquetes perdidos por desbordamiento del buffer del driver
# sar -n DEV: estadísticas de red históricas
sar -n DEV 1 5 # Tráfico por interfaz, 5 muestras
sar -n EDEV 1 5 # Errores de red (rxerr, txerr, rxdrop...)
# iftop: tráfico por conexión (como top pero para la red)
sudo apt install iftop
sudo iftop -i eth0 # Monitorizar la interfaz eth0
sudo iftop -n # Sin resolución de DNS (más rápido y legible)
# nethogs: tráfico por PROCESO (quién está generando el tráfico)
sudo apt install nethogs
sudo nethogs eth0
# iperf3: medir el ancho de banda disponible entre dos puntos
# En el servidor (receptor):
iperf3 -s
# En el cliente:
iperf3 -c IP-SERVIDOR # Test TCP básico
iperf3 -c IP-SERVIDOR -u -b 100M # Test UDP a 100 Mbps
iperf3 -c IP-SERVIDOR -P 4 # 4 flujos paralelos
# El resultado establece la "línea base" de la capacidad del enlace
# Diagnóstico de retransmisiones (señal de pérdida de paquetes)
ss -ti state established | grep retrans # Contador de retransmisiones por socket
ping -c 20 destino | tail -2 # Latencia y pérdida de paquetes
mtr --report destino # Traceroute continuo con estadísticas
15.6 — Trazado y perfilado de procesos
strace — Trazar llamadas al sistema
# strace: intercepta todas las llamadas al sistema de un proceso
# ÚTIL PARA: entender qué hace un proceso que va lento o no funciona
# COSTE: puede ralentizar el proceso hasta 10× (solo en diagnóstico, nunca en prod continuo)
# Trazar un proceso nuevo
strace ls /tmp
strace -o /tmp/strace.txt ls /tmp # Guardar en archivo
# Adjuntarse a un proceso ya en ejecución
strace -p 1234
# Las opciones más valiosas:
strace -c programa # Resumen estadístico: % de tiempo por syscall
strace -T programa # Tiempo empleado en cada llamada individual
strace -e trace=file programa # Solo syscalls de archivos (open, read, write, stat...)
strace -e trace=network programa # Solo syscalls de red (connect, send, recv...)
strace -f programa # Seguir procesos hijo (fork/exec)
strace -ff -o /tmp/out programa # Un archivo por PID (útil para procesos multi-proceso)
# Caso de uso: ¿por qué tarda tanto este comando?
strace -c -T find /var/log -name "*.log" 2>&1 | head -20
# Los syscalls con mayor tiempo acumulado son el cuello de botella
# Encontrar a qué servidor DNS consulta una aplicación
strace -e trace=network -f curl https://ejemplo.com 2>&1 | grep connect
lsof — Archivos y sockets abiertos
# lsof: list open files (en Linux, todo es un archivo: sockets, pipes, dispositivos...)
sudo lsof | wc -l # Total de file descriptors abiertos en el sistema
# Por proceso
sudo lsof -p 1234 # Todos los archivos del proceso 1234
sudo lsof -p 1234 | grep REG # Solo archivos regulares
sudo lsof -p 1234 | grep "IPv4\|IPv6" # Solo sockets de red
# Por archivo o directorio
sudo lsof /var/log/nginx/access.log # ¿Qué procesos tienen abierto este archivo?
sudo lsof +D /var/www # ¿Qué procesos usan algún archivo de /var/www?
# Sockets de red
sudo lsof -i # Todos los sockets de red
sudo lsof -i :80 # Solo los que usan el puerto 80
sudo lsof -i TCP:443 # TCP en el puerto 443
sudo lsof -i -sTCP:LISTEN # Solo sockets en escucha
# CASO CLÁSICO: recuperar un archivo de log borrado accidentalmente
# Si el proceso sigue escribiendo en el archivo borrado, los datos aún están en disco
# hasta que el proceso cierre el file descriptor
sudo lsof -p $(pgrep nginx) | grep deleted # Archivos borrados pero aún abiertos
# FD column muestra el número: 7u, 8w, etc.
sudo cp /proc/$(pgrep nginx | head -1)/fd/7 /tmp/log-recuperado.txt
perf — Perfilado de rendimiento a nivel de CPU
sudo apt install linux-perf
# perf top: profiler en tiempo real (como top pero a nivel de función del kernel/app)
sudo perf top # Todo el sistema
sudo perf top -p 1234 # Solo el proceso 1234
# Muestra: % de ciclos de CPU por función → identifica hot paths
# perf record + report: captura para análisis posterior
sudo perf record -g -p 1234 sleep 10 # Capturar 10s con call graph
sudo perf record -g -a sleep 10 # Todo el sistema
sudo perf report # Análisis interactivo (TUI)
sudo perf report --stdio | head -40 # Salida de texto plana
# perf stat: estadísticas de contadores de hardware
sudo perf stat -p 1234 sleep 5
# Muestra: ciclos, instrucciones, cache-misses, branch-misses...
# IPC (instructions per cycle) < 1 → stalls por memoria o E/S
# cache-misses / cache-refs alto → código con mala localidad de datos
# Flame graphs: la forma más intuitiva de ver perf
git clone --depth=1 https://github.com/brendangregg/FlameGraph /opt/flamegraph
sudo perf record -F 99 -g -p 1234 sleep 30
sudo perf script | /opt/flamegraph/stackcollapse-perf.pl | \
/opt/flamegraph/flamegraph.pl > flamegraph.svg
# Abrir flamegraph.svg en el navegador
# El ANCHO de cada barra = % del tiempo total en esa función/pila de llamadas
eBPF y bpftrace — La nueva generación de observabilidad
# eBPF (extended Berkeley Packet Filter): permite ejecutar programas verificados
# DENTRO del kernel SIN parchearlo ni reiniciarlo.
# Overhead mínimo: ideal para producción donde strace es demasiado costoso.
# Usado por Netflix, Facebook, Google, Cloudflare para observabilidad en producción.
sudo apt install bpftrace
# Trazar qué archivos abre cualquier proceso (en tiempo real)
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat {
printf("%s %s\n", comm, str(args->filename));
}'
# Distribución de latencia de la syscall read() (histograma)
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_read { @start[tid] = nsecs; }
tracepoint:syscalls:sys_exit_read /@start[tid]/ {
@us = hist((nsecs - @start[tid]) / 1000);
delete(@start[tid]);
}'
# BCC tools: scripts bpftrace/eBPF listos para usar
sudo apt install bpfcc-tools
sudo opensnoop-bpfcc # Qué archivos abre cada proceso
sudo execsnoop-bpfcc # Qué procesos se lanzan (fork+exec)
sudo biolatency-bpfcc -D # Distribución de latencia de I/O de bloque
sudo tcpconnect-bpfcc # Conexiones TCP salientes en tiempo real
sudo tcpaccept-bpfcc # Conexiones TCP entrantes aceptadas
sudo runqlat-bpfcc # Distribución de latencia en la run queue de CPU
sudo cachetop-bpfcc # Uso del page cache por proceso
15.7 — Recolección histórica
sysstat / sar
sudo apt install sysstat
# Activar la recolección automática (cada 10 minutos, cron o timer)
sudo systemctl enable --now sysstat
# sar: analizar los datos históricos
sar # CPU del día actual
sar -u 1 5 # CPU en tiempo real, 5 muestras
sar -r # Memoria del día actual
sar -b # E/S de disco del día actual
sar -n DEV # Tráfico de red del día actual
sar -q # Load average y run queue
# Datos de días anteriores (archivos en /var/log/sysstat/saDD)
sar -u -f /var/log/sysstat/sa$(date -d yesterday +%d)
sar -r -f /var/log/sysstat/sa15 # El día 15 del mes actual
# CASO DE USO REAL: "el servidor fue lento ayer a las 14:00"
# Con sar puedes reconstruir exactamente qué pasó:
FILE=/var/log/sysstat/sa$(date -d yesterday +%d)
echo "=== CPU ayer 14:00 ===" && sar -u -f $FILE | grep "^14:"
echo "=== MEMORIA ===" && sar -r -f $FILE | grep "^14:"
echo "=== DISCO ===" && sar -b -f $FILE | grep "^14:"
echo "=== RED ===" && sar -n DEV -f $FILE | grep "^14:"
atop — Registro continuo y detallado
sudo apt install atop
# atop registra TODO el sistema cada vez (por defecto cada 10 minutos)
# en archivos diarios en /var/log/atop/
sudo systemctl enable --now atop
# Ver el estado actual (interfaz interactiva)
atop # Vista general
# Teclas dentro de atop:
# d → detalle de disco
# n → detalle de red
# m → detalle de memoria
# 1 → vista de CPUs individuales
# Reproducir el pasado (ANÁLISIS POST-MORTEM)
atop -r /var/log/atop/atop_$(date -d yesterday +%Y%m%d)
# Dentro de atop: 'b'=inicio del día, 't'=avanzar 10min, 'T'=retroceder
# Permite ver exactamente qué hacía el sistema en el momento del incidente:
# qué procesos estaban activos, qué consumían, qué servicios respondían
15.8 — Gestión de logs
Revisión de journald y rsyslog
# journald: el diario binario de systemd (módulo 09)
journalctl -n 100 # Las últimas 100 líneas
journalctl -f # Seguimiento en tiempo real
journalctl -u nginx -n 50 # Logs de una unidad específica
journalctl --since "2024-01-15 10:00" --until "2024-01-15 11:00"
journalctl -p err -b # Solo errores del arranque actual
journalctl -p err --since today # Errores de hoy
# Tamaño del journal y limpieza
journalctl --disk-usage
sudo journalctl --vacuum-size=500M # Reducir a 500 MB
sudo journalctl --vacuum-time=30d # Eliminar entradas de más de 30 días
# Configuración en /etc/systemd/journald.conf:
# Storage=persistent → guardar en disco (default: auto)
# SystemMaxUse=500M → tamaño máximo total del journal en disco
# SystemKeepFree=200M → espacio mínimo a dejar libre
# MaxRetentionSec=1month → retención máxima
# rsyslog: el daemon de logs clásico
# Escribe a /var/log/syslog, /var/log/auth.log, /var/log/kern.log
# Recibe de journald via imjournal o socket /dev/log
# Severidades RFC 5424: emerg alert crit err warning notice info debug
# Facilities: kern user mail daemon auth syslog cron local0-local7
logrotate — Que los logs no llenen el disco
# logrotate: rotación automática de logs
# Configuración: /etc/logrotate.conf (global) + /etc/logrotate.d/* (por aplicación)
cat /etc/logrotate.d/nginx # Ver la configuración de nginx como ejemplo
# Crear configuración para una aplicación propia:
sudo tee /etc/logrotate.d/mi-app << 'EOF'
/var/log/mi-app/*.log {
daily # Rotar diariamente
rotate 30 # Conservar 30 archivos rotados (30 días)
compress # Comprimir con gzip los archivos rotados
delaycompress # No comprimir el más reciente (el proceso puede escribir aún)
missingok # No fallar si el archivo no existe
notifempty # No rotar si el archivo está vacío
create 0640 mi-usuario adm # Crear el nuevo archivo con estos permisos
sharedscripts # Ejecutar postrotate una vez para todos los *.log
postrotate
# Señalizar al proceso para que reabra el archivo de log
systemctl kill -s HUP mi-app.service 2>/dev/null || true
endscript
}
EOF
# Probar sin hacer cambios reales
sudo logrotate -d /etc/logrotate.d/mi-app # Debug: qué haría
sudo logrotate -f /etc/logrotate.d/mi-app # Forzar rotación ahora (para testing)
Centralización de logs
# Opción 1: rsyslog remoto (protocolo syslog clásico, simple y robusto)
# En el SERVIDOR receptor:
sudo tee /etc/rsyslog.d/10-server.conf << 'EOF'
module(load="imtcp")
input(type="imtcp" port="514")
EOF
# En los CLIENTES emisores:
sudo tee /etc/rsyslog.d/50-remote.conf << 'EOF'
# Enviar todos los logs al servidor de logs vía TCP (más fiable que UDP)
*.* action(type="omfwd" target="log-servidor.interno" port="514" protocol="tcp")
EOF
sudo systemctl restart rsyslog
# Opción 2: Loki + Promtail (stack Grafana, más moderno)
# Loki no indexa el contenido de los logs, solo las etiquetas (labels)
# → Mucho más económico en almacenamiento y memoria que Elasticsearch
# Promtail: agente ligero que lee los logs (journald, archivos) y los envía a Loki
# Grafana puede consultar Loki con LogQL y mostrar logs junto a métricas Prometheus
15.9 — Observabilidad moderna: Prometheus y Grafana
Los tres pilares de la observabilidad
MÉTRICAS: valores numéricos a lo largo del tiempo
"La CPU estuvo al 95% durante 3 minutos a las 14:23"
→ Prometheus, VictoriaMetrics, InfluxDB, Grafana
LOGS: eventos textuales con timestamp y contexto
"nginx: 500 Internal Server Error en /api/users"
→ journald, Loki, Elasticsearch, Graylog
TRAZAS: recorrido completo de una petición a través del sistema
"La petición /api tardó 2s: 50ms en nginx, 1.9s en la DB"
→ Jaeger, Zipkin, OpenTelemetry
Para un servidor Linux standalone: métricas + logs es suficiente.
Para microservicios y Kubernetes: los tres pilares son necesarios.
Prometheus + node_exporter
# node_exporter: exporta métricas del sistema Linux en formato Prometheus
# Expone: CPU, memoria, disco, red, filesystem, temperatura, carga del sistema...
# Instalación de node_exporter
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.0/\
node_exporter-1.8.0.linux-amd64.tar.gz
tar xzf node_exporter-*.tar.gz
sudo mv node_exporter-*/node_exporter /usr/local/bin/
# Servicio systemd para node_exporter
sudo tee /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/node_exporter \
--collector.systemd \
--collector.processes
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
# Verificar que node_exporter sirve métricas
curl -s http://localhost:9100/metrics | grep "node_cpu_seconds" | head -5
# Instalación de Prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.52.0/\
prometheus-2.52.0.linux-amd64.tar.gz
tar xzf prometheus-*.tar.gz
sudo mv prometheus-*/prometheus /usr/local/bin/
sudo mv prometheus-*/promtool /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
# Configuración de Prometheus
sudo tee /etc/prometheus/prometheus.yml << 'EOF'
global:
scrape_interval: 15s # Recoger métricas cada 15 segundos
evaluation_interval: 15s # Evaluar reglas de alerta cada 15 segundos
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
labels:
hostname: 'servidor-principal'
# Múltiples servidores:
# - job_name: 'fleet'
# static_configs:
# - targets: ['192.168.1.10:9100', '192.168.1.11:9100']
EOF
# Reglas de alerta
sudo mkdir -p /etc/prometheus/rules
sudo tee /etc/prometheus/rules/alertas.yml << 'EOF'
groups:
- name: sistema
rules:
- alert: CPUAltaUtilizacion
expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
for: 5m
labels:
severity: warning
annotations:
summary: "CPU alta en {{ $labels.instance }}"
description: "CPU al {{ $value | humanize }}% durante más de 5 minutos"
- alert: MemoriaCritica
expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.10
for: 2m
labels:
severity: critical
annotations:
summary: "Memoria crítica en {{ $labels.instance }}"
description: "Solo queda el {{ $value | humanizePercentage }} de memoria disponible"
- alert: DiscoLleno
expr: (node_filesystem_size_bytes - node_filesystem_avail_bytes) /
node_filesystem_size_bytes > 0.90
for: 5m
labels:
severity: critical
annotations:
summary: "Disco al {{ $value | humanizePercentage }} en {{ $labels.mountpoint }}"
EOF
# Añadir rule_files a prometheus.yml:
# rule_files:
# - "/etc/prometheus/rules/*.yml"
# Servicio systemd para Prometheus
sudo tee /etc/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=Prometheus
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus \
--storage.tsdb.retention.time=30d \
--web.listen-address=0.0.0.0:9090
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo chown -R nobody /etc/prometheus /var/lib/prometheus
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
# UI: http://IP-SERVIDOR:9090
PromQL: consultas fundamentales
# CPU utilizada (todos los modos menos idle), promedio 5 minutos
100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# Memoria disponible en GB
node_memory_MemAvailable_bytes / 1073741824
# Porcentaje de disco utilizado
(node_filesystem_size_bytes - node_filesystem_avail_bytes) /
node_filesystem_size_bytes * 100
# Tráfico de red entrante en Mbps (interfaz eth0)
rate(node_network_receive_bytes_total{device="eth0"}[5m]) * 8 / 1048576
# Load average
node_load1 # Último minuto
node_load5 # Últimos 5 minutos
node_load15 # Últimos 15 minutos
# Número de procesos en estado D (esperando I/O — métrica de saturación de disco)
node_procs_blocked
Grafana
# Instalar Grafana
sudo apt install -y apt-transport-https software-properties-common wget
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | \
sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update && sudo apt install grafana
sudo systemctl enable --now grafana-server
# UI: http://IP-SERVIDOR:3000 (admin/admin por defecto — cambiar inmediatamente)
# Configurar la fuente de datos (vía UI):
# Configuration → Data Sources → Add → Prometheus
# URL: http://localhost:9090 → Save & Test
# Dashboard preconstruido para node_exporter:
# Dashboards → Import → ID: 1860 (Node Exporter Full)
# Cubre: CPU detallado por core, memoria, swap, I/O de disco, red, temperatura
# Alertas en Grafana (Alerting → Alert rules):
# Condition: avg(cpu_usage) > 90 during 5m
# Contact point: email, Slack, PagerDuty, webhook...
Anexos
A. Resumen del método USE por recurso
| Recurso | Utilización | Saturación | Errores |
|---|---|---|---|
| CPU | top (%us+%sy) | vmstat r > nproc | perf stat (stalls) |
| Memoria | free (used/total) | vmstat si/so > 0 | dmesg (OOM killed) |
| Disco | iostat %util | iostat avgqu > 1 | smartctl -H |
| Red (NIC) | sar -n DEV txkB | ss -s backlog | ethtool -S errors |
B. Interrelaciones con otros módulos
◀ Módulo 09 — Procesos y systemd
│ load average, estados de proceso (R, D, S), señales, cgroups para límites
◀ Módulo 12 — Almacenamiento avanzado
│ El tipo de dispositivo (NVMe/SSD/HDD/RAID) determina los valores
│ normales de iostat await y avgqu-sz
◀ Módulo 13 — Arranque y kernel
│ sysctl: vm.dirty_ratio, vm.swappiness afectan el comportamiento de I/O
│ Gobernadores de CPU (cpupower) afectan los benchmarks
◀ Módulo 14 — Seguridad
│ Prometheus expone un endpoint HTTP: proteger con ufw/nftables
│ Los logs de auditd se integran en la estrategia de observabilidad
▶ Módulo 16 — Virtualización y contenedores
│ cAdvisor: node_exporter equivalente para contenedores Docker
│ Kubernetes expone métricas vía kube-state-metrics y metrics-server
▶ Módulo 17 — Linux como servidor
│ node_exporter + Prometheus para monitorizar servidores web y de BD
│ Alertas de disco lleno y memoria para gestión proactiva de SLAs
Referencias y Bibliografía
-
Brendan Gregg — Systems Performance, 2ª ed.
Addison-Wesley, 2020. La referencia definitiva sobre rendimiento en Linux/Unix. -
Brendan Gregg — BPF Performance Tools
Addison-Wesley, 2019. eBPF, bpftrace y BCC tools en profundidad. -
Brendan Gregg — The USE Method
http://www.brendangregg.com/usemethod.html -
Brendan Gregg — Linux Performance Analysis in 60 seconds
http://www.brendangregg.com/Articles/Netflix_Linux_Perf_Analysis_60s.pdf -
Brendan Gregg — Flame Graphs
http://www.brendangregg.com/flamegraphs.html -
Prometheus documentation
https://prometheus.io/docs/ -
PromQL documentation
https://prometheus.io/docs/prometheus/latest/querying/basics/ -
Grafana documentation
https://grafana.com/docs/grafana/ -
node_exporter — GitHub
https://github.com/prometheus/node_exporter -
sysstat / sar documentation
https://github.com/sysstat/sysstat -
atop documentation
https://www.atoptool.nl/ -
fio — Flexible I/O Tester
https://fio.readthedocs.io/ -
strace manual — man7.org
https://man7.org/linux/man-pages/man1/strace.1.html -
perf documentation — kernel.org
https://perf.wiki.kernel.org/ -
bpftrace documentation — GitHub
https://github.com/bpftrace/bpftrace -
eBPF — What is eBPF?
https://ebpf.io/what-is-ebpf/ -
Linux Observability with BPF — David Calavera, Lorenzo Fontana
O'Reilly, 2019. -
logrotate man page
https://linux.die.net/man/8/logrotate -
Practical Monitoring — Mike Julian
O'Reilly, 2017. -
Unix and Linux System Administration Handbook — Nemeth et al.
Pearson, 2017. Capítulo 28: Performance Analysis.
Preguntas de autoevaluación
- Explica el método USE. ¿Cuáles son sus tres dimensiones? ¿Por qué es superior a "probar comandos al azar"?
- Un sistema tiene
load average: 8.5, 6.2, 4.1con 4 CPUs. ¿Qué indica? ¿Cómo distinguirías si el problema es de CPU o de E/S? free -hmuestra "free: 200M" pero "available: 8G". ¿Hay problema de memoria? Explica.- ¿Qué indica un
wa(iowait) alto entop? ¿Qué herramienta usarías a continuación? - En
iostat -x, ¿qué diferencia hay entre%utilyavgqu-sz? ¿Cuál es más indicativo de saturación? - Explica la diferencia entre
fio --direct=1yddpara benchmarks de disco. ¿Por qué dd puede engañar? - ¿Para qué sirve
strace? ¿Por qué no se usa en producción de forma continua? ¿Qué herramienta lo sustituye con menor overhead? - Describe cómo recuperar el contenido de un archivo de log borrado accidentalmente cuando el proceso que lo escribe sigue activo.
- ¿Qué es un flame graph? ¿Qué representa el ancho de cada barra? ¿Cómo se genera con
perf? - ¿Qué ventaja tiene eBPF/bpftrace sobre
stracepara observabilidad en producción? - ¿Para qué sirve
atop -ry cuándo es más útil quesar? - Escribe una consulta PromQL que calcule el porcentaje de CPU en uso (todos los modos menos idle), con una ventana de 5 minutos.
Laboratorios prácticos
Lab 15.1 — Los primeros 60 segundos
# Secuencia de diagnóstico inicial completa
echo "=== uptime ===" && uptime
echo "=== dmesg errors ===" && dmesg -T -l err 2>/dev/null | tail -5
echo "=== vmstat ===" && vmstat 1 3
echo "=== free ===" && free -h
echo "=== ss summary ===" && ss -s
echo "=== iostat ===" && iostat -x 1 2 2>/dev/null || echo "instala sysstat"
Lab 15.2 — Identificar un proceso que consume CPU
# 1. Generar carga artificial en background
sudo apt install stress-ng -y 2>/dev/null
stress-ng --cpu 1 --timeout 20s &
STRESS_PID=$!
# 2. Identificar con pidstat
pidstat 1 5 | grep stress
# 3. Ver las syscalls que hace
strace -c -p $STRESS_PID sleep 3 2>&1 | head -20
# 4. Limpiar
wait $STRESS_PID 2>/dev/null
Lab 15.3 — Analizar memoria con /proc y smem
# 1. Estado actual de la memoria
free -h
cat /proc/meminfo | grep -E "MemTotal|MemAvailable|Cached:|Dirty:|SwapUsed"
# 2. Top 10 procesos por uso de memoria
ps aux --sort=-%mem | head -12
# 3. OOM score de procesos clave
for proc in sshd systemd bash; do
pid=$(pgrep $proc | head -1)
[ -n "$pid" ] && echo "$proc (PID $pid): OOM score $(cat /proc/$pid/oom_score)"
done
Lab 15.4 — lsof: inspeccionar archivos y sockets abiertos
# 1. Total de FDs abiertos en el sistema
sudo lsof 2>/dev/null | wc -l
# 2. Archivos del proceso sshd
sudo lsof -p $(pgrep sshd | head -1) 2>/dev/null | head -15
# 3. Qué proceso tiene /var/log/syslog abierto
sudo lsof /var/log/syslog 2>/dev/null
# 4. Todos los sockets TCP en escucha
sudo lsof -i -sTCP:LISTEN 2>/dev/null | head -10
Lab 15.5 — Configurar logrotate
# 1. Crear un log de prueba
sudo mkdir -p /var/log/lab-logrotate
sudo bash -c 'seq 100 | xargs -I{} echo "$(date) Línea {}" > /var/log/lab-logrotate/app.log'
# 2. Configuración de logrotate
sudo tee /etc/logrotate.d/lab-logrotate << 'EOF'
/var/log/lab-logrotate/*.log {
daily
rotate 7
compress
missingok
notifempty
create 0640 root adm
}
EOF
# 3. Probar en modo debug
sudo logrotate -d /etc/logrotate.d/lab-logrotate
# 4. Forzar rotación y verificar
sudo logrotate -f /etc/logrotate.d/lab-logrotate
ls -lh /var/log/lab-logrotate/
# 5. Limpiar
sudo rm -rf /var/log/lab-logrotate
sudo rm /etc/logrotate.d/lab-logrotate
Lab 15.6 — Prometheus: explorar métricas vía API
# Si node_exporter está instalado:
if curl -s http://localhost:9100/metrics > /dev/null 2>&1; then
echo "=== Memoria disponible ==="
curl -s http://localhost:9100/metrics | grep "^node_memory_MemAvailable"
echo "=== CPU total seconds ==="
curl -s http://localhost:9100/metrics | grep "^node_cpu_seconds_total" | head -5
echo "=== Filesystem disponible ==="
curl -s http://localhost:9100/metrics | grep "^node_filesystem_avail" | head -3
else
echo "node_exporter no está corriendo en el puerto 9100"
echo "Para instalarlo: ver §15.9 de este módulo"
fi
Resumen del módulo
✅ Metodología USE: Utilización, Saturación, Errores — el marco que sustituye "probar comandos al azar"
✅ Los primeros 60s: uptime, dmesg -T, vmstat 1, mpstat, top, iostat -x, free -h, ss -s
✅ CPU: top (us/sy/wa/st), mpstat por núcleo, pidstat, procesos en estado D, gobernadores
✅ Memoria: free -h bien interpretado, vmstat (si/so), smem PSS, OOM killer y oom_score_adj
✅ Disco: iostat -x (await/avgqu-sz/%util), iotop, fio con O_DIRECT, schedulers de E/S
✅ Red: ss -s, nstat, ethtool -S, iftop, nethogs, iperf3, retransmisiones TCP
✅ Trazado: strace -c/-T/-e, lsof (recuperar archivos borrados), perf top/record, flame graphs
✅ eBPF: bpftrace, BCC tools (opensnoop, biolatency, execsnoop, runqlat, cachetop)
✅ Histórico: sar con sysstat, atop con replay post-mortem
✅ Logs: journald, rsyslog, logrotate, centralización con syslog remoto o Loki
✅ Observabilidad: Prometheus + node_exporter (scrape 15s), PromQL, Grafana + alertas, tres pilares
Próximo paso: Módulo 16 — Virtualización y contenedores. Con el sistema monitorizado y entendido, el siguiente desafío es multiplexar la infraestructura: VMs con KVM, contenedores con Docker/Podman y orquestación con Kubernetes.
Última actualización: 2024-06
Versión: 1.0
Estado: ✅ Listo para enseñanza