Sobrecompromiso de Memoria en Virtualización: Guía Completa

Introducción

El sobrecompromiso de memoria es una poderosa técnica de virtualización que permite asignar más memoria a las máquinas virtuales de la que está físicamente disponible en el host. Esta capacidad habilita una mayor densidad de VMs, mejor utilización de recursos y ahorros de costos, pero requiere configuración y monitoreo cuidadosos para evitar la degradación del rendimiento.

Esta guía completa explora estrategias de sobrecompromiso de memoria, tecnologías y mejores prácticas para entornos KVM/QEMU. Aprenderá cómo sobrecomprometer memoria de forma segura, implementar ballooning de memoria, configurar KSM (Kernel Same-page Merging), y monitorear la presión de memoria para mantener un rendimiento óptimo mientras maximiza la eficiencia de la infraestructura.

Sin comprender la mecánica del sobrecompromiso de memoria, corre el riesgo de subutilizar hardware costoso siendo demasiado conservador, o causar problemas graves de rendimiento a través del sobrecompromiso excesivo que conduce a swapping y eliminaciones OOM. La clave es encontrar el equilibrio correcto basado en las características de la carga de trabajo y las capacidades de monitoreo.

Al final de esta guía, dominará las técnicas de sobrecompromiso de memoria que permiten ejecutar más VMs por host mientras mantiene garantías de rendimiento, comprenderá las compensaciones involucradas y sabrá cómo solucionar problemas relacionados con la memoria en entornos virtualizados.

Comprender el Sobrecompromiso de Memoria

¿Qué es el Sobrecompromiso de Memoria?

El sobrecompromiso de memoria significa que la suma de memoria asignada a todas las VMs excede la RAM física disponible en el host.

Ejemplo:

RAM Física del Host: 64 GB
VM1: 16 GB
VM2: 16 GB
VM3: 16 GB
VM4: 16 GB
VM5: 16 GB
Total Asignado: 80 GB
Ratio de Sobrecompromiso: 1.25:1 (80/64)

¿Por Qué Sobrecomprometer Memoria?

Beneficios:

  • Mayor densidad de VMs (más VMs por host)
  • Mejor utilización de recursos (las VMs rara vez usan 100% de RAM)
  • Ahorros de costos (se necesitan menos servidores físicos)
  • Flexibilidad en el dimensionamiento de VMs

Riesgos:

  • Degradación del rendimiento si ocurre presión de memoria
  • Swapping a disco (extremadamente lento)
  • Eliminaciones OOM (Out of Memory)
  • Rendimiento impredecible

Tecnologías de Sobrecompromiso de Memoria

1. Memory Ballooning

  • El invitado coopera con el host
  • Devuelve memoria no utilizada al host
  • Requiere driver de balloon en el invitado

2. KSM (Kernel Same-page Merging)

  • Deduplica páginas de memoria idénticas
  • Reduce el uso real de memoria
  • Sobrecarga de CPU para escaneo

3. Transparent Huge Pages (THP)

  • Usa páginas de 2MB en lugar de 4KB
  • Reduce fallos de TLB
  • Mejor rendimiento

4. Memory Swapping

  • Mecanismo de último recurso
  • Extremadamente lento
  • Debe evitarse

5. zswap/zram

  • Caché de RAM comprimida
  • Mejor que swap de disco
  • Sobrecarga de CPU para compresión

Verificar Estado de Memoria del Host

Ver Memoria Física

# Memoria total del sistema
free -h

# Salida:
#               total        used        free      shared  buff/cache   available
# Mem:           62Gi       15Gi       30Gi       1.0Gi       16Gi        45Gi
# Swap:          8.0Gi       0B         8.0Gi

# Información detallada de memoria
cat /proc/meminfo | head -20

# Memoria por nodo NUMA
numactl --hardware

# Memoria libre por nodo
numastat -m

Verificar Uso de Memoria Actual de VMs

# Listar todas las VMs con asignación de memoria
virsh list --all
for vm in $(virsh list --name); do
    echo "VM: $vm"
    virsh dominfo $vm | grep memory
done

# Memoria total asignada
virsh list --name | while read vm; do
    virsh dominfo $vm | grep "Max memory"
done | awk '{sum+=$3} END {print "Total allocated: " sum/1024/1024 " GB"}'

# Uso real de memoria por VM
virsh list --name | while read vm; do
    echo -n "$vm: "
    virsh dommemstat $vm 2>/dev/null | grep actual
done

Calcular Ratio de Sobrecompromiso Actual

#!/bin/bash
# Calcular ratio de sobrecompromiso de memoria

HOST_MEM=$(free -b | awk 'NR==2 {print $2}')
HOST_MEM_GB=$(echo "scale=2; $HOST_MEM/1024/1024/1024" | bc)

TOTAL_ALLOCATED=0
for vm in $(virsh list --all --name); do
    VM_MEM=$(virsh dominfo $vm 2>/dev/null | grep "Max memory" | awk '{print $3}')
    TOTAL_ALLOCATED=$((TOTAL_ALLOCATED + VM_MEM))
done

TOTAL_ALLOCATED_GB=$(echo "scale=2; $TOTAL_ALLOCATED/1024/1024" | bc)
OVERCOMMIT=$(echo "scale=2; $TOTAL_ALLOCATED_GB / $HOST_MEM_GB" | bc)

echo "Host Memory: ${HOST_MEM_GB} GB"
echo "Total Allocated: ${TOTAL_ALLOCATED_GB} GB"
echo "Overcommit Ratio: ${OVERCOMMIT}:1"

if (( $(echo "$OVERCOMMIT > 1.5" | bc -l) )); then
    echo "WARNING: High overcommit ratio!"
fi

Memory Ballooning

Comprender Memory Ballooning

El ballooning de memoria permite al host reclamar memoria de las VMs dinámicamente:

┌─────────────────────────────────────┐
│         Máquina Virtual              │
│                                      │
│  ┌────────────────────────────┐    │
│  │   Driver Balloon (virtio)  │    │
│  │   Infla/Desinfla           │    │
│  └────────────────────────────┘    │
│           │                         │
└───────────┼─────────────────────────┘
            │ Control de Balloon
┌───────────▼─────────────────────────┐
│         Sistema Host                 │
│   Memoria reclamada/asignada        │
└─────────────────────────────────────┘

Configurar Memory Ballooning

Habilitar dispositivo balloon en VM:

# Verificar si la VM tiene dispositivo balloon
virsh dumpxml ubuntu-vm | grep balloon

# Si no está presente, agregarlo
virsh edit ubuntu-vm

# Agregar antes de </devices>:
<memballoon model='virtio'>
  <stats period='10'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</memballoon>

# Reiniciar VM
virsh shutdown ubuntu-vm
virsh start ubuntu-vm

# Verificar dispositivo balloon
virsh dumpxml ubuntu-vm | grep balloon

Dentro de la VM invitada (verificar driver):

# Verificar si el driver balloon está cargado
lsmod | grep virtio_balloon

# Si no está cargado
modprobe virtio_balloon

# Hacer persistente
echo "virtio_balloon" >> /etc/modules

Usar Memory Ballooning

# Ver configuraciones actuales de memoria
virsh dominfo ubuntu-vm | grep memory

# Salida:
# Max memory:     4194304 KiB (4 GB)
# Used memory:    4194304 KiB (4 GB)

# Establecer memoria máxima (requiere reinicio de VM)
virsh setmaxmem ubuntu-vm 4G --config

# Establecer memoria actual (en vivo, usando balloon)
virsh setmem ubuntu-vm 2G --live

# La VM ahora efectivamente tiene 2GB, el host reclamó 2GB

# Ver estadísticas de memoria
virsh dommemstat ubuntu-vm

# Salida:
# actual 2097152  (asignación actual)
# swap_in 0
# swap_out 0
# major_fault 2234
# minor_fault 89563
# unused 1572864  (no usado por invitado)
# available 2097152
# usable 1835008  (invitado puede usar)
# rss 2359296     (RSS del host)

Ballooning Automático

Usar numad para gestión automática de NUMA y memoria:

# Instalar numad
apt install numad  # Debian/Ubuntu
dnf install numad  # RHEL/CentOS

# Iniciar numad
systemctl start numad
systemctl enable numad

# Configurar VM para gestión automática
virsh edit ubuntu-vm

<vcpu placement='auto'>4</vcpu>
<numatune>
  <memory mode='strict' placement='auto'/>
</numatune>

# numad automáticamente:
# - Colocará VM en nodo NUMA óptimo
# - Ajustará memoria basado en uso
# - Balanceará entre nodos NUMA

Kernel Same-page Merging (KSM)

Comprender KSM

KSM escanea la memoria en busca de páginas idénticas y las fusiona, manteniendo solo una copia. Cuando se modifica una página, se copia (COW - Copy-on-Write).

Cómo funciona KSM:

Antes de KSM:
VM1: Página A (contenido: "xxxxx")  ─┐
VM2: Página A (contenido: "xxxxx")  ─┤ Páginas idénticas
VM3: Página A (contenido: "xxxxx")  ─┘
Total: 3 páginas

Después de KSM:
VM1: ─┐
VM2: ─┤──> Página A Compartida (contenido: "xxxxx")
VM3: ─┘
Total: 1 página (2 páginas liberadas)

Habilitar KSM

# Verificar estado de KSM
cat /sys/kernel/mm/ksm/run
# 0 = deshabilitado, 1 = habilitado

# Habilitar KSM
echo 1 | sudo tee /sys/kernel/mm/ksm/run

# Configurar parámetros de KSM
# Páginas a escanear por ejecución
echo 100 | sudo tee /sys/kernel/mm/ksm/pages_to_scan

# Espera entre escaneos (milisegundos)
echo 20 | sudo tee /sys/kernel/mm/ksm/sleep_millisecs

# Hacer persistente
cat > /etc/tmpfiles.d/ksm.conf << 'EOF'
w /sys/kernel/mm/ksm/run - - - - 1
w /sys/kernel/mm/ksm/pages_to_scan - - - - 100
w /sys/kernel/mm/ksm/sleep_millisecs - - - - 20
EOF

# O crear servicio systemd
cat > /etc/systemd/system/ksm.service << 'EOF'
[Unit]
Description=Enable Kernel Same-page Merging

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo 1 > /sys/kernel/mm/ksm/run'
ExecStart=/bin/bash -c 'echo 100 > /sys/kernel/mm/ksm/pages_to_scan'
ExecStart=/bin/bash -c 'echo 20 > /sys/kernel/mm/ksm/sleep_millisecs'

[Install]
WantedBy=multi-user.target
EOF

systemctl enable ksm
systemctl start ksm

Monitorear Eficiencia de KSM

# Estadísticas de KSM
cat /sys/kernel/mm/ksm/pages_sharing
cat /sys/kernel/mm/ksm/pages_shared
cat /sys/kernel/mm/ksm/pages_unshared
cat /sys/kernel/mm/ksm/pages_volatile

# Calcular memoria ahorrada
SHARING=$(cat /sys/kernel/mm/ksm/pages_sharing)
SHARED=$(cat /sys/kernel/mm/ksm/pages_shared)
SAVED=$((SHARING - SHARED))
SAVED_MB=$((SAVED * 4 / 1024))
echo "Memory saved by KSM: ${SAVED_MB} MB"

# Información detallada de KSM
grep -H '' /sys/kernel/mm/ksm/*

# Monitorear KSM a lo largo del tiempo
watch -n 5 'echo "Pages sharing: $(cat /sys/kernel/mm/ksm/pages_sharing)"; \
             echo "Pages shared: $(cat /sys/kernel/mm/ksm/pages_shared)"; \
             echo "Saved: $(( ($(cat /sys/kernel/mm/ksm/pages_sharing) - \
                                $(cat /sys/kernel/mm/ksm/pages_shared)) * 4 / 1024 )) MB"'

Configurar VMs para KSM

# Habilitar fusión de memoria en VM
virsh edit ubuntu-vm

<memoryBacking>
  <nosharepages/>  <!-- Deshabilitar KSM para esta VM (si es necesario) -->
</memoryBacking>

# O habilitar explícitamente (comportamiento por defecto)
# Simplemente elimine <nosharepages/> o no lo incluya

# Para máximo beneficio de KSM, las VMs deberían:
# - Ejecutar OS similar (más páginas idénticas)
# - Usar aplicaciones similares
# - Tener configuraciones similares

Ajustar Rendimiento de KSM

# Escaneo agresivo (más CPU, mejor fusión)
echo 500 | sudo tee /sys/kernel/mm/ksm/pages_to_scan
echo 10 | sudo tee /sys/kernel/mm/ksm/sleep_millisecs

# Escaneo conservador (menos CPU, menos fusión)
echo 50 | sudo tee /sys/kernel/mm/ksm/pages_to_scan
echo 100 | sudo tee /sys/kernel/mm/ksm/sleep_millisecs

# Balanceado (recomendado)
echo 100 | sudo tee /sys/kernel/mm/ksm/pages_to_scan
echo 20 | sudo tee /sys/kernel/mm/ksm/sleep_millisecs

# Monitorear impacto en CPU
top -d 1
# Buscar proceso [ksmd]

Transparent Huge Pages (THP)

Comprender THP

Páginas normales: 4KB Páginas grandes: 2MB (512x más grandes)

Beneficios:

  • Fallos de TLB reducidos
  • Menor sobrecarga de tabla de páginas
  • Mejor rendimiento de memoria

Habilitar THP para VMs

# Verificar estado de THP
cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never

# Habilitar THP
echo always | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

# Configurar defrag (compactación)
echo defer | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
# Opciones: always defer defer+madvise madvise never

# Hacer persistente
cat >> /etc/rc.local << 'EOF'
echo always > /sys/kernel/mm/transparent_hugepage/enabled
echo defer > /sys/kernel/mm/transparent_hugepage/defrag
EOF

chmod +x /etc/rc.local

Configurar VMs para THP

# Las VMs automáticamente usan THP si está habilitado en el host
# Verificar dentro del invitado
cat /proc/meminfo | grep Huge

# AnonHugePages: 2097152 kB (2GB en páginas grandes)

# Verificar asignación de THP
cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed

# Monitorear efectividad de THP
watch -n 1 'cat /proc/meminfo | grep Huge'

THP vs Páginas Grandes Regulares

# THP (Transparent Huge Pages)
# - Automático
# - Sin preasignación
# - Dinámico
# - Puede causar picos de latencia (compactación)

# Páginas Grandes Regulares
# - Configuración manual
# - Preasignadas
# - Disponibilidad garantizada
# - Sin sobrecarga de compactación

# Configurar páginas grandes regulares para VM
virsh edit ubuntu-vm

<memoryBacking>
  <hugepages>
    <page size='2048' unit='KiB'/>
  </hugepages>
  <locked/>
</memoryBacking>

# Preasignar páginas grandes en el host
echo 4096 > /proc/sys/vm/nr_hugepages
# 4096 páginas * 2MB = 8GB

Memory Swapping y zswap

Comprender VM Swapping

Swapping debe evitarse:

  • Extremadamente lento (disco vs RAM)
  • 100-1000x más lento que RAM
  • Causa degradación severa del rendimiento
  • Indica presión de memoria

Configurar Swap para el Host

# Verificar swap actual
free -h
swapon --show

# Crear archivo de swap si es necesario
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Hacer persistente
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Configurar swappiness (qué tan agresivamente hacer swap)
# Por defecto: 60, Rango: 0-100
# Menor = menos swapping

sudo sysctl vm.swappiness=10
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf

Habilitar zswap (Caché de RAM Comprimida)

# zswap comprime páginas antes de escribir a swap
# Mucho más rápido que swap de disco

# Habilitar zswap
echo 1 | sudo tee /sys/module/zswap/parameters/enabled

# Configurar zswap
echo 20 | sudo tee /sys/module/zswap/parameters/max_pool_percent
echo lz4 | sudo tee /sys/module/zswap/parameters/compressor
echo z3fold | sudo tee /sys/module/zswap/parameters/zpool

# Hacer persistente (agregar a parámetros del kernel)
sudo vim /etc/default/grub
GRUB_CMDLINE_LINUX="zswap.enabled=1 zswap.compressor=lz4 zswap.max_pool_percent=20"

sudo update-grub
sudo reboot

# Verificar estadísticas de zswap
cat /sys/kernel/debug/zswap/*

Alternativa: zram (Dispositivo de Bloque Comprimido)

# zram crea dispositivo de bloque comprimido en RAM
# Mejor que zswap para algunas cargas de trabajo

# Instalar herramientas zram
apt install zram-config  # Debian/Ubuntu
dnf install zram  # RHEL/CentOS

# Configuración manual
modprobe zram
echo lz4 > /sys/block/zram0/comp_algorithm
echo 4G > /sys/block/zram0/disksize
mkswap /dev/zram0
swapon /dev/zram0 -p 10  # prioridad 10

# Verificar
zramctl
swapon --show

# Monitorear ratio de compresión
cat /sys/block/zram0/mm_stat

Monitorear Uso de Memoria

Monitoreo de Memoria en Tiempo Real

# Monitoreo de memoria del sistema
free -h -s 1  # Actualizar cada segundo

# Uso de memoria por VM
virsh list --name | while read vm; do
    echo "=== $vm ==="
    virsh dommemstat $vm 2>/dev/null
done

# Observar presión de memoria
watch -n 1 'free -h; echo ""; virsh list --name | while read vm; do \
    echo "$vm:"; virsh dommemstat $vm 2>/dev/null | grep -E "actual|rss|usable"; done'

# Monitorear con virt-top
virt-top
# Presionar 2 para vista de memoria

Monitoreo Avanzado de Memoria

#!/bin/bash
# memory-monitor.sh - Monitoreo completo de memoria

LOG="/var/log/vm-memory.log"

while true; do
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')

    # Memoria del host
    host_total=$(free -b | awk 'NR==2 {print $2}')
    host_used=$(free -b | awk 'NR==2 {print $3}')
    host_free=$(free -b | awk 'NR==2 {print $4}')
    host_available=$(free -b | awk 'NR==2 {print $7}')

    # Estadísticas de KSM
    ksm_sharing=$(cat /sys/kernel/mm/ksm/pages_sharing 2>/dev/null || echo 0)
    ksm_shared=$(cat /sys/kernel/mm/ksm/pages_shared 2>/dev/null || echo 0)
    ksm_saved=$(( (ksm_sharing - ksm_shared) * 4096 ))

    echo "$timestamp | Host: Used=$host_used Free=$host_free Available=$host_available | KSM_Saved=$ksm_saved" >> $LOG

    # Estadísticas por VM
    for vm in $(virsh list --name); do
        vm_mem=$(virsh dommemstat $vm 2>/dev/null | grep "actual" | awk '{print $2}')
        vm_rss=$(virsh dommemstat $vm 2>/dev/null | grep "rss" | awk '{print $2}')
        vm_usable=$(virsh dommemstat $vm 2>/dev/null | grep "usable" | awk '{print $2}')

        echo "$timestamp | VM: $vm | Allocated=$vm_mem RSS=$vm_rss Usable=$vm_usable" >> $LOG
    done

    sleep 60
done

Configurar Alertas

#!/bin/bash
# memory-alert.sh - Alertar sobre presión de memoria

THRESHOLD=90  # Alertar si uso de memoria > 90%
EMAIL="[email protected]"

check_memory() {
    used=$(free | awk 'NR==2 {print $3}')
    total=$(free | awk 'NR==2 {print $2}')
    percent=$(( used * 100 / total ))

    if [ $percent -gt $THRESHOLD ]; then
        message="WARNING: Memory usage at ${percent}%"
        echo "$message" | mail -s "Memory Alert" $EMAIL
        logger "$message"
    fi
}

# Ejecutar cada 5 minutos
while true; do
    check_memory
    sleep 300
done

Estrategias de Sobrecompromiso Seguro

Sobrecompromiso Conservador (1.2:1)

# Seguro para producción
# Host de 64GB → 76GB asignados
# Bajo riesgo, algo de ganancia de eficiencia

# Ejemplo de configuración:
# VM1: 16GB
# VM2: 16GB
# VM3: 16GB
# VM4: 16GB
# VM5: 12GB
# Total: 76GB en host de 64GB

Sobrecompromiso Moderado (1.5:1)

# Aceptable para la mayoría de cargas de trabajo
# Host de 64GB → 96GB asignados
# Requiere monitoreo, KSM, ballooning

# Habilitar tecnologías:
# - KSM (esperar 10-20% de ahorros)
# - Memory ballooning
# - THP
# - Alertas de monitoreo

# Ejemplo:
# 6 VMs * 16GB = 96GB en host de 64GB

Sobrecompromiso Agresivo (2:1 o mayor)

# Alto riesgo, requiere gestión cuidadosa
# Host de 64GB → 128GB+ asignados
# Solo para escenarios específicos:
#   - Entornos dev/test
#   - VMs con bajo uso de memoria
#   - Cargas de trabajo uniformes
#   - Monitoreo activo

# Requerido:
# - KSM habilitado y ajustado
# - Memory ballooning activo
# - Monitoreo 24/7
# - Alertas configuradas
# - Procedimientos documentados para presión de memoria

Mejores Prácticas

1. Conocer Sus Cargas de Trabajo:

# Perfilar uso de memoria de VMs a lo largo del tiempo
for vm in $(virsh list --name); do
    echo "$vm memory usage:"
    virsh dommemstat $vm | grep -E "actual|rss|usable"
done

# Muchas VMs usan < 50% de memoria asignada
# Aquí es donde el sobrecompromiso ayuda

2. Comenzar Conservador:

# Comenzar con sobrecompromiso 1.2:1
# Monitorear por 1-2 semanas
# Aumentar gradualmente si es seguro
# Nunca exceder 2:1 para producción

3. Habilitar Todas las Tecnologías:

# KSM
echo 1 > /sys/kernel/mm/ksm/run

# THP
echo always > /sys/kernel/mm/transparent_hugepage/enabled

# Ballooning (en configuraciones de VM)
virsh edit vm-name  # Agregar dispositivo balloon

# zswap
echo 1 > /sys/module/zswap/parameters/enabled

4. Monitorear Continuamente:

# Configurar monitoreo automatizado
# Alertar sobre:
#   - Uso de memoria > 85%
#   - Uso de swap > 10%
#   - Eliminaciones OOM
#   - Fallos mayores altos

5. Planificar para Crecimiento:

# Dejar margen para:
#   - Picos de memoria
#   - Nuevas VMs
#   - Actualizaciones/mantenimiento
#   - Escenarios de emergencia

# Regla: Nunca asignar > 90% incluso con sobrecompromiso

Solucionar Problemas de Memoria

Identificar Presión de Memoria

# Verificar indicadores de presión de memoria
free -h  # Baja memoria disponible

# Verificar uso de swap
swapon --show
vmstat 1 10  # Observar columnas si/so (swap in/out)

# Eventos OOM
dmesg | grep -i oom
journalctl | grep -i "out of memory"

# Fallos mayores por VM (indica swapping)
virsh dommemstat ubuntu-vm | grep major_fault

# Presión del sistema
cat /proc/pressure/memory

Reducir Presión de Memoria

Acciones inmediatas:

# 1. Aumentar deflación de balloon (dar menos memoria a VMs)
for vm in $(virsh list --name); do
    current=$(virsh dominfo $vm | grep "Used memory" | awk '{print $3}')
    reduced=$(( current * 80 / 100 ))  # Reducir a 80%
    virsh setmem $vm ${reduced}K --live
done

# 2. Migrar VMs a otros hosts
virsh migrate --live vm-name qemu+ssh://other-host/system

# 3. Apagar VMs no críticas
virsh shutdown dev-vm

# 4. Liberar cachés (alivio temporal)
sync; echo 3 > /proc/sys/vm/drop_caches

Soluciones a largo plazo:

# 1. Agregar RAM física

# 2. Reducir ratio de sobrecompromiso
# Migrar VMs a hosts adicionales

# 3. Optimizar asignación de memoria de VMs
# Dimensionar correctamente VMs basado en uso real

# 4. Ajustar KSM más agresivamente
echo 500 > /sys/kernel/mm/ksm/pages_to_scan
echo 10 > /sys/kernel/mm/ksm/sleep_millisecs

# 5. Habilitar páginas grandes
echo 4096 > /proc/sys/vm/nr_hugepages

Manejar Situaciones OOM

# Verificar registros del OOM killer
dmesg | grep -i "killed process"
journalctl -k | grep -i oom

# Identificar víctimas de OOM
grep -i "killed process" /var/log/kern.log

# Configurar prioridades OOM (por VM)
# Puntuación menor = menos probable de ser eliminada

ps aux | grep qemu | grep vm-name
# Obtener PID

echo -17 > /proc/<PID>/oom_score_adj
# Rango: -1000 (nunca eliminar) a 1000 (eliminar primero)

# Hacer persistente vía XML de VM
virsh edit ubuntu-vm

# Esto requiere scripts de inicio personalizados
# Crear /etc/libvirt/hooks/qemu:
#!/bin/bash
if [ "$1" = "ubuntu-vm" ] && [ "$2" = "started" ]; then
    pid=$(pgrep -f "qemu.*ubuntu-vm")
    echo -500 > /proc/$pid/oom_score_adj
fi

Degradación del Rendimiento

# Síntomas de problemas de sobrecompromiso de memoria:
# - Rendimiento lento de VM
# - Alta espera de I/O
# - Tiempos de espera de aplicación
# - Tiempos de respuesta inconsistentes

# Diagnóstico:
# 1. Verificar uso de swap
free -h
vmstat 1 10

# 2. Verificar fallos mayores
virsh dommemstat vm-name | grep major_fault
# Alto y creciente = swapping

# 3. Verificar impacto de KSM
top | grep ksmd
# Alto uso de CPU puede indicar KSM agresivo

# 4. Verificar bloqueo por presión de memoria
cat /proc/pressure/memory

# Soluciones:
# - Reducir sobrecompromiso
# - Agregar RAM
# - Optimizar aplicaciones
# - Migrar VMs

Scripts de Monitoreo

Panel de Monitoreo Completo

#!/bin/bash
# vm-memory-dashboard.sh

while true; do
    clear
    echo "================================"
    echo "   Panel de Memoria de VMs"
    echo "   $(date)"
    echo "================================"
    echo ""

    # Memoria del host
    echo "MEMORIA DEL HOST:"
    free -h | grep -E "Mem|Swap"
    echo ""

    # Estadísticas de KSM
    if [ -f /sys/kernel/mm/ksm/pages_sharing ]; then
        sharing=$(cat /sys/kernel/mm/ksm/pages_sharing)
        shared=$(cat /sys/kernel/mm/ksm/pages_shared)
        saved=$(( (sharing - shared) * 4 / 1024 ))
        echo "KSM: Ahorrado ${saved} MB"
        echo ""
    fi

    # Ratio de sobrecompromiso
    host_mem=$(free -b | awk 'NR==2 {print $2}')
    total_alloc=0
    echo "VMs:"
    echo "Nombre                Asignado     RSS         Uso%"
    echo "--------------------------------------------------------"

    for vm in $(virsh list --name); do
        alloc=$(virsh dominfo $vm 2>/dev/null | grep "Max memory" | awk '{print $3}')
        rss=$(virsh dommemstat $vm 2>/dev/null | grep "rss" | awk '{print $2}')

        if [ -n "$alloc" ] && [ -n "$rss" ]; then
            alloc_mb=$(( alloc / 1024 ))
            rss_mb=$(( rss / 1024 ))
            usage=$(( rss * 100 / alloc ))
            printf "%-20s %7d MB   %7d MB   %3d%%\n" "$vm" "$alloc_mb" "$rss_mb" "$usage"
            total_alloc=$(( total_alloc + alloc ))
        fi
    done

    echo ""
    overcommit=$(echo "scale=2; $total_alloc / $host_mem" | bc)
    echo "Total Asignado: $(( total_alloc / 1024 / 1024 )) GB"
    echo "Ratio de Sobrecompromiso: ${overcommit}:1"

    sleep 5
done

Conclusión

El sobrecompromiso de memoria es una técnica poderosa para maximizar la eficiencia de la infraestructura de virtualización, pero requiere planificación, implementación y monitoreo cuidadosos. Al aprovechar tecnologías como memory ballooning, KSM y transparent huge pages, puede ejecutar de forma segura más VMs por host mientras mantiene un rendimiento aceptable.

Conclusiones clave:

  • Comenzar con ratios conservadores de sobrecompromiso (1.2:1)
  • Habilitar todas las tecnologías de optimización de memoria (KSM, THP, ballooning)
  • Monitorear continuamente para indicadores de presión de memoria
  • Comprender las características de su carga de trabajo
  • Planificar para crecimiento y uso pico
  • Nunca exceder 2:1 para entornos de producción
  • Tener procedimientos listos para situaciones de presión de memoria

Las estrategias exitosas de sobrecompromiso de memoria equilibran eficiencia con confiabilidad, usando monitoreo y automatización para asegurar que las restricciones de recursos nunca impacten cargas de trabajo de producción. Con configuración adecuada y vigilancia, el sobrecompromiso de memoria puede reducir significativamente los costos de infraestructura mientras mantiene el rendimiento y disponibilidad que sus aplicaciones requieren.

Recuerde que el sobrecompromiso es una compensación: mayor densidad de VMs versus mayor complejidad y requisitos de monitoreo. La estrategia óptima depende de sus cargas de trabajo específicas, tolerancia al riesgo y capacidades operacionales. Cuando se hace correctamente, el sobrecompromiso de memoria es una piedra angular de infraestructura de virtualización eficiente y rentable.