Cuando un servidor responde lento, lo primero que suele mirarse es la CPU. Pero un load average alto no siempre significa que falte CPU: puede tratarse de disco lento, de un vecino ruidoso en la virtualización o de un único hilo bloqueado. En esta guía aprenderás a distinguir esos casos en Ubuntu 24.04 con top, ps, pidstat, mpstat y vmstat, a localizar el proceso y el código responsable, y a limitar su consumo mientras lo corriges.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Los comandos funcionan igual en Debian 12.
- Un usuario no root con privilegios
sudo. - El paquete
sysstat, que proporcionapidstat,mpstat,iostatysar. Lo instalarás en el primer paso.
Paso 1: Instalar sysstat
top y ps vienen con el sistema, pero las herramientas que miden la CPU por proceso e intervalo están en sysstat:
sudo apt update
sudo apt install sysstat
Comprueba que está disponible:
pidstat -V
sysstat version 12.6.1
(C) Sebastien Godard (sysstat <at> orange.fr)
Paso 2: Comparar la carga con el número de núcleos
El load average es el número medio de tareas que están ejecutándose o esperando para ejecutarse (incluidas las que esperan al disco) en los últimos 1, 5 y 15 minutos. Por sí solo no dice nada: hay que compararlo con el número de núcleos.
nproc
uptime
4
11:02:17 up 3 days, 2:41, 1 user, load average: 9.12, 7.40, 4.05
Con 4 núcleos, una carga de 9 significa que hay más del doble de trabajo del que la CPU puede atender. Estas son las pautas generales:
| Carga (1 min) respecto a núcleos | Significado |
|---|---|
| Por debajo del número de núcleos | Hay capacidad libre |
| Igual al número de núcleos | CPU al límite, sin cola |
| Claramente por encima | Hay tareas esperando: el servidor irá lento |
Si la carga del minuto es mucho mayor que la de 15 minutos, el problema acaba de empezar; si es al revés, ya está remitiendo.
Paso 3: Averiguar en qué se va el tiempo de CPU
Antes de buscar el proceso culpable, averigua qué tipo de consumo es. mpstat muestra el desglose por núcleo; este ejemplo toma 3 muestras de 2 segundos:
mpstat -P ALL 2 3
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 71.30 0.00 9.85 0.40 0.00 0.62 1.10 0.00 0.00 16.73
Average: 0 98.50 0.00 1.50 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: 1 62.10 0.00 12.40 0.50 0.00 0.80 1.60 0.00 0.00 22.60
Average: 2 61.80 0.00 13.00 0.60 0.00 0.90 1.40 0.00 0.00 22.30
Average: 3 62.80 0.00 12.50 0.50 0.00 0.80 1.40 0.00 0.00 22.00
Así se interpreta cada columna relevante:
| Columna | Qué mide | Si es alta |
|---|---|---|
%usr | Código de aplicaciones | Busca el proceso en el paso 4 |
%sys | Código del kernel (llamadas al sistema) | Muchas llamadas al sistema, red o disco: usa strace en el paso 6 |
%iowait | CPU ociosa esperando al disco | No es un problema de CPU: revisa el disco con iostat |
%soft | Interrupciones de software, sobre todo red | Mucho tráfico de red o un posible ataque |
%steal | Tiempo que el hipervisor dio a otras máquinas | Contención en el host físico |
En el ejemplo, el núcleo 0 está al 98 % en %usr mientras los demás tienen margen: es típico de un proceso de un solo hilo que no puede repartir su trabajo, como un script o una instancia de Redis.
Paso 4: Encontrar el proceso con top
Abre top ordenado por CPU:
top -o %CPU
Dentro de top, estas teclas son las más útiles:
1: muestra una línea por núcleo, comompstat.c: alterna entre el nombre del proceso y la línea de comandos completa.H: muestra hilos en lugar de procesos.u: filtra por usuario (por ejemplowww-data).k: envía una señal a un PID.q: sale.
Si necesitas guardar una instantánea (para un ticket de soporte o un log), usa el modo batch:
top -b -n 1 -o %CPU | head -20
Notaen
top, un proceso puede superar el 100 %. El valor es relativo a un núcleo, así que un proceso que usa 4 núcleos completos aparece con un 400 %.
Paso 5: Confirmar con ps y pidstat
ps da un listado fácil de filtrar y guardar:
ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -10
PID PPID USER %CPU %MEM ELAPSED CMD
21877 1 www-data 96.4 3.2 41:10 php-fpm: pool www
21880 1 www-data 88.1 3.0 41:09 php-fpm: pool www
1204 1 mysql 35.7 18.6 3-02:40:11 /usr/sbin/mysqld
Ten en cuenta que el %CPU de ps es la media desde que arrancó el proceso, no el consumo actual. Un proceso que lleva días en marcha y acaba de dispararse puede aparecer con un valor bajo. Para medir el consumo real en un intervalo, usa pidstat. Este ejemplo toma 3 muestras de 5 segundos de los procesos activos:
pidstat -u 5 3
Average: UID PID %usr %system %guest %wait %CPU CPU Command
Average: 33 21877 91.20 4.60 0.00 2.10 95.80 - php-fpm8.3
Average: 33 21880 85.40 3.20 0.00 3.00 88.60 - php-fpm8.3
Average: 112 1204 30.10 6.40 0.00 0.80 36.50 - mysqld
La columna %wait indica el tiempo que el proceso estuvo listo para ejecutarse pero esperando CPU. Si es alta en muchos procesos, la máquina se ha quedado corta de núcleos.
Para un proceso con muchos hilos (Java, MySQL, Node.js con workers), ve hilo a hilo con -t. Sustituye PID por el número del proceso:
pidstat -t -p PID 2 5
Y para ver cambios de contexto, útiles cuando %sys es alto:
pidstat -w -p PID 2 5
Un número muy alto de cambios de contexto involuntarios (nvcswch/s) indica que el proceso compite por la CPU; muchos voluntarios (cswch/s) indican que se bloquea continuamente esperando E/S o locks.
Paso 6: Ver la cola de ejecución con vmstat
vmstat resume el sistema en una línea por intervalo:
vmstat 2 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
9 0 0 412304 88120 2310456 0 0 4 36 2210 5120 81 10 8 0 1
8 0 0 410988 88120 2310520 0 0 0 52 2305 5340 83 9 7 0 1
Mira estas columnas:
r: procesos esperando CPU. Si se mantiene por encima del número de núcleos, falta CPU.b: procesos bloqueados esperando E/S. Si es alto, el cuello de botella es el disco.siyso: memoria que entra y sale de swap. Si no son cero de forma constante, el problema real es la memoria y la CPU se consume intercambiando páginas.st: tiempo robado por el hipervisor.
Paso 7: Investigar qué hace el proceso
Una vez localizado el PID, averigua a qué servicio pertenece. systemctl status acepta un PID y muestra la unidad que lo gestiona:
systemctl status PID
Para saber en qué llamadas al sistema pasa el tiempo, strace -c las cuenta durante unos segundos. Pulsa Ctrl+C para ver el resumen:
sudo strace -c -f -p PID
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
62.14 0.412230 12 33210 read
21.07 0.139781 8 16804 1203 stat
Advertencia
straceralentiza mucho el proceso mientras está conectado. Úsalo solo unos segundos en producción.
Si el tiempo se va en código de usuario (%usr alto), perf muestra qué funciones consumen la CPU. Instálalo con las herramientas que corresponden a tu kernel:
sudo apt install linux-tools-common linux-tools-$(uname -r)
sudo perf top -p PID
perf top muestra las funciones más calientes en tiempo real. En lenguajes interpretados (PHP, Python, Ruby) verás sobre todo funciones del intérprete; en esos casos es más útil el perfilador propio del lenguaje o los logs de la aplicación.
Algunas causas habituales según el proceso:
- PHP-FPM: activa el slow log del pool (
slowlogyrequest_slowlog_timeouten/etc/php/8.3/fpm/pool.d/www.conf) para ver qué scripts tardan. - MySQL: ejecuta
SHOW FULL PROCESSLIST;para ver las consultas en curso y activa el slow query log. - Un proceso que no reconoces: puede ser un minero de criptomonedas instalado tras un compromiso. Consulta la guía sobre cómo detectar si tu servidor está bajo ataque.
Paso 8: Limitar el consumo mientras lo corriges
Si no puedes arreglar la causa de inmediato, reduce el impacto sobre el resto del sistema.
Baja la prioridad de un proceso en ejecución. Un valor nice mayor significa menos prioridad (de -20 a 19):
sudo renice -n 10 -p PID
Para un servicio de systemd, es mejor fijar una cuota de CPU. Este ejemplo limita myapp.service al equivalente a medio núcleo:
sudo systemctl set-property myapp.service CPUQuota=50%
El cambio se aplica al momento y persiste tras reiniciar. Compruébalo con:
systemctl show myapp.service -p CPUQuotaPerSecUSec
CPUQuotaPerSecUSec=500ms
Si el proceso está colgado en un bucle, reinicia el servicio con sudo systemctl restart myapp. Usa kill -9 solo como último recurso, porque el proceso no puede cerrar ficheros ni conexiones limpiamente.
Paso 9: Consultar el histórico con sar
Muchas veces el pico ya ha pasado cuando lo investigas. sysstat puede guardar métricas cada 10 minutos. En Ubuntu la recogida está desactivada por defecto; actívala editando el fichero de configuración:
sudo nano /etc/default/sysstat
Cambia la línea ENABLED="false" por:
ENABLED="true"
Activa el servicio:
sudo systemctl enable --now sysstat
A partir de ese momento, puedes consultar la CPU y la carga del día:
sar -u
sar -q
Y los de un día anterior leyendo su fichero en /var/log/sysstat/, donde saDD corresponde al día del mes (por ejemplo sa24):
sar -u -f /var/log/sysstat/sa24
Solución de problemas
- Load average alto pero CPU ociosa: la carga incluye procesos en estado
D(esperando E/S sin interrupción). Lístalos conps -eo state,pid,cmd | awk '$1=="D"'y revisa el disco coniostat -xz 2 3. %stealpor encima del 10 % de forma sostenida: la máquina virtual no recibe toda la CPU que pide porque el host físico está ocupado. No lo puedes arreglar desde dentro del servidor; contacta con el soporte de CubePath o valora un plan con más recursos.ksoftirqdconsumiendo CPU: el kernel está procesando muchas interrupciones de red. Comprueba el tráfico consar -n DEV 1 5; puede ser un pico legítimo o un ataque.perfno encuentra el paquetelinux-tools-$(uname -r): estás usando un kernel sin paquete de herramientas disponible. Instalalinux-tools-generico actualiza al kernel más reciente de la distribución.
Conclusión
Has visto cómo pasar de un síntoma genérico ("el servidor va lento") a una causa concreta: comparar la carga con los núcleos, identificar el tipo de consumo con mpstat, localizar el proceso con top y pidstat, e investigarlo con strace y perf. Como siguientes pasos, deja activa la recogida de sar para tener histórico, configura alertas de CPU en tu sistema de monitorización y revisa también la guía de diagnóstico de alto uso de memoria, ya que la falta de memoria suele manifestarse como alto uso de CPU.
