El peor tipo de problema de almacenamiento es el que “normalmente funciona”. La VM arranca. La base de datos supera sus pruebas iniciales.
Luego alguien ejecuta una carga real a las 10:14 un martes y tu gráfica de latencia iSCSI se convierte en arte moderno.
El síntoma es un tirón: pausas periódicas, colas de latencia largas y usuarios describiéndolo como “lentitud” como si fuera una métrica válida.
Si exportas ZVOLs de ZFS por iSCSI, estás manejando una cadena de cuchillos afilados: grupos de transacciones ZFS, semántica de sync,
encolamiento iSCSI, multipath y caché del sistema invitado. Si te equivocas con la geometría, pasarás la semana culpando “la red”
mientras ZFS espera educadamente a que tu pequeño SLOG deje de fundirse.
Un modelo mental: de dónde vienen los tirones
El “tirón” bajo carga rara vez es solo ancho de banda bruto. Es variabilidad. Tu I/O mediano puede verse bien, pero el percentil 99.9 se vuelve feo:
el invitado se pausa, el checkpoint de la base de datos se ralentiza, el hipervisor hace panic y reintentos, y el equipo de aplicaciones abre un ticket titulado
“El almacenamiento se congela aleatoriamente”.
Con ZVOLs de ZFS exportados vía iSCSI, los tirones suelen surgir de uno de estos puntos de estrangulamiento:
- Manejo de escrituras síncronas: el cliente emite una escritura con semántica FUA/flush; ZFS debe confirmar durabilidad. Sin un SLOG adecuado, aparecen picos de latencia.
- Comportamiento del grupo de transacciones (TXG): ZFS agrupa escrituras y las sincroniza periódicamente. Límites de datos sucios mal dimensionados o un pool lento pueden hacer que el tiempo de sync de un TXG se dispare.
- Desajuste de tamaño de bloque: el cliente hace escrituras aleatorias de 4K pero tu ZVOL tiene volblocksize de 128K, forzando amplificación por lectura-modificación-escritura.
- Encolamiento y presión de retorno: profundidad de cola del iniciador iSCSI, encolamiento en el target y colas de vdev de ZFS pueden crear latencia “sierra”.
- Outliers de latencia desde la capa física: un SSD que falla, un HBA problemático, una ruta que parpadea en multipath. ZFS te lo dirá si formulas la pregunta correcta.
El objetivo práctico: latencia predecible bajo carga sostenida, incluso si el pico de throughput baja un poco.
En producción, lo aburrido y consistente gana.
Datos interesantes y contexto (para que dejes de repetir la historia)
- ZFS nació en Sun a mediados de los 2000 como una pila de almacenamiento de extremo a extremo: checksums, almacenamiento en pool, snapshots y copy-on-write. No es tanto “un sistema de archivos encima de RAID” como “almacenamiento que se niega a mentir.”
- Copy-on-write hace que los snapshots sean baratos, pero también implica que las sobrescrituras se convierten en nuevas escrituras, y la fragmentación existe. Los workloads de bloques con muchas sobrescrituras aleatorias pueden “envejecer” un pool más rápido de lo esperado.
-
Los ZVOLs no son archivos. Un ZVOL es un dispositivo de bloques respaldado por ZFS. Esa distinción importa: los ZVOLs no tienen
recordsize; tienenvolblocksize, y es más difícil cambiarlo después. - iSCSI data de finales de los 90 como “SCSI sobre TCP”. Ganó porque Ethernet ganó, no por ser encantador. También explica por qué “rendimiento de almacenamiento” puede verse afectado por pequeños comportamientos de TCP.
- El ZFS Intent Log (ZIL) existe para hacer durables las escrituras síncronas. El dispositivo de log separado (SLOG) no es una caché de escritura; es una plataforma de baja latencia para la intención de escritura síncrona.
- Las guías tempranas de ZFS se diseñaron para discos giratorios y grandes escrituras secuenciales. Pools modernos con SSD/NVMe cambian el cuello de botella desde el tiempo de búsqueda a la amplificación de latencia y el comportamiento de colas.
- Los sectores de 4K lo cambiaron todo (Advanced Format). Si alineas mal ashift, puedes convertir una escritura de 4K en una lectura-modificación-escritura a nivel del disco. Ese impuesto lo pagas para siempre.
- La compresión antes era temida en workloads de bloques. LZ4 moderno es lo suficientemente rápido como para que activar la compresión a menudo reduzca I/O y mejore latencia, especialmente para imágenes de VM y bases de datos con patrones repetitivos.
- Multipath originalmente fue por redundancia pero ahora también es por rendimiento. Si lo configuras mal puedes balancear carga hasta causar pérdida de paquetes y timeouts.
Decisiones de diseño que importan (y las que no)
Elige ZVOL vs dataset con intención
Si el cliente espera un dispositivo de bloques (datastore del hipervisor, volumen Windows, base de datos clusterizada que quiere discos crudos), usa un ZVOL.
Si puedes presentar ficheros (NFS, SMB) y controlas los patrones de I/O de la aplicación, un dataset suele ser más fácil de ajustar y observar.
Pero este artículo trata sobre ZVOLs, así que nos quedaremos en ese campo de batalla.
Volblocksize: la decisión de “formato” que no puedes rehacer a la ligera
volblocksize es el tamaño de bloque interno que ZFS usa para el ZVOL. Influye fuertemente en la amplificación de escrituras y la rotación de metadatos.
Bloques más pequeños se adaptan mejor a I/O aleatorio. Bloques más grandes reducen la sobrecarga de metadatos para workloads secuenciales pero penalizan escrituras aleatorias pequeñas.
- Discos de arranque/sistema de VM: 8K o 16K es un buen inicio. 8K suele ganar para lecturas/escrituras mixtas aleatorias. 16K puede reducir sobrecarga si el workload no es muy conversador.
- Bases de datos (OLTP-ish): 8K si el tamaño de página de la BD es 8K (común). Haz coincidir la realidad. No luches contra la física.
- Grandes secuenciales (destinos de backup, media): 64K–128K puede ser apropiado, pero no exportes eso como datastore general de VMs salvo que disfrutes de paradas misteriosas.
Puedes cambiar volblocksize solo recreando el ZVOL y migrando datos. Eso no es un proyecto de fin de semana si ya estás en producción.
Ashift: decide una vez, sufre para siempre
ashift es el exponente del tamaño de sector del pool (por ejemplo, 12 significa 2^12 = 4096 bytes). Si tus dispositivos físicos son 4K (lo son), establece ashift=12.
Para muchos SSD, 12 es correcto; para algunos dispositivos con sectores de 8K, podrías querer 13.
La clave: no dejes que “auto-detect” falle y lo descubras después de que el pool tenga datos.
Escrituras síncronas: comprende lo que el cliente te pide garantizar
Las escrituras síncronas son la parte donde el sistema de almacenamiento promete que los datos no desaparecerán si se corta la energía.
En iSCSI, los invitados y los sistemas de archivos emiten flushes y escrituras FUA más de lo que se piensa—especialmente en pilas virtualizadas.
ZFS puede manejar escrituras síncronas sin un SLOG escribiendo en el pool principal, pero la latencia seguirá la del vdev más lento para escrituras estables.
Si te importa la latencia de cola, probablemente quieras un SLOG dedicado en SSD/NVMe de baja latencia con protección contra pérdida de energía (PLP).
SLOG: no es “más caché”, es “menos espera”
Un SLOG acelera el reconocimiento de escrituras síncronas al persistir rápidamente la intención. Luego, ZFS vacía el grupo de transacciones al pool principal.
Si tu workload síncrono es intenso, el SLOG necesita:
- Baja latencia bajo escrituras sostenidas (no solo “rápido secuencial”).
- Protección contra pérdida de energía o puedes perder escrituras síncronas confirmadas.
- Suficiente resistencia para la tasa de escritura (las escrituras ZIL pueden ser brutales).
Chiste #1: Comprar un “NVMe gaming” para SLOG es como contratar a un sprinter como vigilante nocturno—rápido, sí, pero dormido cuando se corta la energía.
Compresión: enciéndela salvo que tengas una razón fuerte en contra
Usa compression=lz4 para la mayoría de workloads ZVOL. Incluso si los datos no comprimen mucho, la sobrecarga es pequeña en CPUs modernas.
El beneficio suele ser menos bytes escritos en disco y menos I/O, lo que puede reducir la latencia.
Dedup: no lo uses
Dedup en ZVOLs es un clásico “se veía bien en una diapositiva”. Aumenta la presión de memoria y puede amplificar la latencia.
A menos que lo hayas modelado, benchmarkeado y puedas permitir la RAM y la complejidad operativa, no lo uses.
vdevs especiales y metadata: útiles, pero fáciles de malusar
Dispositivos de asignación especial pueden acelerar metadata y bloques pequeños.
En sistemas con muchos ZVOLs, esto puede ayudar ciertos patrones, pero también añade un nuevo dominio de fiabilidad.
Si pierdes un special vdev que contiene metadata, puedes perder el pool a menos que esté correctamente en espejo.
Trátalo como almacenamiento central, no como un “SSD de bonificación”.
Red: 10/25/40/100GbE no arregla la latencia
iSCSI es sensible a pérdidas, presión de buffers e inestabilidad de rutas. Un enlace rápido con microbursts aún puede producir tirones.
Tu objetivo es latencia consistente, no solo números grandes en iperf.
Construir un objetivo iSCSI ZVOL que se mantenga suave
Supuestos de base
Los ejemplos asumen un host ZFS basado en Linux ejecutando OpenZFS, exportando LUNs de bloques por iSCSI usando LIO (targetcli).
El cliente es un iniciador Linux, pero señalaremos peculiaridades de Windows/ESXi.
Ajusta a tu plataforma, pero conserva los principios: alinea la geometría, respeta sync y mide la latencia donde se genera.
Diseño del pool: mirrors superan a RAIDZ para latencia de escrituras aleatorias
Para workloads de VM/iSCSI de bloques, los mirrors suelen superar a RAIDZ en latencia e IOPS consistentes. RAIDZ puede estar bien para workloads mayormente secuenciales
o de solo lectura, pero las escrituras aleatorias pequeñas deben tocar paridad y pueden amplificar la latencia durante reconstrucciones.
Si debes usar RAIDZ por razones de capacidad, contempla escrituras síncronas más lentas y colas de latencia más pronunciadas durante scrubs/resilvers.
Aún puedes ejecutar producción en ello; solo que no puedes sorprenderte luego.
Crear el ZVOL con propiedades sensatas
Un buen conjunto inicial para un ZVOL estilo datastore general para VM:
volblocksize=8Ko16Ksegún el workloadcompression=lz4sync=standard(no pongasdisabledpara “arreglar” latencia salvo que te guste la pérdida de datos)logbias=latencypara workloads con muchas escrituras síncronas (común en almacenamiento de VM)
También decide si quieres aprovisionamiento delgado. Los ZVOLs pueden ser sparse (delgados) o thick. Delgados son cómodos. Delgados también permiten
oversubscribe hasta que el pool llega al 100% y todo se vuelve un incidente en cámara lenta.
Expórtalo vía iSCSI con encolamiento predecible
Con LIO, típicamente:
- Crear un backstore apuntando al ZVOL
- Crear un IQN de target iSCSI y un portal
- Crear un mapeo de LUN y ACLs
- Opcionalmente afinar sesiones, recuperación de errores y timeouts
Donde se esconden los tirones: I/O pendientes excesivas pueden hacer que la latencia parezca “congelación periódica” cuando la cola se vacía.
Subajustar puede limitar throughput, pero sobreajustar causa picos de latencia en cola y timeouts. Quieres suficiente profundidad de cola para mantener los discos ocupados,
no tanto como para crear un atasco de tráfico I/O.
Multipath en el lado cliente: aburrido, específico y obligatorio en producción
Multipath resuelve dos problemas: conmutación por error y distribución de carga. También crea un nuevo modo de fallo: path flapping, donde el cliente
hace thrash entre rutas y tu almacenamiento parece “perder paquetes” cuando en realidad está siendo balanceado por políticas.
Usa dos rutas físicas separadas si reclamas redundancia. NICs separadas, switches separados si es posible, todo separado. De lo contrario, es teatro.
Una cita que pertenece realmente a ops
“La esperanza no es una estrategia.” — idea parafraseada frecuentemente atribuida a operadores e ingenieros de confiabilidad
Tareas prácticas: comandos, salidas y decisiones
No puedes afinar aquello que no puedes observar. Abajo hay tareas prácticas que puedes ejecutar en el target ZFS/iSCSI y en el iniciador.
Cada tarea incluye: el comando, qué significa una salida típica y qué decisión tomar a partir de ello.
Tarea 1: Verificar salud del pool y errores de hardware obvios
cr0x@server:~$ sudo zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 0 days 02:11:43 with 0 errors on Sun Dec 22 03:10:16 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
errors: No known data errors
Significado: cualquier READ/WRITE/CKSUM no cero es una pista, no una sugerencia. Incluso un único dispositivo inestable puede crear “tirones”
debido a reintentos y finalización lenta de I/O.
Decisión: si ves errores o un vdev degradado, deja de afinar. Arregla el hardware primero. Trabajar el rendimiento sobre almacenamiento roto es solo cosplay.
Tarea 2: Confirmar ashift y topología de vdev (las expectativas de latencia empiezan aquí)
cr0x@server:~$ sudo zdb -C tank | egrep -i 'ashift|vdev_tree|type'
type: 'root'
type: 'mirror'
ashift: 12
type: 'mirror'
ashift: 12
Significado: ashift=12 indica alineación de sector de 4K. Si descubres ashift=9/10/11 en dispositivos 4K, has encontrado un impuesto permanente.
Decisión: ashift incorrecto suele significar “reconstruir el pool correctamente”. Si eso no es posible de inmediato, documenta el riesgo y deja de prometer baja latencia.
Tarea 3: Comprobar cuán lleno está el pool (ZFS se pone quisquilloso cuando está abarrotado)
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME USED AVAIL REFER MOUNTPOINT
tank 18.2T 2.11T 256K /tank
Significado: con solo ~10% libre, la fragmentación y el comportamiento del asignador pueden aumentar la variabilidad de latencia, especialmente en workloads de bloques.
Decisión: apunta a mantener espacio libre significativo (a menudo 20%+ para pools ocupados). Si estás justo, planifica capacidad antes de ajustar profundidades de cola.
Tarea 4: Inspeccionar las propiedades del ZVOL (tamaño de bloque, compresión, sync)
cr0x@server:~$ zfs get -o name,property,value -s local,default volblocksize,compression,sync,logbias,refreservation tank/zvol/vmstore
NAME PROPERTY VALUE
tank/zvol/vmstore volblocksize 8K
tank/zvol/vmstore compression lz4
tank/zvol/vmstore sync standard
tank/zvol/vmstore logbias latency
Significado: esta es tu lista básica de “¿está sensato?”. sync=disabled en un datastore de VM es una bandera roja salvo que hayas tomado la decisión de riesgo explícita.
Decisión: si volblocksize está claramente mal para el workload (p. ej., 128K para OLTP), planifica migrar a un nuevo ZVOL. No finjas que es un ajuste de sysctl.
Tarea 5: Crear un ZVOL correctamente (ejemplo) y explicar por qué
cr0x@server:~$ sudo zfs create -V 4T -b 8K -o compression=lz4 -o logbias=latency -o sync=standard tank/zvol/vmstore2
Significado: -V crea un volumen de bloques, -b establece volblocksize al crear, y estamos eligiendo explícitamente comportamiento amigable con la latencia para escrituras síncronas.
Decisión: elige 8K cuando no sepas mejor y esperes escrituras aleatorias. Elige 16K si tu workload es mixto pero no de I/O muy pequeño y quieres algo menos de sobrecarga de metadata.
Tarea 6: Confirmar que existe el dispositivo de bloque y ver sus tamaños de sector
cr0x@server:~$ ls -l /dev/zvol/tank/zvol/vmstore2
lrwxrwxrwx 1 root root 13 Dec 25 10:12 /dev/zvol/tank/zvol/vmstore2 -> ../../zd16
cr0x@server:~$ sudo blockdev --getss /dev/zd16
4096
cr0x@server:~$ sudo blockdev --getpbsz /dev/zd16
4096
Significado: el ZVOL presenta sectores lógicos de 4K aquí. Eso normalmente es bueno para invitados modernos y se alinea con ashift=12.
Decisión: si tu stack iniciador/OS espera 512 y presentas 4K, algunos invitados antiguos se comportan mal. Para sistemas modernos, 4K suele estar bien y a menudo es mejor.
Tarea 7: Verificar si tienes un SLOG dedicado y si está en espejo
cr0x@server:~$ sudo zpool status tank | sed -n '1,120p'
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
logs
mirror-2 ONLINE 0 0 0
nvme4n1 ONLINE 0 0 0
nvme5n1 ONLINE 0 0 0
Significado: un SLOG en espejo reduce el riesgo de que la falla de un dispositivo de log provoque pérdida de escrituras síncronas recientes (según el modo de fallo).
Decisión: si ejecutas iSCSI con muchas escrituras síncronas y te importa la corrección, usa un SLOG en espejo con PLP. Si no puedes, acepta mayor latencia de sync y ajusta expectativas, no la física.
Tarea 8: Observar latencia y encolamiento de ZFS en tiempo real
cr0x@server:~$ sudo zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 2.11T 820 1900 91.3M 76.2M
mirror - - 410 950 45.6M 38.1M
nvme0n1 - - 205 470 22.8M 19.3M
nvme1n1 - - 205 480 22.8M 18.8M
mirror - - 410 950 45.7M 38.1M
nvme2n1 - - 205 475 22.9M 19.1M
nvme3n1 - - 205 475 22.8M 19.0M
logs - - 0 600 0 12.0M
mirror - - 0 600 0 12.0M
nvme4n1 - - 0 300 0 6.0M
nvme5n1 - - 0 300 0 6.0M
Significado: puedes ver si las escrituras están alcanzando el dispositivo de log (workload síncrono) y si algún vdev está atrasado.
Decisión: si un dispositivo consistentemente muestra menos ops o ancho de banda en un mirror, sospecha latencia del dispositivo, firmware, estrangulamiento térmico o problemas de topología PCIe.
Tarea 9: Revisar comportamiento de TXG y pistas de la “cadencia del tirón”
cr0x@server:~$ sudo arcstat.py 1 5
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
10:20:01 920 80 8 0 0% 40 50% 40 50% 128G 128G
10:20:02 980 70 7 0 0% 35 50% 35 50% 128G 128G
10:20:03 910 95 10 0 0% 47 49% 48 51% 128G 128G
10:20:04 940 82 9 0 0% 41 50% 41 50% 128G 128G
10:20:05 960 78 8 0 0% 39 50% 39 50% 128G 128G
Significado: la presión de ARC y misses a menudo se correlacionan con latencia de lectura, no con tirones de escritura. Pero si tu “tirón” es realmente oleadas de misses de caché de lectura,
esto lo mostrará: altas tasas de miss mientras la app se pausa.
Decisión: si ARC está al máximo y miss% es alto, considera memoria, tamaño de trabajo o mover workloads intensivos en lectura a protocolos de archivo donde la caché funcione mejor.
No saltes a L2ARC sin medirlo.
Tarea 10: Confirmar configuración del target iSCSI y LUNs mapeados
cr0x@server:~$ sudo targetcli ls
o- / ............................................................................. [...]
o- backstores ................................................................. [...]
| o- block ............................................................. [Storage Objects: 1]
| | o- vmstore2 ........................................ [/dev/zvol/tank/zvol/vmstore2 (4.0TiB)]
o- iscsi ............................................................... [Targets: 1]
o- iqn.2025-12.lab:storage.tank ............................................. [TPGs: 1]
o- tpg1 .......................................................... [no-gen-acls, no-auth]
o- acls ............................................................... [ACLs: 1]
| o- iqn.2025-12.lab:client01 .............................................. [Mapped LUNs: 1]
o- luns ............................................................... [LUNs: 1]
| o- lun0 ............................... [block/vmstore2 (/dev/zvol/tank/zvol/vmstore2)]
o- portals ......................................................... [Portals: 1]
o- 10.0.10.10:3260 .............................................................. [OK]
Significado: verifica que el backstore apunte al ZVOL previsto y que las ACLs mapeen el IQN del iniciador correcto.
Decisión: si ves backstores fileio para almacenamiento de VM de alto rendimiento, reconsidéralos: los backstores de bloque a ZVOLs suelen ser más limpios y rápidos.
Tarea 11: En el iniciador, confirmar sesiones y parámetros negociados
cr0x@server:~$ sudo iscsiadm -m session -P 3 | sed -n '1,120p'
iSCSI Transport Class version 2.0-870
iscsiadm version 2.1.9
Target: iqn.2025-12.lab:storage.tank
Current Portal: 10.0.10.10:3260,1
Persistent Portal: 10.0.10.10:3260,1
DataDigest: None
HeaderDigest: None
MaxRecvDataSegmentLength: 262144
MaxXmitDataSegmentLength: 262144
FirstBurstLength: 262144
MaxBurstLength: 1048576
InitialR2T: No
ImmediateData: Yes
Significado: estos parámetros influyen en rendimiento y coste CPU. Los digests añaden sobrecarga CPU pero ayudan a detectar corrupción en redes malas.
La mayoría de redes de DC limpias funcionan con digest desactivado.
Decisión: si la CPU es el cuello de botella o ves retransmisiones, revisa la red y MTU primero. No “ajustes” bursts iSCSI como primer movimiento; raramente es el problema principal.
Tarea 12: Verificar estado del multipath (los path flaps crean “tirones”)
cr0x@server:~$ sudo multipath -ll
mpatha (36001405f3f2b7f8d9d5b3d2a8c1e0001) dm-3 IET,VIRTUAL-DISK
size=4.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 4:0:0:0 sdb 8:16 active ready running
`-+- policy='service-time 0' prio=50 status=enabled
`- 5:0:0:0 sdc 8:32 active ready running
Significado: quieres rutas estables “active ready running”. Si ves rutas cambiando entre failed/active, ese es el generador de picos de latencia.
Decisión: arregla cableado/switching/NIC/MTU antes de tocar parámetros de ZFS. La afinación de almacenamiento no puede contradecir la física y la pérdida de paquetes.
Tarea 13: Buscar retransmisiones TCP y drops de NIC en el target
cr0x@server:~$ sudo nstat -az | egrep 'TcpRetransSegs|TcpExtTCPRenoReorder|IpInDiscards'
TcpRetransSegs 12 0.0
IpInDiscards 0 0.0
Significado: las retransmisiones añaden variabilidad de latencia. Unas pocas en mucho uptime está bien; que aumenten rápidamente bajo carga no lo está.
Decisión: si las retransmisiones se disparan durante tu “tirón”, investiga buffers de switch/ECN, desajuste MTU, óptica/cables defectuosos o saturación IRQ/CPU en la NIC.
Tarea 14: Observar la latencia de disco directamente (no adivines)
cr0x@server:~$ sudo iostat -x 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.10 0.00 5.20 2.80 0.00 79.90
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %util await r_await w_await
nvme0n1 210.0 480.0 24000 20000 0.0 0.0 71.0 1.80 1.20 2.10
nvme1n1 215.0 470.0 24500 19800 0.0 0.0 69.0 1.90 1.30 2.20
nvme2n1 205.0 475.0 23500 19900 0.0 0.0 73.0 1.70 1.10 2.00
nvme3n1 205.0 475.0 23600 20100 0.0 0.0 72.0 1.75 1.15 2.05
Significado: si await salta a decenas/centenas de milisegundos durante el tirón, los dispositivos del pool son el cuello de botella (o están siendo forzados a esperas síncronas).
Decisión: si la latencia de dispositivo está bien pero el cliente ve tirones, sospecha encolamiento iSCSI, flaps de multipath o comportamiento de escrituras síncronas (SLOG, oleadas de flush).
Tarea 15: Identificar presión de escrituras síncronas (pistas de uso ZIL/SLOG)
cr0x@server:~$ sudo zfs get -o name,property,value sync,logbias tank/zvol/vmstore2
NAME PROPERTY VALUE
tank/zvol/vmstore2 sync standard
tank/zvol/vmstore2 logbias latency
cr0x@server:~$ sudo zpool iostat -v tank 1 | sed -n '1,20p'
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 2.11T 200 2400 22.0M 98.0M
logs - - 0 1200 0 24.0M
Significado: operaciones de escritura significativas en logs indican actividad síncrona (ZIL). Si no tienes SLOG, esas escrituras síncronas van a los vdevs principales y pueden provocar picos de latencia.
Decisión: si tu workload es intensivo en sync y sensible a latencia, implementa un SLOG apropiado. Si ya tienes uno y persisten los tirones, valida que no esté saturado o con throttling térmico.
Tarea 16: Ejecutar un test fio controlado desde el iniciador (mide lo correcto)
cr0x@server:~$ sudo fio --name=iscsi-4k-randwrite --filename=/dev/mapper/mpatha --direct=1 --rw=randwrite --bs=4k --iodepth=32 --numjobs=4 --time_based=1 --runtime=60 --group_reporting
iscsi-4k-randwrite: (groupid=0, jobs=4): err= 0: pid=4121: Thu Dec 25 10:30:12 2025
write: IOPS=18.2k, BW=71.2MiB/s (74.7MB/s)(4272MiB/60001msec)
slat (usec): min=4, max=1120, avg=15.2, stdev=9.8
clat (usec): min=90, max=84210, avg=650.1, stdev=2100.4
lat (usec): min=110, max=84230, avg=666.2, stdev=2101.0
clat percentiles (usec):
| 1.00th=[ 140], 10.00th=[ 180], 50.00th=[ 310], 90.00th=[ 980], 99.00th=[ 5800]
| 99.90th=[38000], 99.99th=[79000]
Significado: la latencia media parece aceptable, pero 99.90th en 38ms y 99.99th en 79ms es tu “tirón”. Eso es lo que sienten los usuarios.
Decisión: optimiza para la latencia de cola, no la media. Si las colas se disparan periódicamente, correlaciónalas con tiempos de sync de TXG, comportamiento del SLOG y retransmisiones de red.
Guía rápida de diagnóstico
Cuando ocurre el tirón, necesitas una lista corta que reduzca el radio de impacto rápidamente. Este es el orden que uso porque encuentra
la clase de “obviamente roto” antes de que pierdas horas en tunables.
Primero: descarta fallos y flaps
- zpool status: ¿algún dispositivo con errores, vdev degradado o resilver? Si sí, esa es la historia.
- multipath -ll en iniciadores: ¿alguna ruta fallando/parpadeando? Si sí, arregla red/rutas.
- nstat / contadores NIC: retransmisiones, drops, overruns de ring. Si sí, tienes un problema de red/CPU/IRQ del host.
Segundo: decide si es latencia de disco o semántica de sync
- iostat -x en target: ¿picos de await? Si sí, discos o SLOG lentos o saturados.
- zpool iostat -v 1: ¿los dispositivos de log muestran muchas escrituras? Si sí, eres sync-heavy; la calidad del SLOG importa.
- percentiles de fio: latencias de cola altas con media moderada suelen apuntar a flush/sync periódicos o eventos de vaciado de cola.
Tercero: busca desajustes de configuración y amplificación
- volblocksize: ¿desajustado al workload? Un ZVOL 128K para escrituras aleatorias 4K hará tirones como reloj bajo presión.
- llenado del pool: pools cercanos a lleno amplifican problemas del asignador y la fragmentación.
- RAIDZ + escrituras síncronas aleatorias pequeñas: espera tails más altos, especialmente durante scrubs/resilvers.
Cuarto: afina profundidad de cola con cuidado
Afinar la profundidad de cola es el último paso porque puede enmascarar problemas y crear otros nuevos. Pero una vez verificado que el sistema está sano,
ajustar depth del iniciador y políticas de multipath puede suavizar la latencia sin sacrificar corrección.
Errores comunes: síntoma → causa raíz → solución
-
Síntoma: picos periódicos de latencia cada pocos segundos bajo carga de escritura
Causa raíz: presión de sync de TXG + almacenamiento estable lento, a menudo sin SLOG o SLOG malo
Solución: añade un SLOG en espejo con PLP; verifica que las escrituras de log lo alcancen; asegúrate de que el pool no esté casi lleno; programa scrubs/resilvers fuera de horas pico. -
Síntoma: buen throughput pero “congelaciones” en VMs, especialmente en invitados Windows
Causa raíz: oleadas de flush (sistema de archivos invitado, hipervisor o app), latencia de escrituras síncronas expuesta sobre iSCSI
Solución: SLOG correcto, mantenersync=standard; considera ajustes específicos en el invitado (política de caché de escritura) solo tras una revisión de riesgos. -
Síntoma: IOPS penosos en escrituras aleatorias 4K, alta utilización de disco, ancho de banda sorprendentemente bajo
Causa raíz: volblocksize demasiado grande causando amplificación read-modify-write
Solución: crea un nuevo ZVOL con volblocksize 8K/16K y migra; no intentes “solucionarlo” con tunables. -
Síntoma: el tirón aparece solo con multipath habilitado
Causa raíz: ruta secundaria inestable, path checker demasiado agresivo, misconfiguración de switch, ruteo asimétrico
Solución: estabiliza L2/L3 primero; ajusta políticas multipath sensatas; evita “round-robin todo” si tu target o red no lo manejan limpiamente. -
Síntoma: la latencia empeora tras habilitar L2ARC
Causa raíz: L2ARC robando RAM/CPU, thrash de caché o contención del SSD con workload del pool
Solución: quita L2ARC; aumenta RAM; añade L2ARC solo cuando hayas medido el working set de lectura y puedas dedicar un dispositivo rápido. -
Síntoma: el rendimiento colapsa durante scrub/resilver
Causa raíz: diseño del pool (RAIDZ), margen IOPS limitado, scrub compitiendo con producción, desequilibrio de vdevs
Solución: programa scrubs; ajusta comportamiento de scrub si es necesario; diseña pools con margen; mirrors para workloads de bloques críticos en latencia. -
Síntoma: pausas “aleatorias”; los logs muestran timeouts/reconexiones iSCSI
Causa raíz: retransmisiones TCP, desajuste MTU, problemas con offloads de NIC, saturación de IRQ CPU
Solución: valida MTU extremo a extremo; revisa drops; fija IRQs; considera desactivar offloads problemáticos; mantenlo simple y medible. -
Síntoma: uso de espacio parece bien, luego de repente todo se ralentiza cerca de la capacidad
Causa raíz: oversubscription por aprovisionamiento delgado + pool alcanzando alta utilización
Solución: aplica cuotas/refreservation; alerta antes; mantén espacio libre; trata la capacidad como un SLO, no como una hoja de cálculo.
Tres micro-historias corporativas desde el campo
Micro-historia 1: El incidente causado por una suposición errónea (volblocksize “no importa”)
Una empresa mediana migró desde un SAN Fibre Channel antiguo a un target iSCSI basado en ZFS. El plan de pruebas fue “copiar algunas VMs,
ejecutar pruebas de login y darlo por bueno.” Todo parecía bien en el laboratorio. En producción, el sistema ERP empezó a “colgarse” unos segundos
en horas pico de entrada de datos.
El equipo de infra asumió que la red estaba congestionada porque iSCSI es “sobre TCP”, y TCP es “frágil”. Añadieron ancho de banda:
actualizaron uplinks, reorganizaron VLANs e incluso reemplazaron un switch. El tirón permaneció, educadamente sin cambios. Los usuarios seguían describiéndolo como
“se pausa y luego se pone al día.”
La pista estuvo en un fio focalizado que reprodujo el problema: escrituras aleatorias de 4K mostraron grandes latencias en cola, aunque la latencia media
parecía aceptable. En el lado ZFS, el ZVOL se había creado con volblocksize de 128K—porque alguien leyó un post que decía “bloques grandes son más rápidos.”
Para el workload del ERP, el I/O era pequeño, aleatorio y con muchas escrituras síncronas.
Bajo carga, ZFS hacía ciclos read-modify-write en bloques grandes por pequeñas actualizaciones, generando churn de metadata y forzando I/Os extra.
El sistema no estaba “lento” tanto como “explosivo con miseria periódica.” La solución fue poco glamorosa: crear un nuevo ZVOL con volblocksize 8K,
migrar el LUN a nivel de hipervisor y mantener la compresión activada.
La mejora de red no fue en vano—mejoró el margen—pero no tocó la causa raíz. El postmortem cambió el proceso de construcción:
el tamaño de bloque pasó a ser un input formal de diseño, no un valor por defecto.
Micro-historia 2: La optimización que salió mal (sync=disabled “por rendimiento”)
Otro equipo operaba un clúster de virtualización en ZFS iSCSI. Tenían un buen pool, red decente y aún así recibían quejas por pausas de VMs
durante ventanas de parcheo. Alguien descubrió que poner sync=disabled hacía que los benchmarks cantaran. Lo aplicaron al ZVOL principal de VM
durante una ventana de mantenimiento y declararon victoria.
Por un tiempo, todo parecía excelente. Las gráficas de latencia se suavizaron. El helpdesk se quedó en silencio. Luego un evento de energía afectó a un rack—no todo el datacenter,
solo una fila donde falló un PDU. El servidor de almacenamiento se reinició. Un puñado de VMs arrancó con sistemas de archivos corruptos.
No todas. Justo las suficientes para que el incidente fuera real y desesperante.
La “optimización” del equipo no fue un cambio de afinación. Fue un cambio de integridad. Con sync deshabilitado, el sistema reconocía escrituras
que aún estaban en caché volátil. Para algunas VMs no importó; para otras sí. La recuperación fue mezclar restauraciones desde backups,
reparación de sistemas de archivos y un fin de semana largo explicando por qué la “solución rápida” borró datos.
La solución a largo plazo no fue una charla, sino arquitectura: SLOG en espejo con PLP para workloads síncronos, y negarse a cambiar semántica de seguridad de datos
para perseguir gráficas más bonitas. También añadieron pruebas que simulan pérdida de energía forzando reboots duros durante cargas sintéticas de escrituras síncronas
en preproducción.
Chiste #2: sync=disabled es el equivalente en almacenamiento a quitar detectores de humo porque el pitido molesta.
Micro-historia 3: La práctica aburrida pero correcta que salvó el día (margen de capacidad + disciplina de scrub)
Una firma financiera ejecutaba ZFS iSCSI para dev/test y un subconjunto de workloads analíticos de producción. Su responsable de almacenamiento tenía una política obstinada:
mantener los pools por debajo de umbral de utilización y ejecutar scrubs con programación y alertas claras por cualquier error de checksum.
Era aburrido. También significó que rutinariamente discutían con gerentes de proyecto sobre solicitudes de capacidad. Pero mantenían margen, y trataban
los scrubs como “higiene no opcional” en lugar de “algo que hacemos cuando estamos aburridos.”
En un trimestre, un job por lotes empezó a golpear el almacenamiento con escrituras aleatorias y flushes síncronos inesperados. La latencia aumentó, pero no se volvió
catastrófica. El pool aún tenía espacio libre, el asignador no estaba acorralado y los mirrors tenían margen de IOPS. El equipo pudo frenar el job por lotes,
ajustar horarios y afinar la profundidad de cola del iniciador sin presión existencial.
Durante el mismo periodo, un scrub detectó errores de checksum tempranos en un dispositivo. Lo reemplazaron preventivamente. Sin outage, sin drama, sin “perdimos medio día.”
La política no los hizo héroes. Hizo el sistema predecible, que es mejor.
Listas de verificación / plan paso a paso
Paso a paso: construir un nuevo ZFS iSCSI ZVOL que no se bloquee
- Elige la disposición del pool para latencia: mirrors para VM/iSCSI salvo que tengas una razón fuerte para otra cosa.
-
Confirma ashift antes de crear datos: verifica con
zdb -C. Si está mal, arréglalo ahora, no después. - Decide volblocksize según el workload: 8K/16K para stores generales de VM; coincide con el tamaño de página de BD cuando se conozca.
- Crea el ZVOL con propiedades explícitas: compresión lz4, sync standard, logbias latency si es sync-heavy.
- Planea espacio libre: objetivo operativo (p. ej., 20% libre). Configura alertas antes de llegar al dolor.
- Añade un SLOG apropiado si hay mucho sync: en espejo, PLP, baja latencia, resistencia acorde al ritmo de escritura.
- Exporta vía iSCSI con configuración estable: backstore de bloque a ZVOL; ACLs explícitas; configuración de portal consistente.
- Configura multipath en iniciadores: valida que ambas rutas sean realmente independientes; confirma “active ready running” estable.
- Ejecuta percentiles fio desde iniciadores: mide colas, no solo medias; prueba patrones sync-ish (fsync) y asíncronos.
- Registra una línea base: zpool iostat, iostat -x, retransmisiones, percentiles de latencia. Esto será tu “conocido bueno”.
Lista operativa: al añadir nuevos LUNs o nuevos tenants
- Confirma umbral de espacio libre del pool y crecimiento proyectado.
- Valida que
volblocksizecoincida con el perfil de I/O esperado del tenant. - Decide si usar
refreservationpara evitar sorpresas de aprovisionamiento delgado. - Revisa salud del SLOG y indicadores de desgaste (fuera del alcance de comandos ZFS, pero obligatorio).
- Programa scrubs y monitoriza errores de checksum como señal de primera clase.
- Ejecuta una prueba corta de humo con fio tras cambios en red o políticas de multipath.
Preguntas frecuentes
1) ¿Debo usar un dataset (archivo) sobre NFS en lugar de ZVOL iSCSI?
Si tu hipervisor y workload funcionan bien con NFS y quieres tuning y observabilidad más simples, los datasets NFS suelen ser más fáciles.
Usa ZVOL iSCSI cuando necesites semántica de bloque o el sistema operativo lo exija.
2) ¿Qué volblocksize debo elegir para almacenamiento de VM?
Comienza con 8K para workloads generales de VM cuando te importe la latencia de escrituras aleatorias. Usa 16K si has medido que tus workloads se inclinan hacia I/O más grande
y quieres algo menos de sobrecarga de metadata. Evita 64K/128K para stores VM mixtos salvo que realmente tengas patrones secuenciales.
3) ¿Puedo cambiar volblocksize más tarde?
No in-place. Normalmente creas un nuevo ZVOL con el volblocksize deseado y migras datos desde el cliente/hipervisor.
Planea esa realidad desde el principio.
4) ¿Necesito un SLOG para iSCSI?
Si tu workload emite escrituras síncronas (muchos lo hacen) y te importa la consistencia de latencia, sí—un SLOG en espejo PLP adecuado suele ser la diferencia
entre “suave” y “pausas misteriosas”. Si tu workload es mayormente asíncrono y puedes tolerar latencia de sync, puedes omitirlo.
5) ¿Por qué no simplemente poner sync=disabled y disfrutar la velocidad?
Porque cambia la corrección. Puedes perder escrituras reconocidas ante pérdida de energía o crash, y el fallo puede ser parcial y desagradable.
Si aceptas ese riesgo para un entorno de pruebas, documenta la decisión. En producción, no lo hagas.
6) ¿Ayuda L2ARC al rendimiento de ZVOL iSCSI?
A veces, para workloads de solo lectura con working set mayor que la RAM. Pero L2ARC consume RAM y CPU y puede competir con dispositivos.
Mide hit rates de ARC y latencia real de lectura antes de añadirlo. No es una palanca mágica de “más caché”.
7) Mirrors vs RAIDZ para iSCSI: ¿cuál es la diferencia práctica?
Los mirrors generalmente ofrecen mejor latencia en escrituras aleatorias y IOPS más predecibles durante rebuild/scrub. RAIDZ intercambia eso por eficiencia de capacidad.
Para VM/bases de datos sobre iSCSI, mirrors son la opción predeterminada más segura.
8) Mi red es 25/100GbE—¿por qué sigo teniendo tirones?
Porque el ancho de banda no arregla la latencia de cola. Microbursts, retransmisiones, flaps de rutas y saturación de interrupciones CPU pueden causar pausas incluso en enlaces rápidos.
Revisa drops/retransmisiones y estabilidad de multipath primero.
9) ¿Debo habilitar compresión en ZVOLs?
Sí, normalmente lz4. A menudo reduce I/O físico y mejora la latencia. Existen excepciones (flujos ya comprimidos),
pero “desactivarlo por defecto” es una superstición antigua.
10) ¿Por qué los benchmarks se ven bien pero las apps aún se quedan pausadas?
Muchos benchmarks reportan medias y ocultan latencias de cola. Los usuarios sienten el percentil 99.9. Usa percentiles de fio y correlaciónalos con TXG de ZFS,
actividad del SLOG y retransmisiones de red.
Conclusión: próximos pasos que puedes hacer esta semana
Si tu ZFS iSCSI ZVOL tiene tirones bajo carga, usualmente no es una perilla mágica. Es una cadena: geometría de tamaño de bloque, semántica de sync, calidad del dispositivo de log,
encolamiento y estabilidad de red. Tu trabajo es encontrar dónde se crean las esperas y luego eliminar las peores sin engañar sobre durabilidad.
Pasos prácticos:
- Ejecuta la guía rápida de diagnóstico durante un evento de tirón y captura evidencia:
zpool status,zpool iostat -v 1,iostat -x 1, contadores de retransmisiones y percentiles fio. - Audita el
volblocksizede cada ZVOL e identifica los outliers que no coinciden con la realidad del workload. - Decide explícitamente si necesitas un SLOG. Si sí, compra la clase correcta de dispositivo (PLP, baja latencia, en espejo), no “NVMe de consumo rápido.”
- Confirma la estabilidad de multipath de extremo a extremo. Elimina path flapping antes de tocar tunables de almacenamiento.
- Define una política de capacidad y alertas que mantenga el pool fuera de la zona “casi lleno” donde el tirón se convierte en un estilo de vida.