Compraste “almacenamiento rápido”. El pool rinde bien el primer día. Luego, un mes después, tus bases de datos empiezan
a comportarse como si cada consulta caminara por cemento húmedo. Grafana muestra latencia. El equipo de la app dice
que es la red. El equipo de red dice “no somos nosotros”. Ejecutas zpool iostat y aparece: un vdev sentado en la esquina,
con la cara roja, sudando, arrastrando todo el pool como si subiera un sofá por tres tramos de escalera.
ZFS es notablemente justo y notablemente implacable. Usará todos los vdev… hasta que uno no pueda seguir el ritmo.
Entonces el pool queda efectivamente regido por el participante más lento, especialmente para escrituras y cargas sensibles a la latencia.
Esto no es una historia de “ZFS es malo”. Es una historia de “la física es ruda”, más un puñado de decisiones de diseño
que puedes aprovechar, abusar o arreglar.
Qué significa realmente “desequilibrio de vdev” (y qué no)
En ZFS, un pool es una colección de vdevs. Un vdev es la unidad atómica de asignación de almacenamiento: ZFS distribuye
datos en franjas a través de vdevs, no a través de discos individuales (con la salvedad importante de que un vdev RAIDZ o mirror
usa internamente múltiples discos).
“Desequilibrio de vdev” es cuando un vdev realiza una cantidad desproporcionada de trabajo, o completa su trabajo mucho más
lentamente, de modo que la latencia o el rendimiento a nivel de pool quedan limitados. Puede ser:
- Desequilibrio de rendimiento: el vdev A tiene mayor latencia / menos IOPS que el vdev B bajo carga similar.
- Desequilibrio de asignación: el vdev A está mucho más lleno / fragmentado, así que las nuevas asignaciones son más difíciles y lentas.
- Desequilibrio de carga: roles “especiales” (SLOG, special vdev, patrones de metadata en L2ARC) canalizan la E/S a un subconjunto.
- Desequilibrio por modo de fallo: un dispositivo está reenviando comandos, remapeando o muriendo en silencio, y pagas la penalidad en la latencia de cola.
Lo que usualmente no es: que ZFS “escoja favoritos” al azar. ZFS tiene reglas. Si un vdev es más lento, más lleno,
más fragmentado o muestra errores intermitentes, ZFS seguirá enviando E/S y la latencia visible por el usuario del pool se convierte
en la suma de mil pequeños momentos de “espera por el lento”.
Chiste seco #1: Un vdev lento es como una reunión de estado que “solo tomará cinco minutos”: igual seguirás allí a las 11:30.
Cómo ZFS reparte la E/S entre vdevs
El pool es una franja entre vdevs, no una sopa mágica de rendimiento
El modelo mental básico que te mantiene cuerdo: ZFS asigna bloques a vdevs y, por lo general, intenta mantener el espacio libre equilibrado (con ponderación)
entre vdevs. Cuando tienes varios vdevs de primer nivel, el pool se comporta como una franja a nivel de vdev. Para muchas cargas,
eso significa que el rendimiento escala con el número de vdevs. Pero también significa que el pool hereda el peor comportamiento de latencia
de cualquier vdev que participe en la carga.
Decisiones de asignación: metaslabs, space maps y preferencia por lo “menos terrible”
ZFS divide los vdevs en metaslabs. Las metaslabs tienen space maps y ZFS usa heurísticas para elegir dónde colocar nuevos bloques. Prefiere
metaslabs con más espacio libre y mejores características de asignación. Con el tiempo, la fragmentación y el llenado cambian el costo de asignación.
Dos consecuencias importantes:
-
Al llenarse los vdevs, la asignación se vuelve más costosa y más fragmentada. Un vdev con 80–90% usado
puede volverse significativamente más lento que uno con 40–60% usado, incluso si los discos son idénticos. -
“Espacio libre equilibrado” no es igual a rendimiento igual. ZFS puede mantener el espacio libre aproximadamente parejo,
pero no puede igualar el comportamiento físico del dispositivo, los fallos de firmware o errores ocultos en el medio.
Lecturas vs escrituras: por qué sientes el dolor primero en las escrituras
Las lecturas a menudo tienen más “vías de escape”: caché ARC, prefetch, efectos de compresión y la posibilidad de que tus datos calientes
se agrupen en el vdev más rápido (por accidente o por política). Las escrituras tienen menos salidas. Cuando la app espera una escritura sync,
el eslabón más lento se convierte en toda la cadena.
Special vdevs, SLOGs y el problema del “embudo de rendimiento”
Algunas características de ZFS dirigen intencionalmente E/S específica a dispositivos concretos:
- SLOG (registro separado) para escrituras sincrónicas (ZIL). Genial si es rápido y seguro ante pérdida de energía; catastrófico si es lento o está sobrecargado.
- Special vdev para metadata y (opcionalmente) bloques pequeños. Genial si está bien provisionado; un cuello de botella si es pequeño o más lento que los vdevs principales.
- L2ARC para caché de lectura. No ralentiza directamente las escrituras, pero puede cambiar patrones de lectura y ocultar problemas hasta que los fallos de caché aumenten.
Si diseñas un embudo, lo posees. Pones un dispositivo lento en el fondo y has construido una máquina de latencia.
Por qué un vdev lento perjudica todo el pool
La latencia de cola es el límite real del pool
Las discusiones sobre rendimiento de almacenamiento adoran los promedios porque los promedios son educados. Los sistemas de producción viven en
percentiles porque los percentiles son honestos. Si un vdev tiene picos periódicos de 200–800 ms debido a reintentos de firmware,
amplificación por reescritura SMR o una cola de controlador saturada, esos picos se propagan.
ZFS no está haciendo un “esperar a todos” síncrono entre vdevs para cada bloque del pool. Pero la vista de latencia de tu
aplicación sigue moldeándose por la E/S más lenta de la que depende: commits de transaction group, flush de log de write sync,
actualizaciones de metadata, bloques indirectos y E/S aleatoria pequeña donde la paralelización está limitada.
RAIDZ y mirrors: la geometría interna importa
Un vdev de primer nivel puede ser un mirror, un RAIDZ1/2/3 o un disco único (no lo hagas). Si un disco dentro de un vdev RAIDZ
se vuelve más lento—porque está fallando, porque es SMR, porque está detrás de un expander extraño—entonces la latencia de todo el vdev RAIDZ
puede inflarse. No puedes “saltar” el disco lento; la aritmética de paridad y las lecturas de reconstrucción son actividades grupales.
Los mirrors se comportan diferente: las lecturas pueden ser atendidas por cualquier lado (ZFS elige según heurísticas), pero las escrituras
deben ir a ambos. Un único miembro del mirror lento eleva la latencia de escritura del vdev mirror.
El planificador del pool no puede arreglar un vdev malo
ZFS puede encolar E/S de forma inteligente. Puede emitir más a vdevs rápidos. Puede distribuir asignaciones. No puede convertir un dispositivo lento
en uno rápido, ni puede eliminar la física de la ecuación. Cuando la carga tiene escrituras sync, dependencias de metadata o I/O pendiente limitado,
un vdev lento se convierte en metrónomo del pool.
Idea parafraseada (cita de fiabilidad)
Idea parafraseada: la esperanza no es una estrategia
— Gene Kranz, flight director (ampliamente citado en la cultura ops; la frase varía).
En almacenamiento, “esperar a que el vdev lento deje de ser lento” no es un plan de remediación. Es un evento en el calendario esperando ocurrir.
Datos y contexto histórico que puedes usar en discusiones
- ZFS se originó en Sun Microsystems a mediados de los 2000 con un objetivo central: integridad de datos end-to-end mediante checksums y copy-on-write.
- El diseño de “vdev como unidad de asignación” es deliberado: simplifica dominios de fallo y el modelado de rendimiento en comparación con striping por-disco gestionado en múltiples lugares.
- Las primeras implementaciones de ZFS apostaron por RAIDZ para reducir el write hole de RAID5 y mejorar la integridad; los compromisos de rendimiento siempre fueron parte del trato.
- OpenZFS moderno añadió “special vdev” para acelerar metadata/bloques pequeños en SSDs; puede ser transformador—o convertirse en un punto único de estrangulamiento.
- El caché ARC de ZFS precede a la era actual de SSDs por todas partes; muchas quejas de “ZFS es lento” en realidad son “mi carga de trabajo ya no cabe en ARC”.
- Los discos SMR cambiaron el panorama de fallos: pueden parecer normales hasta que las escrituras aleatorias o actualizaciones sostenidas fuerzan comportamientos de read-modify-write y picos de latencia.
- Sectores 4K y ashift se volvieron un impuesto de rendimiento a largo plazo: un ashift incorrecto es permanente para ese vdev y puede cortar silenciosamente el rendimiento de escritura.
- Los scrubs de ZFS son una decisión de diseño, no una tarea opcional de vanidad: los scrubs regulares encuentran errores latentes antes de que un resilver los necesite.
- Los timeouts y reintentos de dispositivo son el enemigo oculto: incluso una pequeña cantidad de reintentos puede dominar la latencia de cola y la experiencia de usuario.
Guía rápida de diagnóstico (revisar primero/segundo/tercero)
Primero: confirma que es un cuello de botella de vdev, no que la app te mienta
- Ejecuta
zpool iostat -vcon columnas de latencia si están disponibles en tu plataforma, y observa qué vdev tiene peor await o mayor tiempo de servicio. - Comprueba si el pool está haciendo un scrub/resilver. Si es así, deja de adivinar: tu línea base de rendimiento ya no es válida.
- Verifica el tipo de carga: escrituras sync, lecturas aleatorias pequeñas, streaming secuencial o carga intensiva en metadata. La manifestación de “vdev lento” difiere.
Segundo: aísla si el vdev es lento porque está ocupado, falla o está estructuralmente en desventaja
- Ocupado: alta utilización, gran profundidad de cola, tasa de I/O sostenida alta.
- Fallo: tasa de I/O media pero picos enormes de latencia, errores que se incrementan, resets de enlace, timeouts.
- Desventaja estructural: mucho más lleno que otros, special vdev subdimensionado, ashift incorrecto, SMR mezclado con CMR, recordsize pequeño causando inanición de IOPS.
Tercero: decide si puedes arreglarlo en caliente o necesitas reconstrucción/migración
- Arreglo en vivo: reemplazar un dispositivo, quitar un log device, añadir vdevs, ajustar propiedades de dataset, reequilibrar reescribiendo datos.
- Reconstrucción/migración: vdev del tipo incorrecto, ashift equivocado, medios mixtos que siempre se comportarán mal, special vdev demasiado pequeño para crecer sin rediseño.
Chiste seco #2: RAIDZ no se preocupa por tus sentimientos, solo por tu presupuesto de IOPS.
Tareas prácticas: comandos, salidas y decisiones (12+)
Task 1: Identificar el vdev lento bajo carga real
cr0x@server:~$ zpool iostat -v 2 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 7.45T 8200 4100 780M 420M
raidz2-0 9.10T 3.72T 4100 2000 390M 205M
sda - - 1100 520 105M 54.0M
sdb - - 1000 510 95.0M 53.5M
sdc - - 950 500 92.0M 52.0M
sdd - - 1050 520 98.0M 54.0M
sde - - 1000 510 95.0M 52.5M
sdf - - 1000 510 95.0M 53.0M
raidz2-1 9.10T 3.73T 4100 2100 390M 215M
sdg - - 1050 540 98.0M 55.0M
sdh - - 1000 530 95.0M 54.0M
sdi - - 200 520 18.0M 53.0M
sdj - - 1050 540 98.0M 55.0M
sdk - - 1000 530 95.0M 54.0M
sdl - - 1000 530 95.0M 54.0M
Qué significa: El disco sdi contribuye con muchas menos lecturas que sus pares. Eso puede significar que esté lento, con errores,
o recibiendo tantos reintentos que el planificador lo evita para lecturas.
Decisión: Pasa inmediatamente a SMART + logs del kernel para sdi, y comprueba cableado/ruta del controlador. Si es miembro de un mirror,
considera reemplazarlo; si está en RAIDZ, espera que todo el vdev sufra durante lecturas de reconstrucción.
Task 2: Comprobar el estado del pool y si se acumulan errores
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Replace the device or clear the errors.
scan: scrub repaired 0B in 12:41:20 with 0 errors on Tue Dec 24 03:12:51 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
sdg ONLINE 0 0 0
sdh ONLINE 0 0 0
sdi ONLINE 3 0 0
sdj ONLINE 0 0 0
sdk ONLINE 0 0 0
sdl ONLINE 0 0 0
errors: Permanent errors have been detected in the following files:
/tank/vmstore/vm-104-disk-0
Qué significa: sdi tiene errores de lectura. Además, hay errores permanentes en un archivo: la tubería de checksum/reparación no pudo corregirlo por completo.
Decisión: Trata a sdi como sospechoso. Reemplázalo y luego restaura los datos afectados desde backups o réplicas. No “limpies y esperes” hasta entender el impacto.
Task 3: Comprobar si hay scrub/resilver en curso que esté enmascarando el comportamiento normal
cr0x@server:~$ zpool status tank
pool: tank
state: ONLINE
scan: resilver in progress since Wed Dec 25 01:10:02 2025
3.22T scanned at 1.14G/s, 920G issued at 322M/s, 18.0T total
920G resilvered, 5.00% done, 0:46:10 to go
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
Qué significa: Estás en tierra de resilver. Las quejas de rendimiento durante un resilver son esperadas; lo que importa es si un vdev está desproporcionadamente lento.
Decisión: Si tu SLA se está sangrando, considera programar resilvers/scrubs en ventanas de baja carga y asegúrate de que ashift, la clase de dispositivo y las rutas del controlador no estén creando una carretera de un solo carril.
Task 4: Confirmar si un vdev está mucho más lleno que otros
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME USED AVAIL REFER MOUNTPOINT
tank 18.2T 7.45T 192K /tank
cr0x@server:~$ zpool list -v tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH
tank 25.6T 18.2T 7.45T - - 38% 70% 1.00x ONLINE
raidz2-0 12.8T 9.10T 3.72T - - 31% 70% - ONLINE
raidz2-1 12.8T 9.10T 3.73T - - 46% 70% - ONLINE
Qué significa: Ambos vdevs tienen asignación similar, pero la fragmentación difiere: raidz2-1 está más fragmentado.
Decisión: Espera mayor sobrecosto de asignación y peor latencia de cola en el vdev más fragmentado. Si la fragmentación es alta y estable, planifica una estrategia de reescritura/rebalanceo (send/recv o migración de datasets).
Task 5: Capturar el patrón de “un dispositivo está reintentando” en los logs del kernel
cr0x@server:~$ dmesg -T | egrep -i "ata|scsi|nvme|reset|timeout|error" | tail -n 20
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] tag#1034 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] Sense Key : Medium Error [current]
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] Add. Sense: Unrecovered read error
[Wed Dec 25 02:13:22 2025] blk_update_request: I/O error, dev sdi, sector 7814037096 op 0x0:(READ)
[Wed Dec 25 02:13:25 2025] ata12.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
[Wed Dec 25 02:13:26 2025] ata12.00: failed command: READ FPDMA QUEUED
[Wed Dec 25 02:13:27 2025] ata12: hard resetting link
Qué significa: Resets duros y errores de lectura no recuperables crean largas paradas. Incluso si ZFS “cura” lecturas, pagas en latencia y bloqueos de cola.
Decisión: Reemplaza el dispositivo e inspecciona toda la ruta: firmware del HBA, expander, backplane, cables. Si varios discos muestran resets, sospecha primero de la ruta.
Task 6: Obtener SMART/NVMe y buscar contadores de “muriendo en silencio”
cr0x@server:~$ smartctl -a /dev/sdi | egrep -i "realloc|pending|uncorrect|offline|error|timeout|crc"
5 Reallocated_Sector_Ct 0x0033 098 098 010 Pre-fail Always - 24
197 Current_Pending_Sector 0x0012 100 100 000 Old_age Always - 6
198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 6
199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age Always - 34
Qué significa: Sectores pendientes/uncorrectable apuntan a problemas de medio. Errores CRC suelen señalar problemas de cableado/backplane.
Decisión: Si CRC está subiendo, reinstala/reemplaza cable/backplane y observa. Si hay pending/uncorrectable, programa el reemplazo. No negocies con la entropía.
Task 7: Comprobar si las escrituras sync están condicionadas por un SLOG lento o ausente
cr0x@server:~$ zpool status tank | sed -n '1,80p'
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
logs
nvme0n1p2 ONLINE 0 0 0
Qué significa: Hay un dispositivo de log dedicado. Si la latencia de escrituras sincrónicas es terrible, este dispositivo es sospechoso—o simplemente está saturado.
Decisión: Mide la latencia en el vdev de log específicamente (iostat, smart, nvme). Si es un NVMe de consumo sin protección ante pérdida de energía, replantea: seguridad de datos y picos de latencia no son características opcionales.
Task 8: Identificar special vdev y si se está convirtiendo en cuello de botella
cr0x@server:~$ zpool status tank | sed -n '1,120p'
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
special
mirror-2 ONLINE 0 0 0
nvme1n1p1 ONLINE 0 0 0
nvme2n1p1 ONLINE 0 0 0
Qué significa: La metadata (y tal vez bloques pequeños) viven en el special vdev. Si está lento, todo el pool se siente lento—especialmente cargas pesadas en metadata.
Decisión: Verifica propiedades del dataset como special_small_blocks. Asegura que el special vdev tenga margen de capacidad suficiente y resistencia/latencia comparable a tu carga.
Task 9: Ver ajustes de dataset que pueden amplificar el desequilibrio de vdev
cr0x@server:~$ zfs get -o name,property,value -s local recordsize,compression,atime,sync,logbias,special_small_blocks tank/vmstore
NAME PROPERTY VALUE
tank/vmstore recordsize 16K
tank/vmstore compression lz4
tank/vmstore atime off
tank/vmstore sync standard
tank/vmstore logbias latency
tank/vmstore special_small_blocks 16K
Qué significa: Recordsize pequeño más special_small_blocks=16K significa que muchos bloques van al special vdev. Eso está bien si el special vdev es rápido y con espacio.
Decisión: Si el special vdev está casi lleno o con alta latencia, reduce special_small_blocks (o desactívalo), o rediseña: más capacidad special, dispositivos más rápidos o cambiar recordsize según la carga.
Task 10: Cuantificar la latencia del vdev directamente con estadísticas por dispositivo
cr0x@server:~$ iostat -x 2 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
9.21 0.00 3.14 7.88 0.00 79.77
Device r/s w/s rkB/s wkB/s aqu-sz await r_await w_await svctm %util
sda 95.0 52.0 97280 53248 1.2 10.5 9.8 11.7 2.1 31.0
sdi 18.0 50.0 18432 51200 14.8 214.2 390.1 62.3 6.8 97.0
nvme0n1 620.0 410.0 640000 420000 0.9 1.4 1.2 1.7 0.2 18.0
Qué significa: sdi tiene un await enorme y está casi al 100% de utilización con cola profunda. Ese es el síntoma de vdev lento en neón.
Decisión: Si esto es persistente, reemplaza/evacúa el disco o arregla la ruta. Si es esporádico, busca trabajos en background (scrub, backup, snapshots) o comportamiento SMR.
Task 11: Comprobar ashift para detectar errores permanentes de alineación
cr0x@server:~$ zdb -C tank | egrep -i "vdev_tree|ashift" -n | head -n 30
54: vdev_tree:
78: ashift: 12
141: ashift: 9
Qué significa: Valores mixtos de ashift en un pool son un olor a problema. Un ashift de 9 (512B) en discos nativos 4K puede causar penalizaciones de read-modify-write.
Decisión: Si encuentras un ashift incorrecto, no puedes “ajustarlo”. Planifica el reemplazo/migración de vdev. No construyas nuevos pools sin establecer ashift deliberadamente si te importa el rendimiento predecible.
Task 12: Detectar fragmentación severa y patología de asignación
cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,health tank
NAME SIZE ALLOC FREE FRAG CAP HEALTH
tank 25.6T 18.2T 7.45T 38% 70% ONLINE
Qué significa: La fragmentación no es automáticamente fatal, pero cuando sube con el llenado del pool, las cargas de escritura aleatoria se ven castigadas.
Decisión: Si FRAG está alto y el rendimiento sufre, planifica un ciclo de reescritura (send/recv a un pool nuevo, o migración de datasets) en lugar de ajuste interminable.
Task 13: Ver si un vdev hace I/O desproporcionado a lo largo del tiempo
cr0x@server:~$ zpool iostat -v -l 5 3
operations bandwidth total_wait
pool read write read write read write
------------------------- ---- ----- ----- ----- ----- -----
tank 8200 4100 780M 420M 12ms 28ms
raidz2-0 4100 2000 390M 205M 8ms 16ms
raidz2-1 4100 2100 390M 215M 45ms 82ms
------------------------- ---- ----- ----- ----- ----- -----
Qué significa: raidz2-1 tiene tiempo de espera mucho mayor que raidz2-0 con throughput similar. Eso es desequilibrio a nivel vdev, no un accidente.
Decisión: Profundiza en los dispositivos dentro de raidz2-1. Si están sanos, sospecha de llenado/fragmentación, ruta del controlador o modelos/firmware de discos mezclados.
Task 14: Identificar quién genera la E/S (porque “el almacenamiento está lento” no es un proceso)
cr0x@server:~$ zpool iostat -v 1
...output...
cr0x@server:~$ iotop -oPa
Total DISK READ: 145.20 M/s | Total DISK WRITE: 81.33 M/s
PID USER DISK READ DISK WRITE SWAPIN IO> COMMAND
23144 root 90.12 M/s 1.23 M/s 0.00 % 22.14 % /usr/sbin/zfs receive -u tank/vmstore
18201 postgres 8.10 M/s 45.77 M/s 0.00 % 10.31 % postgres: checkpointer
Qué significa: Un zfs receive está escribiendo fuerte y Postgres está haciendo checkpoints. Eso puede crear ráfagas de escrituras sync y churn de metadata.
Decisión: Si esto es replicación planificada, aplica limitación de tasa o prográmalo. Si no estaba planificado, encuentra al responsable del job. Luego ajusta datasets (recordsize, comportamiento de sync) apropiadamente, no emocionalmente.
Modos de fallo comunes que crean desequilibrio de vdev (lo que realmente pasa)
1) Medios mixtos o unidades de “clase de comportamiento” mixta
Mezclar modelos de HDD que parecen similares en papel aún puede crear desequilibrio de vdev porque el firmware y el comportamiento de caché difieren.
Mezclar unidades CMR y SMR es peor: SMR puede mostrar picos masivos de latencia bajo escrituras aleatorias sostenidas o tareas de mantenimiento.
Mezclar SATA y SAS detrás de expanders diferentes también puede crear “un vdev está bien, el otro está encantado”.
Si tu pool tiene dos vdevs RAIDZ y uno fue construido con “lo que había”, no tienes un pool; tienes un experimento.
La producción no necesita experimentos.
2) Un único disco marginal dentro de RAIDZ o mirror
ZFS mantendrá el vdev online mientras un disco cojee con reintentos. Eso es bueno para disponibilidad. Es malo para latencia.
Un disco puede estar “suficientemente sano” para no fallar, pero lo suficientemente lento para destruir tu latencia de cola. Esto es común con:
- Incremento de sectores realojados/pending
- Errores CRC de interfaz por un cable/backplane inestable
- Trote térmico en chasis densos
- Bugs de firmware que provocan resets periódicos
3) Special vdev subdimensionado o demasiado lento
El special vdev es un multiplicador de rendimiento cuando se hace bien y un cuello de botella del pool cuando se hace mal.
La metadata es pequeña pero constante. Si colocas bloques pequeños en special y luego ejecutas imágenes VM con bloques de 8K–16K,
tu special vdev ahora es la ruta de escritura para gran parte de la carga.
Si el special vdev se llena, deja de aceptar asignaciones y puedes obtener comportamientos feos. Más sutilmente: incluso antes de llenarse,
si es más lento que tus vdevs principales (o simplemente está saturado), verás que el pool “se siente” con la latencia del special vdev.
4) Ashift incorrecto: deuda de rendimiento permanente
Las escrituras desalineadas crean ciclos de read-modify-write en el disco. Eso no es una molestia ajustable; es un defecto de diseño.
Si un vdev tiene un ashift erróneo, puede comportarse como un vdev lento para siempre, incluso cuando los dispositivos son idénticos.
5) Fragmentación + alto llenado del pool
La fragmentación en ZFS no es lo mismo que la fragmentación tradicional de sistemas de ficheros, pero el efecto es similar: más seeks, más metadata,
más I/O pequeño. RAIDZ es especialmente sensible a escrituras aleatorias pequeñas porque la aritmética de paridad y el read-modify-write amplifican el trabajo.
Con alta utilización, la selección de metaslabs se vuelve restringida y la opción “mejor” del asignador suele ser “menos terrible”.
6) Trabajo en background que olvidaste
Scrubs, resilvers, eliminación de snapshots, receives de replicación y compresión pesada pueden dominar la E/S. Un patrón común:
un vdev es ligeramente más débil, así que el trabajo en background se acumula más allí, lo que lo vuelve más débil, lo que acumula más cola.
Felicitaciones, has creado un bucle de realimentación positiva.
Tres mini-historias del mundo corporativo (anonimizadas, plausibles, técnicamente precisas)
Mini-historia 1: El incidente causado por una suposición equivocada
Una empresa mediana operaba un clúster de virtualización respaldado por un pool ZFS: dos vdevs RAIDZ2 de primer nivel, cada uno con seis discos.
El equipo supuso que “misma capacidad” significaba “mismo rendimiento”. Un vdev se construyó con una tanda de discos ligeramente más nueva
con una línea de firmware diferente. Compras dijo “equivalente”. No lo era.
Todo parecía bien en pruebas sintéticas: el throughput secuencial era excelente. Luego llegó el lunes—tormentas de boot de VMs,
inicios de sesión y una base de datos que nunca se cansó de lecturas aleatorias pequeñas. La latencia se disparó y se mantuvo elevada.
El equipo de aplicación vio timeouts. El equipo de almacenamiento no vio nada “caído”. El pool estaba ONLINE, los scrubs pasaban, la vida era verde.
El avance fue admitir que salud y rendimiento son estados separados. zpool iostat -v mostró un vdev
con tiempos de espera consistentemente más altos durante picos de lectura aleatoria. iostat -x por disco y logs del kernel mostraron resets
intermitentes de enlace en solo dos discos—suficientes para bloquear ese grupo RAIDZ.
La solución no fue un parámetro ZFS ingenioso. Fue aburrida: reemplazar los discos sospechosos y, más importante, arreglar la ruta SAS
que causaba los resets. También cambiaron su estándar de construcción: cada vdev debe ser homogéneo en modelo/firmware y cada ruta HBA/backplane
debe validarse bajo carga antes del corte a producción.
La suposición equivocada fue sutil: “ZFS balanceará entre vdevs, así que un vdev ligeramente extraño no importará.” ZFS balanceó
las asignaciones perfectamente. La carga no se preocupó por la equidad. Se preocupó por la latencia de cola.
Mini-historia 2: La optimización que salió mal
Otra empresa tenía un pool que servía directorios home y artefactos de CI. Las búsquedas de metadata eran intensas, así que añadieron un special vdev
sobre un par de NVMe de consumo. Al principio fue rápido. Tan rápido que la gente empezó a llamarlo “el modo turbo SSD”, frase que debería
activar una revisión de riesgos.
El equipo habilitó special_small_blocks ampliamente porque mejoró los tiempos de job de CI. Luego la mezcla de datasets cambió:
más archivos pequeños, más capas de contenedores, más escrituras aleatorias pequeñas. El special vdev se convirtió tanto en almacén de metadata como en sitio
para bloques pequeños. El desgaste aumentó. La latencia empezó a tambalear. Nadie lo notó—ARC y L2ARC enmascaraban lecturas y las escrituras “usualmente”
se completaban rápido.
Meses después, una ráfaga de escrituras sync en horas pico expuso la debilidad. Los NVMe de consumo empezaron a estrangularse por calor
y escrituras sostenidas. El pool no cayó. Simplemente pareció una caída: los prompts colgaban, los builds fallaban y todos culparon al sistema de CI.
El postmortem fue directo: optimizaron lo incorrecto. Trataron el special vdev como una caché (opcional, mejor esfuerzo).
No lo es. Es almacenamiento primario para lo que pongas allí. La solución implicó mover la asignación de bloques pequeños de vuelta a los vdevs principales
para la mayoría de datasets, mejorar la refrigeración y reconstruir el special vdev con dispositivos de grado empresarial con protección ante pérdida de energía.
El desastre no fue porque special vdev sea malo. Falló porque lo convirtieron en camino crítico y luego lo hicieron como un juguete.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día
Un equipo de servicios financieros operaba NFS sobre ZFS para una mezcla de análisis y shares de usuarios. Tenían un ritual: scrub semanal, revisión mensual
de tendencias SMART y una regla permanente de que cualquier disco con CRC creciente o conteos de sectores pending se reemplaza en horario laboral.
No porque esté fallando ahora, sino porque no les gustan las sorpresas.
Un jueves, la latencia empezó a subir. No un pico—solo una subida lenta. El on-call miró zpool iostat y vio el tiempo de espera de un vdev
subiendo. zpool status estaba limpio. Sin errores. Todo ONLINE. Aquí es donde muchos equipos paran.
Su práctica “aburrida” entró en acción: sacaron SMART de todo el chasis y encontraron un disco con un pequeño pero constante incremento en
UDMA_CRC_Error_Count. Eso no grita “reemplázame”. Susurra “tu cable está flojo”. Reinstalaron el cable, los errores dejaron de subir
y la latencia se normalizó sin drama.
Dos días después, durante una ventana de mantenimiento programada, reemplazaron el arnés de cables y auditaron el mapeo del backplane.
Sin outage, sin pérdida de datos, sin pager a medianoche. El pool nunca quedó DEGRADED. Ese es el punto. El mejor incidente es el que nunca genera un ticket.
Errores comunes: síntoma → causa raíz → solución
1) “El throughput del pool está bien, pero la latencia es horrible”
Síntoma: Grandes copias secuenciales se ven rápidas; bases de datos y VM I/O se paran; p99 con picos.
Causa raíz: Un vdev/disco tiene alta latencia de cola (reintentos, estrangulamiento, comportamiento SMR), o el special vdev/SLOG está saturado.
Solución: Identifica el vdev lento con zpool iostat -v + iostat -x. Reemplaza/repara el componente lento. Verifica dimensionamiento y clase de dispositivo del special vdev.
2) “Un vdev muestra mayor tiempo de espera incluso con discos idénticos”
Síntoma: Dos vdevs RAIDZ, mismos modelos de disco, pero uno es consistentemente más lento.
Causa raíz: Diferente ruta de controlador, expander, ajustes de cola o un único disco marginal dentro del vdev.
Solución: Revisa logs del kernel por resets, verifica cableado/backplane, compara await/%util por disco. Intercambia discos entre bahías si necesitas pruebas.
3) “Scrub/resilver tarda una eternidad y el rendimiento cae”
Síntoma: La ETA del resilver oscila; la I/O de usuario se para durante el scan.
Causa raíz: Un disco débil o vdev saturado; alta fragmentación; carga concurrente pesada; discos SMR.
Solución: Reduce la carga competidora, prioriza la ventana de reparación y reemplaza discos lentos. Si hay SMR, planifica migración; no lo debates.
4) “Después de añadir un nuevo vdev, nada mejoró”
Síntoma: Añadiste capacidad/IOPS pero el rendimiento sigue limitado.
Causa raíz: Los datos existentes permanecen en los vdevs antiguos; el sesgo de asignación no rebalancea retroactivamente; el conjunto de trabajo caliente no se movió.
Solución: Rebalancea reescribiendo datos (send/recv, rsync a nuevo dataset o migración de VMs). No esperes magia por “añadir vdev”.
5) “Carga intensiva en metadata es lenta, pero los discos están ociosos”
Síntoma: Listados de directorio, operaciones de archivo pequeño, desempaquetado de contenedores lentos; %util de disco no es alto.
Causa raíz: Special vdev sobrecargado o casi lleno; presión de ARC causando misses constantes de metadata; desajuste de recordsize.
Solución: Inspecciona uso del special vdev, estadísticas ARC y propiedades del dataset. Expande o rediseña el special vdev; ajusta special_small_blocks y recordsize.
6) “El rendimiento de escritura aleatoria colapsó tras el pool alcanzar ~80%”
Síntoma: Misma carga, peor rendimiento con el tiempo; sin cambios de hardware.
Causa raíz: Fragmentación + restricciones del asignador + amplificación de pequeñas escrituras en RAIDZ.
Solución: Mantén pools con margen para cargas de escritura aleatoria, o planifica reescrituras periódicas/migración. El tuning no desfragmentará un vdev.
Listas de verificación / plan paso a paso
Cuando suenan las alarmas de latencia: triage de 15 minutos
- Ejecuta
zpool status. Si scrub/resilver está activo, anota el incidente y ajusta expectativas. - Ejecuta
zpool iostat -v 2 5. Identifica qué vdev está lento (desbalance wait/throughput) y qué disco es raro. - Ejecuta
iostat -x 2 3. Confirma high await/%util en los dispositivos sospechosos. - Revisa
dmesgpor resets/timeouts. Si están presentes, deja de debatir; arregla la ruta o reemplaza el disco. - Extrae SMART/NVMe. Busca pending/uncorrectable y tendencias CRC.
- Si hay escrituras sync involucradas, inspecciona salud y carga del SLOG. Si es intensivo en metadata, inspecciona el special vdev.
Estabiliza primero, optimiza después
- Elimina el componente fallando (reemplaza disco, arregla cable/ruta HBA).
- Limita o reprograma jobs en background (receives de replicación, scrubs, borrado de snapshots) durante picos.
- Verifica utilización y fragmentación del pool; planifica capacidad antes de llegar al punto crítico del asignador.
- Sólo tras estabilizar: afina propiedades de datasets para la carga (recordsize, compresión, atime, sync/logbias según corresponda).
Plan de reequilibrio (porque añadir vdevs no mueve bloques antiguos)
- Crea un dataset nuevo (o un pool nuevo) con propiedades correctas.
- Usa
zfs send/zfs receivepara reescribir los datos en la nueva disposición de asignación. - Hacia los consumidores (mountpoints, shares, configuración de VM).
- Destruye datasets antiguos para liberar espacio y reducir la fragmentación.
Lista de diseño para prevenir desequilibrio (lo que exigiría en un estándar de construcción)
- Vdevs homogéneos: mismo modelo de disco, familia de firmware y nivel de desgaste aproximado.
- Ashift consistente (configurarlo deliberadamente).
- Separar roles de rendimiento solo con dispositivos apropiados (PLP para SLOG, SSDs empresariales para special vdev).
- Margen de capacidad: no operar pools al 85–95% si te importa I/O aleatorio.
- Sanidad de la ruta del controlador: validar expanders/backplanes; mantener colas consistentes entre vdevs.
- Higiene operativa: scrubs regulares, monitorización de tendencias SMART y responsabilidad clara para jobs de alta I/O.
Preguntas frecuentes
1) ¿Un disco lento siempre ralentiza todo el pool ZFS?
No siempre, pero lo suficiente como para planificar en consecuencia. Si el disco lento está dentro de un vdev RAIDZ, puede elevar la latencia de ese vdev.
Si tu carga depende de la I/O de ese vdev (lo hará), la latencia p99 puede saltar. ARC puede ocultar el dolor de lectura hasta que ya no alcance.
2) ¿Por qué ZFS “usa” el vdev lento en absoluto?
Porque el pool se construye a partir de vdevs y ZFS asigna entre ellos. Puede favorecer asignaciones según espacio libre y heurísticas,
pero no puede evitar permanentemente un vdev sin removerlo. Si quieres que ZFS no lo use, debes rediseñar: reemplazar o remover.
3) Si añado un vdev nuevo y rápido, ¿ZFS rebalanceará los datos existentes?
No. Los bloques existentes permanecen donde están. Las nuevas asignaciones tenderán a ir a vdevs con más espacio libre, así que el rendimiento puede mejorar
lentamente a medida que el working set cambia. Si necesitas rebalance inmediato, reescribe los datos (send/recv o migración).
4) ¿RAIDZ es más sensible al desequilibrio de vdev que los mirrors?
En general sí para escrituras aleatorias pequeñas y comportamiento de reconstrucción. RAIDZ tiene overhead de paridad y puede hacer read-modify-write para franjas parciales.
Los mirrors pueden servir lecturas desde cualquiera de sus miembros, lo que a veces enmascara un miembro lento en lecturas, pero las escrituras siguen pagando por el miembro más lento.
5) ¿Un special vdev puede convertirse en cuello de botella aunque sea SSD?
Absolutamente. SSD no es una garantía; es una clase de dispositivo con amplia variación. Un special vdev pequeño puede llenarse, y un SSD de consumo puede estrangularse,
sufrir picos de latencia o desgastarse más rápido bajo churn de metadata/bloques pequeños. Trata el special vdev como almacenamiento nivel-0, no como caché.
6) ¿Debería desactivar las escrituras sync para “arreglar” rendimiento?
Solo si puedes tolerar perder escrituras reconocidas ante una pérdida de energía o crash, y entiendes lo que eso significa para tu aplicación.
Para bases de datos y almacenamiento de VM, poner sync=disabled a la ligera es una regresión de fiabilidad disfrazada de mejora en benchmarks.
7) ¿Qué tan lleno es «demasiado lleno» para un pool?
Depende de la carga, pero si te importa la latencia de escritura aleatoria, empieza a preocuparte por encima de ~70–80% y planifica capacidad antes del 85%.
El asignador tiene menos buenas opciones conforme el espacio libre se reduce; la fragmentación y el overhead de metadata se acumulan.
8) ¿Cuál es la forma más rápida de probar que el problema es hardware y no “ajuste de ZFS”?
Combina: zpool iostat -v mostrando un vdev con mayor wait, iostat -x mostrando alto await/%util en dispositivos específicos,
y dmesg/smartctl mostrando resets o contadores de error. Ese triángulo es difícil de discutir en una reunión.
9) ¿Un ashift incorrecto puede causar que un vdev sea más lento que otros?
Sí, y es permanente para ese vdev. La desalineación puede aumentar la amplificación de escritura y la latencia. Si encuentras un vdev con ashift erróneo,
planifica su reemplazo/migración. No pierdas semanas afinando alrededor de un error de geometría.
10) ¿Por qué el pool se siente lento cuando solo un dataset está ocupado?
Porque los vdevs son recursos compartidos y ZFS tiene trabajo global (commits txg, actualizaciones de metadata, space map updates). Un dataset vecino ruidoso puede
saturar un vdev, elevar tiempos de espera y derramar en otras cargas. Usa separación de cargas (pools diferentes) cuando lo que está en juego es alto.
Conclusión: próximos pasos que realmente mejoran
ZFS no se “vuelve lento misteriosamente”. Hace exactamente lo que está diseñado para hacer: preservar integridad, asignar entre vdevs y seguir funcionando
incluso cuando partes del sistema cojean. El precio es que sientes cada componente lento en los lugares que importan: latencia de escrituras sync,
churn de metadata y comportamiento de cola.
Haz esto a continuación:
- Encuentra el vdev lento con
zpool iostat -vy confirma coniostat -x. - Revisa la ruta: logs del kernel + contadores SMART. Reemplaza cables y discos sospechosos temprano.
- Audita special vdev y diseño de SLOG. Si están en el camino crítico, deben construirse como producción, no como laboratorio.
- Planifica reequilibrio basado en reescritura después de expansiones. Añadir vdevs añade potencial; reescribir datos lo realiza.
- Mantén margen. Si quieres I/O aleatorio predecible, deja de tratar pools al 90% como normales.
Si recuerdas una cosa: el pool es tan rápido como el vdev más lento en el momento en que tu carga lo necesita. No discutas con eso.
Diseña en torno a ello, monitoriza y reemplaza tus eslabones más débiles antes de que se presenten a tus clientes.