Diagnosticar disk IO lento en Linux con iostat e iotop

Identifica cuellos de botella de disco en Linux usando iostat e iotop. Métricas %util, await, r/s, w/s explicadas con ejemplos prácticos para sysadmins.

Aplicación lenta, load average alto y CPU mostrando 20% de uso casi siempre apuntan al mismo culpable: el disco. El síntoma clásico es una query MySQL que normalmente corre en 50ms pasar a tardar 8 segundos sin cambio en el plan de ejecución, o un deploy de Node.js que demoraba 30 segundos quedar trabado en 5 minutos en npm install.

Antes de provisionar más CPU o RAM, necesitas confirmar que el cuello de botella es IO de disco. CPU baja con load alto es la primera señal — los procesos están en estado D (uninterruptible sleep) esperando operaciones de disco. Este tutorial muestra cómo usar iostat e iotop para confirmarlo en 5 minutos e identificar exactamente qué proceso está saturando tu almacenamiento.

La persona aquí es el sysadmin Linux que ya hizo lo básico (top, htop, free) y necesita cavar más profundo. Tiempo estimado de ejecución: 10-15 minutos para recopilar evidencia concluyente.

Prerrequisitos

Prerrequisitos

Necesitas una máquina Linux (Ubuntu 22.04+, Debian 12+, RHEL 9+ o similar) con acceso sudo o root. Las herramientas vienen en paquetes separados que no forman parte de la instalación mínima por defecto.

Paquete iostat sysstat
Paquete iotop iotop
Permiso iotop root o CAP_NET_ADMIN
Kernel mínimo 5.4+

Confirma también que CONFIG_TASK_IO_ACCOUNTING está habilitado en el kernel — sin esto, iotop muestra valores en cero. Verifica con:

grep CONFIG_TASK_IO_ACCOUNTING /boot/config-$(uname -r)

La salida debe ser CONFIG_TASK_IO_ACCOUNTING=y. En kernels custom o contenedores restringidos puede aparecer como # CONFIG_TASK_IO_ACCOUNTING is not set — en ese caso, usa pidstat -d como alternativa.

Instalando las herramientas

La mayoría de las distribuciones no incluyen sysstat ni iotop en la instalación base. Ocupan menos de 5 MB combinados.

01

Instala sysstat (que provee iostat, sar, pidstat, mpstat):

sudo apt update
sudo apt install -y sysstat

En RHEL/Rocky/Alma:

sudo dnf install -y sysstat
02

Instala iotop:

sudo apt install -y iotop

En RHEL/Rocky/Alma:

sudo dnf install -y iotop
03

Confirma las versiones instaladas:

iostat -V
iotop --version

Versiones mínimas recomendadas: sysstat 12.0+ e iotop 0.6+. Versiones muy antiguas tienen bugs conocidos en el cálculo de %util y en la columna svctm.

Primera lectura con iostat

iostat muestra estadísticas agregadas por dispositivo de bloque. La primera ejecución muestra promedios desde el boot — descarta esos números y observa las lecturas subsiguientes.

01

Ejecuta iostat en modo extendido con intervalo de 2 segundos:

iostat -xz 2 5

Flags importantes:

  • -x — extendido, muestra todas las columnas relevantes (await, %util)
  • -z — omite dispositivos sin actividad (reduce ruido)
  • 2 5 — 5 muestras de 2 segundos cada una

La primera muestra es el promedio desde el boot y debe ser ignorada. Analiza desde la segunda en adelante.

02

Identifica el dispositivo de interés en la columna Device. En VPS modernas será algo como vda, sda o nvme0n1. Las particiones (vda1, nvme0n1p1) también aparecen pero quieres el dispositivo padre para ver la actividad total.

Interpretando las métricas

Las columnas que importan para diagnóstico están concentradas en 6 campos. Ignora el resto hasta dominar estos.

MétricaSignificadoUmbral de alerta
r/sLecturas por segundo (IOPS de lectura)Depende del disco
w/sEscrituras por segundo (IOPS de escritura)Depende del disco
rkB/sThroughput de lectura en KB/sCompara con el spec del disco
wkB/sThroughput de escritura en KB/sCompara con el spec del disco
awaitLatencia promedio por solicitud en ms>20ms sospechoso, >100ms crítico
%util% del tiempo con solicitudes pendientes>80% saturación en HDD
%util engaña en SSD/NVMe

En discos rotacionales (HDD), %util cerca del 100% indica saturación real. En SSDs y NVMes que procesan IO en paralelo, %util del 100% puede ocurrir con 10% del ancho de banda real en uso. Usa await y compara rkB/s + wkB/s contra el spec del disco para evaluar saturación real en medios modernos.

La regla práctica: si await está por encima de 20ms en un SSD o por encima de 100ms en un NVMe, tienes latencia anormal. En HDDs, valores de 50-100ms ya son esperados, pero por encima de 200ms indica sobrecarga.

Ejemplo de salida saludable

Device   r/s   w/s    rkB/s   wkB/s  await  %util
nvme0n1  142   89     8520    4310   0.42   12.30

0.42ms de latencia en un NVMe — normal. 12% util y ~12 MB/s combinados — disco respirando bien.

Ejemplo de salida con cuello de botella

Device   r/s   w/s    rkB/s   wkB/s  await  %util
vda      890   1240   45200   78900  148.6  99.80

148ms de await es crítico — algo está haciendo mucho IO sincronizado o el disco está saturado. %util en 99.8% en un disco rotacional confirma saturación. 2.130 IOPS combinados en un disco que normalmente hace 200 IOPS sostenidos es evidencia de batch job mal comportado o swap thrashing.

Encontrando el proceso culpable con iotop

iostat te dice QUE hay cuello de botella. iotop te dice QUIÉN lo está causando.

01

Ejecuta iotop en modo interactivo:

sudo iotop -o

Flags:

  • -o — muestra solo procesos con IO activo (oculta los en cero)
  • Tecla r — invierte la ordenación
  • Tecla o — alterna modo “only active”
  • Tecla q — sale
02

Identifica las columnas DISK READ y DISK WRITE. Los procesos en el tope de la lista son los mayores consumidores de IO en el momento.

La columna IO> muestra el porcentaje del tiempo que el proceso pasó esperando IO. Valores por encima del 30% sostenidos indican proceso IO-bound — no se volverá más rápido con más CPU.

03

Para capturar evidencia sin dejar iotop corriendo indefinidamente, usa modo batch:

sudo iotop -o -b -n 5 -d 2 > /tmp/iotop-snapshot.txt

Esto captura 5 snapshots de 2 segundos y sale. Útil para recopilar evidencia durante una ventana de lentitud reportada y analizar después.

Alternativa cuando iotop no funciona

En contenedores o kernels sin TASK_IO_ACCOUNTING, usa pidstat -d 2 5 (viene en sysstat). Muestra IO por proceso usando contadores diferentes que no dependen del mismo flag de kernel.

Verificación

Para confirmar que tu hipótesis de cuello de botella de disco es correcta, combina 3 evidencias:

  1. iostat -xz 2 5 mostrando await alto y %util alto sostenidos
  2. iotop -o apuntando proceso específico en el tope de la lista
  3. top o htop mostrando procesos en estado D (uninterruptible sleep) — columna S o STATE
ps -eo pid,state,comm | awk '$2 == "D"'

Si esta lista tiene procesos diferentes del PID que iotop mostró, probablemente son víctimas (esperando que el disco sea liberado por el culpable). Si es el propio culpable, está haciendo IO síncrono pesado.

Resolución de problemas

iotop retorna “Could not run iotop as a non-root user”

iotop necesita privilegios para leer estadísticas de procesos ajenos. Ejecuta con sudo. Si quieres permitirlo para un usuario específico sin sudo cada vez, da la capability:

sudo setcap 'cap_net_admin+eip' $(which iotop)

iostat muestra %util del 100% pero la aplicación no está lenta

Caso clásico de SSD/NVMe donde %util perdió significado. Observa rkB/s + wkB/s y compara con el ancho de banda nominal del disco. Si está por debajo del 50% del ancho de banda spec, no es saturación real.

Latencia alta intermitente que iostat no captura

iostat muestra promedios en un intervalo. Picos de latencia sub-segundo quedan escondidos en el promedio. Usa iostat -x 1 (intervalo 1s) durante la ventana problemática, o bpftrace para capturar latencias de bloque individuales.

No confundas swap con IO de aplicación

Si iotop muestra kswapd0 o [kswapd] en el tope, tu sistema está en swap thrashing — sin memoria RAM, el kernel está moviendo páginas al disco constantemente. La solución no es optimizar IO; es agregar RAM o encontrar la fuga de memoria. Verifica free -h y ajusta vm.swappiness.

Próximos pasos

Con el cuello de botella identificado, los caminos comunes son:

  1. Aplicar tuning de IO scheduler — mq-deadline para workloads transaccionales, none para NVMe puro
  2. Habilitar recopilación histórica con sar (parte de sysstat) para análisis de tendencia a lo largo de semanas
  3. Investigar con bpftrace o perf para capturar stack traces de los syscalls de IO más lentos
  4. Evaluar migración a almacenamiento NVMe si el workload exige IOPS sostenidos por encima de 10k

Si estás poniendo una aplicación IO-intensiva en producción, una VPS Hostini con almacenamiento NVMe local ya entrega latencia consistente sub-1ms — lo que elimina la mayor fuente de variabilidad en diagnósticos de disco.

Preguntas frecuentes

¿%util del 100% siempre significa que el disco es el cuello de botella?

No. En SSDs y NVMe, %util refleja solamente si hay alguna solicitud en vuelo, no saturación real. Un NVMe puede mostrar 100% util y aún estar usando 5% del ancho de banda real. Confía en await, IOPS y throughput antes de concluir saturación en medios modernos.

¿Cuál es la diferencia entre await y svctm en iostat?

await es el tiempo total que una solicitud pasa en el sistema (cola + servicio), en milisegundos. svctm intentaba medir solo el tiempo de servicio, pero el cálculo era incorrecto en kernels modernos y fue removido en versiones recientes de sysstat. Usa await como métrica principal de latencia.

iotop muestra cero IO pero el sistema está lento — ¿por qué?

iotop necesita CONFIG_TASK_IO_ACCOUNTING habilitado en el kernel. En contenedores y algunos kernels personalizados aparece en cero. Confirma con cat /proc/self/io — si el archivo no existe o está vacío, el accounting está deshabilitado y necesitas usar pidstat -d o bpftrace.

¿Por qué await alto pero %util bajo?

Generalmente indica disco remoto con latencia de red (NFS, iSCSI, almacenamiento en la nube) o throttling del hipervisor en entornos virtualizados. El disco local no está saturado, pero cada solicitud demora porque va por la red. Verifica el tipo de almacenamiento y métricas de red.

iostat -x muestra rrqm/s y wrqm/s altos — ¿es malo?

No, es lo opuesto. rrqm/s y wrqm/s son solicitudes fusionadas por el kernel antes de ir al disco — significa que el IO scheduler está combinando operaciones secuenciales en batches mayores y más eficientes. Valores altos aquí suelen indicar workload secuencial bien optimizado.

¿Puedo ejecutar iotop en producción sin impacto?

Sí, el overhead de iotop es bajo (~1-2% CPU en servidores ocupados). Usa iotop -o -b -n 5 -d 2 para capturar 5 snapshots de 2 segundos en modo batch y salir — ideal para recopilar evidencia sin dejar el proceso corriendo indefinidamente.

Temas:
Próximos pasos Cloud Ryzen con NVMe y protección DDoS siempre activa.Pon en producción en un VPS Hostini →
¿Te resultó útil este tutorial?
Hablar por WhatsApp