Ejecutaste fio, obtuviste un número heroico, lo enviaste a compras y seis semanas después la producción parece que avanza entre azúcar espeso.
Ahora todos miran “el almacenamiento” como si fuera un villano consciente.
Los benchmarks sintéticos no solo fallaron al predecir la realidad—te convinieron activamente de lo contrario de lo que era cierto.
Eso no es mala suerte. Es un modo de fallo. Y puedes aprender a identificarlo rápido, antes de que se lance.
Qué son los benchmarks sintéticos (y qué asumen en silencio)
Un benchmark sintético es una carga de trabajo diseñada: eliges la mezcla de lectura/escritura, el tamaño de bloque, la profundidad de la cola, el número de hilos, la aleatoriedad, la duración y el tamaño del conjunto de datos.
Es una rata de laboratorio. Útil. También no son tus usuarios.
La mentira no es que las herramientas sintéticas sean “erróneas”. La mentira es que son incompletas por defecto, y la gente trata la salida como una orden de compra.
El rendimiento del almacenamiento es una propiedad del sistema: hardware, firmware, kernel, sistema de archivos, controladores, multipath, red, virtualización y el vecino ruidoso que no sabías que existía.
El contrato del benchmark que no leíste
Cada resultado sintético viene con suposiciones no declaradas. Cuando ejecutas “4k randread QD=64”, estás afirmando:
- Que tu carga real lee en fragmentos de 4k (o al menos se comporta de forma similar en la capa de E/S).
- Que tu carga puede mantener profundidad de cola 64 sin bloquearse corriente arriba.
- Que tu aplicación tolera la misma distribución de latencias, no solo la misma media.
- Que tus cachés (page cache, caché del controlador, CDN, caché de la app) se comportan de forma similar.
- Que la ruta de E/S es la misma: mismo sistema de archivos, mismas opciones de montaje, mismo cifrado/compresión, mismas configuraciones de replicación.
En producción, esas suposiciones son masacradas por la realidad. El benchmark aún imprime un número limpio. Esa es la parte peligrosa.
Aquí está el modelo mental que te mantiene honesto: los benchmarks no miden la “velocidad del disco”. Miden una tubería bajo un conjunto muy específico de condiciones.
Cambia las condiciones, cambia la historia.
Broma #1: Los benchmarks sintéticos son como los currículos—todo el mundo parece increíble hasta que llamas a las referencias y descubres que “experto en Kubernetes” significaba “una vez abrió el panel de control”.
Cómo mienten los benchmarks sintéticos: los mecanismos habituales
Los benchmarks “mienten” de formas predecibles. Si aprendes los patrones, puedes atraparlos temprano—a veces solo mirando el gráfico y haciendo una pregunta desagradable.
1) Caché, caché, caché (y el benchmark que nunca tocó el disco)
El clásico: tu benchmark lee los mismos datos repetidamente y la caché de páginas del SO los sirve desde RAM.
O la caché write-back de un controlador RAID absorbe escrituras y luego las vuelca al disco mientras el benchmark celebra.
Las cargas reales no suelen tener caché cálida infinita. Tienen localidad parcial, tormentas de expulsión y “iba rápido hasta las 09:03”.
Los benchmarks que no dimensionan el conjunto de datos más allá de la caché solo están midiendo ancho de banda de memoria con pasos extra.
2) Fantasía de profundidad de cola: QD=64 no es “más realista”, es “otro universo”
Una alta profundidad de cola infla el rendimiento en dispositivos que pueden reordenar y paralelizar internamente. NVMe lo adora. SATA lo tolera. Las redes a veces fingen.
Pero las aplicaciones pueden nunca generar ese tipo de concurrencia porque bloquean en locks, puntos de compromiso, idas y vueltas RPC o CPU.
Si tu app es single-threaded o está serializada por un fsync de WAL de base de datos, los resultados con QD=64 son trivialidades.
Debes medir con la profundidad de cola que tu sistema puede sostener de extremo a extremo.
3) Teatro del tamaño de bloque: “IOPS” sin tamaño de bloque es insignificante
1M de rendimiento secuencial y 4k de IOPS aleatorios son deportes distintos. Un sistema puede brillar en uno y ser un desastre en el otro.
A algunos proveedores les encanta mostrar la métrica que los favorece. A algunos ingenieros también, si somos sinceros.
Si tu carga es “muchas lecturas pequeñas de metadatos” y mides “lectura secuencial de 128k”, no mediste tu carga. Mediaste tus esperanzas.
4) Las medias de latencia son fan fiction del rendimiento
Las medias ocultan lo que hace sonar tu on-call: latencia en la cola (p95, p99, p99.9) y picos de latencia.
Muchas pruebas sintéticas informan una media que parece bien mientras que p99 es una pesadilla.
Lo que importa depende del sistema. Para un sistema de colas, p99 puede impulsar reintentos, timeouts y fallos en cascada.
Para una base de datos, unos pocos fsyncs largos pueden bloquear commits y crear hordas estruendosas.
5) “Direct IO” vs IO en búfer: elige mal y mides el subsistema equivocado
El IO en búfer incluye comportamiento del page cache, writeback y umbrales de páginas sucias. El Direct IO evita el page cache y cambia requisitos de alineación.
En producción suele ser una mezcla: las bases de datos usan Direct IO para archivos de datos pero dependen de IO en búfer en otros lugares; los servicios pueden almacenar lecturas en búfer sin querer.
Si mides con --direct=1 y tu carga usa mayormente lecturas en búfer, subestimarás el efecto del caché. Si mides en búfer pero esperas semántica direct, prometerás de más.
Elige el modo de IO que coincida con la ruta real de tu aplicación, no la preferencia del que corre el benchmark.
6) Sistema de archivos y opciones de montaje: el multiplicador invisible
Ext4 con data=ordered se comporta distinto de XFS bajo presión de metadatos. ZFS tiene su propio universo (ARC, recordsize, comportamiento sync).
Opciones de montaje como noatime pueden eliminar escrituras de metadatos. Opciones como barriers, modo de journaling y discard pueden desplazar la latencia.
Los benchmarks sintéticos se ejecutan en un sistema de archivos vacío con localidad perfecta. La producción está fragmentada, tiene millones de inodos y carga concurrente.
7) El estado del dispositivo importa: los SSD recién sacados de la caja también mienten
Muchos SSDs rinden más cuando están vacíos debido a cachés SLC y flash limpio. Bajo escrituras aleatorias en estado estacionario, la recolección de basura y el wear leveling aparecen.
Una “prueba rápida” puede mostrar una fantasía que colapsa tras horas o días de actividad real.
8) Compactación, checksum, cifrado, replicación: el trabajo real cuesta ciclos reales
Las pilas de almacenamiento a menudo hacen trabajo extra: checksums, compresión, cifrado en reposo, deduplicación, replicación, codificación por borrado, snapshots.
Los benchmarks sintéticos que no activan las mismas funciones no están midiendo tu sistema. Están midiendo otro.
9) Virtualización y vecinos: benchmarkeaste el host; la producción vive en el edificio de apartamentos
En infraestructura compartida no posees el controlador, la caché, el uplink de red o el horario de “alguien está haciendo una copia de seguridad”.
Tu benchmark pudo correr de noche, solo. La producción corre al mediodía, con mil hermanos.
10) El benchmark se convierte en la carga (y todo se optimiza para él)
Los ingenieros ajustan sysctls y planificadores de E/S hasta que fio se ve genial, y luego lo envían. El benchmark se vuelve la prueba de aceptación.
El sistema ahora está optimizado para el patrón sintético, a veces a costa de cargas mixtas o latencia.
Broma #2: Si ajustas un sistema hasta que el benchmark es perfecto, felicidades—has entrenado con éxito tu almacenamiento para aprobar un examen estandarizado.
Hechos e historia interesantes (sí, importa)
- IOPS se puso de moda porque los HDDs eran malos en I/O aleatorio. Las discusiones empresariales tempranas se obsesionaban con “cuántas lecturas aleatorias de 4k” porque los discos eran el cuello de botella.
- La latencia media se reportaba históricamente porque era fácil. La latencia de cola se volvió mainstream más tarde, cuando los sistemas distribuidos a gran escala hicieron que los picos p99 fueran un problema de fiabilidad.
- La caché write-back del controlador RAID puede hacer que pequeños benchmarks de escritura parezcan sobrenaturales. A menudo es una caché DRAM con batería—rápida hasta que debe vaciarse a los discos.
- Los SSDs tienen modos de “ráfaga corta” (por ejemplo, caché SLC) que distorsionan pruebas breves. Muchos dispositivos están diseñados para verse bien en tests cortos y trazas de consumo.
- El page cache de Linux puede satisfacer lecturas sin tocar el almacenamiento en absoluto. A menos que uses Direct IO o dimensionas el dataset correctamente, estás midiendo RAM.
- Los planificadores de E/S evolucionaron porque distintos medios necesitaban distintos encolamientos. Lo que ayudaba a discos rotacionales (reordenar seeks) puede ser irrelevante o dañino en NVMe.
- “fsync() lo hace real” es solo parcialmente cierto. Dispositivos y controladores pueden reconocer escrituras antes de persistirlas a menos que las barreras, ajustes de caché y protección ante pérdida de energía estén alineados.
- Los discos cloud suelen anunciar rendimiento/IOPS separado de latencia. Puedes alcanzar objetivos de IOPS mientras aún fallas SLOs porque la latencia de cola es lo que sienten los usuarios.
- Algunos suites de benchmarks se convirtieron en herramientas de compras. Una vez que un número determina una compra, los proveedores optimizan para él, a veces sin mejorar cargas reales.
Una idea útil parafraseada de W. Edwards Deming: cuando una métrica se convierte en objetivo, deja de ser una buena métrica. La versión para almacenamiento es simple:
si “fio IOPS” es tu meta, obtendrás fio IOPS—ya sea que tu base de datos deje de agotar timeouts o no.
Tres micro-historias del mundo corporativo
Micro-historia #1: El incidente causado por una suposición equivocada
Una compañía SaaS mediana migró de NVMe local a una plataforma de bloques respaldada por red.
El plan de migración se aprobó porque una prueba sintética mostró “IOPS similares” y “mayor throughput”. La presentación estaba impecable.
La primera semana tras el cambio, la latencia cara al cliente se elevó cada mañana. No fue una caída total, solo un sangrado lento: timeouts, reintentos y una cola en crecimiento.
El equipo on-call miró CPU y memoria—bien. ¿Red? Bien. El panel de almacenamiento mostraba IOPS por debajo del límite anunciado.
“Así que no puede ser el almacenamiento,” dijo alguien, que es una frase que ha terminado muchas carreras felices.
Asumían que la capacidad de IOPS implicaba estabilidad de latencia.
La diferencia oculta eran escrituras intensivas en fsync. La aplicación usaba una base de datos con durabilidad estricta en commit.
El benchmark sintético era mayormente lecturas aleatorias con profundidad de cola alta y grandes lotes. En producción había muchas escrituras sincronizadas pequeñas con concurrencia modesta.
Bajo la carga matutina, la latencia de cola del sistema de almacenamiento subió y la latencia de commit se amplificó hasta latencia de petición.
La solución no fue “más IOPS”. Fue alinear la carga de trabajo: medir la latencia de escritura sincronizada a la concurrencia que la base de datos realmente produce.
Al final ajustaron el tipo de volumen y afinaron los parámetros de commit de la base de datos con cuidado, y dejaron de aprobar cambios de almacenamiento basándose en un solo perfil de fio.
La lección fue dolorosamente simple: no puedes razonar a partir del benchmark equivocado.
Los incidentes de almacenamiento suelen ser causados por un desajuste entre las condiciones medidas y las condiciones de producción, no por que un componente “se haya puesto más lento”.
Micro-historia #2: La optimización que resultó contraproducente
Un equipo de plataforma de datos tenía una carga por lotes nocturna. Estaban orgullosos de su disciplina de benchmarks: cada nuevo tipo de nodo corría la misma suite sintética.
Un ingeniero notó que cambiar el planificador de E/S y aumentar la profundidad de cola hizo que los números del benchmark saltaran.
Implementaron el ajuste en toda la flota y declararon victoria.
Dos semanas después, las consultas interactivas diurnas comenzaron a mostrar fluctuaciones.
Nada catastrófico, solo suficiente latencia de cola para que los paneles se sintieran pegajosos y el on-call se pusiera de mal humor.
El ajuste había optimizado el throughput bajo alta concurrencia, pero cambió la equidad bajo cargas mixtas.
El problema real fue la contención: el planificador y las configuraciones de cola permitieron que la E/S por lotes dominara los intervalos de tiempo del dispositivo.
Los benchmarks sintéticos no incluían una carga sensible a la latencia compitiendo, así que nunca mostraron el hambre por recursos.
La producción sí lo hizo.
Revertir el ajuste mejoró el p99 de las consultas inmediatamente, mientras que el throughput por lotes cayó ligeramente.
El equipo aprendió a medir escenarios “modo mixto”: un trabajo que empuja throughput mientras otro mide latencia.
También aprendieron que un ajuste que embellece un benchmark puede ser un impuesto sobre la experiencia del usuario.
Micro-historia #3: La práctica aburrida pero correcta que salvó el día
Un equipo de servicios financieros operaba una plataforma de almacenamiento con control de cambios estricto. No eran glamorosos al respecto.
Antes de cualquier actualización, capturaban una línea base: versiones de firmware del dispositivo, ajustes de cola, opciones de montaje del sistema de archivos y un pequeño conjunto de pruebas representativas de la carga.
Guardaban resultados con marcas de tiempo y versiones del kernel. Era aburrido. También era una máquina del tiempo.
Tras una actualización rutinaria del kernel, vieron un aumento sutil en la latencia de escritura p99. Los usuarios casi no lo notaron—hasta que llegó la carga de fin de mes.
Porque tenían líneas base, pudieron decir “esta deriva comenzó exactamente después de la actualización,” no “el almacenamiento se siente raro últimamente.”
Eso acotó la búsqueda a cambios en la pila de E/S, no a un vago “tal vez el hardware está fallando.”
Usaron sus trabajos fio de referencia más métricas a nivel de aplicación para confirmar la regresión.
Luego compararon ajustes de la capa de bloques y hallaron que un valor por defecto cambió en su entorno (el comportamiento de encolamiento y la selección del planificador diferían en el nuevo kernel).
Restauraron el comportamiento previo y programaron una prueba de seguimiento controlada para probar los nuevos valores por defecto correctamente.
El fin de mes pasó sin drama. Nadie celebró. Ese es el punto.
La práctica que los salvó no fue un benchmark mágico; fue medición repetible, atribución de cambios y negarse a “ajustar a ciegas.”
Guía de diagnóstico rápido: qué verificar primero/segundo/tercero
Cuando “el almacenamiento está lento”, necesitas un embudo rápido. No un proyecto de benchmarking de una semana. Aquí está el orden que suele encontrar la verdad rápidamente.
Primero: prueba si es latencia, throughput o saturación
- Mira la latencia de cola (p95/p99), no solo la media.
- Revisa la utilización: ¿está el dispositivo al 100% ocupado? ¿La cola está creciendo?
- Correlaciona con la carga: ¿cambió la concurrencia? ¿Empezó una copia de seguridad? ¿Se activó una compactación?
Segundo: localiza la capa del cuello de botella
- Aplicación: locks, pausas de GC, agotamiento de pools de conexiones, frecuencia de fsync.
- Sistema de archivos: presión del journal, tormentas de metadatos, fragmentación, opciones de montaje.
- Capa de bloques: profundidad de cola, planificador, comportamiento de merge, throttling.
- Dispositivo: caída de rendimiento en estado estacionario del SSD, peculiaridades de firmware, estrangulamiento térmico.
- Red / tejido de almacenamiento: retransmisiones, congestión, multipath inestable.
- Virtualización / entorno compartido: vecino ruidoso, steal de CPU del host, políticas de limitación.
Tercero: reproduce de forma segura con una micro-prueba representativa
- Elige una prueba que coincida con tu tamaño de E/S, mezcla lectura/escritura, comportamiento sync y concurrencia.
- Ejecutala junto a la carga de producción si es posible (con cuidado), o reproduce trazas en un clon de staging.
- Valida con métricas del sistema y métricas de la aplicación. Si no coinciden, confía en la aplicación.
Este plan funciona porque es escéptico: asume que el síntoma podría estar corriente arriba, corriente abajo o ser auto-infligido por la mitología del benchmarking.
Tareas prácticas: comandos, qué significa la salida y la decisión que tomas
Estas son las tareas que realmente ejecuto cuando alguien me entrega un resultado de benchmark o un ticket de “el almacenamiento está lento”.
Cada tarea incluye: comando, salida de ejemplo, qué significa y la decisión que impulsa.
Task 1: Identificar los dispositivos de bloque y su topología
cr0x@server:~$ lsblk -o NAME,MODEL,SIZE,ROTA,TYPE,MOUNTPOINTS
NAME MODEL SIZE ROTA TYPE MOUNTPOINTS
nvme0n1 Samsung SSD 1.8T 0 disk
├─nvme0n1p1 512M 0 part /boot
└─nvme0n1p2 1.8T 0 part /
sda ST8000NM0045 7.3T 1 disk
└─sda1 7.3T 1 part /mnt/archive
Significado: ROTA=0 indica estado sólido; ROTA=1 indica rotacional. El modelo sugiere el controlador y la clase.
Saber si estás en NVMe vs SATA vs HDD cambia lo que es “bueno” y qué comportamiento de colas tiene sentido.
Decisión: Elige perfiles de benchmark apropiados para la clase de dispositivo. No uses profundidades de cola estilo NVMe en un HDD único y lo llames “hardware injusto.”
Task 2: Comprobar sistema de archivos y opciones de montaje (las perillas silenciosas de rendimiento)
cr0x@server:~$ findmnt -no SOURCE,TARGET,FSTYPE,OPTIONS /
/dev/nvme0n1p2 / ext4 rw,relatime,errors=remount-ro
Significado: Las opciones de montaje te dicen si estás pagando impuestos de metadatos (atime), qué comportamiento de journal tienes y si discard está habilitado.
Decisión: Si tu entorno de benchmark usa opciones de montaje diferentes a producción, detente. Alinealas y vuelve a probar.
Task 3: Confirmar que no estés benchmarkeando accidentalmente la RAM vía page cache
cr0x@server:~$ grep -E 'MemTotal|MemAvailable|Cached' /proc/meminfo
MemTotal: 263824032 kB
MemAvailable: 221443104 kB
Cached: 78455232 kB
Significado: Un valor grande de Cached más un dataset menor que la RAM a menudo significa que las lecturas vendrán de caché.
Decisión: Dimensiona el dataset más allá de la RAM (o usa Direct IO). Si no puedes, indica explícitamente que mediste rendimiento cacheado, no disco.
Task 4: Comprobar la presión de writeback y umbrales de páginas sucias
cr0x@server:~$ sysctl vm.dirty_background_ratio vm.dirty_ratio
vm.dirty_background_ratio = 10
vm.dirty_ratio = 20
Significado: Estos controlan cuánto dato sucio puede acumularse antes de que el writeback fuerce throttling.
Los benchmarks que escriben datos en búfer pueden lucir bien hasta que el kernel decide que es tiempo de vaciar, y entonces la latencia se dispara.
Decisión: Si ves acantilados periódicos de latencia en pruebas de escritura en búfer, reproduce con Direct IO o ajusta la duración de la prueba y monitoriza el comportamiento de writeback sucio.
Task 5: Ver si el dispositivo está saturado (utilización y profundidad de cola)
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server) 01/12/2026 _x86_64_ (64 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.10 0.00 4.20 6.50 0.00 77.20
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 820.0 52480.0 0.0 0.0 2.10 64.0 610.0 78144.0 0.0 0.0 8.40 128.1 5.10 92.00
Significado: %util cerca de 100% sugiere saturación. aqu-sz indica acumulación en la cola. r_await/w_await muestran latencia incluyendo tiempo de encolamiento.
Decisión: Si está saturado, necesitas más dispositivos, mejor paralelismo o menos trabajo por E/S (elecciones de compresión, batching, caché). Si no está saturado pero la latencia es alta, busca firmware, throttling o bloqueos arriba.
Task 6: Medir comportamiento de E/S por proceso (quién lo está haciendo realmente)
cr0x@server:~$ pidstat -d 1 3
Linux 6.5.0 (server) 01/12/2026 _x86_64_ (64 CPU)
# Time UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
12:00:01 999 18422 0.00 41280.00 0.00 45 postgres
12:00:01 0 2211 0.00 5120.00 0.00 6 rsync
Significado: Puedes separar “el almacenamiento es lento” de “un proceso está haciendo mucho.”
iodelay es un indicador aproximado del tiempo esperando E/S.
Decisión: Si un trabajo en segundo plano domina, prográmalo de forma diferente o throtealo. Si el servicio principal está esperando, céntrate en latencia y ruta de durabilidad.
Task 7: Confirmar planificador de E/S y ajustes de cola (especialmente tras actualizaciones del kernel)
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq
Significado: El planificador seleccionado está entre corchetes. NVMe a menudo usa none de forma efectiva; otros dispositivos pueden beneficiarse de mq-deadline bajo cargas mixtas.
Decisión: No ajustes ciegamente por throughput de benchmark. Si tienes cargas sensibles a latencia, prueba bajo contención y elige el planificador que preserve la latencia de cola.
Task 8: Detectar throttling de dispositivo o errores en los logs del kernel
cr0x@server:~$ dmesg -T | tail -n 12
[Mon Jan 12 11:58:10 2026] nvme nvme0: failed command: WRITE, cmdid 123 qid 4
[Mon Jan 12 11:58:10 2026] nvme nvme0: status: { DNR }
[Mon Jan 12 11:58:11 2026] EXT4-fs (nvme0n1p2): warning: mounting fs with errors, running e2fsck is recommended
Significado: Los números del benchmark son irrelevantes si el dispositivo está fallando o el sistema de archivos está comprometido.
Los picos de latencia pueden ser reintentos de errores, resets o modos degradados.
Decisión: Detén las pruebas de rendimiento. Estabiliza el sistema: revisa SMART/NVMe logs, verifica cableado/controlador y soluciona errores del sistema de archivos.
Task 9: Ejecutar un fio centrado en latencia con Direct IO (más honesto para muchas rutas DB)
cr0x@server:~$ fio --name=lat4k --filename=/mnt/testfile --size=8G --direct=1 --rw=randread --bs=4k --iodepth=4 --numjobs=4 --time_based --runtime=60 --group_reporting
lat4k: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=4
...
read: IOPS=42000, BW=164MiB/s (172MB/s)(9840MiB/60001msec)
slat (nsec): min=1800, max=21000, avg=5400.10, stdev=1100.30
clat (usec): min=45, max=9200, avg=90.20, stdev=40.10
lat (usec): min=49, max=9210, avg=96.10, stdev=40.50
clat percentiles (usec):
| 1.00th=[ 55], 5.00th=[ 62], 10.00th=[ 68], 50.00th=[ 84]
| 90.00th=[ 112], 95.00th=[ 135], 99.00th=[ 240], 99.90th=[ 1200]
Significado: IOPS está bien, pero los percentiles cuentan la historia real. p99.9 en 1.2ms puede estar bien—o puede romper un SLO si tu ruta de petición acumula varias E/S.
Decisión: Si la latencia de cola es alta, reduce la contención, baja la profundidad de cola, revisa GC/throttling o cambia a una clase de dispositivo con mejor latencia en estado estacionario.
Task 10: Probar throughput secuencial con tamaño de bloque y concurrencia realistas
cr0x@server:~$ fio --name=seqread --filename=/mnt/testfile --size=16G --direct=1 --rw=read --bs=1M --iodepth=8 --numjobs=2 --time_based --runtime=60 --group_reporting
seqread: (g=0): rw=read, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libaio, iodepth=8
...
read: IOPS=980, BW=980MiB/s (1027MB/s)(58800MiB/60001msec)
Significado: Bueno para escaneos masivos, backups y envío de logs. Pero no predice rendimiento aleatorio pequeño.
Decisión: Usa esto para planificar capacidad de operaciones masivas y ventanas de mantenimiento, no para justificar un SLO de latencia de base de datos.
Task 11: Verificar discard/TRIM (puede crear picos de latencia)
cr0x@server:~$ findmnt -no TARGET,OPTIONS /mnt/test
/mnt/test rw,relatime,discard
Significado: El discard continuo puede añadir sobrecarga en algunos dispositivos. Algunos entornos prefieren fstrim periódico.
Decisión: Si ves picos periódicos de latencia alineados con discards, cambia a trim programado y vuelve a probar.
Task 12: Comprobar SMART NVMe y salud del medio (el estado estacionario importa)
cr0x@server:~$ sudo nvme smart-log /dev/nvme0
Smart Log for NVME device:nvme0 namespace-id:ffffffff
critical_warning : 0x00
temperature : 47 C
available_spare : 100%
percentage_used : 3%
data_units_read : 12,345,678
data_units_written : 9,876,543
media_errors : 0
num_err_log_entries : 0
Significado: La temperatura y los contadores de error pueden explicar throttling y reintentos. percentage_used da un indicador aproximado de desgaste.
Decisión: Si la temperatura es alta o aparecen errores, arregla hardware/flujo de aire antes de echar la culpa a la carga o a “mal ajuste.”
Task 13: Ver si tu prueba “aleatoria” realmente está golpeando los mismos bloques (comprobación de localidad)
cr0x@server:~$ fio --name=randcheck --filename=/mnt/testfile --size=64G --direct=1 --rw=randread --bs=4k --iodepth=1 --numjobs=1 --runtime=30 --time_based --group_reporting --randrepeat=0
randcheck: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
...
read: IOPS=8200, BW=32.0MiB/s (33.6MB/s)(960MiB/30001msec)
Significado: --randrepeat=0 evita repetir la misma secuencia aleatoria entre ejecuciones. Un --size mayor ayuda a derrotar la caché.
Decisión: Si el rendimiento se desploma cuando amplías el dataset, tu resultado anterior probablemente estaba inflado por caché.
Task 14: Confirmar semántica de persistencia (ajuste de caché de escritura a nivel de dispositivo)
cr0x@server:~$ sudo hdparm -W /dev/sda
/dev/sda:
write-caching = 1 (on)
Significado: La caché de escritura puede mejorar la velocidad pero cambia la durabilidad a menos que tengas protección contra pérdida de energía y barreras correctas.
Decisión: Para sistemas que requieren durabilidad estricta, asegúrate de que la pila esté configurada correctamente y mide con patrones fsync/sync—si no, estás midiendo escrituras “acknowledged”, no persistentes.
Task 15: Medir latencia a nivel de archivo desde la perspectiva del sistema de archivos
cr0x@server:~$ strace -T -e trace=fsync -p 18422 -s 0
strace: Process 18422 attached
fsync(57) = 0 <0.012341>
fsync(57) = 0 <0.089120>
fsync(57) = 0 <0.007882>
Significado: Esos tiempos son la realidad de la aplicación. Si fsync a veces tarda 90ms, tu informe de “latencia media 1ms” es irrelevante.
Decisión: Si la latencia de fsync es irregular, busca tormentas de writeback, GC del dispositivo, contención o problemas en la ruta de durabilidad (barriers, flush de caché, almacenamiento en red).
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: “El benchmark dice 500k IOPS, pero la app agota tiempo”
Causa raíz: La profundidad de cola y la concurrencia en el benchmark exceden lo que la app puede sostener; la latencia de cola es el verdadero limitador.
Fix: Mide a concurrencia realista (threads, iodepth). Rastrea p95/p99. Valida con tiempos a nivel de app (fsync, latencia de consulta).
2) Síntoma: “Las lecturas son increíblemente rápidas, luego de repente más lentas después de unos minutos”
Causa raíz: Calentamiento de page cache o caché del controlador; dataset demasiado pequeño o repetido.
Fix: Usa Direct IO o dataset mayor que la RAM; desactiva randrepeat; ejecuta pruebas más largas y vigila razones de aciertos de caché cuando sea posible.
3) Síntoma: “Las escrituras se ven bien en un test de 30 segundos, terribles después de una hora”
Causa raíz: Caché SLC del SSD / buffering a corto plazo oculta la recolección de basura y la amplificación de escritura en estado estacionario.
Fix: Precondiciona el dispositivo (llenar y escribir sostenidamente), ejecuta pruebas de larga duración y mide percentiles de latencia en estado estacionario.
4) Síntoma: “El throughput es alto, pero la latencia interactiva es horrible durante trabajos por lotes”
Causa raíz: Problemas de equidad/prioridad: planificador, colas o falta de aislamiento de E/S. El batch domina el tiempo del dispositivo.
Fix: Prueba cargas mixtas; aplica controles de E/S de cgroup o programa cargas; elige planificador para equidad de latencia, no para throughput pico.
5) Síntoma: “Mismo benchmark en dos nodos ‘idénticos’ difiere enormemente”
Causa raíz: Diferencias de firmware, ancho de enlace/speed PCIe, estrangulamiento térmico, scrubs en background o estado del sistema de archivos.
Fix: Inventaría versiones de firmware/kernel; verifica velocidad/anchura del enlace; comprueba temperaturas; confirma tareas en background; alinea opciones de sistema de archivos/montaje.
6) Síntoma: “IOPS de escritura aleatoria está bien, pero fsync es lento”
Causa raíz: El benchmark no está emitiendo escrituras sync; la ruta de durabilidad (flush de caché, barriers, journal) es el cuello de botella.
Fix: Usa fio con --fsync=1 o motores sync; mide fsync directamente en la app; valida caché de escritura del controlador y supuestos de protección ante pérdida de energía.
7) Síntoma: “El almacenamiento parece inactivo, aun así la latencia es alta”
Causa raíz: Bloqueos corriente arriba (locks, throttling de CPU, retransmisiones de red) o resets/intermitencias del dispositivo.
Fix: Correlaciona razones de espera de la app; revisa dmesg; verifica estadísticas de red si es remoto; inspecciona esperas de E/S por proceso y tiempo de steal de CPU.
Listas de comprobación / plan paso a paso para benchmarking honesto
Plan paso a paso: de “números bonitos” a “resultados aptos para decisiones”
- Escribe la pregunta. ¿Estás eligiendo hardware? ¿Validando una migración? ¿Depurando una regresión de latencia? Diferentes preguntas requieren distintas pruebas.
- Extrae las características de la carga. Distribución de tamaños de E/S, mezcla lectura/escritura, comportamiento sync, concurrencia, tamaño del working set, ráfagas y latencia de cola aceptable.
- Alinea la pila. Mismo sistema de archivos, opciones de montaje, cifrado/compresión, replicación, kernel y controladores que en producción. Nada de “casi igual”.
- Decide qué reportarás. Incluye siempre tamaño de bloque, profundidad de cola, numjobs, direct vs buffered, tiempo de ejecución, tamaño del dataset y percentiles.
- Vence la velocidad falsa. Dataset más grande que las cachés,
--randrepeat=0, ejecuta lo suficiente para alcanzar estado estacionario y evita presumir por los “primeros 10 segundos”. - Mide señales del sistema y de la app. iostat/pidstat/histogramas de latencia más latencia de solicitud y tasas de error de la aplicación.
- Prueba cargas mixtas. Un trabajo de throughput más una sonda de latencia. La producción no es un solo job de fio corriendo solo a medianoche.
- Ejecuta al menos tres veces. Si los resultados varían mucho, tu sistema es inestable o tu método está mal. En cualquier caso, no lo publiques.
- Establece línea base y guarda artefactos. Conserva archivos de trabajo fio, versiones del kernel, firmware, sysctls y salidas crudas. Tu yo futuro los necesitará en un incidente.
- Traduce resultados en decisiones. “p99 fsync < 5ms a 200 commits/s” es una decisión. “1M IOPS” es un póster.
Lista de revisión de benchmark (úsala para atrapar mentiras en el informe de otro)
- ¿El informe incluye tamaño de bloque, mezcla lectura/escritura, iodepth, numjobs, tiempo de ejecución y tamaño del dataset?
- ¿Incluye latencias p95/p99/p99.9, no solo la media?
- ¿El dataset fue mayor que la RAM y la caché del controlador?
- ¿Se usó Direct IO apropiadamente para la carga objetivo?
- ¿Se precondicionó el dispositivo para escrituras en estado estacionario?
- ¿El sistema de archivos estaba lleno/fragmentado lo suficiente para representar producción, o era un volumen nuevo y vacío?
- ¿Hubo carga competidora, o el benchmark se ejecutó en aislamiento?
- ¿Hay logs del kernel que muestren errores/reintentos durante la ejecución?
- ¿Los resultados se alinean con tiempos a nivel de aplicación?
Qué evitar (opiniones firmes, ganadas por experiencia)
- No aceptes un benchmark de un solo número. Ningún número único de IOPS sobrevive al contacto con cargas reales.
- No ajustes solo en base a una prueba sintética. El ajuste cambia el comportamiento bajo contención; si no probaste contención, no probaste el riesgo.
- No hagas benchmarking en un sistema con tareas de fondo desconocidas. Scrubs, rebuilds, backups e indexados producirán “variación misteriosa.” No es misteriosa.
- No ignores la latencia de cola. Es literalmente lo que sienten los usuarios y lo que los sistemas distribuidos amplifican.
Preguntas frecuentes
1) ¿Son inútiles los benchmarks sintéticos?
No. Son excelentes para comparaciones controladas y para aislar variables. Son inútiles cuando se tratan como una promesa del comportamiento en producción sin alinear carga, pila y contención.
2) ¿Cuál es la razón principal por la que los resultados no coinciden con producción?
Desajuste de caché y concurrencia. El benchmark a menudo corre con un dataset que cabe en caché y una profundidad de cola que la aplicación no puede sostener.
El resultado es un throughput inflado y latencia de cola oculta.
3) ¿Debo usar siempre Direct IO en fio?
Si tu carga objetivo usa Direct IO (muchas bases de datos lo hacen para archivos de datos), sí. Si tu carga depende del page cache (muchos servicios web lo hacen), mide IO en búfer también.
La respuesta honesta es: prueba la ruta que ejecutas realmente.
4) ¿Por qué mayor iodepth mejora IOPS pero a veces empeora la latencia?
La profundidad de cola aumenta paralelismo y oportunidades de reordenamiento, lo que aumenta throughput. Pero también incrementa el retraso por encolamiento, especialmente bajo saturación.
La latencia de cola es donde aparece el dolor.
5) Mi proveedor me dio números de benchmark. ¿Cómo los valido rápido?
Vuelve a ejecutar un conjunto mínimo: una prueba de latencia de lectura 4k con iodepth/numjobs realistas, una prueba de escritura 4k sync enfocada en fsync y una prueba secuencial de throughput.
Asegúrate de que el tamaño del dataset supere la caché y reporta percentiles.
6) ¿Qué significa “estado estacionario” para benchmarking de SSD?
Significa el rendimiento después de que el dispositivo ha sido escrito lo suficiente para que la recolección de basura y el wear leveling estén activos.
Las pruebas cortas en un dispositivo limpio suelen medir comportamiento de caché de ráfaga, no rendimiento a largo plazo.
7) ¿Cómo mido honradamente un sistema de almacenamiento distribuido (conectado por red)?
Incluye la red y la pila del cliente. Mide retransmisiones, CPU y latencia de cola.
Ejecuta pruebas desde múltiples clientes concurrentes, porque los sistemas distribuidos a menudo se comportan distinto bajo fan-in que con un solo cliente.
8) ¿Por qué mis resultados de fio difieren entre ejecuciones?
Causas comunes: caché, trabajos en background, estrangulamiento térmico, comportamiento GC del dispositivo y estado del sistema de archivos (fragmentación, espacio libre).
Si la variación es alta, trátalo como una señal: tu entorno no está controlado o tu almacenamiento es inestable.
9) ¿Qué métricas debo incluir en un informe de benchmark para que no se pueda malinterpretar?
Incluye: definición de la carga (mezcla rw, bs, iodepth, numjobs, direct/buffered), tamaño del dataset, tiempo de ejecución, throughput/IOPS, percentiles de latencia y contexto del sistema (kernel, sistema de archivos, opciones de montaje).
Si falta alguno de estos, alguien lo “interpretará” mal amablemente.
Conclusión: próximos pasos que sobreviven en producción
Los benchmarks sintéticos no mienten porque sean maliciosos. Mienten porque son estrechos, y la gente es optimista.
Los sistemas en producción no son optimistas. Están ocupados, concurridos, desordenados y llenos de trabajo en segundo plano que olvidaste.
Próximos pasos que realmente ayudan:
- Elige 3–5 perfiles de benchmark que mapeen a tu carga real (incluyendo escrituras sincronizadas si te importa la durabilidad).
- Exige percentiles de latencia y tamaño de dataset en cada informe de rendimiento.
- Establece línea base antes de cambios y guarda artefactos para que las regresiones se puedan atribuir a un cambio específico.
- Prueba cargas mixtas, no solo “fio solo en un volumen vacío”.
- Cuando dudes, confía en el tiempo de la aplicación por sobre el panel de almacenamiento.
El objetivo no es prohibir los benchmarks sintéticos. El objetivo es dejar de permitir que aprueben decisiones que no midieron.
Los benchmarks son herramientas. La producción es el examen. Actúa en consecuencia.