Gestión de Memoria y Optimización de Swap

La gestión de memoria impacta fundamentalmente el rendimiento del sistema, con políticas de memoria ineficientes causando thrashing, picos de latencia y rendimiento reducido. Linux proporciona controles sofisticados de gestión de memoria incluyendo ajuste de swappiness, políticas de caché de página y configuración de swap. Esta guía cubre optimización de utilización de memoria para patrones de carga de trabajo específicos y evitar problemas comunes de gestión de memoria.

Tabla de Contenidos

  1. Fundamentos de Gestión de Memoria
  2. Configuración de Swappiness
  3. Ajuste de Caché de Página
  4. Configuración del Asesino de OOM
  5. Gestión de Archivo de Swap
  6. zswap y Swap Comprimido
  7. Páginas Enormes
  8. Monitoreo de Memoria
  9. Conclusión

Fundamentos de Gestión de Memoria

Jerarquía de Memoria

# Jerarquía de asignación de memoria de Linux:
# 1. Caché de página (archivos accedidos recientemente)
# 2. Memoria de aplicación (heap, stack)
# 3. Swap (desbordamiento basado en disco)

# Ver uso actual de memoria
free -h

# Desglose detallado de memoria
cat /proc/meminfo | head -20

# Memoria por proceso
ps aux | head -5
# RSS: Resident Set Size (RAM actual usado)
# VSZ: Tamaño de memoria virtual (asignado pero no todo en RAM)

Presión de Memoria

# Verificar métricas de presión de memoria
cat /proc/pressure/memory

# La salida muestra:
# some: Tiempo que tareas esperaron por memoria
# full: Tiempo que el sistema no podría asignar memoria

# Monitorear presión de memoria en tiempo real
watch -n 1 'cat /proc/pressure/memory'

Configuración de Swappiness

Entender Swappiness

# Valor actual de swappiness (0-100)
cat /proc/sys/vm/swappiness

# Valores más altos (por defecto 60):
# - Uso de swap más agresivo
# - Mejor para escritorio (respuesta interactiva)
# - Problemático para servidores (picos de latencia)

# Valores más bajos (0-30):
# - Mantener datos en RAM
# - Mejor para servidores y bases de datos
# - Puede golpear OOM más rápido

# Cero (no recomendado en kernels actuales):
# - Históricamente deshabilitaba swap
# - Causa muertes por OOM en lugar de degradación elegante

Ajuste de Swappiness

# Verificar swappiness actual
sysctl vm.swappiness

# Ajustar swappiness para cargas de trabajo de servidor
sudo sysctl -w vm.swappiness=10

# Más agresivo para bases de datos que necesitan RAM
sudo sysctl -w vm.swappiness=5

# Caso extremo (solo emergencia)
sudo sysctl -w vm.swappiness=1

# Verificar cambios
sysctl vm.swappiness

# Hacer persistente
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.d/99-memory-tuning.conf
sudo sysctl -p /etc/sysctl.d/99-memory-tuning.conf

Swappiness en la Práctica

# Monitorear uso de swap con diferentes configuraciones de swappiness
watch -n 1 'free -h && echo "---" && cat /proc/sys/vm/swappiness'

# Identificar presión de swap
grep Swap /proc/meminfo

# Verificar actividad de E/S de swap
vmstat 1

# Observar fallos de página aumentados
grep pgfault /proc/stat

# Detectar thrashing de swap
watch -n 1 'grep -E "pswpin|pswpout" /proc/vmstat'

Ajuste de Caché de Página

Presión de Caché

# Ver presión actual de caché
cat /proc/sys/vm/cache_pressure

# Por defecto 100: Comportamiento de caché normal
# 0-50: Aumentar retención de caché
# 100: Comportamiento equilibrado
# 200+: Descartar caché agresivamente

# Aumentar retención de caché para cargas de trabajo que se benefician del almacenamiento en caché
sudo sysctl -w vm.cache_pressure=50

# Descartar caché agresivamente para cargas de trabajo de working-set
sudo sysctl -w vm.cache_pressure=200

# Ajuste específico de aplicación
# Base de datos con gran pool de búfer: presión de caché más baja
# Streaming de alto rendimiento: presión de caché más alta

Comportamiento de Reclamación de Memoria

# Comportamiento de descarga de caché de archivo
cat /proc/sys/vm/dirty_ratio      # Porcentaje de memoria para vaciar
cat /proc/sys/vm/dirty_background_ratio

# Aumentar relación dirty para escrituras de alto throughput
sudo sysctl -w vm.dirty_ratio=20      # Por defecto 20%
sudo sysctl -w vm.dirty_background_ratio=5  # Por defecto 10%

# Reducir para sensibilidad en tiempo real
sudo sysctl -w vm.dirty_ratio=5
sudo sysctl -w vm.dirty_background_ratio=2

# Timeout para páginas dirty (centisegundos)
cat /proc/sys/vm/dirty_expire_centisecs  # Por defecto 3000 = 30 segundos

Configuración del Asesino de OOM

Entender el Asesino de OOM

# El asesino de OOM se activa cuando memoria completamente agotada
# Selecciona y mata el proceso para liberar memoria

# Monitorear eventos de OOM
dmesg | grep -i "out of memory"

# Verificar registros del sistema
journalctl -u kernel --grep="OOM"

# Estado actual del asesino de OOM
sysctl vm.oom_dump_tasks

# Pánico en OOM (reinicio del sistema en lugar de matar)
sudo sysctl -w vm.panic_on_oom=1

Ajuste de Puntuación de OOM de Proceso

# Ver puntuación de OOM de proceso
cat /proc/*/oom_score | sort -n | tail -5

# Puntuación de OOM más baja = menos probable ser matado
# Puede ser negativa (0-15)

# Ajustar para proceso específico
echo -500 > /proc/$(pgrep mysql)/oom_score_adj

# Deshabilitar asesino de OOM para proceso crítico
echo -1000 > /proc/$(pgrep critical_app)/oom_score_adj

# Hacer proceso más fácil de matar (limpieza de emergencia)
echo 500 > /proc/$(pgrep cleanup_worker)/oom_score_adj

# Puntuación de OOM persistente vía systemd
# Agregar a archivo de servicio:
# OOMScoreAdjust=-500

Gestión de Archivo de Swap

Crear Archivos de Swap

# Verificar swap actual
swapon --show

# Crear archivo de swap
sudo dd if=/dev/zero of=/swapfile bs=1G count=4

# Asegurar archivo de swap (solo root)
sudo chmod 600 /swapfile

# Formatear como swap
sudo mkswap /swapfile

# Habilitar swap
sudo swapon /swapfile

# Verificar
swapon --show

# Habilitar al arranque (agregar a /etc/fstab)
echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab

# Verificar sintaxis de fstab
sudo mount -a

Prioridad de Swap

# Verificar prioridades de swap
swapon --show

# Agregar segundo swap con prioridad
sudo swapon --priority 10 /swapfile2

# O vía fstab (la prioridad es opción)
# /swapfile none swap sw,priority=10 0 0

# Prioridad más alta: usado primero
# Prioridad más baja: usado como desbordamiento

# Monitorear selección de swap
watch -n 1 'grep -E "pswpin|pswpout" /proc/vmstat'

zswap y Swap Comprimido

Configuración de zswap

# Verificar disponibilidad de zswap
grep -i zswap /boot/config-$(uname -r)

# Cargar módulo zswap
sudo modprobe zswap

# Configurar parámetros de zswap
sudo sysctl -w vm.zswap.enabled=1

# Tamaño de pool de memoria zswap (por defecto 20% de RAM)
cat /sys/module/zswap/parameters/max_pool_percent
echo 30 | sudo tee /sys/module/zswap/parameters/max_pool_percent

# Algoritmo de compresión (por defecto lzo)
cat /sys/module/zswap/parameters/compressor
# Opciones: lzo, lz4, zstd (si se compila)

# Pool de compresión (por defecto z3fold)
cat /sys/module/zswap/parameters/zpool

zswap vs Swap Físico

# Ventajas de zswap:
# - Memoria comprimida en RAM (compresión típica de 2-4x)
# - Más rápido que swap de disco
# - Reduce E/S de swap

# Desventajas:
# - Usa CPU para compresión
# - Reduce memoria de aplicación disponible
# - No adecuado para intercambiar cantidades masivas

# Enfoque híbrido:
# - Habilitar zswap para desbordamiento de ráfaga
# - Tener swap de disco para desbordamiento sostenido
# - Equilibra latencia y capacidad

Páginas Enormes

Habilitar Páginas Enormes

# Verificar configuración de página enorme
cat /proc/meminfo | grep -i huge

# Verificar tamaños de página enormes disponibles
grep . /sys/kernel/mm/hugepages/*/nr_hugepages

# Asignar páginas enormes de 2MB
echo 512 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# Asignar páginas enormes de 1GB
echo 4 | sudo tee /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages

# Configuración persistente vía sysctl
echo "vm.nr_hugepages=512" | sudo tee -a /etc/sysctl.d/hugepages.conf
sudo sysctl -p /etc/sysctl.d/hugepages.conf

Soporte de Páginas Enormes de Aplicación

# Base de datos (MongoDB/Redis) con páginas enormes
# Usualmente requiere configuración explícita:

# Configuración de Redis
# En redis.conf:
# config set maxmemory-policy noeviction

# Iniciar con páginas enormes
sudo numactl --cpunodebind=0 --membind=0 redis-server --maxmemory 16gb

# Monitorear uso de página enorme
watch -n 1 'cat /proc/meminfo | grep Huge'

Monitoreo de Memoria

Monitoreo de Memoria en Tiempo Real

# Uso general de memoria
free -h

# Desglose detallado de memoria
cat /proc/meminfo

# Información de presión de stall de memoria
watch -n 1 'cat /proc/pressure/memory'

# Memoria por proceso
ps aux --sort=-%mem | head -10

# Estadísticas de memoria virtual
vmstat 1

# Fallos de página e intercambio
watch -n 1 'grep -E "pgfault|pswpin|pswpout" /proc/vmstat'

Perfilado de Memoria

# Monitorear memoria de proceso específico
watch -n 1 'ps aux | grep mysql'

# Mapa de memoria detallado del proceso
cat /proc/$(pgrep mysql)/maps | head -20

# Uso de memoria por biblioteca
cat /proc/$(pgrep mysql)/smaps | grep -i "Size"

# Estadísticas de caché
cat /proc/meminfo | grep -E "Buffers|Cached"

# Porcentaje de memoria libre
free | awk '/Mem/ {printf "%.2f%% free\n", $NF/$2 * 100}'

Conclusión

La gestión de memoria de Linux impacta directamente la estabilidad del sistema, latencia y throughput. Al ajustar swappiness, gestionar swap apropiadamente, configurar páginas enormes y entender el comportamiento de OOM, los equipos de infraestructura previenen degradación de rendimiento y aseguran comportamiento del sistema predecible. Diferentes cargas de trabajo requieren diferentes políticas de memoria; la optimización requiere entender requisitos de aplicación específicos y monitorear comportamiento bajo carga realista. Combinado con ajuste de E/S de almacenamiento y optimización de CPU, la optimización de gestión de memoria crea la base para infraestructura de alto rendimiento.