Problema
En entornos Proxmox con ZFS como pool de almacenamiento, es frecuente observar picos de consumo de RAM que superan la capacidad física disponible. Cuando el sistema simultáneamente utiliza swap (ya sea una partición o un volumen ZFS), la presión de memoria puede desencadenar cuelgues del host, reinicios inesperados o mensajes de error como “Purging GPU Memory”. El patrón típico es:
- Un workload intensivo (por ejemplo, una copia de seguridad nocturna) dispara la expansión del ARC de ZFS.
- El ARC crece sin límite, ocupando la mayor parte de la RAM.
- El kernel empieza a paginar hacia swap, que a su vez consume I/O del mismo pool ZFS.
- La combinación de alta latencia de swap y falta de RAM libre lleva al host a un estado inestable.
Este comportamiento no es exclusivo de una configuración concreta; cualquier nodo Proxmox que use ZFS sin restricciones de ARC y que tenga swap habilitado puede experimentar los mismos síntomas.
Causa
1. Ausencia de límites en ZFS ARC
ZFS gestiona su caché de lectura (ARC) de forma dinámica, ajustando su tamaño según la disponibilidad de memoria. En instalaciones modernas, el valor por defecto suele ser un porcentaje amplio del total de RAM (hasta 80 %). Cuando el ARC no está limitado, cualquier carga de I/O intensiva (por ejemplo, zfs send/receive o rsync sobre ZFS) puede inflar el ARC rápidamente.
2. Swap en el mismo pool ZFS
Crear una partición de swap o un volumen ZFS (swapfile o zvol) dentro del mismo pool que aloja los datasets críticos introduce una dependencia cíclica: el ARC compite por la misma memoria que el swap necesita para almacenar páginas evictadas. Además, el acceso a swap en ZFS implica escrituras en el mismo pool, aumentando la carga de I/O y reduciendo el rendimiento del propio ARC.
3. Parámetro vm.swappiness alto
El kernel decide cuánto usar swap mediante vm.swappiness. Un valor por defecto (60) favorece el uso de swap incluso cuando todavía hay RAM libre, lo que acelera la presión de memoria en entornos con ARC sin límites.
Solución
La estrategia se basa en tres pilares: limitar el ARC, eliminar o reubicar swap y ajustar swappiness. Cada pilar es independiente, pero su combinación brinda la mayor estabilidad.
A. Definir límites de ARC
-
Calcular valores razonables
Un buen punto de partida es reservar entre el 10 % y el 20 % de la RAM para el sistema y los contenedores, y usar el resto como máximo para ARC. En un host de 64 GB, unzfs_arc_maxde 8 GB y unzfs_arc_minde 2 GB suele ser suficiente. -
Persistir la configuración
Añadir las opciones al archivo de módulos garantiza que los valores se apliquen en cada arranque.
B. Reubicar o eliminar swap
- Preferir swap en un disco distinto (por ejemplo, una unidad SSD dedicada) o, si la carga de memoria es controlada, eliminarlo por completo.
- Si se necesita swap por seguridad, crear un archivo de swap fuera del pool ZFS evita la sobrecarga de I/O dentro del mismo pool.
C. Ajustar swappiness
Reducir vm.swappiness a 10 o 5 indica al kernel que prefiera mantener las páginas en RAM antes de recurrir a swap, reduciendo la frecuencia de paginación bajo carga.
Cuándo aplicar esta solución
Se recomienda cuando se cumplan al menos uno de los siguientes criterios:
- Picos de uso de RAM que superan el 70 % durante tareas programadas (backups, replicación, snapshots).
- Presencia de swap dentro del pool ZFS o en la misma unidad de arranque.
- Mensajes de kernel relacionados con “out of memory” o “OOM killer” en los logs.
- Inestabilidad del host que ocurre en horarios de alta actividad de I/O.
No es necesario si:
- El host tiene más RAM de la que cualquier carga prevista pueda consumir (p.ej., 256 GB con workloads que nunca superan 32 GB).
- Se usa un pool ZFS exclusivamente para datos y el swap está en un disco independiente.
- El ARC está ya limitado mediante
zfs_arc_maxyzfs_arc_miny se ha verificado que no alcanza esos límites.
Código
# 1. Limitar ARC (crear/editar /etc/modprobe.d/zfs.conf)
cat <<EOF > /etc/modprobe.d/zfs.conf
options zfs zfs_arc_min=2147483648 # 2 GB
options zfs zfs_arc_max=8589934592 # 8 GB
EOF
# 2. Regenerar initramfs y actualizar bootloader de Proxmox
update-initramfs -u -k all
proxmox-boot-tool refresh
# 3. Desactivar swap en ZFS (ejemplo: zvol llamado rpool/swap)
zfs destroy -r rpool/swap
swapoff /dev/zvol/rpool/swap
# 4. Crear swap externo (ejemplo: archivo en /mnt/ssd)
dd if=/dev/zero of=/mnt/ssd/swapfile bs=1M count=8192
chmod 600 /mnt/ssd/swapfile
mkswap /mnt/ssd/swapfile
swapon /mnt/ssd/swapfile
echo '/mnt/ssd/swapfile none swap sw 0 0' >> /etc/fstab
# 5. Reducir swappiness
sysctl -w vm.swappiness=10
echo 'vm.swappiness=10' >> /etc/sysctl.d/99-swappiness.conf
Verificación
-
Comprobar límites de ARC
cat /sys/module/zfs/parameters/zfs_arc_max cat /sys/module/zfs/parameters/zfs_arc_minLos valores deben coincidir con los configurados (8 GB y 2 GB).
-
Validar que el swap externo está activo
swapon --showLa salida debe listar el archivo creado en
/mnt/ssd/swapfile. -
Monitorizar uso de RAM durante una carga típica
Ejecutarhtopofree -hmientras se realiza una copia de seguridad. El ARC no debe superar el límite establecido y la columna “Swap” debe permanecer cercana a 0 %. -
Revisar logs
journalctl -k | grep -i oomNo deberían aparecer eventos de OOM después de aplicar los cambios.
Notas adicionales
- En Proxmox, los contenedores LXC comparten la misma memoria del host. Si varios contenedores ejecutan workloads intensivos, ajustar
zfs_arc_maxa un valor más bajo (p.ej., 4 GB) puede ser necesario. - Cuando se elimina un swap ZFS, es recomendable ejecutar
zpool scrubpara asegurarse de que el pool no tenga bloques pendientes de limpieza. - Si el host dispone de varias interfaces de red y la replicación ZFS se realiza a través de la red, la latencia de I/O puede empeorar la presión de memoria. En esos casos, combinar la limitación de ARC con QoS de red ayuda a estabilizar el rendimiento.
- Cambios en
zfs_arc_minyzfs_arc_maxsolo surten efecto después de reiniciar el host o recargar el módulo ZFS. En producción, planifique una ventana de mantenimiento para aplicar la actualización.