Proxmox: La razón oculta por la que tu VM se siente lenta (incluso en NVMe)

¿Te fue útil?

«Pero está en NVMe.» Esa frase ha cerrado más llamadas de incidente de las que ha resuelto. Compraste medios rápidos, puedes hacer benchmarks, y aun así la VM parece estar pensando la respuesta antes de contestar. Los inicios de sesión se retrasan. Las instalaciones de paquetes avanzan lentamente. Tu base de datos afirma que está «limitada por I/O», lo cual es útil y a la vez insuficiente.

La razón oculta normalmente no es el rendimiento bruto. Es la latencia, especialmente la latencia de escritura, creada por una pila de valores por defecto que son seguros, genéricos y a veces crueles: semántica de sincronización, modos de caché, encolamiento, comportamiento de provisión delgada, amplificación CoW, replicación de almacenamiento y contención en el host. NVMe no arregla malas decisiones; sólo las hace ocurrir más rápido.

La razón oculta: tu VM está pagando por latencia que no presupuestaste

El marketing de NVMe es una celebración del throughput. Tus usuarios, sin embargo, experimentan la latencia de cola: el retraso en los percentiles 95/99 de «pequeñas operaciones síncronas que deben completarse antes de que ocurra lo siguiente». La «lentitud» de una VM suele ser sólo miles de pequeñas escrituras síncronas esperando educadamente detrás de la idea de durabilidad de otra carga.

En Proxmox, la ruta de almacenamiento es una tarta por capas:

  • Sistema de ficheros y semánticas de la aplicación en el invitado (fsync, O_DIRECT, journaling, barriers)
  • Modelo del dispositivo virtual (virtio-scsi vs virtio-blk, colas, iothreads)
  • Modo de caché de QEMU (writeback/writethrough/none/directsync) y AIO
  • Sistema de ficheros del host y gestor de volúmenes (ZFS, LVM-thin, directory, Ceph RBD)
  • Capa de bloque del host (planificador, comportamiento de merge, multipath)
  • Comportamiento del dispositivo físico (firmware NVMe, throttling térmico, caché SLC, protección contra pérdida de energía)

La «razón oculta» suele ser un desacople entre las expectativas del invitado y las garantías del host. El invitado emite escrituras síncronas y en algún punto inferior la pila dice: «Vale, confirmaré eso cuando sea realmente seguro». Eso es buena ingeniería. También es la razón por la que la instalación de un paquete pequeño puede sentirse como hacer la declaración de impuestos.

Consejo con criterio: deja de perseguir los MB/s de titulares. Empieza a medir IOPS a baja profundidad de cola, latencia de fsync y tiempo de espera en el host. La mayoría de incidentes de «NVMe lento» son (a) latencia de escritura síncrona (ZFS, Ceph, write barriers), (b) contención/encolamiento (un vecino ruidoso), o (c) una «optimización» como discard, compresión o snapshots que interactúan mal con tu carga.

Broma #1: NVMe es como darle a tu becario un coche deportivo: impresiona hasta que descubres que sigue tomando la ruta escénica al centro de datos.

Hechos e historia interesantes (porque los valores por defecto tienen antecedentes)

  1. Los modos de caché de QEMU existen porque el almacenamiento miente. En los primeros años de virtualización, «writeback» podía ser rápido pero arriesgado si la pila subyacente no persistía realmente los datos cuando decía que lo hacía.
  2. ZFS se diseñó pensando en checksums y copy-on-write. Eso te da integridad y snapshots, pero cambia los patrones de escritura y puede amplificar pequeñas escrituras aleatorias según la elección de recordsize/volblocksize.
  3. La gran ventaja de NVMe es el paralelismo. El protocolo soporta muchas colas de envío/completado, pero una VM con una sola cola aún puede bloquearse por CPU y bloqueo.
  4. Los planificadores de I/O de Linux evolucionaron para discos magnéticos. Algunos siguen siendo útiles para equidad y control de latencia; otros sólo añaden sobrecarga a rutas NVMe que no necesitan reordenamiento.
  5. Los barriers y flushes de escritura se endurecieron con el tiempo. Los sistemas de ficheros aprendieron por las malas que «rápido» sin durabilidad ordenada se convierte en «corrupción rápida», especialmente tras una pérdida de energía.
  6. La provisión delgada se hizo popular porque la capacidad era cara. Pero los thin pools pueden fragmentarse y su metadata puede convertirse en un limitador silencioso de rendimiento si no se vigila.
  7. TRIM/discard no es «gratis». Ayuda a la longevidad y al rendimiento en estado estable, pero el discard online puede crear picos de latencia periódicos según el firmware del disco y la carga.
  8. La fuerza de Ceph es la durabilidad distribuida. Esa durabilidad añade latencia de red y replicación; NVMe en los nodos OSD no elimina mágicamente los costes de quórum y reconocimiento.

Guía rápida de diagnóstico

No necesitas una semana de afinado. Necesitas 20 minutos de observación controlada. Aquí tienes el orden que encuentra el cuello de botella más rápido en producción.

Primero: confirma que el síntoma es latencia de I/O, no steal de CPU o presión de memoria

  • Dentro del invitado: comprueba iowait y la latencia de disco. Si la CPU está saturada o la memoria está intercambiando, el ajuste de almacenamiento es teatro.
  • En el host: revisa comportamiento tipo CPU steal (sobrecarga del host), KSM ballooning y swapping.

Segundo: identifica el backend de almacenamiento y sus semánticas de durabilidad

  • ZFS: comportamiento sync, presencia/calidad de SLOG, recordsize/volblocksize, compresión, vdevs especiales.
  • LVM-thin: uso de datos/metadata, comportamiento de discard, señales de fragmentación.
  • Ceph RBD: latencia en la ruta de red, commit/apply en OSD, replicación, ajustes del cliente.
  • Directory/ext4/xfs: opciones de montaje en el host, caché de escritura, barriers, salud del sistema de ficheros.

Tercero: comprueba el modelo de dispositivo de la VM y su encolamiento

  • virtio-scsi con iothread y múltiples colas cuando proceda.
  • Modo de caché correcto para el backend (y honestidad sobre las compensaciones de riesgo).

Cuarto: busca contención y latencia de cola

  • Busca una VM que esté haciendo escrituras intensas, backups o fusiones de snapshots.
  • Mide la utilización del disco y la profundidad de cola en el host, no sólo dentro de la VM.

Quinto: verifica que el NVMe en sí no sea el cuello de botella

  • Throttling térmico, rarezas del firmware, velocidad del enlace PCIe y ajustes de energía pueden convertir «rápido» en «educado».

Regla de decisión: si no puedes señalar una de (a) latencia síncrona, (b) encolamiento/contención, (c) presión de CPU/memoria, (d) mala configuración del backend, todavía estás adivinando. Sigue midiendo.

Tareas prácticas: comandos, salidas y decisiones

Estos son los chequeos que realmente ejecuto. Cada tarea incluye un fragmento realista de salida y qué decisión tomar a partir de ello.

Task 1: Identify the VM disk backend from Proxmox

cr0x@server:~$ qm config 104 | egrep -i 'scsi|virtio|ide|sata|boot|machine'
boot: order=scsi0;net0
machine: q35
scsi0: nvme-zfs:vm-104-disk-0,iothread=1,cache=none,discard=on,ssd=1,size=80G
scsihw: virtio-scsi-single

Qué significa: Esta VM usa un volumen respaldado por ZFS, virtio-scsi-single, cache=none, iothread activado, discard on.

Decisión: Si esta VM es sensible a latencia y emite escrituras síncronas, tus siguientes comprobaciones son la ruta sync de ZFS y si virtio-scsi-single limita el paralelismo de colas.

Task 2: Confirm host storage type (ZFS vs LVM-thin vs directory)

cr0x@server:~$ pvesm status
Name        Type     Status           Total            Used       Available        %
local       dir      active        19684272        4181248        15403024   21.24%
nvme-zfs    zfspool  active       960123904      412345344       547778560   42.95%
ceph-rbd    rbd      active               0               0               0    0.00%

Qué significa: El disco de la VM está en un pool ZFS llamado nvme-zfs.

Decisión: Enfócate en propiedades del dataset/zvol de ZFS (sync, volblocksize, compresión) y en si existe un SLOG apropiado.

Task 3: Check VM-visible latency inside the guest (quick and dirty)

cr0x@server:~$ iostat -x 1 5
Linux 6.1.0 (guest)  02/04/2026  _x86_64_  (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           8.02    0.00    3.11   22.70    0.00   66.17

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  svctm  %util
vda              3.00   45.00   120.0  2480.0     114.7     2.80   58.20    8.20   61.60   2.10  10.20

Qué significa: w_await está alrededor de ~62 ms. Eso no es «rápido para NVMe». Eso indica que algo está forzando que las escrituras esperen.

Decisión: Busca restricciones en la ruta de escrituras síncronas: ZFS sync, replicación Ceph, modo de caché o contención en el host.

Task 4: Check host-side disk latency and queueing

cr0x@server:~$ iostat -x 1 5
Linux 6.5.13-pve (pve-host)  02/04/2026  _x86_64_  (16 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          10.40    0.00    4.80   18.20    0.00   66.60

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  svctm  %util
nvme0n1          20.00  800.00   900.0 68000.0     167.5    45.20   55.10    9.80   56.30   0.45  99.00

Qué significa: %util está al máximo y avgqu-sz es enorme. El dispositivo está saturado o limitado, y la latencia sube.

Decisión: Encuentra quién está escribiendo, si son backups/scrubs, y si la unidad «rápida» está alcanzando límites de escritura sostenida o throttling térmico.

Task 5: Identify top I/O consumers on the host

cr0x@server:~$ pidstat -d 1 5
Linux 6.5.13-pve (pve-host)  02/04/2026  _x86_64_  (16 CPU)

#      Time   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
12:01:10     0      21456      0.00  82000.00  12000.00  vzdump
12:01:10     0      17890      0.00  12000.00      0.00  qemu-system-x86
12:01:10     0      17891      0.00  11800.00      0.00  qemu-system-x86

Qué significa: vzdump está martillando escrituras. El host está ocupado haciendo backups, lo que probablemente causa picos de latencia en las VMs.

Decisión: Limita la velocidad de los backups, muévelos fuera del pool primario o prográmalos fuera de las horas pico. Si ya haces eso, valida el comportamiento de snapshot/merge y el backend de almacenamiento.

Task 6: Check ZFS pool health and latency indicators

cr0x@server:~$ zpool status -v nvme-zfs
  pool: nvme-zfs
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        nvme-zfs    ONLINE       0     0     0
          nvme0n1   ONLINE       0     0     0

errors: No known data errors

Qué significa: No hay errores obvios. Salud no es rendimiento.

Decisión: Pasa a propiedades de ZFS y comportamiento sync; también comprueba si existe un SLOG y si es apropiado.

Task 7: Check ZFS dataset and zvol properties that affect latency

cr0x@server:~$ zfs get -r compression,atime,recordsize,logbias,sync,primarycache,secondarycache nvme-zfs
NAME      PROPERTY        VALUE           SOURCE
nvme-zfs  compression     zstd            local
nvme-zfs  atime           off             local
nvme-zfs  recordsize      128K            local
nvme-zfs  logbias         latency         local
nvme-zfs  sync            standard        local
nvme-zfs  primarycache    all             default
nvme-zfs  secondarycache  all             default

Qué significa: sync=standard significa que las escrituras síncronas se honran. Bien. Si tu carga hace muchas fsync, la latencia depende de la capacidad del pool para confirmar de forma segura.

Decisión: Si la latencia sync es alta y te importa la corrección, añade un SLOG adecuado (con protección contra pérdida de energía) o rediseña el patrón de escritura. No cambies sync=disabled salvo que disfrutes explicando pérdida de datos a los responsables.

Task 8: Confirm whether a SLOG exists and is actually separate

cr0x@server:~$ zpool status nvme-zfs | sed -n '1,40p'
  pool: nvme-zfs
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        nvme-zfs    ONLINE       0     0     0
          nvme0n1   ONLINE       0     0     0

errors: No known data errors

Qué significa: No hay un vdev de logs. Las escrituras síncronas deben confirmarse en el vdev principal.

Decisión: Si ejecutas bases de datos, servidores de correo, runners de CI o cualquier cosa con muchas fsync, considera un dispositivo SLOG dedicado con protección contra pérdida de energía. Si no puedes, al menos acepta la latencia como el coste de la durabilidad.

Task 9: Measure ZFS latency live

cr0x@server:~$ zpool iostat -v nvme-zfs 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
nvme-zfs     393G   519G     40    820  1.2M  70.1M
  nvme0n1    393G   519G     40    820  1.2M  70.1M
----------  -----  -----  -----  -----  -----  -----

Qué significa: Muchas operaciones de escritura y ancho de banda. Esto no muestra latencia directamente, pero te dice que el pool está ocupado y debes correlacionar con iostat -x del host y la programación de backups/scrubs.

Decisión: Si «ocupado» coincide con el dolor de los usuarios, necesitas aislar cargas: pools separados, destinos de backup separados o limitación de I/O vía cgroups / límites de Proxmox.

Task 10: Check NVMe health and throttling hints

cr0x@server:~$ nvme smart-log /dev/nvme0n1 | egrep -i 'temperature|warning|critical|media|power_cycles|unsafe_shutdowns'
critical_warning                    : 0x00
temperature                         : 72 C
available_spare                     : 100%
media_errors                        : 0
power_cycles                        : 38
unsafe_shutdowns                    : 2

Qué significa: 72°C está caliente. Algunos discos hacen throttling alrededor de este rango según el modelo y el flujo de aire. Los apagados inseguros también importan para la integridad si dependes de caches volátiles.

Decisión: Mejora la refrigeración y confirma que el dispositivo no está reduciendo prestaciones bajo escrituras sostenidas. Si detectas problemas térmicos, tu «VM lenta» es en realidad «física lenta».

Task 11: Verify PCIe link speed/width (quietly common)

cr0x@server:~$ lspci -s 03:00.0 -vv | egrep -i 'LnkSta|NVMe'
Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller
LnkSta: Speed 8GT/s (ok), Width x2 (downgraded)

Qué significa: La unidad está funcionando a PCIe x2, no x4. Eso puede limitar el throughput y a veces aumentar efectos de contención.

Decisión: Mueve el dispositivo a una ranura con lanes completas, ajusta la BIOS o deja de compartir lanes con algo que no debería estar ahí.

Task 12: Check the host I/O scheduler for NVMe

cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[mq-deadline] none kyber bfq

Qué significa: mq-deadline está activo. A menudo es un valor sensato para cargas mixtas porque controla la latencia bajo carga.

Decisión: Si ves picos de latencia bajo contención, mantén un planificador orientado a latencia (mq-deadline o kyber). Si tienes una única carga y quieres la mínima sobrecarga, prueba none, pero sólo con mediciones.

Task 13: Inspect VM’s virtio-scsi and queue configuration

cr0x@server:~$ qm config 104 | egrep -i 'scsihw|iothread|queues|numa|cpu|machine'
machine: q35
scsihw: virtio-scsi-single
scsi0: nvme-zfs:vm-104-disk-0,iothread=1,cache=none,discard=on,ssd=1,size=80G
cpu: host
numa: 0

Qué significa: virtio-scsi-single usa una sola cola por diseño. Para algunas cargas, eso se convierte en un cuello de botella en invitados con múltiples vCPU.

Decisión: Considera virtio-scsi-pci con múltiples colas para I/O paralelo si la carga del invitado se beneficia. No cambies a ciegas: las bases de datos a menudo valoran más la consistencia de latencia que las colas paralelas brutas.

Task 14: Check for host memory pressure (which masquerades as “slow disk”)

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:            62Gi        54Gi       1.2Gi       2.1Gi       6.8Gi       3.0Gi
Swap:          8.0Gi       2.6Gi       5.4Gi

Qué significa: Swap está en uso y la memoria disponible es baja. Bajo presión, el reclaim y el swapping del host pueden paralizar rutas de I/O y vCPUs de las VMs.

Decisión: Arregla overcommit, la política de ballooning o añade RAM. El ajuste de almacenamiento no superará el swapping.

Task 15: Detect TRIM/discard behavior and whether it’s causing spikes

cr0x@server:~$ systemctl status fstrim.timer | sed -n '1,12p'
● fstrim.timer - Discard unused blocks once a week
     Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled; preset: enabled)
     Active: active (waiting) since Mon 2026-02-03 00:00:00 UTC; 1 day 12h ago
    Trigger: Mon 2026-02-10 00:00:00 UTC; 5 days left

Qué significa: TRIM semanal está programado. Eso suele ser mejor que discard continuo para consistencia de latencia.

Decisión: Prefiere TRIM periódico sobre discard siempre activo para muchas cargas de servidor. Si usas discard=on en la configuración del disco VM, confirma que no está creando picos de latencia durante alta churn.

Task 16: Identify snapshot/backup merges (a classic “why now?”)

cr0x@server:~$ zfs list -t snapshot -o name,used,creation -s creation | tail -n 5
nvme-zfs/vm-104-disk-0@vzdump-2026_02_04-000001  1.2G  Tue Feb  4 00:00 2026
nvme-zfs/vm-107-disk-0@replica-2026_02_04-001500 800M  Tue Feb  4 00:15 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-001500 650M  Tue Feb  4 00:15 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-003000 700M  Tue Feb  4 00:30 2026
nvme-zfs/vm-104-disk-0@replica-2026_02_04-004500 720M  Tue Feb  4 00:45 2026

Qué significa: Snapshots frecuentes por backups/replicación. El churn de snapshots puede aumentar la amplificación de escritura en sistemas CoW y degradar la localidad.

Decisión: Reduce la frecuencia de snapshots para volúmenes con alto churn, separa destinos de backup o ajusta la retención para evitar largas cadenas de snapshots antiguos que fijan bloques.

Análisis profundo: qué hace que NVMe se sienta lento

1) El throughput miente; la latencia dice la verdad

La mayoría de tickets «mi VM está lenta» son humanos reportando que las interacciones se sienten pegajosas: SSH tarda un segundo más, los gestores de paquetes se detienen, sitios web se entrecortan. Esas son pequeñas operaciones I/O con cadenas de dependencia. Un único fsync que dure 40 ms no aparece como un problema de ancho de banda, pero puede arruinar un log de transacciones, una instalación apt o un filesystem con journaling.

NVMe brilla en IOPS altas y throughput alto, pero sólo si la pila puede mantener las colas llenas y completar el trabajo de forma consistente. Una carga de VM a menudo corre a baja profundidad de cola con flushes frecuentes. Si tu backend convierte esos flushes en esperas costosas, tu NVMe se convierte en un dispositivo muy rápido que mayormente espera permiso.

2) Escrituras síncronas: ZFS y el coste de ser honesto

La postura por defecto de ZFS es: cuando una aplicación pide durabilidad, ZFS lo toma en serio. Eso significa que las escrituras síncronas se confirman en almacenamiento estable antes de reconocerlas. En un pool sin un ZIL/SLOG dedicado, esos commits aterrizan en los vdev(s) principales. Con un solo NVMe eso puede estar bien—hasta que mezclas cargas, desencadenas escrituras sostenidas o topas con comportamiento del firmware que hace que los flushes sean caros.

La trampa es asumir «NVMe único = sync instantáneo». Muchos NVMe de consumo aceleran escrituras usando caches volátiles y mecanismos de folding. Si carecen de protección contra pérdida de energía, deben ser conservadores con las semánticas de flush, y pueden hacer housekeeping interno que provoca picos de latencia. ZFS no conoce el marketing de tu unidad; sólo conoce las promesas de tu unidad.

Haz: para cargas intensivas en sync, usa un NVMe empresarial con protección contra pérdida de energía o un dispositivo SLOG separado diseñado explícitamente para escrituras síncronas de baja latencia.

Evita: establecer sync=disabled como «arreglo de rendimiento» salvo que te importe perder escrituras ya reconocidas en un crash. Eso no es hipotético; ocurre en incidentes reales.

3) Modos de caché de QEMU: el rendimiento es un contrato, no una sensación

En Proxmox, el modo de caché de disco cambia cómo QEMU interactúa con la caché de página del host y el comportamiento de flush. La versión corta:

  • cache=none: I/O directo (O_DIRECT) evita la caché de páginas del host. A menudo bueno para reducir doble cache y hacer la latencia más predecible.
  • cache=writeback: puede ser rápido, pero depende de la caché del host. También puede aumentar el riesgo si la pila subyacente u hardware miente sobre durabilidad.
  • cache=writethrough/directsync: más conservador; puede amplificar la latencia.

No hay «mejor» universal. Sólo hay «mejor según tus requisitos de durabilidad y rendimiento». Si ejecutas bases de datos y valoras la corrección, alinea el modo de caché y el backend para que los flushes signifiquen lo que el invitado cree que significan.

4) virtio-scsi-single: una cola que los embotella a todos

virtio-scsi-single existe por una razón: compatibilidad y simplicidad. Pero también serializa I/O a través de una sola cola, lo que puede convertirse en un punto de contención de CPU y locks para invitados multi-vCPU con I/O paralelo.

Si tu carga hace múltiples flujos I/O independientes—piensa servidores de compilación, múltiples contenedores en una sola VM o un servidor de ficheros ocupado—una cola puede crear latencia artificialmente alta incluso cuando el NVMe está relativamente inactivo.

Haz: considera virtio-scsi-pci con configuraciones de colas adecuadas y iothread=1 para dispositivos de disco que se beneficien.

Evita: convertir todo en «más colas» sin observar. Algunas cargas empeoran al aumentar la concurrencia porque la latencia de cola se difunde bajo contención.

5) Provisión delgada: la lenta erosión de los metadatos

LVM-thin es perfectamente utilizable y común en despliegues Proxmox. Pero los thin pools tienen dos trampas de rendimiento:

  • Presión de metadata: cuando la metadata está ajustada o se actualiza mucho, los picos de latencia aparecen.
  • Fragmentación: con el tiempo, las asignaciones se dispersan, especialmente bajo churn de snapshots y escrituras aleatorias.

Si tratas los thin pools como magia, eventualmente te recordarán que son sistemas de contabilidad con afición por ser dispositivos de bloque.

6) Churn de snapshots y backups: CoW no es gratis

Proxmox facilita backups y snapshots, lo cual es bueno. También facilita crear una máquina de amplificación de escrituras en segundo plano:

  • Snapshots frecuentes fijan bloques antiguos.
  • Las escrituras aleatorias deben asignar nuevos bloques (CoW), aumentando la fragmentación.
  • Los procesos de backup leen discos enteros y pueden expulsar cachés, incrementando la latencia para cargas interactivas.

Los backups son necesarios. Pero «cada 15 minutos para todo» es una política escrita por alguien que no recibe llamadas de paginación.

7) Contención: el vecino ruidoso suele ser tú

Un solo NVMe puede manejar IOPS impresionantes, pero cargas mixtas de lectura/escritura con flushes síncronos pueden saturarlo. Peor: una VM que haga escrituras secuenciales grandes (destino de backup, agregador de logs) puede arruinar la latencia para otra VM que haga pequeñas escrituras aleatorias síncronas (base de datos). Ambos están «bien» individualmente. Juntos, pelean.

Aislamiento vence a la afinación heroica. Pools separados. Dispositivos separados. Tráfico de backups separado. O al menos usa límites de I/O de Proxmox para imponer equidad.

8) El NVMe en sí: caché SLC, firmware y térmicas

Los NVMe de consumo suelen publicitar rendimiento en ráfaga ayudado por caché SLC. Bajo escrituras sostenidas, se desploman. No lo notas en benchmarks de 30 segundos; lo notas a las 02:00 cuando tus backups y replicación duran 90 minutos.

Las térmicas son otro asesino silencioso. Los controladores NVMe hacen throttling para protegerse, y tu «almacenamiento rápido» se vuelve «almacenamiento prudente». Esto puede producir el gráfico más irritante en operaciones: un perfecto diente de sierra de rendimiento mientras el dispositivo se calienta y enfría.

Broma #2: He resuelto más misterios de rendimiento con un ventilador que con un doctorado; eso es a la vez humilde y ruidoso.

9) Mentalidad de fiabilidad: una cita que vale la pena guardar

Idea parafraseada (con atribución): Gene Kim suele impulsar el principio operativo de que mejorar el flujo requiere reducir el trabajo en curso y la demora de retroalimentación, no sólo añadir potencia.

Los problemas de rendimiento de almacenamiento son con frecuencia problemas de flujo: demasiadas tareas de fondo concurrentes, demasiado encolamiento y muy poca visibilidad en la latencia.

Tres mini-historias corporativas del mundo real

Mini-historia 1: El incidente causado por una suposición errónea («NVMe significa que sync es barato»)

Una empresa SaaS mediana migró varias VMs críticas de PostgreSQL a un nuevo clúster Proxmox. El argumento era sencillo: espejos NVMe locales, ZFS para snapshots y replicación de Proxmox para recuperación rápida. La primera semana fue tranquila. La segunda semana tuvo una lente de tiempo lenta durante un pico rutinario.

La capa de aplicación empezó a expirar. No en todas partes—sólo lo suficiente para confundir. La CPU estaba bien. La red estaba bien. Desde dentro de la VM de base de datos, iostat mostró esperas de escritura feas. La primera reacción del equipo fue culpar el sistema de ficheros del invitado y afinar opciones de montaje. Eso no solucionó nada.

En el host, se hizo obvio: las escrituras síncronas se acumulaban detrás de otras escrituras, y los NVMe mostraban latencia de cola larga bajo carga mixta sostenida. La suposición errónea fue creer que NVMe hace fsync básicamente gratis. No lo hace. Hace posible ser rápido—si tu dispositivo y configuración soportan commits durables de baja latencia.

La solución fue aburrida: añadir dispositivos SLOG con protección contra pérdida de energía, reducir la frecuencia de snapshots en los zvols de la base de datos y programar la replicación fuera de las horas pico. La historia de «NVMe es rápido» se convirtió en «la durabilidad tiene un coste, págalo explícitamente».

Mini-historia 2: La optimización que salió mal («activar discard en todas partes»)

Un equipo de TI empresarial estandarizó plantillas Proxmox. Activaron discard=on para todos los discos VM y cambiaron los sistemas de ficheros invitados a discard continuo porque parecía limpio en papel: mejor nivelado de desgaste SSD, mejor reclaim de espacio, menos sorpresas de almacenamiento. Lo desplegaron con satisfacción.

Luego la mesa de ayuda empezó a ver «congelamientos aleatorios» en VMs. No bloqueos totales. Sólo interrupciones periódicas de varios segundos. Fue peor en servidores de terminal Windows ocupados y algunas VMs Linux con alto churn en directorios temporales. Los usuarios describían que «el teclado deja de responder por un segundo». Los ingenieros lo llamaban «no reproducible», que es una forma más amable de decir «aún no».

Las métricas del host eventualmente correlacionaron los stalls con ráfagas de discard. Algunos modelos NVMe lo manejaban bien; otros convertían discard en eventos de recolección de basura interna con picos de latencia notables. Bajo virtualización, esos picos se amplificaron porque múltiples invitados hacían la misma «optimización» simultáneamente.

El rollback fue quirúrgico: desactivar discard continuo en invitados, mantener fstrim periódico y sólo activar discard=on para volúmenes que realmente necesitaban reclaim online. La optimización no falló porque discard sea malo; falló porque «en todas partes, siempre» no es una estrategia de rendimiento.

Mini-historia 3: La práctica rutinaria que salvó el día («medir latencia de cola y aislar backups»)

Un equipo de servicios financieros ejecutaba Proxmox para herramientas internas y algunos servicios sensibles a la latencia. Nada glamuroso. Tenían una regla simple: los backups no deben compartir el mismo pool que bases de datos productivas con escrituras intensas, salvo que haya un presupuesto I/O medido y aplicado.

Implementaron almacenamiento separado: un pool para discos VM y un segundo para destinos de backup. También mantuvieron un pequeño panel centrado en latencia de disco percentil 95/99 en hosts durante horas laborales. No sólo promedios. Latencia de cola. La métrica que coincide con las quejas humanas.

Un martes, un servicio nuevo desplegado con logging muy chatty y política de retención agresiva empezó a escribir constantemente. El panel de latencia se encendió en minutos, y porque los backups estaban aislados, el radio de impacto se mantuvo pequeño. Ralentizaron la VM ruidosa, ajustaron logging y la vida siguió.

Sin heroicos análisis post-mortem. Sin drama de «NVMe roto». Sólo guardarraíles que asumían que alguien, algún día, haría algo entusiasta con escrituras en disco. Tenían razón.

Errores comunes: síntoma → causa raíz → solución

  • Síntoma: La VM se siente lenta, las instalaciones de paquetes se detienen, las bases de datos reportan alto tiempo de fsync.

    Causa raíz: Latencia de escritura síncrona en ZFS sin SLOG adecuado o en NVMe de consumo bajo carga mixta sostenida.

    Solución: Añadir SLOG con PLP o NVMe empresarial; reducir churn de snapshots; aislar escritores ruidosos; mantener sync=standard para corrección.

  • Síntoma: Stalls aleatorios de varios segundos en múltiples VMs en intervalos extraños.

    Causa raíz: Ráfagas de discard/TRIM o mantenimiento en segundo plano (fstrim, GC del disco) causando picos de latencia.

    Solución: Preferir fstrim periódico en lugar de discard continuo; probar discard=on selectivamente; revisar térmicas y firmware NVMe.

  • Síntoma: Alta utilización de disco en el host, pero VMs individuales muestran bajo throughput; todo «simplemente lento».

    Causa raíz: Cargas encoladas/contendientes (backup, replicación, scrub, otra VM) saturando el dispositivo con pequeñas escrituras y flushes.

    Solución: Mover backups fuera del pool; programar trabajos pesados; añadir límites I/O; pools separados para diferentes clases de latencia.

  • Síntoma: Una VM con múltiples vCPU no supera IOPS modestos; la latencia sube cuando corren trabajos paralelos.

    Causa raíz: virtio-scsi-single cuello de botella de cola única o falta de iothread.

    Solución: Usar virtio-scsi-pci y habilitar iothread; considerar multiqueue donde esté soportado; volver a probar con fio en el invitado.

  • Síntoma: El rendimiento es excelente durante 30–60 segundos y luego colapsa en escrituras largas.

    Causa raíz: Agotamiento de caché SLC del NVMe y throttling por escrituras sostenidas.

    Solución: Elegir discos con rating de escritura sostenida; sobreaprovisionar; mejorar refrigeración; separar workloads de backup/ingest.

  • Síntoma: Tras habilitar compresión/dedupe «por eficiencia», la latencia empeora.

    Causa raíz: Sobrecarga de CPU y amplificación; dedup es especialmente brutal sin la memoria y características de carga correctas.

    Solución: Usar compresión con criterio (a menudo sí); evitar dedup para discos VM salvo que tengas un caso probado; medir impacto en CPU y latencia.

  • Síntoma: «NVMe es rápido» pero el host muestra swapping; las VMs se congelan durante presión de memoria.

    Causa raíz: Overcommit de memoria del host; swapping y reclaim bloquean I/O y planificación de CPU.

    Solución: Corregir dimensionado de RAM, ballooning y límites ARC de ZFS; dejar de usar swap en hipervisores salvo que sepas por qué lo quieres.

  • Síntoma: Benchmarks de almacenamiento parecen bien, pero las aplicaciones reales son lentas.

    Causa raíz: Los benchmarks prueban throughput secuencial o colas profundas; tu app es intensiva en sync a baja profundidad de cola.

    Solución: Benchmarker lo correcto: random reads/writes a baja QD, latencia fsync y percentiles de cola—dentro del invitado y en el host.

Listas de verificación / plan paso a paso

Paso a paso: diagnosticar una VM lenta sin complicar en exceso

  1. Confirma que el problema es consistente. Obtén una ventana temporal y correlaciona con backups, scrubs, replicación y despliegues.
  2. Dentro del invitado: revisa iostat -x y vmstat 1. Si iowait es alto, continúa. Si swap está activo, arregla memoria primero.
  3. En el host: ejecuta iostat -x para el dispositivo NVMe. Busca await alto, avgqu-sz elevado y %util al máximo.
  4. Encuentra al escritor: pidstat -d y correlación con PIDs de qemu-system-x86 o herramientas de backup.
  5. Identifica el backend: pvesm status y qm config. ¿ZFS? ¿LVM-thin? ¿Ceph? Aplican playbooks diferentes.
  6. Valida el modelo de dispositivo VM: virtio-scsi-single vs virtio-scsi-pci, iothread activado, modo de caché apropiado.
  7. Comprueba la realidad del NVMe: nvme smart-log (térmicas), lspci -vv (anchura de lanes) y asegúrate de que no está haciendo throttling.
  8. Haz un cambio a la vez. Reprueba la operación de usuario original (no sólo un benchmark sintético).

Checklist: «haz esto, evita aquello» para rendimiento de almacenamiento en Proxmox

  • Haz: monitoriza percentiles de latencia de disco en hosts. Evita: confiar en gráficos de throughput promedio.
  • Haz: aislar el tráfico de backups. Evita: ejecutar backups pesados en el mismo pool que bases de datos de baja latencia durante horas pico.
  • Haz: usar dispositivos con PLP para acelerar sync. Evita: drives de consumo para expectativas de durabilidad de WAL.
  • Haz: mantener políticas de snapshot intencionales. Evita: snapshots de alta frecuencia en volúmenes de alto churn sin medir impacto.
  • Haz: elegir virtio y colas deliberadamente. Evita: mantener defaults cuando hay evidencia de que son cuello de botella.
  • Haz: tratar el discard como una herramienta. Evita: activar discard continuo en todas partes porque «suena limpio».

Preguntas frecuentes

1) ¿Por qué mi VM está lenta si el NVMe hace gigabytes por segundo en benchmarks?

Porque tu carga probablemente depende de latencia síncrona a baja profundidad de cola (fsync/flush), no de throughput secuencial. Mide await y tiempos de fsync, no sólo MB/s.

2) ¿Debo poner ZFS sync=disabled para arreglar latencia?

Sólo si aceptas perder escrituras ya reconocidas ante un crash. Para bases de datos y la mayoría de servicios con estado, es una mala compensación. Arregla la ruta sync con hardware apropiado (SLOG con PLP/NVMe empresarial) o aisla la carga en su lugar.

3) ¿Es cache=none siempre lo mejor en Proxmox?

No. A menudo es un buen valor por defecto para predictibilidad y evitar doble caché, pero el «mejor» modo depende del backend y de los requisitos de durabilidad. Trata el modo de caché como parte de un contrato de corrección.

4) ¿Qué pasa con virtio-scsi-single?

No tiene nada de malo—hasta que necesitas paralelismo. Usa una sola cola, lo que puede embotellar cargas multi-hilo de I/O. Si ves contención de CPU/locks y IOPS limitados, considera virtio-scsi-pci con colas y iothreads.

5) ¿Los snapshots son inherentemente lentos?

Los snapshots no son inherentemente lentos, pero los snapshots frecuentes en volúmenes con mucho churn aumentan la sobrecarga CoW y la fragmentación. El dolor suele aparecer durante merges, backups y escrituras aleatorias sostenidas.

6) ¿Activar discard mejora el rendimiento?

Puede mejorar el comportamiento en estado estable y el reclaim de espacio, pero también puede introducir picos de latencia. Muchos entornos funcionan mejor con fstrim periódico que con discard continuo, especialmente con muchas VMs.

7) ¿Cómo sé si el NVMe está haciendo throttling?

Comprueba la temperatura vía nvme smart-log y correlaciona caídas de rendimiento con el aumento térmico. También vigila patrones de diente de sierra en latencia y throughput bajo escrituras sostenidas.

8) ¿Debo cambiar el planificador I/O de Linux para NVMe?

A veces. none puede reducir sobrecarga, mientras que mq-deadline o kyber pueden mejorar equidad de latencia bajo contención. Elige según la latencia de cola medida, no por ideología.

9) ¿Por qué los backups hacen lentas a las VMs interactivas aunque los backups sean «de lectura»?

Las lecturas pueden expulsar cachés y aumentar colas de dispositivo, y los backups basados en snapshots pueden desencadenar trabajo adicional de metadata. Si los backups compiten por el mismo pool, las cargas sensibles a latencia lo sufrirán.

10) ¿Cuál es la solución más efectiva para «VMs lentas en almacenamiento rápido»?

Aislamiento. Pools separados (o al menos límites I/O estrictos) para diferentes clases de latencia, y deja de mezclar tormentas de backup/scrub/replicación con cargas transaccionales interactivas.

Siguientes pasos prácticos

Si quieres que la VM deje de sentirse lenta, haz esto en orden:

  1. Mide latencia, no throughput. Captura iostat -x en invitado y host durante la ventana del problema.
  2. Identifica el backend. ZFS vs LVM-thin vs Ceph cambia lo que es «normal» y cómo se arregla.
  3. Encuentra la contención. Backups y churn de snapshots son reincidentes. Confírmalo con pidstat -d y correlación temporal.
  4. Arregla la ruta de durabilidad honestamente. Si necesitas escrituras sync rápidas, usa hardware que las entregue con seguridad (SLOG con PLP/NVMe empresarial) o acepta la latencia como coste de corrección.
  5. Ajusta las colas de la VM deliberadamente. Si estás en virtio-scsi-single y la carga es paralela, cambia a un modelo mejor y valida con pruebas de carga reales.
  6. Deja de «optimizar» globalmente. Discard, snapshots agresivos y cachés demasiado ingeniosas son formas seguras de crear jitter en la flota. Haz cambios por clase de carga.

La recompensa no es sólo VMs más rápidas. Son menos tickets misteriosos, menos llamadas nocturnas para culpar a alguien y una pila de almacenamiento que se comporta como un sistema—no como un rumor.

← Anterior
Resolutores DNS: Caché negativa — la configuración que hace que las interrupciones duren más
Siguiente →
Instalación de Rocky Linux 10: compatible con RHEL sin el dolor de la suscripción

Deja un comentario