Suena la alarma porque “el almacenamiento está lento”. La gráfica muestra que la latencia subió, pero solo a veces. El equipo de la aplicación
asegura que no cambiaron nada.
Inicias sesión, ejecutas zpool status, y ahí está: un vdev nuevo brillante añadido la semana pasada, apoyado junto a vdevs más antiguos y llenos como un nuevo contratado
que recibió todos los tickets fáciles y aun así rompió producción.
ZFS hace que sea fácil añadir capacidad. También hace fácil crear una disposición del pool que quede permanentemente desequilibrada en rendimiento y riesgo.
La trampa es simple: zpool add añade un vdev al pool, pero ZFS no redistribuye automáticamente los datos existentes entre vdevs.
Esa decisión de diseño es la razón por la que tu “expansión rápida” se convierte en el incidente de almacenamiento del próximo trimestre.
La trampa de «Add VDEV»: qué ocurre realmente
Cuando ejecutas zpool add, no estás “añadiendo discos” a un grupo de redundancia existente. Estás añadiendo un vdev de nivel superior completamente nuevo
al pool. ZFS entonces stripea las nuevas escrituras a través de los vdevs de nivel superior según el espacio y algunas heurísticas, pero no mueve los bloques antiguos.
Los vdevs antiguos permanecen llenos de datos antiguos; el vdev nuevo comienza vacío y absorbe muchas de las nuevas asignaciones.
Esto parece inocuo hasta que recuerdas qué significa un vdev de nivel superior: las IOPS del pool, el throughput y la tolerancia a fallos son la suma (o el mínimo)
de sus vdevs de nivel superior. Añade un vdev con diferente ancho, otra clase de disco, distinto ashift o un perfil de salud diferente, y has cambiado el
comportamiento del pool para el resto de su vida.
Un pool, muchas personalidades
Los pools ZFS no son “un RAID”. Un pool es una colección de vdevs de nivel superior. Cada vdev de nivel superior tiene su propia redundancia (mirror, raidz, dRAID),
y el pool hace striping entre ellos. Ese es el modelo. Es poderoso. También es cómo la gente construye accidentalmente un quimera de almacenamiento:
tres vdevs RAIDZ2 anchos, luego un mirror único “solo para añadir capacidad rápido”, luego un vdev SSD especial “por metadatos”, y ahora el pool
se comporta como un comité donde todos votan y la persona más lenta sigue bloqueando la reunión.
Por qué ZFS no rebalancea por defecto
La ausencia de auto-rebalanceo no es pereza; es conservadurismo. Mover bloques en un pool en vivo es costoso, desgasta unidades, arriesga casos límite por pérdida de energía
y complica las garantías. ZFS prefiere mantener punteros a donde ya viven los datos. Optimiza para corrección y supervivencia, no para “quedar bonito”.
La consecuencia operativa es directa: si añades un vdev y luego te preguntas por qué un vdev hace todo el trabajo, la respuesta es «porque está vacío y estás escribiendo
datos nuevos». Si te preguntas por qué las lecturas siguen golpear vdevs antiguos, es porque los datos antiguos siguen allí. ZFS no está siendo misterioso.
Está siendo literal.
Hechos y contexto que explican el comportamiento
- ZFS nació en Sun a principios de los 2000, diseñado para integridad de datos end-to-end con checksums en cada bloque, no solo «RAID rápido».
- Los pools fueron un cambio radical: en vez de tallar LUNs de grupos RAID fijos, agregas vdevs y asignas dinámicamente.
- Copy-on-write es la mecánica central: ZFS nunca sobreescribe bloques en vivo; escribe nuevos bloques y cambia punteros. Genial para snapshots, complejo para «rebalance».
- Los vdevs de nivel superior son la unidad de fallo: pierdes un vdev de nivel superior, pierdes el pool. Por eso un vdev de un solo disco es una bomba de tiempo.
- RAIDZ no es RAID5/6 en detalles de implementación; es stripe variable con paridad, interactuando con recordsize y patrones de asignación de formas que sorprenden a quienes migran desde RAID hardware.
- Ashift es para siempre por vdev: elegir la alineación de sector equivocada puede fijar amplificación de escritura durante la vida de ese vdev.
- Los vdevs especiales (metadata/pequeños bloques) hicieron más práctico los pools híbridos, pero también introdujeron un nuevo componente cuyo fallo puede dejar el pool inservible a menos que esté en mirror.
- L2ARC nunca fue un caché de escritura: es un caché de lectura y se reinicia en reinicio salvo que se habilite L2ARC persistente y sea soportado. La gente todavía lo trata como RAM mágica.
- El comportamiento de resilver difiere según tipo de vdev: mirrors resilverean el espacio usado; RAIDZ resilverea más y toca más la geometría del vdev.
Por qué el desequilibrio perjudica: rendimiento, resiliencia y coste
Rendimiento: el pool es tan fluido como su vdev más lento
En un pool equilibrado, tus IOPS y throughput escalan al añadir más vdevs de nivel superior de capacidad similar. En un pool desequilibrado, obtienes rarezas:
picos de buen rendimiento seguidos de saltos de latencia cuando un vdev se satura mientras otros están infrautilizados.
Aquí está el patrón clásico: añades un vdev nuevo, las escrituras nuevas caen mayoritariamente ahí, y tu monitorización se ve bien. Luego la carga cambia a lecturas de datos antiguos
(restauraciones de backup, trabajos analíticos que tocan particiones históricas, o una flota de VMs arrancando desde imágenes antiguas). De repente los vdevs antiguos se vuelven hotspots de lectura,
y el vdev nuevo está ocioso.
Resiliencia: mezclar niveles de redundancia es comprar riesgo con CAPEX
La tolerancia a fallos de un pool no es la “redundancia media”. Es la redundancia de cada vdev de nivel superior, y perder cualquiera de ellos mata el pool.
Añade un vdev mirror simple junto a varios vdevs RAIDZ2, y acabas de introducir un eslabón más débil: un mirror de dos discos sobrevive a un fallo,
mientras tus RAIDZ2 sobreviven a dos. Ahora tienes dominios de fallo desiguales.
Añade un vdev de un solo disco «temporalmente» y felicitaciones: acabas de crear un pool que está a un fallo de disco de perderse completamente.
La palabra «temporal» tiene una vida media larga en infraestructura.
Coste: pagas dos veces — por los discos y por las consecuencias
Los pools desequilibrados son caros de maneras aburridas: más tiempo on-call, más escalados, más «por qué este host es más lento» en debugging, más upgrades prematuros.
Y si tienes que «arreglar» el layout, la solución suele ser disruptiva: migrar datos, reconstruir pools o reescrituras controladas de bloques que toman semanas.
Broma #1: Añadir un vdev desajustado a un pool ZFS es como poner una rueda de repuesto en un coche de carreras—sí, rueda, y sí, todos la escuchan.
Guía de diagnóstico rápido (primera/segunda/tercera comprobación)
Cuando alguien dice “ZFS se volvió lento después de añadir discos”, no empieces por sintonizar recordsize. Empieza por probar si el pool está desequilibrado y dónde se va el tiempo.
Primera: ¿Un vdev de nivel superior está haciendo todo el trabajo?
- Comprueba I/O y latencia por vdev con
zpool iostat -v. - Busca un vdev con busy/await consistentemente más alto que los demás.
- Si lo ves, para. No estás depurando “rendimiento ZFS”. Estás depurando “disposición y asignación”.
Segunda: ¿Es bound por lectura, por escritura o por sync?
- Mix lectura/escritura:
zpool iostat -v 1yarcstat(si está disponible) para ver tasa de aciertos del ARC y presión de lectura. - Escrituras sync: comprueba
zfs get syncy si existe un SLOG y está sano. - Si los picos de latencia se correlacionan con ráfagas de escrituras sync, estás mirando ZIL/SLOG o latencia de escritura en la capa subyacente.
Tercera: ¿Realmente estás bloqueado en la capa de dispositivo?
- Revisa estadísticas de dispositivos del kernel:
iostat -xy contadores de errores consmartctl. - Confirma ashift y tamaños de sector. Un vdev nuevo con tamaño de sector físico distinto puede comportarse diferente bajo carga.
- Busca travesuras silenciosas: un enlace de controlador degradado, una unidad en modo SATA 1.5G o NCQ deshabilitado.
Tareas prácticas (comandos, salidas, decisiones)
Debajo hay tareas reales que puedes ejecutar en un host Linux con OpenZFS típico. Cada una incluye qué significa la salida y qué decisión tomar.
Úsalas como una lista de verificación cuando estés privado de sueño y la ventana de cambios esté cerrándose.
Tarea 1: Mostrar la topología del pool y detectar el “vdev nuevo” inmediatamente
cr0x@server:~$ sudo zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 03:12:44 with 0 errors on Tue Dec 10 02:40:11 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 0 0 0
sdj ONLINE 0 0 0
sdk ONLINE 0 0 0
sdl ONLINE 0 0 0
mirror-2 ONLINE 0 0 0
nvme0n1p2 ONLINE 0 0 0
nvme1n1p2 ONLINE 0 0 0
errors: No known data errors
Significado: Este pool tiene dos vdevs RAIDZ2 grandes y después un mirror. Ese mirror es de otra clase (NVMe) y tiene un perfil de redundancia distinto.
Decisión: Trátalo como un pool heterogéneo. Espera sesgo en las asignaciones y “modos” de rendimiento. Si ese mirror se añadió por capacidad, planifica una migración
o un enfoque deliberado de rebalance en lugar de más chapuzas.
Tarea 2: Identificar qué vdev está caliente (IOPS y ancho de banda)
cr0x@server:~$ sudo zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 82.1T 21.9T 3.21K 1.05K 410M 198M
raidz2-0 41.0T 3.7T 2.80K 190 360M 31M
sda - - 470 32 61M 5.2M
sdb - - 458 30 59M 5.1M
sdc - - 472 31 61M 5.1M
sdd - - 469 33 60M 5.3M
sde - - 467 31 60M 5.2M
sdf - - 464 33 59M 5.2M
raidz2-1 40.9T 3.8T 380 175 49M 29M
sdg - - 64 29 8.1M 4.8M
sdh - - 63 30 8.0M 4.9M
sdi - - 62 28 8.0M 4.7M
sdj - - 64 29 8.2M 4.8M
sdk - - 63 29 8.0M 4.8M
sdl - - 64 30 8.1M 4.9M
mirror-2 250G 850G 30 690 1.2M 138M
nvme0n1p2 - - 15 345 0.6M 69M
nvme1n1p2 - - 15 345 0.6M 69M
-------------------------- ----- ----- ----- ----- ----- -----
Significado: Las lecturas están dominadas por raidz2-0. Las escrituras están dominadas por el mirror NVMe. Ese es el clásico comportamiento de “el vdev nuevo absorbe escrituras”
y “los vdevs antiguos sirven lecturas”.
Decisión: Si las quejas de latencia son por lecturas, añadir más vdevs orientados a escritura no lo arreglará. Necesitas mover datos calientes,
añadir más vdevs RAIDZ similares o reconsiderar el diseño del pool.
Tarea 3: Confirmar el sesgo de asignación y su gravedad
cr0x@server:~$ sudo zpool list -v tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 104T 82.1T 21.9T - - 28% 78% 1.00x ONLINE -
raidz2-0 45.5T 41.0T 3.7T - - 34% 91% - ONLINE
raidz2-1 45.5T 40.9T 3.8T - - 31% 90% - ONLINE
mirror-2 1.09T 250G 850G - - 2% 22% - ONLINE
Significado: Dos vdevs grandes están ~90% llenos, el mirror nuevo está ~22% usado. Eso no es “capacidad equilibrada”, por lo tanto no será carga equilibrada
a menos que tu carga consista mágicamente solo de escrituras nuevas.
Decisión: No sigas añadiendo vdevs pequeños esperando que ZFS “lo distribuya”. Decide si vas a añadir más vdevs equivalentes de la misma clase/anchura
o migrar a un pool nuevo con un layout limpio.
Tarea 4: Comprobar ashift y detectar el problema de “vdev nuevo diferente”
cr0x@server:~$ sudo zdb -C tank | sed -n '1,120p'
MOS Configuration:
version: 5000
name: 'tank'
state: 0
txg: 1293387
pool_guid: 14772854026870511222
vdev_children: 3
vdev_tree:
type: 'root'
id: 0
guid: 14772854026870511222
children[0]:
type: 'raidz'
ashift: 12
nparity: 2
children[0]: type: 'disk' path: '/dev/sda'
...
children[2]:
type: 'mirror'
ashift: 13
children[0]: type: 'disk' path: '/dev/nvme0n1p2'
children[1]: type: 'disk' path: '/dev/nvme1n1p2'
Significado: Los vdevs RAIDZ tienen ashift=12 (4K). El mirror tiene ashift=13 (8K). No es automáticamente incorrecto, pero es una diferencia de comportamiento permanente.
Decisión: Si ves desajustes de ashift accidentales por detección errónea de sectores o por mezcla de tipos de dispositivo, deja de hacer “arreglos incrementales”.
Planifica una reconstrucción con ashift correcto en lugar de apilar más inconsistencia.
Tarea 5: Verificar propiedades de datasets que afectan la latencia (sync, recordsize, compression)
cr0x@server:~$ sudo zfs get -r compression,recordsize,sync tank/vmstore
NAME PROPERTY VALUE SOURCE
tank/vmstore compression lz4 local
tank/vmstore recordsize 16K local
tank/vmstore sync standard default
Significado: Valores razonables para VMs: compresión lz4 y recordsize 16K. Sync es standard, lo que significa que las escrituras síncronas se respetan.
Decisión: Si ves latencia por escrituras sync y no tienes SLOG, considera añadir un SLOG en mirror sobre dispositivos con protección ante pérdida de energía.
No “arregles” la latencia sync poniendo sync=disabled a menos que estés dispuesto a explicar pérdida de datos en el postmortem.
Tarea 6: Comprobar si existe un SLOG y si es un punto único de dolor
cr0x@server:~$ sudo 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
mirror-2 ONLINE 0 0 0
logs
mirror-3 ONLINE 0 0 0
nvme2n1p1 ONLINE 0 0 0
nvme3n1p1 ONLINE 0 0 0
Significado: Hay un dispositivo de registro en mirror. Bien: no es un SLOG de un solo disco. Además, está separado del mirror de nivel superior.
Decisión: Si los logs aparecen como un solo disco, arréglalo antes de cualquier otra cosa. Un SLOG único es una interrupción esperando ocurrir,
y un SLOG lento es una fábrica de latencia para cargas con mucho sync.
Tarea 7: Medir latencia real y colas en el nivel del SO
cr0x@server:~$ iostat -x 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 78.0 5.0 62.1 4.1 173.2 9.80 110.2 120.3 18.1 2.8 23.1
sdg 12.0 4.0 9.5 3.2 194.0 0.90 22.4 24.1 17.3 2.4 3.8
nvme0n1 1.0 420.0 0.2 132.0 64.0 1.10 2.6 1.9 2.6 0.1 4.2
Significado: sda tiene await alto y profundidad de cola comparado con otros discos. Eso suele significar que el vdev al que pertenece está saturado.
Decisión: Confirma que esto se alinea con zpool iostat -v. Si es así, tienes un vdev caliente.
Si no, podrías tener problemas de controlador o de path específicos de ese disco.
Tarea 8: Comprobar presión del ARC y si las lecturas fallan en caché
cr0x@server:~$ sudo arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% size c
12:01:11 3200 1200 37 800 25 350 11 50 2 118G 128G
12:01:12 3400 1500 44 980 29 420 12 60 2 118G 128G
12:01:13 3350 1480 44 950 28 430 13 60 2 118G 128G
Significado: La tasa de misses del caché es ~40%+ bajo carga. Eso puede convertir tu historia de “vdev nuevo rápido” en “las lecturas en vdevs antiguos nos están matando”, porque el ARC
no te está salvando.
Decisión: Si los misses de lectura se correlacionan con latencia, considera añadir RAM (a menudo la mejor mejora de IOPS por dolar),
o separar datasets calientes en vdevs rápidos y redundantes en lugar de mezclarlos.
Tarea 9: Inspeccionar fragmentación y reconocer el precipicio de “RAIDZ casi lleno”
cr0x@server:~$ sudo zpool get -H -o property,value fragmentation tank
fragmentation 28%
Significado: La fragmentación es no trivial. En RAIDZ, alta ocupación + fragmentación puede amplificar el coste de escritura y la variabilidad de latencia.
Decisión: Si tus vdevs RAIDZ están al 85–90% y la frag aumenta, deja de intentar “tunear” eso. Añade vdevs equivalentes o migra.
La física de la asignación ganará.
Tarea 10: Ver si un dataset es el matón (y muévelo si es necesario)
cr0x@server:~$ sudo zfs list -o name,used,available,refer,compressratio -r tank | head -n 12
NAME USED AVAIL REFER RATIO
tank 82.1T 21.9T 128K 1.22x
tank/vmstore 42.8T 21.9T 42.8T 1.05x
tank/backups 25.6T 21.9T 24.1T 1.48x
tank/analytics 11.9T 21.9T 10.7T 1.31x
tank/home 1.8T 21.9T 1.8T 1.63x
Significado: VMstore domina el espacio. Si la carga caliente está ahí, también domina el I/O.
Decisión: Considera mover tank/vmstore a un pool nuevo y bien diseñado y dejar los datasets fríos atrás.
Una separación quirúrgica vence a un “rebalance total” heroico.
Tarea 11: Comprobar errores silenciosos de dispositivo antes de culpar a la asignación
cr0x@server:~$ sudo smartctl -a /dev/sda | egrep "Reallocated_Sector_Ct|Current_Pending_Sector|Offline_Uncorrectable|UDMA_CRC_Error_Count"
Reallocated_Sector_Ct 0
Current_Pending_Sector 0
Offline_Uncorrectable 0
UDMA_CRC_Error_Count 27
Significado: Errores CRC sugieren problemas de cableado/backplane/controlador, no necesariamente medios que estén muriendo. Eso puede presentarse como “un vdev está lento.”
Decisión: Arregla la ruta física y limpia la tendencia de errores (reemplaza cable, vuelve a insertar, cambia de bahía) antes de rediseñar el pool.
Tarea 12: Confirmar que el “vdev nuevo” realmente recibe nuevas asignaciones
cr0x@server:~$ sudo zpool iostat -v tank 5
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 82.1T 21.9T 980 2.20K 210M 420M
raidz2-0 41.0T 3.7T 820 180 180M 40M
raidz2-1 40.9T 3.8T 150 160 28M 36M
mirror-2 250G 850G 10 1.86K 2.0M 344M
-------------------------- ----- ----- ----- ----- ----- -----
Significado: Las escrituras fluyen principalmente al vdev mirror. Eso es esperado cuando está más vacío y es más rápido.
Decisión: Si este mirror no está pensado para ser el sumidero principal de escrituras (por coste, resistencia o políticas),
necesitas rediseñar, no “esperar a que se equilibre”.
Tarea 13: Demuestra que no puedes eliminar después el vdev de nivel superior (la parte irreversible)
cr0x@server:~$ sudo zpool remove tank mirror-2
cannot remove mirror-2: operation not supported on this pool
Significado: La eliminación de vdev de nivel superior puede no estar soportada según tu versión de OpenZFS y flags de características del pool—e incluso cuando está soportada,
es limitada y puede durar mucho.
Decisión: Trata zpool add como permanente a menos que hayas validado soporte para remover vdevs en tu entorno
y puedas tolerar el tiempo y riesgo.
Tarea 14: Validar configuración de vdev especial (porque perderlo puede perder el pool)
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
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
special
mirror-4 ONLINE 0 0 0
nvme4n1p1 ONLINE 0 0 0
nvme5n1p1 ONLINE 0 0 0
Significado: El vdev special está en mirror. Bien. Si fuera un único dispositivo y fallara, podrías perder metadatos/pequeños bloques y efectivamente perder el pool.
Decisión: Nunca uses un vdev special como dispositivo único en producción. Míralo en mirror, monitorízalo y dotalo de capacidad de sobra.
Tres mini-historias corporativas desde el campo
Mini-historia 1: El incidente causado por una suposición equivocada
Una empresa SaaS mediana tenía un pool ZFS que soportaba un clúster de virtualización. Tenían dos vdevs RAIDZ2 de HDD idénticos. El crecimiento fue constante.
Luego llegaron un cliente nuevo y el almacenamiento se disparó. Alguien preguntó lo obvio: “¿Podemos simplemente añadir discos?”
El ingeniero de guardia hizo lo que muchos haríamos a las 2 a.m.: añadió un vdev mirror nuevo usando dos discos de repuesto, porque era rápido y la capacidad era urgente.
Asumió que el pool “se reequilibraría”, o al menos “repartiría el I/O” con el tiempo. El pool se mantuvo online, las gráficas mejoraron, todos volvieron a dormir.
Dos semanas después, el equipo de plataforma desplegó una nueva imagen de VM y la flota arrancó en todo el clúster. Las tormentas de arranque son una fiesta de I/O aleatorio de pequeñas lecturas.
Las lecturas golpearon los datos antiguos en los vdevs RAIDZ casi llenos. La latencia se disparó. El mirror nuevo tenía espacio y velocidad, pero no ayudó porque contenía mayormente bloques nuevos.
El outage no fue misterioso; fue deuda topológica cobrada con intereses. Su solución no fue ajustar finamente. Migraron los datasets de VM más ocupados a un pool nuevo
construido con mirrors (que coincidía con la carga), y luego reutilizaron el pool antiguo para datos más fríos. La lección dolorosa: ZFS no te protege de tus propias suposiciones.
Mini-historia 2: La optimización que salió mal
Un equipo empresarial de analítica quería consultas más rápidas. Tenían un pool ZFS de vdevs RAIDZ2 HDD. Llegó una propuesta bien intencionada de optimización:
“Añadamos un par de NVMe en mirror como vdev, y ZFS stripeará por ahí. Boom: más rápido.”
Añadieron el mirror NVMe como vdev de nivel superior. Las escrituras nuevas (incluyendo datos temporales de spills de consultas) cayeron desproporcionadamente en NVMe. Al principio, se veía fantástico.
Pero las NVMe eran de consumo y no eran seguras ante pérdida de energía. Peor: ahora estaban en la senda caliente de escritura para una carga que hacía muchas escrituras síncronas
debido al comportamiento de las aplicaciones que no controlaban por completo.
Unos meses después, una NVMe empezó a lanzar errores de media. El mirror los protegió de pérdida inmediata de datos, pero el rendimiento se degradó bruscamente durante el manejo de errores
y la actividad de resilver. El impacto en el negocio fue “las consultas a veces tardan 10x más”, que es como se presentan los outages de analítica: no caído, pero inusable.
El retroceso fue sutil: no solo habían “añadido rendimiento”. Cambiaron la asignación, las características de fallo y el perfil operativo del pool entero.
Su solución eventual fue aburrida: mover el scratch analítico a un pool NVMe separado (mirrors), mantener el pool HDD para datos durables y hacer explícitas las semánticas de sync.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día
Una empresa financiera usaba ZFS para un archivo de documentos y una granja de VMs. Su responsable de almacenamiento era alérgico a “arreglos rápidos” e insistía en una política:
los vdevs de nivel superior deben ser idénticos en ancho, tipo y clase de disco; no hay excepciones sin una firma de riesgo por escrito.
La política molestaba porque hacía las expansiones más lentas. Cuando se acercaba la capacidad, no “añadían lo que hubiera”.
Compraron suficientes discos para añadir un nuevo vdev RAIDZ2 completo que coincidiera con los existentes y lo planificaron como un cambio con pruebas de burn-in.
Meses después tuvieron un problema de firmware del controlador que aumentaba intermitentemente la latencia en una ruta SAS. Porque sus vdevs eran consistentes,
las métricas contaron una historia clara: una ruta estaba mal; el layout del pool no enturbió la señal. Aislaron la ruta defectuosa, la pusieron en failover limpiamente,
y planificaron un arreglo de firmware.
La salvación no fue heroica; fue claridad. Vdevs homogéneos y cambios disciplinados hicieron que el sistema se comportara de forma predecible cuando el hardware se puso raro,
que es la única forma en que realmente descubres de qué está hecha tu arquitectura.
Cómo ampliar ZFS de forma segura (qué hacer en su lugar)
Regla 1: Añade vdevs de nivel superior que coincidan, o acepta la rareza permanente
Si vas a crecer un pool añadiendo vdevs, añade vdevs del mismo tipo, mismo ancho y clase de rendimiento similar. Mirrors con mirrors.
RAIDZ2 con RAIDZ2 del mismo número de discos. Ashift similar. Modelos de disco similares si puedes.
Esto no es estético. Es matemática operativa: el pool stripea entre vdevs, y cualquier vdev puede convertirse en el factor limitante según los patrones de acceso.
La homogeneidad hace que la planificación de capacidad y rendimiento sea tractable.
Regla 2: Si necesitas diferentes tipos de medios, usa pools separados o vdevs especiales deliberadamente
¿Quieres rendimiento NVMe y capacidad HDD? Tienes tres patrones sensatos:
- Pools separados: un pool NVMe para datasets sensibles a latencia, un pool HDD para datos masivos. Sencillo, predecible y fácil de razonar.
- Vdev special (en mirror): para metadatos y pequeños bloques, para acelerar operaciones de directorio y I/O aleatorio pequeño manteniendo los datos en HDD.
- SLOG (en mirror, dispositivos con PLP): para acelerar la latencia de escrituras síncronas sin cambiar dónde terminan los datos.
Lo que debes evitar es “solo añadir un vdev rápido” y esperar que ZFS lo convierta en un sistema de niveles (tiering). No lo hará. Lo convertirá en un sumidero de asignación.
Regla 3: Considera reconstruir en lugar de parchear cuando el layout ya está comprometido
A veces la respuesta correcta es: construye un pool nuevo con el layout que querías y luego migra datasets. Sí, es trabajo. También es trabajo finito.
Vivir con un pool comprometido es trabajo infinito.
¿Y el «rebalance»?
ZFS no tiene un comando único online de rebalanceo que redistribuya bloques existentes entre vdevs del modo en que algunos sistemas distribuidos lo hacen.
Si quieres mover datos, por lo general tienes que reescribirlos.
Enfoques prácticos incluyen:
- Send/receive de datasets a un pool nuevo (mejor cuando puedes aprovisionar un pool nuevo).
- Reescritura a nivel de dataset in situ vía replicación a un dataset temporal y de vuelta (funciona, pero es pesada y operativamente arriesgada).
- Migración selectiva de datasets calientes a un pool nuevo, dejando los datos fríos donde están.
Broma #2: ZFS no «rebalancea» tu pool; «preserva la historia». Como tu departamento de auditoría, recuerda todo y no mueve nada sin papeleo.
Listas de verificación / plan paso a paso
Paso a paso: Antes de ejecutar zpool add en producción
- Escribe el objetivo: ¿capacidad, IOPS, throughput o latencia? “Más espacio” no es un plan de rendimiento.
- Confirma la geometría actual de vdev: mirror vs raidz, conteo de discos, ashift, clases de dispositivo.
- Decide si puedes mantener vdevs homogéneos: si no, decide si aceptas heterogeneidad permanente.
- Revisa espacio libre y fragmentación: si ya estás en alta ocupación y fragmentado, espera peor comportamiento bajo escrituras.
- Valida salud del controlador y paths: no añadas complejidad encima de hardware inestable.
- Planifica el rollback: asume que no podrás eliminar el vdev más tarde; planifica cómo migrarías si sale mal.
- Prepara y burn-in de discos: ejecuta tests SMART largos, comprueba firmware, confirma tamaños de sector.
Paso a paso: Patrones de expansión seguros
- Necesitas más capacidad en un pool RAIDZ existente: añade un nuevo vdev RAIDZ que coincida en ancho y paridad.
- Necesitas más IOPS para cargas tipo VM: añade vdevs mirror (múltiples mirrors escalan bien IOPS).
- Necesitas latencia de escritura sync más rápida: añade un SLOG en mirror sobre dispositivos con protección ante pérdida de energía; no añadas un vdev rápido al azar.
- Necesitas aceleración de metadatos/pequeños bloques: añade un vdev special en mirror; configura
special_small_blockssolo con un modelo de dimensionado y monitorización. - Necesitas tiers rápidos y lentos: construye dos pools y coloca datasets explícitamente.
Paso a paso: Si ya caíste en la trampa
- Cuantifica el desequilibrio: %alloc por vdev, iostat por vdev bajo carga real.
- Identifica datasets calientes: qué datasets dominan I/O y las quejas de latencia.
- Elige una arquitectura objetivo: vdevs homogéneos, o pools separados por carga de trabajo.
- Planifica la migración: send/receive con snapshots incrementales, o mueve datasets calientes primero.
- Programa scrubs y resilvers: las expansiones y migraciones son cuando las unidades débiles se revelan.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: “Tras añadir discos, las lecturas siguen lentas”
Causa raíz: Añadiste un vdev nuevo, pero los datos antiguos se quedaron en los vdevs viejos; la carga de lectura sigue golpeando los vdevs antiguos y llenos.
Solución: Mueve datasets calientes a un pool nuevo o reescríbelos para que los bloques se reasignen. Si debes expandir in situ, añade vdevs que coincidan para aumentar el paralelismo de lectura donde viven los datos.
2) Síntoma: “Las escrituras se volvieron rápidas, luego empezamos a ver picos de latencia aleatorios”
Causa raíz: El vdev nuevo está tomando la mayoría de escrituras; los vdevs antiguos están casi llenos y fragmentados; mezclar tipos de medios causa tiempos de servicio desiguales.
Solución: Deja de mezclar clases de vdev para asignación general. Separa pools o usa SLOG/special vdev para aceleración dirigida.
3) Síntoma: “El rendimiento del pool es inconsistente entre hosts / momentos del día”
Causa raíz: Fases de la carga (leer datos antiguos vs escribir datos nuevos) interactúan con sesgos de asignación. El pool tiene “modos”.
Solución: Mide I/O por vdev durante cada fase de la carga. Coloca datasets según patrón de acceso, no según donde había espacio libre.
4) Síntoma: “El scrub o resilver se disparó tras la expansión”
Causa raíz: Vdevs con alta utilización + geometría RAIDZ + discos lentos = operaciones de mantenimiento largas. La expansión no redujo la ocupación de los vdevs antiguos.
Solución: Añade vdevs equivalentes antes de alcanzar alto %CAP. Mantén margen. Reemplaza discos envejecidos proactivamente. Considera mirrors para resilver más rápido si la carga lo exige.
5) Síntoma: “Añadimos un disco individual temporalmente y ahora tenemos miedo de tocar el pool”
Causa raíz: Un vdev de nivel superior de un solo disco deja el pool a un fallo de disco de pérdida total.
Solución: Convierte ese disco único en redundante de inmediato adjuntando un segundo disco (mirror), o migra datos fuera de ese pool.
No lo dejes para “más tarde”.
6) Síntoma: “El vdev nuevo es más rápido pero el pool global se volvió más lento”
Causa raíz: Ashift mezclados, tamaños de sector o amplificación de escritura en un vdev; además, comportamiento de metadatos/pequeños bloques puede concentrarse en ciertos dispositivos.
Solución: Valida ashift y propiedades de los dispositivos antes de añadir. Si están mal, reconstrúyelo con ashift correcto; no sigas añadiendo.
7) Síntoma: “Las escrituras síncronas son terribles, así que alguien propone sync=disabled”
Causa raíz: No hay SLOG o es lento/insalubre. El pool está respetando semánticas sync y pagando la latencia.
Solución: Añade un SLOG en mirror sobre dispositivos con protección ante pérdida de energía; confirma necesidades de la aplicación; mantén sync=standard para durabilidad a menos que aceptes explícitamente pérdida de datos.
FAQ (preguntas que se hacen después del incidente)
1) ¿»añadir discos» es lo mismo que «añadir un vdev» en ZFS?
Prácticamente, sí. O bien reemplazas discos dentro de un vdev existente (creciéndolo o renovándolo), o añades un vdev de nivel superior al pool.
zpool add añade un vdev de nivel superior. Eso cambia el comportamiento del pool permanentemente.
2) ¿ZFS rebalancea automáticamente los datos después de añadir un vdev?
No. Los bloques existentes se quedan donde están. Las nuevas asignaciones tienden a preferir vdevs con más espacio libre, por eso los vdevs nuevos suelen recibir la mayoría de escrituras nuevas.
3) Si añado un vdev más rápido, ¿las lecturas mejorarán?
Solo para datos que estén asignados en ese vdev (o cacheados en ARC/L2ARC). Si tus datos calientes viven en vdevs antiguos, las lecturas seguirán golpeando esos vdevs.
4) ¿Puedo «arreglar el desequilibrio» sin migrar a un pool nuevo?
A veces parcialmente, reescribiendo datos (send/receive a un dataset temporal y de vuelta, o moviendo datasets). Pero no hay almuerzo gratis: para mover bloques debes reescribirlos, y eso consume I/O y tiempo.
5) ¿Es seguro mezclar mirrors y RAIDZ en un mismo pool?
Puede ser seguro en el sentido de que ZFS funcionará, pero rara vez es prudente para rendimiento predecible o características de fallo consistentes.
Si lo haces, hazlo deliberadamente y monitoriza comportamiento por-vdev. Si no, separa pools.
6) ¿Cuál es el movimiento más común que «accidentalmente lo rompe» al expandir ZFS?
Añadir un pequeño vdev mirror a un gran pool RAIDZ porque “solo necesitamos un poco más de espacio”. Terminas con un pool que asigna desproporcionadamente al mirror,
cambia patrones de desgaste y complica la planificación futura.
7) ¿Añadir más vdevs siempre aumenta el rendimiento?
Añadir más vdevs de nivel superior similares suele aumentar el throughput agregado y las IOPS. Añadir vdevs disimilares aumenta la imprevisibilidad.
Además, si tu carga está limitada por CPU, ARC, comportamiento sync o red, más vdevs no ayudarán.
8) ¿Cómo elegir entre mirrors y RAIDZ para crecer?
Los mirrors escalan mejor IOPS aleatorias de lectura/escritura y resilverean más rápido; RAIDZ es eficiente en capacidad pero más sensible a la ocupación y patrones de escritura.
Si ejecutas VMs o bases de datos con mucho I/O aleatorio, los mirrors suelen comportarse mejor operacionalmente.
9) ¿Qué frase debo recordar cuando alguien pide un «arreglo rápido de almacenamiento»?
Werner Vogels (idea parafraseada): “Todo falla, todo el tiempo”. Construye layouts y procedimientos suponiendo que el siguiente fallo ya está programado.
Conclusión: siguientes pasos que puedes hacer esta semana
Si recuerdas una cosa, que sea esta: zpool add no “extiende RAID”. Añade un vdev de nivel superior y no rebalancea datos antiguos.
Eso no es un bug. Es el modelo.
Pasos prácticos:
- Inventario tus pools: ejecuta
zpool statusy anota tipos de vdev, anchos y clases de dispositivo. Si es un lío, admítelo ahora. - Mide carga por-vdev: captura
zpool iostat -v 1durante picos reales de carga. Encuentra el vdev caliente. - Decide arquitectura: vdevs homogéneos en un pool, o múltiples pools por carga. No sigas improvisando.
- Planifica la salida: si ya añadiste un vdev inadecuado, programa una ruta de migración mientras el sistema aún está lo bastante sano para mover datos.
La fiabilidad del almacenamiento es, en gran parte, evitar la sofisticación innecesaria. ZFS te da herramientas poderosas. Úsalas como si fueras quien estará de guardia cuando fallen.