Sabes qué pasó a las tres de la madrugada: quince db_timeout con las 200 conexiones agotadas. Lo que no sabes es por qué. Y ahora Marta añade leña: «Varios comerciales dicen que la web va lenta por las mañanas, sobre las nueve. ¿Es cosa nuestra?». «Va lenta» no es un dato, es una sensación; convertirla en un número, encontrar el recurso culpable y demostrar que el cambio ha servido es justamente el trabajo de esta lección. Vas a aprender un método reproducible en lugar de una colección de comandos sueltos, a interpretar de verdad lo que dicen uptime, free o iostat, y a establecer una línea base de srv-tramontana sin la cual ninguna medición significa nada.
Contenido
- Monitorizar, diagnosticar y el método USE
- CPU: load average,
vmstat,mpstaty el steal - Memoria: qué significa «usada», swap y el OOM killer
- Disco:
iostat -xz, latencia frente a caudal - Red:
sar -n DEV,ss -sy las retransmisiones - Herramientas de conjunto y la historia con
sar - Métricas continuas y los cuatro golden signals
- Procedimiento para «el servidor va lento»
- Ajustes al alcance de un administrador
- La línea base de
srv-tramontana - Caso Tramontana: «la web va lenta por las mañanas»
- Monitorizar, diagnosticar y el método USE
Son dos actividades distintas y se confunden constantemente:
- Monitorizar es saber cómo está el sistema de forma continua y sin que nadie mire: métricas cada quince segundos, guardadas, con alertas. Responde a «¿va bien?» antes de que llame el cliente.
- Diagnosticar es averiguar por qué va mal en un momento concreto, con herramientas interactivas y una hipótesis que se confirma o se descarta.
Un humano mirando top no es monitorización: es diagnóstico manual, ocasional y sin memoria. Necesitas ambas, y la primera hace posible la segunda, porque una medición sin punto de comparación no dice nada: un load de 3,5 puede ser normal o catastrófico, y solo lo sabes si conoces el de ayer.
El método USE (de Brendan Gregg) da el orden en que se mira. Para cada recurso —CPU, memoria, disco, red— se comprueban tres cosas:
| Dimensión | Pregunta | En CPU | En disco |
|---|---|---|---|
| Utilización | ¿Qué parte del tiempo está ocupado? | %us + %sy |
%util de iostat |
| Saturación | ¿Cuánto trabajo espera en cola? | Columna r de vmstat |
aqu-sz, await |
| Errores | ¿Hay fallos contabilizados? | Excepciones de máquina | Errores de E/S en dmesg |
Su utilidad práctica es que evita perder tiempo: en cinco minutos recorres los cuatro recursos con tres preguntas cada uno y sales sabiendo cuál es el cuello de botella.
- CPU: load average,
vmstat, mpstat y el steal
vmstat, mpstat y el stealLos tres números son la media de procesos en estado ejecutable (R) o en espera ininterrumpible (D) durante 1, 5 y 15 minutos. Dos reglas que lo cambian todo. Primera: hay que normalizar por el número de núcleos; con nproc = 2, un load de 3,42 son 1,71 procesos por núcleo y el sistema está saturado, mientras que el mismo 3,42 en una máquina de 16 núcleos sería un 21 % de ocupación, es decir, nada. Segunda: el estado D cuenta, y ese es el matiz que casi nadie conoce, porque en Linux el load incluye los procesos bloqueados esperando disco; por eso puedes ver un load de 8 con la CPU al 5 %.
La tendencia también informa: 3,42 2,10 1,08 es una carga subiendo (el problema empieza ahora); 1,08 2,10 3,42 es una que ya se está resolviendo.
vmstat 1, columna a columna
$ vmstat 1 5
r b swpd libre buff caché si so bi bo in cs us sy id wa st
4 2 0 198432 91240 1842104 0 0 12 48 412 980 18 4 22 56 0
5 3 0 196108 91240 1843320 0 0 8 14620 902 2140 21 6 9 64 0
4 3 0 195884 91240 1843644 0 0 4 15108 918 2205 19 5 8 68 0| Columna | Significado | Cuándo preocupa |
|---|---|---|
r |
Procesos listos para ejecutar, esperando CPU | Si supera de forma sostenida el nº de núcleos |
b |
Procesos bloqueados en E/S (estado D) | Cualquier valor sostenido > 0 apunta al disco |
si / so |
KiB/s entrando y saliendo de swap | Cualquier valor sostenido es malo: thrashing |
bi / bo |
Bloques leídos/escritos por segundo | Contexto para el disco |
us / sy / id |
% de CPU en usuario, kernel y ocioso | sy alto: llamadas al sistema o red |
wa |
% esperando E/S | Alto con id bajo: el disco es el cuello |
st |
% robado por el hipervisor (steal) | > 5 % sostenido: el problema no está en tu VM |
La primera línea de vmstat es la media desde el arranque: ignórala siempre y mira de la segunda en adelante. En el ejemplo, wa en 56–68 % con r en 4–5 y bo disparado dice a gritos que el cuello de botella es el disco, no la CPU.
El st merece un apunte: en una VM es tiempo que el hipervisor le dio a otra máquina, así que un st del 20 % significa que ninguna optimización tuya arreglará nada, porque el problema está en el anfitrión o en el proveedor.
Y el desglose por núcleo y por proceso:
$ mpstat -P ALL 1 1 | tail -3
Media: CPU %usr %nice %sys %iowait %steal %idle
Media: 0 19,2 0,0 4,8 58,1 0,0 17,5
Media: 1 17,9 0,0 5,1 54,3 0,0 22,4
$ pidstat -u 1 1 | sort -k8 -rn | head -3
12:31:03 UID PID %usr %system %wait %CPU CPU Command
12:31:03 997 1284 16,00 3,00 1,00 19,00 0 tramontana
12:31:03 1000 8842 4,00 9,00 22,00 13,00 1 respaldo_tramonmpstat -P ALL revela un caso muy común: la media global parece razonable pero un solo núcleo está al 100 % porque la aplicación no paraleliza. pidstat reparte el consumo por proceso, y su columna %wait —tiempo esperando a que le den CPU— es oro puro para detectar contención.
- Memoria: qué significa «usada», swap y el OOM killer
$ free -h
total usado libre compartido búfer/caché disponible
Mem: 3,8Gi 1,1Gi 208Mi 18Mi 2,5Gi 2,4Gi
Inter.: 2,0Gi 0B 2,0Gi«Libre: 208 Mi» no es un problema. Es exactamente lo contrario: la RAM libre es RAM desaprovechada, y el kernel la usa como caché de página para no volver a leer del disco. Las columnas que importan:
usado es la memoria de procesos sin caché ni buffers; búfer/caché es caché de página y metadatos, que el kernel suelta al instante si hace falta; y disponible es la cifra que hay que mirar: cuánta memoria puede obtener una aplicación nueva sin swapear. Con 2,4 GiB disponibles de 3,8, srv-tramontana va sobrado; la alarma sería disponible cayendo hacia cero, no libre.
$ grep -E 'MemTotal|MemAvailable|Dirty' /proc/meminfo # el detalle crudo; vmstat -s resume
$ ps -eo pid,user,rss,vsz,comm --sort=-rss | head -3
PID USER RSS VSZ COMMAND
1284 svc-tram 219848 1284932 tramontana
1102 postgres 98204 412088 postgresTres cifras que se confunden a diario: VSZ es todo el espacio de direcciones reservado —librerías compartidas y memoria pedida pero nunca tocada incluidas—, casi siempre enorme e irrelevante; RSS son las páginas realmente en RAM, útil pero cuenta entera cada librería compartida en cada proceso, así que sumar los RSS da mucho más que la RAM total; y PSS reparte cada página compartida entre quienes la usan, siendo la única que suma bien (se ve con smem -k o en /proc/PID/smaps_rollup).
Swap y thrashing
Tener swap ocupada no es malo por sí solo: el kernel descarga páginas que nadie toca. Lo grave es el trasiego constante, que se ve en si/so de vmstat. Si esas columnas están activas de forma sostenida, el sistema pasa más tiempo moviendo páginas que trabajando: eso es thrashing, y se percibe como una lentitud brutal con la CPU casi ociosa.
El OOM killer
Cuando no queda memoria ni swap, el kernel elige una víctima y la mata. Saber que ha actuado es fundamental, porque el síntoma que llega es «el servicio se reinició solo»:
$ sudo journalctl -k --since yesterday --grep -i 'out of memory'
ago 17 04:41:07 srv-tramontana kernel: Out of memory: Killed process 1284 (tramontana)
total-vm:1284932kB, anon-rss:2894120kB, oom_score_adj:0Elige por oom_score, que premia matar al proceso que más memoria libera, ponderado por oom_score_adj (de −1000 a 1000). Se consulta en /proc/PID/oom_score y se ajusta en caliente con sudo choom -p 1284 -n -500. Aunque en un servicio de systemd lo correcto es declararlo en la unidad (OOMScoreAdjust=-500) y, sobre todo, poner MemoryMax como viste en 05-05: así el OOM actúa dentro del cgroup del servicio y no se lleva por delante la base de datos.
- Disco:
iostat -xz, latencia frente a caudal
iostat -xz, latencia frente a caudal$ iostat -xz 1 2 | tail -4
Device r/s rkB/s w/s wkB/s rareq-sz wareq-sz aqu-sz r_await w_await %util
dm-0 2,00 8,00 148,00 14620,00 4,00 98,78 3,42 1,20 22,85 97,60
sda 1,00 4,00 92,00 15108,00 4,00 164,22 2,98 0,90 31,10 94,20| Columna | Qué mide | Umbral orientativo |
|---|---|---|
%util |
% de tiempo con al menos una petición en vuelo | > 90 % sostenido: saturado (menos fiable en SSD/NVMe) |
r_await / w_await |
Latencia media por petición, en ms | > 10 ms en SSD o > 20 ms en disco mecánico: hay cola |
aqu-sz |
Profundidad media de la cola | > 1 sostenido: hay saturación |
La distinción crítica es latencia frente a caudal: un disco puede mover 200 MB/s tan tranquilo con una tarea secuencial (caudal alto, latencia baja) y ahogarse con 5 MB/s de escrituras aleatorias pequeñas (caudal ridículo, latencia terrible). Al usuario le duele la latencia, no el caudal.
Y quién está escribiendo:
$ sudo iotop -b -n 1 -o -P | head -3
PID PRIO USER DISK READ DISK WRITE COMMAND
8842 idle operad 0.00 B/s 13.94 M/s respaldo_tramontana.sh
$ sudo lsof -p 8842 | grep -E 'REG.*backups' | head -1
respaldo 8842 operador 4w REG 253,0 /srv/.../tramontana-2026-08-18.tar.gz.parcial
- Red:
sar -n DEV, ss -s y las retransmisiones
sar -n DEV, ss -s y las retransmisiones$ sar -n DEV 1 1 | grep -E 'IFACE|enp0s3'
12:44:01 IFACE rxpck/s txpck/s rxkB/s txkB/s
12:44:02 enp0s3 412,00 398,00 118,42 902,18
$ ss -s | head -2
Total: 214
TCP: 187 (estab 142, closed 21, orphaned 0, timewait 19)
$ ss -tn state established '( dport = :5432 )' | wc -l
200Ese último comando es un adelanto del caso de hoy: doscientas conexiones establecidas contra el puerto de la base de datos, exactamente el max_conexiones de app.conf.
Para ver el tráfico en vivo, nload (por interfaz) o iftop (por conversación) son inmediatos.
Y el indicador de salud de TCP que hay que conocer, nstat -az | grep TcpRetransSegs: las retransmisiones son segmentos que hubo que reenviar porque no llegó confirmación. Un porcentaje pequeño es normal; una tasa creciente indica pérdida de paquetes —cable, saturación de un enlace o un dispositivo intermedio descartando tráfico—. El diagnóstico completo de red, con mtr y las capas, ya lo tienes de 03-08.
- Herramientas de conjunto y la historia con
sar
sar| Herramienta | Aporta |
|---|---|
htop |
top navegable: árbol con F5, filtros, nice interactivo, barras por núcleo |
atop |
Guarda historia cada 10 min y permite «rebobinar» a la hora del incidente |
glances / dstat |
Panel único con alertas de umbral / series por segundo, ideales para CSV |
sysstat / sar |
La memoria del rendimiento: métricas históricas cada 10 minutos |
El punto que más veces se pasa por alto: la foto de ahora no sirve sin la de ayer. Si Marta se queja a las 09:10 de algo ocurrido a las 09:00, top ya no dice nada; sar sí:
sudo apt install sysstat
sudo sed -i.bak-$(date +%F) 's/^ENABLED="false"/ENABLED="true"/' /etc/default/sysstat
sudo systemctl enable --now sysstat sysstat-collect.timersar -u -s 08:50:00 -e 09:30:00 # CPU en esa franja de HOY; -q da el load histórico
sar -r -f /var/log/sysstat/sa17 # memoria del día 17
sar -b -s 04:00:00 -e 05:00:00 # E/S durante la copia nocturnaActivar sysstat cuesta un minuto y es lo que convierte «creo que iba lento» en «a las 09:04 el %iowait subió al 61 %».
- Métricas continuas y los cuatro golden signals
Para más de un servidor, o para alertar sin que nadie mire, el estándar de hoy es Prometheus (base de datos temporal que consulta a los objetivos), node_exporter (expone las métricas del sistema en /metrics), Grafana (paneles) y Alertmanager (avisos). No lo montamos aquí: es materia del Módulo 8. Lo que sí debes llevarte es qué medir, los cuatro golden signals:
| Señal | Qué mide | En Tramontana |
|---|---|---|
| Latencia | Duración de una petición en percentiles (p50, p95, p99), separando las que fallan | ms de acceso.log |
| Tráfico / Errores | Peticiones por segundo / tasa de fallos | Líneas por minuto y los 23 códigos de error del log |
| Saturación | Cuán lleno está el recurso más limitado | conexiones_activas / max_conexiones |
Y una regla sobre alertas: una alerta que suena a diario deja de leerse. Alerta sobre síntomas que le duelen al usuario (latencia p95, tasa de errores), no sobre cada pico de CPU. Es la misma disciplina del «silencio si todo va bien» de tus scripts.
- Procedimiento para «el servidor va lento»
Este es el procedimiento numerado que puedes aplicar tal cual, en este orden, sin saltarte pasos:
- Traduce la queja a un número medible. ¿Qué operación, a qué hora, cuánto tarda ahora y cuánto antes? Sin esto no puedes saber si has arreglado algo.
- Foto de 60 segundos.
uptime,vmstat 1 5,free -h,iostat -xz 1 3,ss -s,systemctl --failed. Con seis comandos sabes si el problema es CPU, memoria, disco o red. - Compara con la línea base. ¿Es anormal, o siempre ha sido así y lo que ha cambiado es la expectativa?
- Identifica el recurso con USE y elige uno, descartando los demás explícitamente.
- Localiza al culpable dentro de ese recurso con
pidstat,iotop,ssotop -H: nombre y PID. - Formula una hipótesis falsable. «La copia de las 04:20 satura el disco y por eso las consultas caducan» se puede confirmar o descartar; «va lento» no.
- Revisa qué cambió:
journalctl --since,/var/log/apt/history.log,git logde tus scripts, elHISTORIAL. El 80 % de los problemas nuevos vienen de un cambio reciente. - Mide antes de tocar nada y guarda las cifras en un fichero con fecha.
- Cambia UNA sola cosa y documenta qué y por qué.
- Mide después, en las mismas condiciones, y compara. Si no mejora, revierte antes de probar otra cosa.
- Anota el resultado en el
HISTORIAL, incluso —sobre todo— si el cambio no sirvió.
Los pasos 8, 9 y 10 son innegociables. Cambiar tres parámetros a la vez y ver que mejora no te enseña nada: no sabes cuál sirvió, y arrastrarás dos ajustes inútiles para siempre.
- Ajustes al alcance de un administrador
Los parámetros del kernel vía sysctl son materia de 07-03 y el perfilado con perf y eBPF es de 07-02. Lo que sí está en tus manos hoy:
Límites de ficheros abiertos. Un servidor con muchas conexiones agota el límite por proceso y rechaza peticiones con Too many open files:
En un servicio de systemd no se toca /etc/security/limits.conf —que solo aplica a sesiones de login vía PAM—, sino la unidad:
Límites de recursos del servicio: MemoryMax y CPUQuota de 05-05, que además de proteger sirven para medir, porque systemd-cgtop muestra si el servicio llega al techo. Y noatime en fstab (05-04), que evita una escritura por cada lectura y se nota en un servidor con muchos ficheros pequeños.
Perfilado somero de hilos: top -H -p 1284 desglosa el consumo hilo a hilo cuando un proceso multihilo va cargado y no sabes qué parte. perf top daría el desglose por función, pero eso es 07-02.
Los parámetros de la propia aplicación, que suelen rendir más que cualquier ajuste del sistema: en Tramontana, max_conexiones y timeout_consulta de /etc/tramontana/app.conf.
- La línea base de
srv-tramontana
srv-tramontanaUna línea base es una foto del comportamiento normal, tomada cuando todo va bien, para comparar cuando no. Se guarda junto a la de referencia del Módulo 1:
#!/usr/bin/env bash
# /home/operador/scripts/linea_base.sh — foto de rendimiento con fecha
set -euo pipefail
destino="/srv/tramontana/backups/lineabase-$(date +%F-%H%M).txt"
{
echo "== $(date --iso-8601=seconds) $(hostname) =="
uptime; nproc; free -h
vmstat 1 5 | tail -4
iostat -xz 1 2 | tail -6
ss -s; df -h /; df -i / | tail -1
} > "$destino"Valores normales medidos en srv-tramontana un martes a las 11:00, con la aplicación en marcha:
| Métrica | Valor normal | Umbral de atención |
|---|---|---|
| Load average (2 vCPU) | 0,15 – 0,40 | > 2,0 sostenido |
CPU id / wa |
85 – 95 % / 0 – 3 % | < 40 % / > 20 % |
| Memoria disponible | 2,3 – 2,5 GiB | < 400 MiB |
si/so de swap |
0 | Cualquier valor sostenido |
w_await en dm-0 |
0,8 – 2,5 ms | > 20 ms |
Conexiones a 5432 / disco / |
30 – 60 / 30 % | > 150 / > 85 % |
Esa tabla, y no la intuición, es lo que convierte una medición en un diagnóstico.
- Caso Tramontana: «la web va lenta por las mañanas»
Paso 1 — Traducir la queja. Preguntamos y medimos: la búsqueda de disponibilidad, que normalmente responde en 180 ms, tarda entre 4 y 9 segundos entre las 08:50 y las 09:15. Ya es un número.
Paso 2-3 — Foto y comparación con la línea base. Como el incidente es recurrente, medimos a las 09:00 del día siguiente:
$ uptime
09:04:11 up 6 days, 22:20, 2 users, load average: 3,42, 2,10, 1,08
$ vmstat 1 3 | tail -1
5 3 0 195884 91240 1843644 0 0 4 15108 918 2205 19 5 8 68 0Load 3,42 con 2 vCPU (línea base: 0,15–0,40) y wa al 68 % (base: 0–3 %) con id al 8 %. No falta CPU: falta disco. Memoria y swap, normales. Recurso identificado: E/S.
Paso 4-5 — El culpable.
$ iostat -xz 1 2 | tail -2
Device r/s rkB/s w/s wkB/s aqu-sz w_await %util
dm-0 2,00 8,00 148,00 14620,00 3,42 22,85 97,60
$ sudo iotop -b -n 1 -o | tail -1
8842 idle operador 13.94 M/s respaldo_tramontana.sh
$ journalctl -u tramontana-respaldo.service --since "2 days ago" -o short-iso | grep -E 'inicio|completada'
2026-08-17T04:20:06+0200 respaldo[8811]: inicio de copia (version=3.2.1)
2026-08-17T06:02:44+0200 respaldo[8811]: copia completada en 6158s
2026-08-18T04:20:07+0200 respaldo[8842]: inicio de copia (version=3.2.1)w_await de 22,85 ms frente a los 0,8–2,5 de la base, %util al 97,6 %, y quien escribe es la copia de seguridad, que en teoría se lanza a las 04:20: la del día 17 tardó 1 h 42 min y la del 18 aún no había terminado a las 09:04. El conjunto de datos ha crecido y la copia se solapa con la hora punta.
Paso 6 — Hipótesis falsable. «La copia de seguridad satura la E/S del disco hasta pasadas las 09:00; eso alarga las consultas a la base de datos, que llegan al timeout_consulta de 30 s y agotan las 200 conexiones de max_conexiones, que es lo que provoca los db_timeout de los logs.»
Comprobación de la segunda mitad:
$ ss -tn state established '( dport = :5432 )' | wc -l # 200: el techo exacto
$ journalctl -u tramontana.service --since "09:00" -p err --no-pager | wc -l
11Doscientas conexiones exactas —el techo— y once errores en cuatro minutos. Hipótesis confirmada: el mismo mecanismo que causó los db_timeout de las 03:00 de la lección anterior.
Paso 7-9 — Qué cambió, medir y cambiar UNA cosa. El HISTORIAL lo dice: el volumen de copias se migró el 18 y el conjunto de datos ha crecido. La causa raíz es la duración de la copia, no las conexiones. El cambio mínimo y reversible:
### /etc/systemd/system/tramontana-respaldo.service.d/override.conf
[Service]
# La copia debe terminar antes de la hora punta (08:45); si no, se aborta y avisa.
RuntimeMaxSec=3h
IOWeight=10$ sudo systemctl edit tramontana-respaldo.timer # OnCalendar=*-*-* 02:30:00
$ sudo systemctl daemon-reload && systemctl list-timers tramontana-respaldo.timer | tail -1
Wed 2026-08-19 02:30:00 CEST 14h left tramontana-respaldo.timerPaso 10 — Medir después, a la misma hora y con los mismos comandos.
| Métrica a las 09:04 | Antes | Después |
|---|---|---|
Load average / CPU wa |
3,42 / 68 % | 0,38 / 2 % |
w_await dm-0 |
22,85 ms | 1,40 ms |
| Conexiones a 5432 | 200 (techo) | 47 |
Errores db_timeout (09:00–09:15) |
11 | 0 |
| Latencia de búsqueda | 4–9 s | 190 ms |
Paso 11 — Documentar. Y el informe para Marta, con la estructura de siempre: «La lentitud de las mañanas la causaba la copia de seguridad, que había crecido hasta tardar más de cuatro horas y seguía escribiendo en hora punta; al saturar el disco, las consultas caducaban y se agotaban las 200 conexiones a la base de datos. Hemos adelantado la copia a las 02:30 y le hemos puesto un límite de 3 horas y menor prioridad de E/S. Medido a las 09:04: la búsqueda vuelve a 190 ms y no hay errores. Qué protege esto: que la copia interfiera con el horario laboral. Qué no protege: si el conjunto de datos sigue creciendo, volveremos a chocar; hay que pasar a copias incrementales, y eso lo abordamos ahora mismo. Tampoco resuelve que 200 conexiones sea un límite ajustado si crece el número de usuarios.»
sudo tee -a /opt/tramontana/HISTORIAL >/dev/null <<'FIN'
2026-08-19 Rendimiento matinal (operador)
- Causa: copia de 4h+ saturando E/S (w_await 22,85 ms, %util 97,6) pasadas las 09:00
- Efecto: consultas a 30s de timeout -> 200/200 conexiones -> db_timeout
- Cambio: timer a 02:30, RuntimeMaxSec=3h, IOWeight=10 (un solo cambio, medido)
- Resultado 09:04: load 0,38 / wa 2% / w_await 1,40ms / 47 conexiones / 0 errores / 190 ms
- Pendiente: copias incrementales (la copia completa seguirá creciendo)
FINErrores Comunes y Consejos
- Leer el load average sin dividir por
nproc. Un 3,42 no significa nada hasta saber cuántos núcleos hay. - Asustarse por «poca memoria libre». La cifra que importa es
disponible; la caché es memoria bien empleada. - Fiarse de la primera línea de
vmstatoiostat. Es la media desde el arranque, no el momento actual. - Mirar
%utilen un SSD como si fuera un disco mecánico. Con colas paralelas, un NVMe puede marcar 100 % y no estar saturado. Miraawaityaqu-sz. - Diagnosticar sin línea base. Sin saber qué es normal, cualquier número parece alarmante o tranquilizador según el ánimo. Y no cambies varias cosas a la vez: no sabrás cuál funcionó, y arrastrarás ajustes inútiles durante años.
- No tener historia. Instala
sysstatel primer día: cuando alguien pregunte por las 09:00, ya será tarde para activarlo. - Confundir un síntoma con la causa. Las 200 conexiones eran el síntoma; la copia era la causa. Subir
max_conexioneshabría escondido el problema. - Consejo: guarda cada medición en un fichero con fecha, junto al
HISTORIAL. Dentro de seis meses, esa carpeta valdrá más que tu memoria.
Ejercicios
- Leer una foto. Un servidor con 4 vCPU muestra
load average: 7,80, 7,20, 6,90,vmstatconus=6 sy=3 id=4 wa=87 st=0,r=1,b=6, yfree -hcon 5,1 GiB disponibles de 8. ¿Cuál es el recurso saturado, cuál no lo es, y cuáles son los dos comandos siguientes? - Un servicio que muere de madrugada.
tramontana.serviceaparece reiniciado cada noche sobre las 03:40 sin que nadie lo toque. Da los comandos para confirmar si fue el OOM killer y, si lo fue, dos formas de evitar que se lleve por delante la base de datos. - Demostrar una mejora. Diseña el protocolo exacto —comandos, momentos y criterio de éxito— para demostrar que activar
noatimeen/srv/tramontana/backupsacorta la copia nocturna, de forma que el resultado convenza a alguien escéptico.
Soluciones
1. El recurso saturado es el disco. La prueba: wa=87 % con id=4 % significa que la CPU está parada esperando E/S, y b=6 son seis procesos bloqueados en estado D, que además son los que inflan el load hasta 7,80 pese a que solo hay r=1 esperando CPU. Normalizado, 7,80 entre 4 núcleos serían 1,95, pero ese número es engañoso aquí precisamente porque lo componen procesos en D, no en R. Lo que no está saturado: la CPU (us+sy = 9 %) ni la memoria (5,1 GiB disponibles de 8, sin swap en movimiento). Los dos comandos siguientes:
iostat -xz 1 3 # qué dispositivo, con qué latencia (w_await) y qué cola (aqu-sz)
sudo iotop -b -n 1 -o # qué proceso concreto está haciendo esa E/S2.
$ sudo journalctl -k --since "03:00" --until "04:00" --grep -i 'out of memory'
ago 17 03:41:12 srv-tramontana kernel: Out of memory: Killed process 1284 (tramontana)
$ systemctl show tramontana.service -p NRestarts # NRestarts=6
$ journalctl -u tramontana.service --since "03:00" | grep 'Main process'
ago 17 03:41:12 systemd[1]: tramontana.service: Main process exited, code=killed, status=9/KILLstatus=9/KILL sin que nadie ejecutara un kill es la firma del OOM killer, y el mensaje del kernel lo confirma. Nótese la coincidencia horaria con la copia nocturna: la caché de página que genera la copia presiona la memoria disponible.
Dos formas de proteger a la base de datos:
# (a) En tramontana.service: el OOM actúa DENTRO del cgroup del servicio
[Service]
MemoryMax=512M
Restart=on-failureLa primera es la buena, porque acota el problema en su origen: cuando Tramontana se pase de memoria morirá Tramontana, y systemd la levantará, sin que el kernel elija víctima en toda la máquina. La segunda es un complemento defensivo: sesga la elección, pero no impide que la máquina se quede sin memoria.
3. El protocolo, que es el método de la sección 8 aplicado:
# 1. Medir el estado actual, tres noches seguidas para tener variabilidad
journalctl -u tramontana-respaldo.service --since "3 days ago" -o cat | grep 'completada en'
# -> 6158s, 5904s, 6021s (mediana 6021 s); sar -b -f /var/log/sysstat/sa17 para la E/S
# 2. Cambiar UNA sola cosa, con copia previa y verificación
sudo cp -a /etc/fstab /etc/fstab.bak-$(date +%F)
sudo sed -i 's|\(/srv/tramontana/backups.*defaults\)|\1,noatime|' /etc/fstab
sudo diff -u /etc/fstab.bak-$(date +%F) /etc/fstab
sudo mount -o remount /srv/tramontana/backups
findmnt -no OPTIONS /srv/tramontana/backups # comprobar que noatime está activo
# 3. Medir otras tres noches, mismos comandos y mismo horario
journalctl -u tramontana-respaldo.service --since "3 days ago" -o cat | grep 'completada en'Criterio de éxito, fijado antes de medir: reducción de la mediana de duración superior al 10 % sin aumento de errores en journalctl -u tramontana-respaldo.service -p err. Tres noches a cada lado porque una sola medición no distingue una mejora de una noche floja. Y si no se cumple el criterio, se revierte con el .bak y se anota en el HISTORIAL que no sirvió: un experimento negativo documentado ahorra que alguien lo repita dentro de un año.
Conclusión
Ya no dependes de que alguien «note» que el servidor va lento. Distingues monitorizar de diagnosticar y aplicas el método USE —utilización, saturación, errores— a los cuatro recursos. Lees el load average normalizado por nproc sabiendo que incluye los procesos en estado D, e interpretas vmstat 1 columna a columna: r y b, si/so, us/sy/id/wa y el st que delata al hipervisor. Repartes el consumo con mpstat -P ALL y pidstat.
En memoria sabes que «libre» es una cifra engañosa y que la buena es disponible, distingues VSZ, RSS y PSS, reconoces el thrashing en si/so, y sabes probar que actuó el OOM killer con journalctl -k y cómo evitar que se lleve al vecino con MemoryMax y OOMScoreAdjust. En disco manejas iostat -xz con %util, await y aqu-sz, tienes clara la diferencia entre latencia y caudal, y localizas al culpable con iotop y lsof. En red usas sar -n DEV, ss -s y las retransmisiones. Conoces htop, atop, glances y dstat, y —lo más importante— has activado sysstat para tener la historia sin la cual la foto de hoy no significa nada. Sabes qué son los cuatro golden signals y por qué una alerta que suena a diario deja de leerse.
Tienes un procedimiento de once pasos para «el servidor va lento», con las tres reglas innegociables: medir antes, cambiar una sola cosa, medir después. Tienes una línea base de srv-tramontana con umbrales escritos. Y has resuelto el caso: la lentitud matinal era la copia de seguridad saturando la E/S hasta pasadas las 09:00, provocando los db_timeout y el agotamiento de las 200 conexiones; adelantarla y limitarla devolvió la búsqueda de 4–9 s a 190 ms, con las cifras de antes y después escritas en el HISTORIAL.
Pero el informe para Marta terminaba con un cabo suelto que no puede esperar: la copia completa seguirá creciendo, y con ella el problema. Y hay algo mucho peor que nadie ha comprobado todavía: nadie ha restaurado nunca esa copia. En Respaldo y Restauración, la última lección del módulo, verás por qué no existen las copias de seguridad sino solo las restauraciones probadas: fijarás RPO y RTO para Tramontana, aplicarás la regla 3-2-1 y la retención por generaciones, resolverás la consistencia con snapshots LVM de 05-04, usarás tar --listed-incremental, rsync --link-dest y una herramienta moderna con deduplicación y cifrado, y escribirás el procedimiento de restauración paso a paso para los tres escenarios que pueden ocurrirte de verdad.
Curso de Linux: De Principiante a Administrador de Sistemas
Módulo 1: Introducción a Linux
- ¿Qué es Linux?
- Historia de Linux
- Distribuciones de Linux
- Instalando Linux
- Primer Contacto con el Sistema
- Estructura del Sistema de Archivos de Linux
Módulo 2: Comandos Básicos de Linux
- Introducción a la Línea de Comandos
- Obtener Ayuda y Documentación del Sistema
- Navegando el Sistema de Archivos
- Operaciones con Archivos y Directorios
- Visualización y Edición de Archivos
- Enlaces Duros y Simbólicos
- Permisos y Propiedad de Archivos
Módulo 3: Habilidades Avanzadas en la Línea de Comandos
- El Entorno del Shell: Variables, Alias e Historial
- Uso de Comodines y Expresiones Regulares
- Búsqueda de Archivos y Contenido: find, locate y grep
- Tuberías y Redirección
- Procesamiento de Texto: cut, sort, uniq, sed y awk
- Gestión de Procesos
- Programación de Tareas con Cron
- Comandos de Redes
Módulo 4: Scripting en Shell
- Introducción al Scripting en Shell
- Variables y Tipos de Datos
- Entrada, Salida y Argumentos de un Script
- Estructuras de Control
- Funciones y Librerías
- Depuración y Manejo de Errores
- Scripts de Producción: Buenas Prácticas
Módulo 5: Administración del Sistema
- Gestión de Usuarios y Grupos
- sudo y Permisos Especiales
- Gestión de Paquetes
- Gestión de Discos
- systemd y la Gestión de Servicios
- Registros del Sistema: journald y syslog
- Monitoreo del Sistema y Optimización del Rendimiento
- Respaldo y Restauración
Módulo 6: Redes y Seguridad
- Configuración de Redes
- SSH y Acceso Remoto
- Firewall y Seguridad Perimetral
- Sistemas de Detección de Intrusos
- Gestión de Secretos y Certificados TLS
- Asegurando Sistemas Linux
Módulo 7: Temas Avanzados
- El Proceso de Arranque y la Recuperación del Sistema
- Diagnóstico Avanzado: strace, perf y eBPF
- Optimización del Kernel de Linux
- Virtualización con Linux
- Contenedores de Linux y Docker
- Automatización con Ansible
- Alta Disponibilidad y Balanceo de Carga
