«Dice 1.000.000 FPS.» Así empieza. Una diapositiva, una hoja de compras, un responsable que sólo quiere cerrar el ticket y un sistema de almacenamiento que—misteriosamente—no mantiene una base de datos por debajo de 30 ms en picos.
“FPS de marketing” (llámelo IOPS, FPS, transacciones, “ops” o “hasta”) es el número que usan los proveedores cuando quieren que deje de hacer preguntas. A producción no le importa ese número. A producción le importan la latencia bajo carga, el comportamiento de la cola, la mezcla lectura/escritura, el conjunto de trabajo y qué sucede cuando la caché está fría y el sistema está moderadamente desagrado.
Qué significa realmente “FPS de marketing” (y qué oculta)
Cuando un proveedor dice “1M IOPS” (o su reetiquetado “FPS”), debe añadir mentalmente las notas al pie que faltan:
- Tamaño de bloque: casi siempre 4K (los bloques pequeños inflan el recuento de operaciones).
- Patrón: lectura aleatoria (las lecturas son más fáciles que las escrituras; lo aleatorio oculta límites de rendimiento secuencial).
- Profundidad de cola: alta (las colas profundas inflan los IOPS mientras la latencia sube en silencio).
- Caché: calentada, y a veces sin llegar realmente al medio.
- Conjunto de datos: cabe en caché o en un búfer SLC, convenientemente.
- Duración: lo bastante corta para evitar el comportamiento en estado estacionario (especialmente para NAND y recolección de basura).
- Unidades: el modelo “top bin”, no lo que le enviarán después de un ajuste de la cadena de suministro.
- Host: un servidor de benchmark afinado como un coche de carreras, no su granja de VM.
Los números de marketing no siempre son mentiras. A menudo son verdaderos para un escenario estrecho y curado. El problema es que quienes hacen compras los tratan como una garantía para su carga de trabajo.
Aquí está la realidad: IOPS no es una métrica de capacidad. Es un punto en una curva. Cambie una variable—tamaño de bloque, mezcla lectura/escritura, profundidad de cola, localidad de datos—y está en otra curva.
Un control rápido de cordura: si un dispositivo promete IOPS enormes pero no puede mover mucho ancho de banda, probablemente sea un titular basado en 4K. Ejemplo: 1.000.000 IOPS a 4K son aproximadamente 4 GB/s. Eso es real, pero sólo si todo lo demás coopera y puede alimentarlo.
Broma #1: “Hasta 1M IOPS” es como “hasta 200 mph” en un coche de alquiler: técnicamente posible, socialmente desaconsejado y no cubierto por la garantía.
Reglas sencillas que lo mantienen fuera de problemas
Regla 1: Si no tiene percentiles de latencia, no tiene una afirmación de rendimiento
Pida latencia P50, P95, P99 a los IOPS declarados. La latencia media es un cuento para dormir; la latencia de cola es la trama. Si el proveedor no proporciona latencia por percentiles bajo las mismas condiciones, trate el número de IOPS como decorativo.
Regla 2: Trate la profundidad de cola como una perilla que intercambia latencia por IOPS de titular
Las colas profundas aumentan los IOPS y entristecen a los usuarios. Su aplicación normalmente no funciona a QD=128 por dispositivo. Bases de datos, motores de búsqueda y servicios request/response suelen tener concurrencia limitada y se preocupan por baja latencia a QD moderado, no por “máximo rendimiento a cualquier costo”.
Regla 3: Separe “ráfaga” de “sostenido”
Unidades NVMe, arreglos y volúmenes en la nube pueden parecer heroicos durante 10–60 segundos. Luego caen a su estado estacionario. Exija al menos 30 minutos de pruebas para afirmaciones con mucha escritura y asegúrese de que el dispositivo esté en estado estacionario (más abajo hay más detalles).
Regla 4: Si el conjunto de datos cabe en caché, está midiendo la caché
La caché es buena. Comprar almacenamiento para que actúe como caché también es válido—si eso era lo que pretendía. Pero no haga pruebas con 20 GB en un sistema con 512 GB de RAM y lo llame “rendimiento de disco”. Eso es “rendimiento de RAM con pasos extra”.
Regla 5: Exija la receta de la prueba completa (tamaño de bloque, mezcla rw, QD, hilos, tiempo de ejecución, preacondicionamiento)
Un número aislado sin receta no es un benchmark; es un eslogan. Requiera un archivo de trabajo fio reproducible o equivalente. Si no pueden entregarlo, su número no sirve para decisiones de ingeniería.
Regla 6: Use “latencia a throughput requerido” como su objetivo de dimensionamiento
No compra “IOPS máximos”. Compra la capacidad de mantenerse por debajo, por ejemplo, de 5 ms P99 en su carga mezclada pico. Comience con sus SLO y trabaje hacia atrás.
Regla 7: Vigile la amplificación de escritura y la recolección de basura
Los sistemas flash pueden degradarse bajo escrituras aleatorias sostenidas, especialmente cerca de alta utilización. Preacondicione discos. Pruebe a niveles de llenado realistas. Pregunte al proveedor qué sucede al 70% de ocupación, no al 7%.
Regla 8: Si la afirmación ignora al host, está incompleta
Drivers, multipathing, CPU, NUMA, manejo de interrupciones, sistema de archivos y cifrado pueden ser cuellos de botella mucho antes que el medio. Una afirmación de almacenamiento que no especifica hardware y software del host es sólo media afirmación.
Regla 9: “IOPS” sin mezcla lectura/escritura es sin sentido
70/30 lectura/escritura no se comporta como 100% lectura. Tampoco lo hace 30/70. Si su carga es mixta, su benchmark debe ser mixto y sus criterios de aceptación también.
Regla 10: Siempre pruebe el modo de fallo que no puede evitar
Se producen reconstrucciones. Hay scrubs en segundo plano. Un camino falla. Un controlador se reinicia. Si sólo prueba el día soleado, producción programará una tormenta.
Hechos interesantes y contexto (el marketing de almacenamiento tiene historia)
- Hecho 1: “IOPS” ganó fama porque los primeros arreglos de disco podían ocultar terribles tiempos de búsqueda con caché y múltiples discos—así que los proveedores necesitaban un número único y contable para acceso aleatorio.
- Hecho 2: La industria se estandarizó en 4K random read para IOPS de titular en parte porque se ajusta a tamaños de página de bases de datos y aumenta el conteo de operaciones en comparación con 8K/16K.
- Hecho 3: Los benchmarks de almacenamiento han sido controvertidos desde los días de SPEC y TPC; los proveedores a menudo afinan configuraciones para ganar ejecuciones de benchmark en lugar de coincidir con despliegues típicos.
- Hecho 4: Muchos SSD usan una caché SLC para escrituras (incluso cuando el NAND es TLC/QLC). Puede crear ráfagas espectaculares que desaparecen en estado estacionario.
- Hecho 5: La NAND requiere borrado antes de escribir a nivel de bloque; la recolección de basura y el wear leveling explican por qué el rendimiento de escritura aleatoria en estado estacionario suele ser mucho menor que “recién sacado de la caja”.
- Hecho 6: La profundidad de cola se volvió palanca de marketing cuando NVMe hizo la paralelización profunda barata; QD alta puede mantener el dispositivo ocupado, pero también oculta picos de latencia hasta que su aplicación falla.
- Hecho 7: En la era HDD, un disco “15K RPM” podía hacer aproximadamente 175–210 IOPS aleatorios; los arreglos llegaron a decenas de miles al distribuir carga entre muchos discos y hacer caché agresiva.
- Hecho 8: Los volúmenes en la nube a menudo tienen créditos de ráfaga explícitos o límites de throughput; el rendimiento puede ser contractual pero limitado en el tiempo, lo que hace que benchmarks cortos resulten engañosamente halagadores.
- Hecho 9: Los primeros controladores RAID con caché de escritura respaldada por batería podían hacer que las escrituras parecieran rápidas hasta un flush de caché; el “acantilado de latencia sorpresa” es anterior a muchos equipos SRE actuales.
Las únicas métricas que importan en sistemas reales
1) Percentiles de latencia (P50/P95/P99) a lo largo del tiempo
Quiere una serie temporal, no un único resumen. Si P99 sube durante la ejecución, está presenciando agotamiento de caché, estrangulamiento térmico, recolección de basura o trabajo en segundo plano.
2) IOPS y ancho de banda juntos
IOPS sin MB/s es cómo obtiene un sistema que parece genial en papel y no puede hacer backups. Ancho de banda sin IOPS es cómo obtiene un sistema que transmite bien pero se atranca con metadatos.
3) Profundidad de cola y concurrencia
Mida la cola de IO que realmente ejecuta. Si la app sólo tiene 16 IO pendientes por nodo, un benchmark a QD=256 es irrelevante.
4) Mezcla lectura/escritura y localidad
Aleatorio vs secuencial no es binario. Muchas cargas son “mayormente secuenciales con metadatos aleatorios molestos”, por eso funcionan hasta que dejan de hacerlo.
5) Estado estacionario y nivel de llenado
Pruebe a utilización realista y después de preacondicionar. El rendimiento flash varía enormemente según cuán lleno y “sucio” esté.
6) Cola de cola bajo contención
La producción tiene vecinos: compactaciones en segundo plano, snapshots, reconstrucciones, scrubs, antivirus, envío de logs, otros inquilinos y sus ventanas de parches. Necesita números bajo dolor moderado, no sólo bajo ausencia de dolor.
Una idea parafraseada, porque es demasiado cierta para ignorarla: una idea parafraseada
— Gene Kranz (director de vuelo de la NASA) suele asociarse con “el fracaso no es una opción”, que en operaciones se traduce en “pruebe la vía fea ahora, no después”.
Tareas prácticas: comandos, salidas y la decisión que toma
Estos son los chequeos que puede ejecutar en un host Linux para evitar dejarse hipnotizar por un único número de IOPS. Cada tarea incluye: un comando, qué significa una salida típica y la decisión que toma.
Task 1: Identificar el dispositivo de almacenamiento y su modelo (no haga benchmark de lo equivocado)
cr0x@server:~$ lsblk -o NAME,MODEL,SIZE,ROTA,TYPE,MOUNTPOINT,FSTYPE
NAME MODEL SIZE ROTA TYPE MOUNTPOINT FSTYPE
nvme0n1 Samsung SSD 990 PRO 1.8T 0 disk
├─nvme0n1p1 512M 0 part /boot ext4
└─nvme0n1p2 1.8T 0 part /data xfs
Qué significa: Está en NVMe (ROTA=0), el modelo es visible y puede ver dónde está montado.
Decisión: Haga benchmark del dispositivo bruto o de un archivo de prueba dedicado en el sistema de archivos correcto. Si el modelo no es el esperado, detenga y corrija las suposiciones de compras/construcción del host.
Task 2: Confirmar que el kernel ve NVMe a la velocidad y anchura de enlace esperadas
cr0x@server:~$ sudo nvme id-ctrl /dev/nvme0 | egrep -i 'mn|fr|mdts'
mn : Samsung SSD 990 PRO 2TB
fr : 5B2QJXD7
mdts : 9
Qué significa: Modelo/firmware correctos; MDTS indica el tamaño máximo de transferencia. No es la comprobación completa del enlace, pero sí una verificación básica de identidad.
Decisión: Si la identidad del dispositivo es inesperada, no continúe. Un firmware equivocado también puede implicar comportamientos de estrangulamiento/bugs conocidos; alinéelo con su baseline de plataforma.
Task 3: Comprobar si el disco está estrangulándose térmicamente (clásico “benchmark empieza rápido y termina triste”)
cr0x@server:~$ sudo nvme smart-log /dev/nvme0 | egrep -i 'temperature|warning|critical'
temperature : 71 C
warning_temp_time : 12
critical_comp_time : 0
Qué significa: El disco alcanzó temperatura de advertencia durante 12 minutos. Eso es una gran flecha roja apuntando a estrangulamiento.
Decisión: Arregle la refrigeración/flujo de aire/ubicación antes de creer cualquier prueba de rendimiento “sostenido”.
Task 4: Verificar opciones de montaje del sistema de archivos (puede estar midiendo journal o barreras por accidente)
cr0x@server:~$ mount | grep ' /data '
/dev/nvme0n1p2 on /data type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
Qué significa: XFS con opciones relativamente por defecto; nada obviamente roto.
Decisión: Si ve opciones inesperadas (p. ej., sync, o cambios exóticos de barrera), alinee con la configuración de producción antes de probar.
Task 5: Ver si ya está limitado por IO (alta utilización) antes de ejecutar fio
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server) 01/21/2026 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.1 0.0 4.2 8.7 0.0 75.0
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s w_await aqu-sz %util
nvme0n1 9.0 320.0 0.0 0.0 1.2 35.6 220.0 8200.0 6.9 1.8 92.4
Qué significa: %util alrededor de 92% indica que el dispositivo está cerca de saturación. w_await es 6.9 ms, y %iowait no es trivial.
Decisión: Si este es un host de producción, ya puede estar al límite—hacer benchmarks ahora mezclará ruido de carga en los resultados. Para troubleshooting: concéntrese en quién está haciendo IO y si la latencia coincide con su SLO.
Task 6: Encontrar qué procesos generan IO (no culpe al almacenamiento por un bug de la app)
cr0x@server:~$ sudo iotop -o -b -n 3
Total DISK READ: 0.00 B/s | Total DISK WRITE: 62.31 M/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
14221 be/4 postgres 0.00 B/s 41.72 M/s 0.00 % 65.12 % postgres: checkpointer
18802 be/4 root 0.00 B/s 18.49 M/s 0.00 % 22.30 % /usr/bin/rsync -a /var/lib/app/ /backup/
Qué significa: El checkpointer de Postgres y un rsync están haciendo la mayoría de las escrituras. Eso es explicable, no misterioso.
Decisión: Arregle la programación/coordinación (mueva la copia de seguridad, ajuste el checkpointing) antes de gastar en almacenamiento.
Task 7: Medir latencia directamente con fio (y registrar percentiles)
cr0x@server:~$ sudo fio --name=randread4k --filename=/data/fio.test --size=40G --direct=1 --rw=randread --bs=4k --iodepth=16 --numjobs=4 --runtime=120 --time_based --group_reporting --ioengine=libaio --percentile_list=50:95:99:99.9
randread4k: (groupid=0, jobs=4): err= 0: pid=21401: Tue Jan 21 11:10:10 2026
read: IOPS=185k, BW=723MiB/s (758MB/s)(84.7GiB/120001msec)
clat (usec): min=62, max=4210, avg=334.18, stdev=91.22
lat (usec): min=64, max=4215, avg=336.49, stdev=91.30
clat percentiles (usec):
| 50.000000th=[ 331], 95.000000th=[ 470], 99.000000th=[ 620], 99.900000th=[ 980]
Qué significa: Buenos IOPS y, lo importante, P99 es 620 µs a esta carga. Ese es un número de ingeniería real.
Decisión: Si su app necesita <2 ms, esto está bien. Si necesita <200 µs, debe reducir la profundidad de cola, cambiar la arquitectura o usar medios/topologías más rápidos.
Task 8: Mostrar cómo la profundidad de cola infla IOPS mientras la latencia empeora
cr0x@server:~$ sudo fio --name=randread4k_qd128 --filename=/data/fio.test --size=40G --direct=1 --rw=randread --bs=4k --iodepth=128 --numjobs=4 --runtime=120 --time_based --group_reporting --ioengine=libaio --percentile_list=50:95:99
randread4k_qd128: (groupid=0, jobs=4): err= 0: pid=21455: Tue Jan 21 11:13:01 2026
read: IOPS=420k, BW=1641MiB/s (1721MB/s)(192GiB/120001msec)
clat (usec): min=85, max=25000, avg=1188.74, stdev=655.10
clat percentiles (usec):
| 50.000000th=[ 1056], 95.000000th=[ 2200], 99.000000th=[ 3900]
Qué significa: Los IOPS más que se duplicaron, pero la latencia mediana ahora es ~1 ms y P99 es 3.9 ms. Esta pantalla es la trampa del “FPS de marketing”.
Decisión: Elija QD que coincida con su carga. Para servicios sensibles a la latencia, acepte menos IOPS para mantener la latencia de cola dentro del SLO.
Task 9: Probar carga mixta (70/30) porque así es la vida real
cr0x@server:~$ sudo fio --name=mix70_30 --filename=/data/fio.test --size=80G --direct=1 --rw=randrw --rwmixread=70 --bs=8k --iodepth=32 --numjobs=8 --runtime=300 --time_based --group_reporting --ioengine=libaio --percentile_list=50:95:99
mix70_30: (groupid=0, jobs=8): err= 0: pid=21510: Tue Jan 21 11:20:01 2026
read: IOPS=110k, BW=859MiB/s (901MB/s)
clat percentiles (usec):
| 50.000000th=[ 540], 95.000000th=[ 1500], 99.000000th=[ 2800]
write: IOPS=47.1k, BW=368MiB/s (386MB/s)
clat percentiles (usec):
| 50.000000th=[ 810], 95.000000th=[ 2600], 99.000000th=[ 5200]
Qué significa: Las escrituras son más lentas y tienen peor cola de latencia. Eso es normal—y por eso los IOPS de lectura al 100% no dimensionan una base de datos.
Decisión: Si el P99 de escritura es demasiado alto, reduzca la amplificación de escritura (batching, ubicación del WAL), añada dispositivos o pase a un sistema optimizado para consistencia de escritura.
Task 10: Preacondicionar un SSD antes de confiar en pruebas sostenidas de escritura
cr0x@server:~$ sudo fio --name=precond --filename=/dev/nvme0n1 --direct=1 --rw=write --bs=1M --iodepth=32 --numjobs=1 --runtime=1800 --time_based --ioengine=libaio --group_reporting
precond: (groupid=0, jobs=1): err= 0: pid=21602: Tue Jan 21 12:00:01 2026
write: IOPS=2900, BW=2900MiB/s (3041MB/s)(5100GiB/1800000msec)
Qué significa: Ha escrito ~5 TB durante 30 minutos; está forzando la unidad a un estado más realista para pruebas de escritura aleatoria posteriores.
Decisión: Si no puede preacondicionar (porque es producción compartida), no puede afirmar honestamente rendimiento de escritura “sostenido” a partir de un benchmark corto.
Task 11: Detectar lectura adelantada o engaño de caché de página (accidental o deliberado)
cr0x@server:~$ sudo fio --name=cached-read --filename=/data/fio.test --size=4G --rw=read --bs=1M --iodepth=1 --numjobs=1 --runtime=30 --time_based --group_reporting
cached-read: (groupid=0, jobs=1): err= 0: pid=21688: Tue Jan 21 12:10:01 2026
read: IOPS=9200, BW=9200MiB/s (9647MB/s)(270GiB/30001msec)
Qué significa: 9.2 GiB/s desde un solo NVMe en un servidor típico es… sospechoso. Está leyendo desde caché (page cache) porque no se usó IO directo y el conjunto de datos es pequeño.
Decisión: Añada --direct=1, incremente el conjunto de datos más allá de la RAM y vuelva a ejecutar. No use este resultado para dimensionar almacenamiento.
Task 12: Comprobar si el dispositivo es el cuello de botella o la CPU lo es
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0 (server) 01/21/2026 _x86_64_ (32 CPU)
11:25:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %idle
11:25:02 AM all 38.2 0.0 18.9 0.7 0.0 2.1 0.0 40.1
11:25:02 AM 7 92.0 0.0 6.0 0.0 0.0 0.0 0.0 2.0
Qué significa: Un CPU está al máximo. Podría ser afinidad de IRQ, un job fio fijado a un núcleo o un cuello de botella del driver.
Decisión: Si la CPU está saturada, “almacenamiento más rápido” no ayudará. Arregle el pinning de CPU, la distribución de IRQ o aumente la paralelización apropiadamente.
Task 13: Buscar ajustes del planificador de IO y de la cola (pequeños mandos, grandes consecuencias)
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq
Qué significa: NVMe usa none (a menudo correcto). Otros planificadores pueden cambiar la distribución de latencia.
Decisión: No haga cargo-cult. Si tiene problemas de latencia de cola bajo carga mixta, pruebe mq-deadline/kyber con su perfil real de carga y mida percentiles.
Task 14: Validar que TRIM/discard no lo sabotea (o que exista cuando lo necesite)
cr0x@server:~$ lsblk -D -o NAME,DISC-GRAN,DISC-MAX,DISC-ZERO
NAME DISC-GRAN DISC-MAX DISC-ZERO
nvme0n1 512B 2T 0
Qué significa: Discard es compatible. Bien—ahora puede elegir cómo usarlo (fstrim periódico vs discard continuo).
Decisión: Si tiene degradación sostenida de escritura, considere programar fstrim en horas valle y confirme que no coincida con ventanas críticas de IO.
Task 15: Observar latencia por dispositivo en tiempo real durante un incidente
cr0x@server:~$ sudo pidstat -d 1 3
Linux 6.5.0 (server) 01/21/2026 _x86_64_ (32 CPU)
11:40:01 AM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
11:40:02 AM 999 14221 0.00 48200.00 0.00 postgres
11:40:02 AM 0 18802 0.00 20600.00 0.00 rsync
Qué significa: Puede correlacionar picos de IO con actividad de procesos, lo que reduce “el almacenamiento está lento” a “estos dos procesos están chocando”.
Decisión: Implemente planificación de IO, cgroups o ventanas de mantenimiento. No empiece con una migración de almacenamiento hasta haber demostrado la saturación del medio.
Task 16: Comprobar reconstrucción md RAID o tareas en segundo plano (el impuesto invisible de rendimiento)
cr0x@server:~$ cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 sdb1[0] sdc1[1]
976630336 blocks super 1.2 [2/2] [UU]
[======>..............] resync = 34.1% (333333333/976630336) finish=120.2min speed=89000K/sec
Qué significa: Resync en progreso. Su rendimiento “normal” no está disponible ahora mismo.
Decisión: Ajuste límites de velocidad de reconstrucción, posponga trabajos pesados o acepte SLO degradado temporalmente. Además: incorpore pruebas de reconstrucción en sus benchmarks previos a compra.
Guion de diagnóstico rápido: encuentre el cuello de botella pronto
Esta es la lista de comprobación que usa cuando alguien avisa “el almacenamiento está lento” y tiene 10 minutos antes de que el canal de incidentes se convierta en danza interpretativa.
Primero: confirme que es latencia de almacenamiento, no tiempo de aplicación
- Compruebe desglose de latencia de solicitudes (métricas de la app) si están disponibles.
- En el host, compruebe
iostat -xz 1por await, aqu-sz y %util. - Si %iowait es alto pero %util es bajo, sospeche algo calle arriba (ruta de almacenamiento en red, estrangulamiento o límites por cgroup).
Segundo: identifique la clase de restricción (dispositivo, ruta, CPU o política)
- Restricción del dispositivo: %util ~100%, await subiendo con la carga, fio lo reproduce en el mismo LUN/dispositivo.
- Restricción de la ruta: problemas de multipath, errores de enlace, congestión; picos de latencia sin %util local al máximo.
- Restricción de CPU: un core al máximo (interrupciones, cifrado, checksums), almacenamiento subutilizado.
- Restricción de política: límite de IOPS de volumen en la nube, QoS SAN, estrangulamiento por vecino ruidoso.
Tercero: pruébelo con una prueba dirigida
- Ejecute un pequeño fio de lectura con
--direct=1en el volumen afectado, coincidiendo tamaño de bloque y profundidad de cola que se parezcan a la carga. - Compare con números de referencia en los que confíe (de sus runbooks, no de una diapositiva del proveedor).
- Si fio está bien pero la app está lenta, el cuello de botella probablemente esté en la app, metadatos del sistema de archivos, contención de locks o ruta de red.
Cuarto: decida la mitigación segura más rápida
- Reduzca IO competidor (pausar jobs por lotes, ralentizar reconstrucciones, mover backups).
- Reduzca la amplificación de escritura (ajuste de checkpoints, batching, ritmo de compactación).
- Escale lecturas (réplicas) o fragmente particiones calientes.
- Sólo entonces: escale almacenamiento o migre.
Broma #2: Si el benchmark del proveedor dice “latencia cero”, accidentalmente midieron la empatía del equipo de ventas.
Errores comunes: síntoma → causa raíz → solución
1) “Alcanzamos los IOPS anunciados, pero la app está más lenta”
Síntoma: fio a QD=256 muestra IOPS enormes; la app sigue expirando o P99 explota.
Causa raíz: La app funciona con baja concurrencia; los benchmarks de colas profundas intercambiaron latencia por IOPS.
Solución: Haga benchmark a QD realista (a menudo 1–32) y dimensione para latencia P99 a ese QD. Si necesita baja latencia y alto rendimiento, escale horizontalmente o use múltiples dispositivos/rutas.
2) “Ayer fue rápido; hoy está a la mitad de velocidad”
Síntoma: El rendimiento sostenido de escritura aleatoria cae tras algún tiempo de ejecución o mayor nivel de llenado.
Causa raíz: SSD fuera de caja vs estado estacionario, recolección de basura, agotamiento de caché SLC o presión en pools thin-provisioned.
Solución: Preacondicione, pruebe más tiempo, pruebe a llenados realistas y asegure sobreaprovisionamiento adecuado. Considere estrategia de TRIM periódica y evite pools al borde del colapso.
3) “Las lecturas van bien; las escrituras se quedan ocasionalmente segundos”
Síntoma: Mayormente OK, luego picos periódicos de latencia de varios segundos en escrituras.
Causa raíz: Eventos de flush de caché, commits de journal, destage del controlador o presión de metadatos del sistema de archivos.
Solución: Revise settings de writeback, política de caché del controlador, tamaño del journal del sistema de archivos y si tareas en segundo plano coinciden con los stalls.
4) “Agregar una optimización empeoró el rendimiento”
Síntoma: Tras afinar “por velocidad”, la latencia de cola empeora o el throughput cae.
Causa raíz: Opciones de montaje mal aplicadas, planificador IO equivocado, readahead demasiado agresivo o sobrecarga de compresión/cifrado en rutas calientes.
Solución: Revierta y luego pruebe cambios uno por uno con percentiles. Trate el tuning como experimentos, no creencias.
5) “El SAN está lento, pero los paneles del array dicen todo en verde”
Síntoma: En el host se ve await alto; el array muestra baja utilización.
Causa raíz: Problemas de ruta (multipath mal configurado), congestión, retransmisiones, límites de cola HBA o QoS que capan por iniciador.
Solución: Valide el estado de multipath, compruebe profundidades de cola, busque errores de enlace y confirme que no haya políticas QoS limitándolo.
6) “Benchmarks de volúmenes en la nube bien por 30 segundos, luego colapsan”
Síntoma: El primer minuto es increíble; luego choca contra un muro.
Causa raíz: Créditos de ráfaga o topes de baseline.
Solución: Haga benchmarks lo suficientemente largos para drenar créditos. Dimensione para el baseline, no para la ráfaga. Si la ráfaga forma parte de su diseño, pruebe el comportamiento de recarga de créditos bajo su ciclo de trabajo.
Tres microhistorias corporativas (anonimizadas, plausibles y técnicamente precisas)
Microhistoria 1: El incidente causado por una suposición equivocada
Sustituyeron un conjunto ruidoso de discos viejos por un arreglo brillante que “hacía 800k ops”. El plan del proyecto tenía una línea de rendimiento: “almacenamiento nuevo más rápido que el antiguo”. Ese fue el único criterio de aceptación. Pasó en una ventana de prueba de una hora. Todos se fueron a casa.
Dos semanas después, empezó el procesamiento de fin de mes. La base de datos no estaba limitada por CPU ni por locks. Simplemente… iba lenta. Los jobs por lotes se acumularon. Las latencias de API crecieron hasta que atención al cliente empezó a monitorear por su cuenta: “¿El sistema está caído?”
El arreglo de almacenamiento entregaba las ops prometidas, pero a una profundidad de cola que la aplicación nunca producía. La caché del arreglo hacía que las lecturas parecieran brillantes; las escrituras, en una carga mixta con commits síncronos, estaban limitadas por una política que no habían advertido: el reconocimiento de escritura estaba fijado en un modo de protección conservador y las escrituras aleatorias pequeñas se serializaban por un camino interno estrecho.
La suposición equivocada no fue “los proveedores mienten”. Fue más sutil: el equipo asumió que un número único de IOPS significaba “más rápido en todo sentido” y que las políticas de protección no tenían personalidad de rendimiento.
Arreglarlo no requirió heroísmo. Recolectaron percentiles a concurrencia realista, cambiaron la configuración de protección para la clase de volumen específica y separaron el WAL/IO de logs a una capa de menor latencia. El fin de mes dejó de ser un sacrificio ritual.
Microhistoria 2: La optimización que salió mal
Un equipo de plataforma intentó “desbloquear rendimiento” subiendo profundidades de cola por doquier. Aumentaron ajustes de cola NVMe, retocaron parámetros de multipath e incentivaron a los equipos a ejecutar con más IO pendientes. Los benchmarks mejoraron. La presentación quedó hermosa.
Luego el tráfico de producción cambió de forma. Un pequeño número de inquilinos empezó a generar ráfagas de lecturas y escrituras aleatorias al mismo tiempo que mantenimiento en segundo plano: snapshots, compactaciones y una reconstrucción en un nodo. El throughput parecía correcto, pero la latencia de cola se convirtió en una antología de horror. Los timeouts de requests subieron porque los servicios tenían deadlines estrictos y no podían esperar detrás de largas colas de dispositivo.
El fracaso era predecible: optimizaron para IOPS agregados, no para SLOs de latencia. Las colas profundas ocultaron el dolor manteniendo los dispositivos ocupados, pero los servicios orientados al usuario necesitan colas cortas y respuestas rápidas. Un dispositivo al 100% de utilización no es “eficiente” si convierte su percentil 99 en una nota de rescate.
La remediación fue tratar la profundidad de cola como configuración por carga de trabajo. Servicios sensibles a latencia recibieron QD más bajo y mayor aislamiento. Trabajos por lotes usaron colas profundas cuando la plataforma tenía margen. También añadieron controles de cgroups IO para impedir que tareas “útiles” en segundo plano se comieran la latencia de tráfico interactivo.
Lo más gracioso fue lo aburrido que quedó el gráfico final. La latencia de cola se aplanó; los IOPS pico cayeron. Nadie volvió a recibir páginas a las 2 a.m., que es el único KPI que importa.
Microhistoria 3: La práctica aburrida pero correcta que salvó el día
Otra compañía tenía una regla: cada plataforma de almacenamiento tenía una receta de benchmark corta y versionada. Mismos jobs fio, mismo runtime, mismos pasos de preacondicionamiento, mismos objetivos de llenado. Sin excepciones. Los ingenieros se quejaban en voz baja, porque la consistencia no es emocionante.
Un viernes llegó un nuevo lote de SSD “equivalentes” por sustitución de suministro. El sistema subió, migraron cargas y a las horas vieron P99 de escritura ligeramente más alto. No catastrófico—solo raro. El on-call sacó los resultados estándar de benchmark de su baseline interno y ejecutó la misma suite en un nodo aislado.
La diferencia fue obvia: el rendimiento sostenido de escritura aleatoria se degradaba más rápido y la cola era más gruesa. Los discos no estaban rotos; eran distintos. Firmware, tipo de NAND, comportamiento de caché—algo había cambiado.
Porque tenían datos de baseline aburridos, no discutieron por impresiones. Pusieron el nuevo lote en cuarentena en una capa menos sensible a latencia, actualizaron las restricciones de compra y exigieron una corrida de calificación para futuras sustituciones. Sin incidente, sin impacto al cliente, sin fin de semana perdido.
Así es como suele lucir la “excelencia operacional”: un gráfico que nadie mostrará y un pager que permanece silencioso.
Listas de verificación / plan paso a paso
Lista de cordura para compras (antes de firmar nada)
- Exija la receta de benchmark: tamaño de bloque, mezcla rw, QD, hilos, runtime, preacondicionamiento, tamaño del dataset.
- Exija latencia por percentiles: al menos P50/P95/P99 a la carga declarada.
- Exija comportamiento en estado estacionario: 30+ minutos para cargas con mucha escritura; incluya gráficos si es posible.
- Pruebe a niveles de llenado realistas: al menos 60–80% para pools flash si así va a operar.
- Especifique rendimiento en modo fallo: impacto de reconstrucción/scrub/fallo de controlador y tiempo de recuperación.
- Especifique requisitos del host: CPU, generación PCIe, HBA, versiones de drivers, ajustes de multipath.
- Aclare ráfaga vs baseline: especialmente para volúmenes en la nube y arreglos con caché.
Plan de ejecución de benchmark (repetible y defendible)
- Reserve un host limpio: desactive cron jobs no relacionados, backups y agentes ruidosos para la ventana.
- Valide identidad y salud: modelo/firmware, SMART, comportamiento térmico.
- Fije variables de prueba: misma versión de fio, mismo kernel, mismas opciones de montaje, misma política NUMA cuando sea posible.
- Preacondicione donde corresponda: especialmente para pruebas sostenidas de escritura.
- Ejecute múltiples perfiles: al menos 4K randread, 4K randwrite, mezcla 70/30 y una prueba de rendimiento secuencial.
- Registre percentiles y series temporales: no sólo salidas resumen; repita ejecuciones.
- Compare con su SLO: acepte/rechace en base a latencia al throughput requerido, no por IOPS pico.
Lista de aceptación en producción (después del despliegue)
- Establezca baselines: snapshots iostat/fio bajo condiciones conocidas como buenas.
- Instruya latencia: recolecte P95/P99 en capa host y app.
- Pruebe un modo de fallo: corte un camino, dispare un failover controlado o simule una ventana de reconstrucción.
- Valide aislamiento: asegure que jobs por lotes no puedan dejar sin recursos a cargas interactivas.
Preguntas frecuentes
Q1: ¿IOPS es inútil?
No. Es simplemente incompleto. IOPS es útil cuando se empareja con tamaño de bloque, profundidad de cola, mezcla lectura/escritura y percentiles de latencia. De lo contrario es un número que ayuda a alguien a ganar una reunión.
Q2: ¿Cuál es una profundidad de cola razonable para benchmarkear?
Haga el benchmark a la profundidad de cola que produce su carga. Si no lo sabe, mídalo indirectamente vía IO pendientes observados y comportamiento de latencia. Para muchos servicios sensibles a latencia, QD en el rango 1–32 por dispositivo es más representativo que 128+.
Q3: ¿Por qué los proveedores siempre usan 4K random read?
Porque produce un número de operaciones grande e impresionante, y es un patrón legítimo para algunas cargas. No es, sin embargo, un proxy universal de “almacenamiento rápido”.
Q4: ¿Cuánto tiempo debería ejecutar fio?
El tiempo suficiente para ver estado estacionario y comportamiento de cola. Para lecturas, unos minutos pueden bastar si el dataset supera la caché. Para escrituras sostenidas, 30 minutos es un buen punto de partida y a menudo se justifica más tiempo.
Q5: ¿Debería benchmarkear en dispositivos de bloque crudos o en archivos?
Si quiere capacidad del dispositivo, use crudo. Si quiere “lo que recibe mi aplicación”, pruebe a través del mismo stack de sistema de archivos que usará en producción. Ambos son válidos; mezclarlos sin decirlo es la causa de largas discusiones.
Q6: ¿Por qué baja el rendimiento cuando el disco está más lleno?
Las capas de traducción de flash necesitan bloques libres para gestionar escrituras eficientemente. Conforme el espacio libre disminuye, suben los costes de recolección de basura y la amplificación de escritura. Muchos sistemas lucen bien al 5–10% llenos y muy distintos al 70–90%.
Q7: ¿Y el “FPS” de un benchmark de aplicación en lugar de fio?
Los benchmarks de aplicación son mejores para dimensionamiento end-to-end—si reflejan su patrón de acceso y concurrencia. Pero aún pueden manipularse con cachés, datasets poco realistas o configuración de durabilidad desactivada. Trátelos con el mismo escepticismo: exija la receta y los percentiles.
Q8: ¿Cómo comparar NVMe local vs SAN vs almacenamiento en la nube?
Compare percentiles de latencia a su throughput requerido e incluya comportamiento ante fallos. SAN y nube suelen añadir latencia de ruta y variabilidad. NVMe local suele tener latencia menor pero es menos compartido y puede tener riesgos operativos distintos (reposición, replicación, fallo de nodo).
Q9: ¿Puedo confiar en una corrida de benchmark dentro de una VM?
Puede hacerlo si entiende la capa de virtualización: colas compartidas del host, políticas de estrangulamiento y vecinos ruidosos pueden dominar los resultados. Para planificación de capacidad, pruebe en el mismo entorno donde correrá. Para cualificación de dispositivo, pruebe en bare metal o con aislamiento estricto.
Q10: ¿Cuál es el criterio de aceptación más simple que no sea estúpido?
Elija un perfil de carga representativo y requiera latencia P99 por debajo de X ms a Y IOPS/MB/s durante al menos Z minutos, con dataset mayor que la caché y con ajustes de durabilidad igual a producción.
Conclusión: próximos pasos prácticos
Si solo recuerda tres movimientos, que sean estos:
- Rechace afirmaciones de rendimiento con un solo número. Pida la receta completa y los percentiles de latencia.
- Haga benchmarks como opera. Profundidad de cola realista, mezcla realista, tamaño de dataset realista, duración realista.
- Dimensione según su SLO, no por un titular. Compre “P99 bajo carga”, no “hasta” nada.
Luego haga lo poco glamoroso que lo hará parecer competente más tarde: escriba sus archivos de trabajo de benchmark, guarde salidas baseline y vuélvalos a ejecutar tras cambios. Cuando surja el próximo “pero el folleto dice…”, tendrá datos, no opiniones.