Solución de problemas de agotamiento de recursos en Linux: CPU, memoria y espacio en disco

Soluciona el agotamiento de CPU, memoria y disco en Linux con comandos prácticos, pasos de limpieza seguros y verificaciones de causa raíz.

Solución de problemas de agotamiento de recursos en Linux: CPU, memoria y espacio en disco

Cuando un servidor Linux se queda sin CPU, memoria o espacio en disco, el primer síntoma suele ser vago: el sitio está lento, SSH se cuelga después de iniciar sesión, las implementaciones fallan o un servicio se reinicia constantemente. La forma más rápida de superar el incidente es identificar qué recurso está agotado y luego encontrar el proceso o sistema de archivos responsable.

Realiza primero las comprobaciones menos riesgosas. Los comandos de solo lectura como top, free, df, du, vmstat y journalctl te dan una imagen sin modificar la máquina. Matar procesos y eliminar archivos puede ser necesario, pero no son un diagnóstico.

Identificando al culpable: Monitoreo de recursos del sistema

Antes de poder solucionar un problema de agotamiento de recursos, debes identificar qué recurso está siendo sobreutilizado y qué proceso es el responsable. Linux proporciona un rico conjunto de herramientas de línea de comandos para este propósito.

Monitoreo de uso de CPU

Un uso elevado de CPU puede hacer que tu sistema se sienta lento y no responda. A menudo es causado por un proceso descontrolado, una aplicación exigente o un script ineficiente.

  • top: Este es un monitor de sistema en tiempo real indispensable. Muestra una lista dinámica de procesos, ordenados por uso de CPU de forma predeterminada. Puedes ver la utilización general de la CPU, el uso de memoria y los detalles de procesos individuales.

    top
    

    Dentro de top, presiona 1 para ver el uso de cada núcleo de CPU. Presiona P para ordenar por uso de CPU. Busca procesos que consuman consistentemente un alto porcentaje de CPU.

  • htop: Una versión interactiva mejorada de top. A menudo se prefiere por su facilidad de uso, salida coloreada y navegación más sencilla.

    htop
    

    Similar a top, htop permite ordenar por uso de CPU y proporciona información detallada del proceso.

  • mpstat: Parte del paquete sysstat, mpstat proporciona estadísticas detalladas de la CPU, incluido el uso por procesador, recuentos de interrupciones y cambios de contexto.

    mpstat -P ALL 1
    

    Este comando mostrará estadísticas de CPU para todos los núcleos cada segundo.

También verifica el promedio de carga contra el número de CPU:

uptime
nproc

Un promedio de carga de 8 significa algo muy diferente en una VM de 2 núcleos que en un host de 32 núcleos. La carga también incluye tareas que esperan en E/S no interrumpible, por lo que un promedio de carga alto con bajo uso de CPU puede apuntar a un problema de disco o almacenamiento en red.

Monitoreo de uso de memoria

Cuando un sistema se queda sin RAM disponible y espacio de intercambio, comienza a usar espacio en disco como memoria virtual, que es significativamente más lenta, lo que lleva a una degradación severa del rendimiento.

  • free -h: Muestra la cantidad total de memoria física y de intercambio libre y utilizada en el sistema, junto con los búferes y cachés utilizados por el kernel. La bandera -h hace que la salida sea legible para humanos (por ejemplo, MB, GB).

    free -h
    

    Presta atención a la memoria available y al espacio de intercambio used. Un uso elevado de intercambio indica RAM insuficiente.

  • top / htop: Tanto top como htop muestran el uso de memoria por proceso. Busca procesos con un valor alto de %MEM.

  • vmstat: Informa estadísticas de memoria virtual. Puede mostrar información sobre procesos, memoria, paginación, E/S de bloque, interrupciones y actividad de la CPU.

    vmstat 5
    

    Este comando informará estadísticas cada 5 segundos. Observa las columnas si (swap-in) y so (swap-out); los valores altos indican una paginación de memoria significativa.

Para posibles muertes por OOM, verifica el registro del kernel:

dmesg -T | grep -i 'killed process'
journalctl -k --since "1 hour ago" | grep -i oom

Una muerte por OOM cambia el incidente. La pregunta inmediata se convierte en qué proceso fue eliminado, por qué excedió la memoria disponible y si systemd o un orquestador lo reinició.

Monitoreo de espacio en disco

Una partición de disco llena puede evitar que las aplicaciones escriban datos, causar errores e incluso impedir que el sistema arranque.

  • df -h: Informa el uso del espacio en disco del sistema de archivos. La bandera -h hace que la salida sea legible para humanos.

    df -h
    

    Este comando listará todos los sistemas de archivos montados y mostrará su tamaño total, espacio usado, espacio disponible y punto de montaje. Busca particiones al 100% o cerca de su uso.

  • du -sh <directorio>: Estima el uso de espacio de archivos para un directorio dado. La bandera -s resume y -h lo hace legible para humanos.

    du -sh /var/log/*
    

    Úsalo para encontrar qué subdirectorios están consumiendo más espacio en disco.

Verifica también el uso de inodos:

df -ih

Un sistema de archivos puede tener gigabytes libres y aún así no poder crear archivos si se ha quedado sin inodos. Esto sucede con millones de archivos pequeños: entradas de caché, colas de correo, archivos de sesión, artefactos de compilación o registros mal rotados.

Resolviendo problemas de agotamiento de recursos

Una vez que hayas identificado el recurso problemático y el proceso ofensor, puedes tomar medidas para resolver el problema.

Abordando el uso elevado de CPU

  1. Identifica el proceso: Usa top o htop para encontrar el ID del proceso (PID) que consume mucha CPU.
  2. Investiga el proceso: Determina qué es el proceso. ¿Es una aplicación de usuario, un servicio del sistema o algo inesperado?
    • Uso legítimo elevado: Si una aplicación legítima está usando mucha CPU (por ejemplo, compilando software, codificando video), es posible que debas esperar a que termine, programarlo para horas de menor actividad o actualizar tu hardware.
    • Proceso descontrolado: Si un proceso está atascado en un bucle o consumiendo CPU excesiva sin intención, puedes intentar reiniciarlo. Si eso no funciona, es posible que debas terminarlo.
  3. Termina el proceso (¡Usar con precaución!): Puedes usar el comando kill para enviar señales a los procesos. Las señales más comunes son:
    • SIGTERM (15): Solicita amablemente al proceso que termine.
    • SIGKILL (9): Termina el proceso a la fuerza inmediatamente. Esto debería ser un último recurso ya que no permite que el proceso se limpie.
    # Terminar amablemente el proceso con PID 1234
    kill 1234
    
    # Terminar a la fuerza el proceso con PID 1234
    kill -9 1234
    
  4. Verifica los registros: Examina los registros del sistema (por ejemplo, /var/log/syslog, /var/log/messages, registros específicos de la aplicación) en busca de errores relacionados con el proceso problemático.
  5. Optimiza aplicaciones/scripts: Si el uso elevado de CPU se debe a una aplicación o script ineficiente, considera optimizar el código o la configuración.

La CPU alta no siempre es mala. Un trabajo por lotes que usa todos los núcleos por un corto tiempo puede estar bien. Un proceso de un solo hilo atascado al 100% de un núcleo mientras las solicitudes se acumulan detrás es diferente. Observa la duración, el impacto en el usuario y si se espera que el proceso esté ocupado.

Si necesitas más contexto antes de reiniciar un servicio, captura una instantánea:

ps -fp <pid>
sudo lsof -p <pid> | head
sudo strace -p <pid> -tt -T -f

Usa strace con cuidado en sistemas de producción. Puede agregar sobrecarga, pero una muestra corta a menudo te dice si el proceso está en un bucle, esperando archivos, fallando llamadas de red o abriendo repetidamente el mismo recurso.

Resolviendo fugas de memoria y agotamiento

Una fuga de memoria ocurre cuando un programa no libera la memoria que ya no necesita, consumiendo gradualmente toda la RAM disponible. Esto puede llevar a una paginación excesiva y a que el sistema no responda.

  1. Identifica el proceso: Usa top o htop para encontrar procesos con valores altos de memoria (%MEM) o tamaño de conjunto residente (RSS) que aumentan constantemente con el tiempo.
  2. Investiga el proceso: Determina la naturaleza de la aplicación. ¿Es una aplicación conocida con posibles problemas de memoria, o algo personalizado?
  3. Reinicia la aplicación/servicio: A menudo, simplemente reiniciar la aplicación o el servicio puede resolver temporalmente una fuga de memoria al liberar la memoria acumulada.
    # Ejemplo: Reiniciar el servidor web Apache
    sudo systemctl restart apache2
    
  4. Verifica el monitoreo específico de la aplicación: Muchas aplicaciones (por ejemplo, servidores web, bases de datos) tienen sus propias herramientas de monitoreo o registros que pueden ayudar a diagnosticar problemas de memoria.
  5. Analiza volcados de núcleo: Para aplicaciones críticas, es posible que debas habilitar los volcados de núcleo y usar herramientas de depuración (como gdb) para analizar el estado de la memoria cuando ocurre la fuga. Este es un paso de solución de problemas avanzado.
  6. Aumenta el espacio de intercambio (medida temporal): Si no puedes resolver la fuga de inmediato, puedes aumentar el espacio de intercambio para proporcionar más memoria virtual. Sin embargo, esto es una solución alternativa, no una solución.
  7. Actualización de hardware: Si tu sistema se queda constantemente sin memoria para su carga de trabajo, es posible que debas agregar más RAM física.

Una mejor investigación de memoria observa el cambio a lo largo del tiempo. Una captura de pantalla de top solo dice quién es grande ahora. Una fuga es una tendencia.

while true; do
  date
  ps -eo pid,comm,rss,%mem --sort=-rss | head -15
  sleep 60
done

Si el mismo proceso sube constantemente entre muestras sin caer después de que el tráfico disminuye, tienes una señal de fuga más fuerte. Si muchos procesos crecen juntos durante el tráfico máximo, la carga de trabajo puede simplemente exceder la capacidad o los límites de concurrencia.

Para servicios systemd, verifica si ya existen límites de memoria:

systemctl show <servicio> -p MemoryCurrent -p MemoryMax

Para contenedores, free -h a nivel de host puede verse bien mientras un contenedor alcanza su propio límite. Verifica docker stats, kubectl top pod o los eventos del orquestador para muertes por OOM.

Gestionando particiones de disco llenas

Cuando una partición de disco se llena, puede causar varias fallas del sistema. Por lo general, se requiere una acción inmediata.

  1. Identifica la partición llena: Usa df -h para localizar la(s) partición(es) al 100% de capacidad.
  2. Encuentra archivos/directorios grandes: Usa du -sh o du -h --max-depth=1 <directorio> para navegar por el árbol de directorios y encontrar lo que consume espacio.
    # Encuentra los directorios más grandes en la partición raíz
    sudo du -h --max-depth=1 / | sort -rh
    
    Los culpables comunes incluyen archivos de registro (/var/log), archivos temporales (/tmp), cachés de paquetes y datos de usuario.
  3. Limpia archivos de registro: Los archivos de registro pueden crecer mucho. A menudo puedes eliminar de forma segura los registros antiguos o configurar la rotación de registros (logrotate) para gestionar su tamaño automáticamente.
    • Eliminando registros antiguos: Ten cuidado y asegúrate de no eliminar registros activos actualmente. Puedes usar find para eliminar archivos más antiguos que un cierto número de días.
      # Eliminar archivos .log más antiguos de 30 días en /var/log/miapp
      sudo find /var/log/miapp -name "*.log" -type f -mtime +30 -delete
      
    • Rotación de registros: Asegúrate de que logrotate esté configurado correctamente para tus servicios. Normalmente se ejecuta diariamente y maneja el archivado y la eliminación de registros antiguos.
  4. Limpia la caché del gestor de paquetes: Los gestores de paquetes a menudo mantienen los archivos de paquetes descargados. Limpiarlos puede liberar espacio significativo.
    • Debian/Ubuntu (apt):
      sudo apt autoremove
      sudo apt clean
      
    • CentOS/RHEL/Fedora (yum/dnf):
      sudo yum autoremove  # o dnf autoremove
      sudo yum clean all   # o dnf clean all
      
  5. Elimina paquetes no utilizados: Desinstala el software que ya no necesitas.
    • Debian/Ubuntu: sudo apt remove <nombre_paquete>
    • CentOS/RHEL/Fedora: sudo yum remove <nombre_paquete> o sudo dnf remove <nombre_paquete>
  6. Verifica directorios temporales: Los archivos en /tmp a menudo son seguros de eliminar, especialmente después de un reinicio, pero ten cuidado si las aplicaciones los están usando activamente.
  7. Vacía la papelera: Si estás usando un entorno de escritorio, verifica las papeleras de los usuarios.
  8. Considera redimensionar particiones: Si el espacio es un problema constante y la limpieza no es suficiente, es posible que debas redimensionar las particiones o agregar más almacenamiento. Esta es una operación más avanzada que podría requerir desmontar particiones o arrancar desde un entorno en vivo.

Ten cuidado con los archivos eliminados que aún están abiertos. df puede mostrar un sistema de archivos lleno incluso después de haber eliminado un archivo de registro grande, porque un proceso en ejecución aún tiene el identificador de archivo abierto.

sudo lsof +L1

Si un archivo eliminado aún se mantiene abierto, reiniciar o recargar el servicio propietario libera el espacio. Hazlo intencionalmente; no reinicies una base de datos o un servicio crítico en medio de un incidente sin comprender el impacto.

Para registros de journal, prefiere la limpieza con journalctl en lugar de eliminar archivos manualmente:

journalctl --disk-usage
sudo journalctl --vacuum-time=14d

Para hosts Docker, verifica los registros de contenedores y las imágenes no utilizadas:

docker system df
docker ps --size

No ejecutes comandos de poda amplios a ciegas en un host de producción. Pueden eliminar imágenes, caché de compilación, contenedores detenidos y redes que alguien esperaba conservar.

Un orden de triaje que funciona bajo presión

Cuando todo está lento, usa un orden fijo para no saltar entre teorías.

  1. Confirma que el host es accesible y no es de solo lectura:

    uptime
    date
    mount | grep ' ro,'
    
  2. Verifica CPU y carga:

    top
    uptime
    
  3. Verifica memoria e intercambio:

    free -h
    vmstat 1 5
    
  4. Verifica espacio en disco e inodos:

    df -h
    df -ih
    
  5. Verifica errores recientes del kernel y del servicio:

    journalctl -p warning..alert --since "30 minutes ago"
    journalctl -k --since "30 minutes ago"
    

Este orden captura las fallas comunes rápidamente: saturación de CPU, tormentas de intercambio, sistemas de archivos llenos, agotamiento de inodos, muertes por OOM y errores de almacenamiento.

Elegir la solución inmediata menos mala

Durante una interrupción, es posible que necesites una solución a corto plazo antes de que la solución permanente esté lista.

Para el agotamiento de CPU, un reinicio de servicio suave puede ser más seguro que kill -9, especialmente para software que escribe estado. Si un trabajo en segundo plano está privando de recursos al tráfico de usuarios, reduce su prioridad:

sudo renice +10 -p <pid>
sudo ionice -c2 -n7 -p <pid>

Para el agotamiento de memoria, reducir la concurrencia suele ser más seguro que agregar intercambio y esperar. Reduce los recuentos de trabajadores web, pausa los trabajos por lotes o deshabilita temporalmente las funciones costosas. El intercambio puede ganar tiempo, pero un intercambio pesado generalmente convierte una falla clara en una falla lenta.

Para el agotamiento del disco, elimina o rota los archivos que entiendas. Buenos candidatos son los registros comprimidos antiguos, los cachés de paquetes, los artefactos de compilación obsoletos y los archivos temporales de trabajos detenidos. Los malos candidatos son los archivos de base de datos, los registros activos, los archivos desconocidos en los directorios de datos de la aplicación y cualquier cosa que no puedas explicar.

Notas de causa raíz para capturar

Después de que el sistema esté estable, escribe qué cambió. Las notas útiles son concretas:

  • El sistema de archivos o recurso exacto que se agotó.
  • El proceso, usuario, servicio, contenedor o trabajo cron involucrado.
  • La salida del comando que lo demostró.
  • La acción inmediata tomada.
  • La solución permanente necesaria.

Esto no es papeleo por sí mismo. El próximo incidente es mucho más fácil cuando sabes que /var se llenó porque los registros de depuración crecieron después de una implementación, o que la presión de la memoria comenzó cuando el recuento de trabajadores se duplicó.

Mejores prácticas para la prevención

  • Monitoreo regular: Implementa un monitoreo regular de CPU, memoria y espacio en disco utilizando herramientas como top, htop, free, df y soluciones de monitoreo dedicadas (por ejemplo, Nagios, Zabbix, Prometheus).
  • Automatiza la rotación de registros: Asegúrate de que logrotate esté configurado correctamente para todos los servicios que generan registros.
  • Ajusta las configuraciones de la aplicación: Optimiza la configuración de la aplicación para que sea más eficiente en el uso de recursos. Por ejemplo, ajusta los procesos de trabajo del servidor web, los grupos de conexiones de la base de datos, etc.
  • Configura alertas: Configura alertas para uso elevado sostenido, crecimiento rápido, muertes por OOM, llenado del sistema de archivos, agotamiento de inodos y reinicios de servicios. Alerta sobre tendencias, no solo límites estrictos.
  • Actualizaciones del sistema: Mantén tu sistema y aplicaciones actualizados, ya que las mejoras de rendimiento y las correcciones de errores a menudo se incluyen en las versiones más nuevas.
  • Límites de recursos: Para sistemas multiusuario o entornos contenerizados, considera establecer límites de recursos (por ejemplo, usando ulimit o cgroups) para evitar que un solo proceso prive de recursos a otros.

La solución de problemas de agotamiento de recursos es principalmente una reducción disciplinada. Encuentra el recurso restringido, identifica al propietario, realiza el cambio de estabilización más pequeño, luego soluciona la razón por la que sucedió. Las herramientas básicas son suficientes para la mayoría de los incidentes si las usas en ese orden y resistes la tentación de eliminar o matar antes de entender lo que estás tocando.