pveperf de Proxmox muestra datos absurdos: cómo medir el rendimiento correctamente

¿Te fue útil?

pveperf dice que tu almacenamiento hace 2.000 MB/s. Tus VMs siguen tartamudeando al descomprimir un archivo y la latencia de la base de datos se dispara como si intentara escapar del gráfico. No estás loco. Estás midiendo mal —o más bien, confías en una herramienta que es demasiado limitada para ser la base de una decisión.

Esta es la guía pragmática que desearía viniera con Proxmox: qué mide realmente pveperf, por qué miente (a veces honestamente, a veces por omisión) y cómo hacer pruebas de rendimiento que aguanten el contacto con producción.

Qué es pveperf (y por qué decepciona)

pveperf es una prueba rápida tipo «smoke test». Está diseñada para darte una señal aproximada: “¿este host está claramente subdimensionado o mal configurado?”. No está pensada para responder preguntas como:

  • ¿Puede mi pool ZFS sostener escrituras síncronas para PostgreSQL?
  • ¿Sobrevivirá mi clúster Ceph a dominios de fallo de 3 nodos en pico?
  • ¿Por qué las VMs se paran cuando corren las copias de seguridad?
  • ¿El problema es CPU steal, latencia IO o jitter de red?

pveperf ejecuta pruebas pequeñas y simplistas (escrituras en sistema de archivos, bucles de CPU) y reporta un número. Las pruebas pequeñas adoran las cachés y odian la realidad. Si tratas ese número como un SLA de almacenamiento, terminarás depurando a las 2 a.m. mientras tus usuarios descubren el «botón de actualizar» sin fin.

Hechos y contexto interesantes que deberías saber (para dejar de medir lo equivocado)

  1. Bonnie++ (y microbenchmarks similares) moldearon la cultura temprana de perf en Linux: los números rápidos se usaban para comparar discos, pero fueron famosos por ser sensibles a la caché y fáciles de manipular.
  2. Fio se convirtió en el estándar porque modela patrones de IO: puede hacer sync vs async, profundidad de cola, aleatorio vs secuencial y reportar distribuciones de latencia —no solo promedios.
  3. La latencia media es una mentirosa: la latencia en cola (p95/p99) es la que hace llorar a las bases de datos. La cultura moderna de benchmarking se desplazó fuertemente hacia percentiles.
  4. El writeback caching cambió el mundo (y los modos de fallo): controladoras y SSDs pueden confirmar escrituras antes de que sean duraderas; los benchmarks se ven bien hasta que hay un corte de energía o se alcanza el límite de flush de caché.
  5. ZFS intercambia velocidad bruta por corrección: copy-on-write y sumas de verificación tienen coste; pretender que se comporte como ext4 en RAID0 es cómo se crean mitos.
  6. Las semánticas de fsync definen la carga de trabajo: una base de datos OLTP es básicamente una máquina de durabilidad; un benchmark que no modele fsync está midiendo optimismo.
  7. NVMe introdujo la profundidad de cola en la vida diaria: SATA a menudo estaba limitado por una cola pequeña; NVMe soporta colas profundas y castiga pruebas superficiales.
  8. Virtio y drivers paravirtuales son características de rendimiento: hacer benchmarking dentro de una VM sin drivers virtio es medir tus errores.

Benchmarking no es un número; es una pregunta. Empieza con la pregunta y luego elige herramientas y parámetros que encajen.

Por qué los resultados de pveperf parecen absurdos

pveperf suele producir números que son al mismo tiempo “verdaderos” e “inútiles”. Aquí están los principales modos de fallo:

1) Mide la página de caché, no el disco

Si el archivo de prueba cabe en RAM, estás midiendo ancho de banda de memoria y comportamiento de buffering del kernel. Tu SSD no se hizo 10x más rápido; tu RAM hizo lo que hace la RAM.

2) Toca una ruta de sistema de archivos con comportamiento no intencionado

En Proxmox, los “tipos” de almacenamiento importan. Probar /var/lib/vz en local-lvm vs local-zfs vs un montaje NFS lo cambia todo: caché, semánticas sync, incluso la sobrecarga de metadatos.

3) Ignora el contrato de durabilidad

Muchos benchmarks “rápidos” de escritura son rápidos porque no esperan al almacenamiento estable. Si tu carga necesita durabilidad (bases de datos, apps con journaling, imágenes de VM), debes medir con escrituras síncronas (o fsync explícito) para saber qué estás comprando.

4) Se ejecuta demasiado poco tiempo

El almacenamiento moderno tiene múltiples fases de rendimiento: ráfagas de caché SLC, throttling térmico, recolección de basura, grupos de transacciones ZFS, recuperación de Ceph. Una prueba de 10 segundos es básicamente un saludo, no una medición.

5) Oculta contención y encolamiento

Los sistemas reales son compartidos: múltiples VMs, scrub en segundo plano, copias de seguridad, replicación. El número “absurdo” suele ser el mejor caso en una fantasía de laboratorio donde no pasa nada más.

Broma #1: pveperf es como pesar tu coche comprobando qué tan rápido rueda cuesta abajo—técnicamente una medición, emocionalmente un error.

Principios de benchmarking que te mantienen fuera de problemas

Decide qué estás midiendo: dispositivo, sistema de archivos o carga

  • Nivel de dispositivo (disco bruto/NVMe): “¿El hardware está sano y configurado correctamente?” Usa herramientas nvme, smartctl, fio con --filename=/dev/nvme0n1 (con precaución).
  • Nivel de sistema de archivos/pool (dataset ZFS, LVM-thin, ext4): “¿Qué entrega mi stack de almacenamiento a las VMs?” Usa fio en un archivo en el montaje objetivo.
  • Nivel de aplicación (base de datos, SO de VM): “¿Mi servicio cumplirá los SLOs?” Usa los propios benchmarks de la aplicación más la telemetría de IO.

Prefiere reproducibilidad sobre números de héroe

Un benchmark que no puede repetirse no es benchmarking; es contar historias. Controla lo que puedas:

  • Ejecuta pruebas en un estado conocido del sistema (sin scrub, sin resilver, sin backup).
  • Registra kernel, versión de Proxmox, diseño de almacenamiento, modelos de disco, firmware.
  • Captura el estado de escalado de frecuencia de CPU.
  • Captura el scheduler de IO, multipath y la política de caché del controlador.

Los percentiles de latencia ganan a los promedios de throughput

El throughput está bien, pero la latencia es lo que sienten los usuarios. Salidas de benchmark que incluyan percentiles de clat marcan la diferencia entre “parece bien” y “¿por qué la API falló?”

Usa un tiempo de ejecución lo bastante largo para alcanzar estado estable

Si no ves que el sistema se estabilice, no lo mediste. Para SSDs, dales tiempo para calentarse. Para ZFS, deja que los grupos de transacciones roten. Para Ceph, espera a que el clúster deje de chismorrear y empiece a trabajar.

Una idea para operaciones (parafraseada porque sigue siendo cierta)

Idea parafraseada (Werner Vogels, fiabilidad/operaciones): “You build it, you run it” implica que lo midas como si te pagaran por ello.

Guion de diagnóstico rápido: encuentra el cuello de botella

Esta es la secuencia “tienes 20 minutos antes de la llamada de incidente”. El objetivo es identificar si el limitador principal es CPU, disco, red o una trampa de configuración.

Primero: confirma el síntoma y localiza la capa

  1. En el host Proxmox: comprueba load, CPU steal (si hay nesting), presión de memoria y IO wait.
  2. En la capa de almacenamiento: comprueba utilización de disco, profundidad de cola y latencia.
  3. En la VM: confirma que realmente es latencia de IO y no swapping en el invitado o bloqueos de la aplicación.

Segundo: determina si estás limitado por throughput, IOPS o latencia

  • MB/s altos, IOPS bajos sugiere límite de ancho de banda secuencial.
  • IOPS altos, MB/s bajos sugiere carga de bloques pequeños (bases de datos típicas).
  • Baja utilización pero alta latencia sugiere penalizaciones sync, caché mal alineada, flushing del controlador o jitter en almacenamiento en red.

Tercero: aísla variables con una corrida controlada de fio

Ejecuta fio en el host contra la ruta de almacenamiento exacta que usan tus VMs. Usa direct IO. Usa un tamaño de archivo mayor que la RAM. Captura percentiles. Decide con base en datos, no en sensaciones.

Tareas prácticas: comandos, significado de la salida, decisiones

Estas son tareas operativas reales. Cada una incluye un comando, qué te dice la salida y la decisión que tomas. Ejecútalas en el host Proxmox salvo que se indique lo contrario.

Task 1: Ver qué está probando realmente pveperf

cr0x@server:~$ pveperf /var/lib/vz
CPU BOGOMIPS:      59840.00
REGEX/SECOND:      2071670
HD SIZE:           222.22 GB (/dev/mapper/pve-root)
FSYNCS/SECOND:     1641.53
DNS EXT:           68.88 ms
DNS INT:           0.34 ms (pve1)

Qué significa: La línea “HD SIZE” te indica qué dispositivo hay detrás de la ruta. Si es pve-root en discos giratorios, no esperes milagros. Si está en ZFS, no te está diciendo las opciones del dataset ZFS.

Decisión: Úsalo solo como comprobación de cordura. Si los resultados no coinciden con el dolor de los usuarios, pasa a fio y telemetría.

Task 2: Confirmar qué almacenamiento respalda los storages de Proxmox

cr0x@server:~$ pvesm status
Name             Type     Status           Total            Used       Available        %
local            dir      active        222.22G          48.13G         162.60G   21.66%
local-lvm        lvmthin  active          1.82T         910.24G         929.76G   50.04%
rpool            zfspool  active          3.62T           1.23T           2.39T   33.98%

Qué significa: El “storage” en Proxmox no es una sola cosa. Un directorio se comporta distinto a LVM-thin, que a su vez es distinto a ZFS.

Decisión: Haz benchmarking en el backing store exacto donde viven los discos de VM. Si las VMs están en local-lvm, no midas /var/lib/vz y des por hecho nada.

Task 3: Comprobar la presión IO y IO wait en vivo

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 421232  91264 882012    0    0    12    44  520  880  6  2 91  1  0
 1  3      0 418904  91272 882140    0    0     0  3240  610  990  5  2 70 23  0
 1  2      0 419120  91280 882188    0    0     0  2800  590  970  5  2 74 19  0

Qué significa: La columna wa es CPU esperando IO. Un wa alto durante las quejas es una pista muy clara, pero no un veredicto final.

Decisión: Si wa es alto, ve directo a latencia por disco (iostat) y encolamiento; si wa es bajo, no te obsesiones primero con discos.

Task 4: Medir latencia y utilización de disco (el suero de la verdad más rápido)

cr0x@server:~$ iostat -x 1 3
Linux 6.8.12-4-pve (pve1) 	12/26/2025 	_x86_64_	(32 CPU)

Device            r/s   w/s  rkB/s  wkB/s  await  svctm  %util
nvme0n1         85.0 120.0  5120  19456    2.10   0.18  37.0
sda              2.0  95.0    64   4096   45.20   0.80  82.0
dm-0            10.0 110.0  1024  16384   39.10   0.00   0.0

Qué significa: await es la latencia media por petición. %util cercano a 100% significa saturación. Si sda muestra await 45ms y 82% util, ese disco es el problema aunque a pveperf le guste o no.

Decisión: Si await está consistentemente por encima de ~10ms para cargas SSD o por encima de ~30ms para HDD bajo carga normal, estás en territorio de “incidente de rendimiento”. Investiga la pila detrás de ese dispositivo.

Task 5: Ver quién está haciendo IO ahora mismo

cr0x@server:~$ pidstat -d 1 3
Linux 6.8.12-4-pve (pve1) 	12/26/2025 	_x86_64_	(32 CPU)

01:12:44 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
01:12:45 PM     0      2123      0.00  82124.00      0.00  vzdump
01:12:45 PM     0      3891      0.00  11200.00      0.00  pveproxy
01:12:45 PM     0     15322    512.00   9200.00      0.00  kvm

Qué significa: Esto liga la presión IO a un proceso. Si vzdump está golpeando con muchas escrituras, tu “ralentización aleatoria de VM” de repente es menos misteriosa.

Decisión: Limita las copias de seguridad, prográmalas o muévelas a almacenamiento separado. No culpes al hipervisor por tu estrategia de backups.

Task 6: Verificar que el escalado de frecuencia de CPU no sabotee los benchmarks

cr0x@server:~$ cpupower frequency-info | sed -n '1,12p'
analyzing CPU 0:
  driver: intel_pstate
  CPUs which run at the same hardware frequency: 0
  available cpufreq governors: performance powersave
  current policy: frequency should be within 800 MHz and 3500 MHz.
                  The governor "powersave" may decide which speed to use
  current CPU frequency: 900 MHz (asserted by call to hardware)

Qué significa: Si haces benchmarking con la CPU aparcada a 900 MHz, obtendrás resultados “absurdos” y culparás al almacenamiento por la pereza de la CPU.

Decisión: Para benchmarks repetibles, pon temporalmente el governor performance. En producción, elige de forma deliberada; no dejes que los valores por defecto decidan por ti.

Task 7: Cambiar al governor performance (temporalmente) y confirmarlo

cr0x@server:~$ sudo cpupower frequency-set -g performance
Setting cpu: 0
Setting cpu: 1
Setting cpu: 2
Setting cpu: 3
cr0x@server:~$ cpupower frequency-info | grep -E 'current policy|current CPU frequency'
  current policy: frequency should be within 800 MHz and 3500 MHz.
  current CPU frequency: 3401 MHz (asserted by call to hardware)

Qué significa: Eliminaste una variable. No se trata de “siempre ejecutar a máxima frecuencia”, se trata de hacer comparables las pruebas.

Decisión: Si el rendimiento cambia drásticamente después de esto, tu carga podría estar limitada por CPU o ser sensible a la latencia de scheduling.

Task 8: Confirmar salud del pool ZFS y detectar desalineaciones evidentes

cr0x@server:~$ zpool status -v
  pool: rpool
 state: ONLINE
  scan: scrub repaired 0B in 00:12:44 with 0 errors on Sun Dec 22 03:12:45 2025
config:

	NAME                        STATE     READ WRITE CKSUM
	rpool                       ONLINE       0     0     0
	  mirror-0                  ONLINE       0     0     0
	    nvme-SAMSUNG_MZVLB1T0   ONLINE       0     0     0
	    nvme-SAMSUNG_MZVLB1T0   ONLINE       0     0     0

errors: No known data errors

Qué significa: Un pool degradado, un resilver o errores de checksum hacen que cualquier benchmark sea sospechoso. Además, la hora del scrub indica actividad en segundo plano.

Decisión: Si no está ONLINE/healthy, arregla el almacenamiento primero. Hacer benchmarks en un pool enfermo solo cuantifica la tristeza.

Task 9: Inspeccionar settings de dataset ZFS que afectan IO de VM

cr0x@server:~$ zfs get -o name,property,value -s local recordsize,compression,atime,sync,primarycache,logbias rpool/data
NAME        PROPERTY      VALUE
rpool/data  recordsize    128K
rpool/data  compression   zstd
rpool/data  atime         off
rpool/data  sync          standard
rpool/data  primarycache  all
rpool/data  logbias       latency

Qué significa: recordsize y sync pueden hacer o deshacer IO tipo base de datos. primarycache=all puede expulsar caché útil bajo carga de VMs, dependiendo del tamaño de memoria.

Decisión: Si los discos de VM están en ZVOLs, también comprobarás volblocksize. Si ves sync=disabled en producción para bases de datos, detente y reevalúa tu postura de riesgo.

Task 10: Comprobar el tamaño de bloque de ZVOL (mismatch común con cargas)

cr0x@server:~$ zfs list -t volume
NAME                USED  AVAIL  REFER  MOUNTPOINT
rpool/vm-101-disk-0  64G   1.1T    64G  -
cr0x@server:~$ zfs get -H -o property,value volblocksize rpool/vm-101-disk-0
volblocksize	8K

Qué significa: volblocksize se establece al crear el ZVOL y no puede cambiarse después. 8K es común; a veces está bien, a veces amplifica la sobrecarga de escritura.

Decisión: Si tienes muchas escrituras aleatorias de 4K, 8K aún puede funcionar pero puede aumentar la amplificación de escritura. Si hospedas cargas secuenciales grandes, considera bloques mayores en volúmenes nuevos.

Task 11: Comprobar el scheduler de IO (especialmente en no-NVMe)

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

Qué significa: El scheduler afecta la latencia bajo contención. En muchos SSDs, mq-deadline es un valor sensato; en NVMe a menudo es none y eso está bien.

Decisión: No ajustes esto porque te aburres. Ajusta porque viste un síntoma de contención y puedes validar el cambio.

Task 12: Validar soporte TRIM/Discard (salud SSD, rendimiento a largo plazo)

cr0x@server:~$ lsblk -D
NAME         DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
sda                 0      512B       4G         0
nvme0n1             0        4K       2G         0
dm-0                0        0B       0B         0

Qué significa: DISC-GRAN distinto de cero indica capacidad de discard. Si nunca descartas en thin provisioning, el rendimiento puede degradarse a medida que el SSD pierde bloques libres internamente.

Decisión: Habilita discard donde corresponda (ZFS autotrim, timers fstrim, thin-lvm discard), pero entiende las compensaciones de latencia en tu entorno.

Task 13: Confirmar salud de la red para tráfico NFS/iSCSI/Ceph

cr0x@server:~$ ip -s link show dev eno1 | sed -n '1,12p'
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 3c:fd:fe:aa:bb:cc brd ff:ff:ff:ff:ff:ff
    RX:  bytes packets errors dropped  missed   mcast
    9876543210  8123456      0       12       0    12345
    TX:  bytes packets errors dropped carrier collsns
    8765432109  7345678      0        0       0       0

Qué significa: Las pérdidas importan. Algunas durante ráfagas pueden ser tolerables, un flujo constante no lo es. El almacenamiento sobre red es alérgico a la pérdida de paquetes.

Decisión: Si errores/drops aumentan, arregla la red antes de afinar almacenamiento. Si no, estarás midiendo retransmisiones.

Task 14: Ejecutar una prueba rápida de fio a nivel host en la ruta del datastore real

cr0x@server:~$ fio --name=randread --directory=/var/lib/vz --rw=randread --bs=4k --iodepth=32 --numjobs=4 --size=8G --time_based=1 --runtime=60 --direct=1 --group_reporting
randread: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=32
...
  read: IOPS=72.4k, BW=283MiB/s (297MB/s)(16.6GiB/60001msec)
    clat (usec): min=70, max=6200, avg=420.11, stdev=190.22
    clat percentiles (usec):
     |  1.00th=[  110],  5.00th=[  170], 10.00th=[  210], 50.00th=[  390]
     | 90.00th=[  690], 95.00th=[  900], 99.00th=[ 1400], 99.90th=[ 2400]

Qué significa: Esto ya es más honesto que pveperf. Obtienes IOPS, ancho de banda y percentiles de latencia. El percentil 99 te dice cómo son los “momentos malos”.

Decisión: Si p99 es demasiado alto para tu carga (las bases de datos suelen importar), necesitas reducir contención, cambiar la ruta sync o mejorar medios/controladoras —no perseguir un mayor MB/s.

Recetas de fio que responden preguntas reales

Fio es una motosierra: poderosa, peligrosa y ocasionalmente usada para cortar pan por personas a las que les gusta el caos. Úsala deliberadamente.

Regla: prueba donde vive la carga

Si las VMs corren en local-lvm, prueba un archivo en ese montaje o un dispositivo de bloque que lo represente (con extrema cautela). Si las VMs usan zvols ZFS, prueba en el zvol o en un archivo en el dataset que los respalda.

Receta 1: Lecturas aleatorias (4k) para “¿se comporta mi pool SSD?”

cr0x@server:~$ fio --name=rr4k --directory=/rpool --rw=randread --bs=4k --iodepth=64 --numjobs=4 --size=16G --time_based=1 --runtime=120 --direct=1 --group_reporting
rr4k: (g=0): rw=randread, bs=(R) 4096B-4096B, ioengine=libaio, iodepth=64
...
  read: IOPS=110k, BW=431MiB/s (452MB/s)(50.5GiB/120001msec)
    clat percentiles (usec):
     | 90.00th=[  520], 95.00th=[  740], 99.00th=[ 1300], 99.90th=[ 2200]

Interpretación: IOPS altos, p99 aceptable. Si p99.9 salta a decenas de milisegundos, probablemente tengas contención o un problema de sync/flush en otra parte.

Decisión: Si p99.9 es inaceptable, ve a telemetría (iostat, zpool iostat, ceph health) e identifica la fuente antes de “tunear”.

Receta 2: Escrituras aleatorias síncronas (4k) para modelar commits de base de datos

cr0x@server:~$ fio --name=rsw4k --directory=/rpool --rw=randwrite --bs=4k --iodepth=1 --numjobs=4 --size=8G --time_based=1 --runtime=120 --direct=1 --fsync=1 --group_reporting
rsw4k: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, ioengine=libaio, iodepth=1
...
  write: IOPS=8200, BW=32.0MiB/s (33.6MB/s)(3.75GiB/120001msec)
    clat (usec): min=120, max=48000, avg=1850.22
    clat percentiles (usec):
     | 90.00th=[ 3200], 95.00th=[ 5800], 99.00th=[18000], 99.90th=[42000]

Interpretación: Las escrituras síncronas exponen la ruta real de durabilidad. Esos picos en cola son lo que causa “la app se congela cada minuto”.

Decisión: Si esto es malo: verifica sync de ZFS, presencia/calidad de SLOG (si se usa), política de caché de la controladora y si tu almacenamiento “rápido” realmente confirma escrituras de forma segura.

Receta 3: Throughput secuencial de lectura (1M) para expectativas de backup/restore

cr0x@server:~$ fio --name=sr1m --directory=/rpool --rw=read --bs=1M --iodepth=16 --numjobs=1 --size=32G --time_based=1 --runtime=120 --direct=1 --group_reporting
sr1m: (g=0): rw=read, bs=(R) 1024KiB-1024KiB, ioengine=libaio, iodepth=16
...
  read: BW=1710MiB/s (1793MB/s)(200GiB/120001msec)

Interpretación: De aquí vienen a veces los felices números de pveperf. Útil para planificar ventanas de migración, no para predecir latencia de BD.

Decisión: Si lo secuencial va genial pero las escrituras sync aleatorias son terribles, tienes un problema de durabilidad/latencia, no un problema de “disco lento”.

Receta 4: Mix lectura/escritura (70/30) aleatorio para imitar churn general de VMs

cr0x@server:~$ fio --name=mix7030 --directory=/var/lib/vz --rw=randrw --rwmixread=70 --bs=16k --iodepth=32 --numjobs=4 --size=16G --time_based=1 --runtime=180 --direct=1 --group_reporting
mix7030: (g=0): rw=randrw, bs=(R) 16.0KiB-16.0KiB, (W) 16.0KiB-16.0KiB, ioengine=libaio, iodepth=32
...
  read: IOPS=18.2k, BW=284MiB/s (298MB/s)
  write: IOPS=7810, BW=122MiB/s (128MB/s)
    clat percentiles (usec):
     | 90.00th=[ 1400], 95.00th=[ 2200], 99.00th=[ 5200], 99.90th=[12000]

Interpretación: IO mixto es donde las pilas de almacenamiento muestran sus modales. Observa p99/p99.9; esa es tu zona de “las VMs se sienten lentas”.

Decisión: Si la latencia se dispara con IO mixto, afina el scheduling, aísla vecinos ruidosos o separa cargas en pools distintos.

Broma #2: Si ejecutas fio en la ruta equivocada, demostrará con fidelidad que tu almacenamiento es más rápido que tu capacidad para leer tus propios mountpoints.

ZFS en Proxmox: trampas y las pruebas correctas

ZFS es un sistema de archivos de grado producción que asume que te importa la integridad. También asume que lo culparás por tus benchmarks si no entiendes cómo compromete datos. Arreglemos eso.

Qué hace difícil el benchmarking de ZFS

  • Copy-on-write significa que pequeñas escrituras aleatorias pueden amplificarse en más IO del esperado, dependiendo de recordsize/volblocksize y fragmentación.
  • Los grupos de transacciones agrupan escrituras; el rendimiento puede parecer por ráfagas. Una prueba corta puede capturar solo la parte “buena”.
  • ARC (caché en RAM) hace que las lecturas se vean increíbles hasta que dejan de serlo. Si quieres números de disco, usa --direct=1 y haz que el working set sea mayor que la RAM.
  • Las escrituras síncronas o se confirman de forma segura o no. ZFS se lo toma en serio; los benchmarks que lo ignoran están midiendo otro contrato.

Visibilidad en host: zpool iostat es tu amigo

cr0x@server:~$ zpool iostat -v 1 3
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
rpool       1.23T  2.39T  8.20K  3.10K   220M  64.0M
  mirror    1.23T  2.39T  8.20K  3.10K   220M  64.0M
    nvme0n1     -      -  4.10K  1.55K   110M  32.0M
    nvme1n1     -      -  4.10K  1.55K   110M  32.0M
----------  -----  -----  -----  -----  -----  -----

Qué significa: Esto te dice qué está empujando ZFS a cada dispositivo. Si fio dice “100k IOPS” pero zpool iostat muestra operaciones modestas, probablemente estás golpeando caché o la prueba no llega a los discos.

Decisión: Alinea parámetros de fio (direct IO, tamaño de archivo) hasta que zpool iostat refleje actividad significativa en los dispositivos.

Semánticas sync: no trates el SLOG como un amuleto mágico

Un SLOG dedicado solo puede ayudar para escrituras síncronas. Y solo si es rápido, de baja latencia y seguro ante pérdida de energía. Un SSD de consumo aleatorio como SLOG es una excelente forma de convencerte de cosas imposibles.

Si usas SLOG, prueba explícitamente escrituras sync y observa percentiles de latencia. Si no hay mejora, el cuello de botella está en otra parte (CPU, layout de vdev, o no estabas realmente limitado por sync).

Compresión: genial en producción, confusa en benchmarks

La compresión puede hacer que tu almacenamiento parezca más rápido al escribir menos bytes. Eso no es “hacer trampa”: es un beneficio real, pero complica comparaciones. Si pruebas datos aleatorios, la compresión no ayudará. Si pruebas ceros, parecerá absurdamente bueno.

Decide qué quieres medir: medio crudo o rendimiento efectivo de la carga. Luego genera datos en consecuencia.

Ceph en Proxmox: medir sin engañarse

Ceph es almacenamiento distribuido. Eso significa que tu benchmark es realmente una prueba de red, medios OSD, replicación, CPU y salud del clúster. Si ejecutas una prueba mientras el clúster está haciendo backfill, estarás midiendo comportamiento de recuperación, no rendimiento en estado estable.

Comprueba la salud del clúster antes de medir

cr0x@server:~$ ceph -s
  cluster:
    id:     2c1e3a6d-9e4d-4a4d-9b2e-1a2b3c4d5e6f
    health: HEALTH_OK

  services:
    mon: 3 daemons, quorum pve1,pve2,pve3
    mgr: pve1(active), standbys: pve2
    osd: 9 osds: 9 up, 9 in

  data:
    pools:   3 pools, 256 pgs
    objects: 1.12M objects, 4.3TiB
    usage:   12TiB used, 18TiB / 30TiB avail
    pgs:     256 active+clean

Qué significa: active+clean PGs y HEALTH_OK es tu línea base. Cualquier otra cosa significa que tus números reflejarán comportamiento de mantenimiento.

Decisión: Si no está clean, pospone el benchmarking o etiqueta explícitamente que es “rendimiento en estado degradado”.

Medir throughput e IOPS bruto de Ceph (y saber qué representa)

cr0x@server:~$ rados bench -p rbd 60 write --no-cleanup
hints = 1
Maintaining 16 concurrent writes of 4194304 bytes to objects of size 4194304 for up to 60 seconds or 0 objects
...
Total written: 2388 MiB
Bandwidth (MB/sec): 39.8
Average IOPS: 9
Average Latency(s): 1.72

Qué significa: Esta es una prueba a nivel de clúster usando objetos RADOS, no necesariamente igual al rendimiento RBD para VMs. Aun así, expone “¿el clúster es fundamentalmente lento?”.

Decisión: Si el ancho de banda es bajo y la latencia alta, comprueba la red (MTU, drops), latencia de discos OSD y saturación CPU. No “optimices Proxmox” primero.

Validar calidad del camino de red para Ceph (latencia y pérdida)

cr0x@server:~$ ping -c 20 -i 0.2 pve2
PING pve2 (10.10.10.12) 56(84) bytes of data.
64 bytes from 10.10.10.12: icmp_seq=1 ttl=64 time=0.286 ms
...
20 packets transmitted, 20 received, 0% packet loss, time 3804ms
rtt min/avg/max/mdev = 0.251/0.302/0.401/0.038 ms

Qué significa: Ceph odia el jitter. Un promedio bajo es bueno; una varianza baja es mejor.

Decisión: Si ves pérdida o alta varianza, arregla switching, NICs, bonding o congestión antes de tocar tunables de Ceph.

El benchmarking de Ceph merece su propio libro, pero el principio permanece: mide salud primero, luego el servicio de almacenamiento, luego la experiencia VM. Si saltas capas, acabarás afinando síntomas.

Tres microhistorias corporativas desde el terreno

Microhistoria 1: El incidente causado por una suposición equivocada

En una empresa mediana con un clúster Proxmox, un equipo reemplazó un SAN envejecido por espejos NVMe locales usando ZFS. La migración fue fluida. pveperf lucía fantástico. Todos chocaron las manos y se fueron a casa a una hora razonable, que debería haber sido la primera pista de que algo iba mal.

Dos semanas después, el portal de clientes empezó a hacer timeouts en horas pico. No constantemente—lo justo para multiplicar tickets de soporte. El ingeniero on-call revisó CPU y memoria. Bien. La red parecía limpia. Los gráficos de almacenamiento mostraban “alto throughput”, así que mentalmente se absolvió al almacenamiento.

El verdadero culpable: la carga más importante era una base de datos ejecutándose en una imagen de VM con fuerte comportamiento de escrituras síncronas. ZFS hacía lo correcto: respetar las semánticas sync. Pero el benchmark que usaron para aprobar la migración era mayormente secuencial, en su mayoría buffered y corto. Midió la ruta fácil.

Cuando ejecutaron fio con --fsync=1 y miraron la latencia p99, la historia cambió. La latencia tail era brutal en pico. No necesitaban “más MB/s”; necesitaban una ruta de escritura sync mejor y menos contención durante ráfagas de commits.

La solución fue aburrida: separar el almacenamiento de la VM de la base de datos en un pool con características de latencia predecible, afinar el dataset para la carga y dejar de tomar un solo número de pveperf como garantía. Tras eso, el portal dejó de fallar.

Microhistoria 2: La optimización que salió mal

Otro entorno corría cargas mixtas: runners de CI, caches de compilación, un par de bases de datos y muchas VMs de propósito general. Alguien leyó que “desactivar sync mejora el rendimiento de ZFS”, vio sync=disabled en un foro y lo aplicó al dataset que alojaba discos de VM.

Los resultados inmediatos del benchmark fueron espectaculares. pveperf subió. fio sin fsync fue básicamente un reel de éxitos. La dirección estaba contenta, porque a la dirección siempre le gustan las gráficas que suben.

Entonces un host se cayó durante un evento de energía. El UPS hizo lo que pudo; la realidad hizo lo que hace. Varias VMs volvieron con sistemas de archivos corruptos y estado de aplicación inconsistente. El problema no fue que ZFS “perdiera datos” aleatoriamente—hizo exactamente lo que le dijeron: confirmar escrituras que no estaban garantizadas como durables.

La optimización también enmascaró el problema real de rendimiento: el sistema estaba limitado por sync y necesitaba o mejor hardware para la ruta sync o ajustes a nivel de aplicación. En vez de eso, cambiaron el contrato y lo pagaron luego en tiempo de recuperación, pérdida de confianza y una semana de reuniones incómodas.

Revirtieron el comportamiento sync, documentaron la razón y construyeron un suite de benchmarks que prueba explícitamente latencia de escrituras sync. El mejor truco de rendimiento es no mentirle a tu yo futuro.

Microhistoria 3: La práctica aburrida pero correcta que salvó el día

Una organización financiera ejecutaba Proxmox con Ceph para almacenamiento de VMs. Nada glamuroso. Mucha presión de cumplimiento. El equipo SRE mantenía una práctica simple: cada trimestre ejecutaban el mismo conjunto de benchmarks en condiciones controladas y almacenaban resultados con snapshots de salud del clúster.

No era nada sofisticado. Un par de perfiles de fio en VMs respaldadas por RBD, un chequeo sanity con rados bench y capturas de telemetría a nivel host (iostat, ceph -s, contadores NIC). También ejecutaban benchmarks tras cualquier actualización mayor o cambio de hardware. Mismos parámetros. Mismo runtime. Mismo almacenamiento de resultados.

Un trimestre, los resultados cambiaron sutilmente: el throughput secuencial estaba bien, pero la latencia p99 en escrituras aleatorias subió. No lo suficiente para un incidente mayor. Suficiente para sospechar. Como tenían líneas base históricas, el cambio fue indiscutible en lugar de discutible.

La causa raíz fue una actualización de firmware en un lote de SSDs que cambió el comportamiento de flush bajo ciertas profundidades de cola. Sin la rutina aburrida, lo habrían descubierto sólo tras un outage. En cambio, aislaron nodos afectados, retrocedieron firmware donde fue posible y ajustaron planes de mantenimiento.

El día se salvó por una hoja de cálculo y consistencia. Sin heroísmos. Solo supervisión adulta.

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

1) “pveperf dice 1500 MB/s pero las VMs son lentas”

Síntoma: Grandes números en pveperf, rendimiento interactivo lento, picos en BD.

Causa raíz: pveperf golpeó caché o midió throughput secuencial; tu carga es IO aleatorio con requisitos sync.

Solución: Ejecuta fio con --direct=1, tamaño de archivo > RAM e incluye pruebas de escritura síncrona (--fsync=1). Decide según latencia p99, no por MB/s pico.

2) “fio muestra números increíbles el lunes, terribles el martes”

Síntoma: Varianza de benchmark que no puedes explicar.

Causa raíz: Actividad en segundo plano: scrub/resilver ZFS, backfill de Ceph, backups, TRIM o throttling térmico del SSD.

Solución: Captura el estado del sistema (zpool status, ceph -s, trabajos de backup), extiende runtime para alcanzar estado estable y vuelve a ejecutar en horas controladas.

3) “La latencia de escrituras aleatorias es terrible, pero los discos casi no están utilizados”

Síntoma: iostat muestra %util modesto, pero fio p99 es feo.

Causa raíz: Comportamiento de flush/sync, caché de escritura deshabilitada, SLOG pobre o jitter de almacenamiento en red causando pausas no reflejadas en %util.

Solución: Verifica política de caché del controlador, comportamiento sync de ZFS, hardware SLOG y pérdidas/latencia de red. Mide con patrones fio que respeten sync.

4) “El rendimiento de Ceph es inconsistente y empeora tras fallos”

Síntoma: IO de VM baja durante outages o reinicios de nodos.

Causa raíz: Recuperación/backfill compite con IO cliente; red sobresuscrita; discos OSD saturados.

Solución: Haz benchmarks solo cuando active+clean. Si es inaceptable operativamente, ajusta prioridades de recuperación y planificación de capacidad, e aisla tráfico Ceph.

5) “Pasar a SSDs más rápidos no ayudó la latencia de la base de datos”

Síntoma: Mejor throughput secuencial, mismos stalls de commit.

Causa raíz: El cuello de botella está en la ruta de escrituras sync (latencia de flush), scheduling de CPU o contención en pool compartido.

Solución: Mide latencia de escrituras sync explícitamente; separa cargas; asegura CPU suficiente y evita vecinos ruidosos; valida protección ante pérdida de energía en la ruta de confirmación de escritura.

6) “Benchmark dentro de la VM parece bien; usuarios siguen quejándose”

Síntoma: Herramientas del invitado muestran rendimiento aceptable, pero la app real sufre.

Causa raíz: El benchmark en el invitado no coincide con el patrón IO de la app; o la contención en host causa picos de latencia que los promedios ocultan.

Solución: Captura percentiles de latencia a nivel host (fio en host, iostat, estadísticas zpool/ceph) durante las ventanas de quejas. Compara p95/p99, no promedios.

7) “Tras activar compresión, los benchmarks se duplicaron”

Síntoma: De repente throughput enorme en escrituras, ancho de banda físico sospechosamente bajo.

Causa raíz: Los datos del benchmark se comprimen extremadamente bien (ceros o patrones repetidos), midiendo CPU+compresión en lugar de límites de disco.

Solución: Usa datos incompresibles para pruebas de medio crudo (fio --buffer_compress_percentage=0 y --refill_buffers=1), o indica explícitamente que mides rendimiento efectivo con compresión.

Listas de verificación / plan paso a paso

Paso a paso: construye una línea base de benchmarking confiable para Proxmox

  1. Elige la pregunta. Ejemplo: “¿Puede este host sostener escrituras sync 4k con p99 < 5ms para 10 VMs?”
  2. Identifica la ruta de almacenamiento exacta. Usa pvesm status y la configuración de disco de la VM para encontrarla.
  3. Comprueba salud. ZFS: zpool status. Ceph: ceph -s. SMART/NVMe health si aplica.
  4. Estabiliza el entorno. Pausa scrubs/backfills si es posible, evita backups durante la ejecución y documenta lo que no pudiste parar.
  5. Controla el escalado de CPU para la prueba. Ajusta el governor de forma intencional (temporal).
  6. Corre telemetría en paralelo. Mantén iostat -x y zpool iostat o métricas de Ceph en ejecución.
  7. Ejecuta fio con direct IO y working set realista. Tamaño > RAM, runtime 120–300s para SSD, más largo para HDD/Ceph si hace falta.
  8. Captura percentiles. Registra p50/p95/p99/p99.9. Si tu herramienta no los muestra, vas a ciegas.
  9. Repite tres veces. Si no puedes repetirlo, no puedes confiar en ello.
  10. Anota la configuración. Propiedades ZFS, layout RAID, versiones de firmware, velocidades NIC, MTU, tamaño de réplica Ceph.
  11. Decide según SLOs. Throughput para backups, percentiles de latencia para bases de datos, IO mixto para clusters de VM.
  12. Almacena resultados con contexto. Un número sin condiciones es trivia.

Checklist rápida: antes de culpar al almacenamiento

  • ¿La VM está haciendo swap? (presión de memoria invitada puede parecer lentitud de almacenamiento)
  • ¿El host está en IO wait? (vmstat)
  • ¿Hay drops en redes de almacenamiento? (ip -s link)
  • ¿Hay backup/scrub/backfill en curso? (pidstat, zpool status, ceph -s)
  • ¿Estás midiendo el datastore correcto? (pvesm status)
  • ¿La CPU está escalando hacia abajo? (cpupower frequency-info)

Preguntas frecuentes

1) ¿Debería dejar de usar pveperf?

No. Úsalo como prueba de humo e indicio de inventario (“¿qué dispositivo respalda esta ruta?”). Deja de usarlo como herramienta de compra o predictor de SLOs de rendimiento.

2) ¿Por qué pveperf mejora después de ejecutarlo una vez?

Las cachés se calientan. Página de caché, ARC, cachés internas de dispositivos. La segunda ejecución suele ser “más rápida” porque mides caché de memoria y metadatos, no discos.

3) ¿Cuál es la métrica más útil para rendimiento de almacenamiento en Proxmox?

Latencia bajo carga, especialmente p95/p99, correlacionada con latencia a nivel host (iostat -x await) y encolamiento.

4) ¿Debería medir en el host o dentro de la VM?

Ambos, pero para preguntas distintas. Benchmarks en host validan la capacidad del stack de almacenamiento. En la VM validan la ruta de drivers del invitado y la realidad de la VM. Si discrepan, la brecha suele estar en ajustes de virtualización, modos de caché o contención.

5) ¿Cómo evito medir RAM por accidente?

Usa fio con --direct=1, elige un tamaño de prueba mayor que la RAM y confirma con zpool iostat/iostat que los dispositivos realmente trabajan.

6) ¿Por qué mi throughput secuencial se ve genial pero mi base de datos es lenta?

Las bases de datos suelen ser intensivas en sync y IO aleatorio. Los benchmarks secuenciales mayormente te dicen qué tan rápido irán backups y restores, no commits.

7) ¿Es aceptable activar ZFS sync=disabled alguna vez?

Puede ser aceptable para cargas no críticas y reconstruibles donde no se requiere durabilidad. Para bases de datos y discos VM importantes, normalmente es una decisión de riesgo que merece justificación escrita y un plan de rollback.

8) ¿Qué runtime debo usar en fio?

Lo bastante largo para alcanzar estado estable: a menudo 120–300 segundos para SSDs, más para arrays HDD y almacenamiento distribuido. Si tu SSD tiene una gran caché SLC, una prueba de 30 segundos es un demo de marketing.

9) ¿Cómo benchmarkear Ceph justamente?

Solo mide cuando HEALTH_OK y los PGs están active+clean, aísla tráfico Ceph en una red fiable y prueba tanto en capa RADOS (rados bench) como en capa VM/RBD (fio en almacenamiento RBD-backed).

10) Mis números de fio son menores que pveperf. ¿Cuál es correcto?

Normalmente fio, si lo configuras bien (direct IO, tamaño realista, ruta correcta, modelo sync apropiado). pveperf suele medir un problema distinto y más fácil.

Conclusión: siguientes pasos que realmente funcionan

Si pveperf “se ve bien” pero los usuarios se quejan, cree a los usuarios. Luego demuéstralo con mediciones que modelen tu carga.

  1. Ejecuta el guion de diagnóstico rápido para identificar si estás limitado por CPU, disco o red.
  2. Haz benchmarks con fio en el datastore real usando direct IO, tamaños de working set realistas y percentiles.
  3. Para ZFS, prueba escrituras sync explícitamente y valida propiedades de pool/dataset. No confundas ancho de banda secuencial con rendimiento de durabilidad.
  4. Para Ceph, mide solo cuando esté healthy y trata la calidad de red como parte del rendimiento de almacenamiento.
  5. Almacena tus resultados con contexto y repítelos tras cambios. La línea base aburrida es cómo capturas regresiones antes de que te suenen las alertas.

Hacer benchmarking bien no te dará un número mágico. Te dará un mapa de límites—y una forma de dejar de discutir con gráficas que nunca tuvieron que soportar tráfico de producción.

← Anterior
Contenido mixto en WordPress: por qué HTTPS sigue mostrando advertencias y cómo arreglarlo correctamente
Siguiente →
PostgreSQL vs Aurora PostgreSQL: sorpresas de costos durante picos (y cómo evitarlas)

Deja un comentario