Compraste “los discos justos” para un RAIDZ. Seis meses después el pool está al 83%, las snapshots se multiplican como conejos y la empresa quiere otro cuarto de datos para ayer.
Aquí es donde la gente descubre que ZFS no es magia: es ingeniería. RAIDZ te da buena densidad y tolerancia a fallos, pero también hace que ampliar capacidad se sienta como discutir con la física. La buena noticia: OpenZFS moderno por fin ha crecido una nueva rama aquí. La mala noticia: todavía necesitas entender qué hace, qué no hace y qué soluciones alternativas son seguras en producción.
Qué es posible hoy (y qué no)
Separemos tres conceptos que se mezclan en hilos de Slack y llamadas de incidentes:
- Expandir un pool: añadir más vdevs de primer nivel (por ejemplo, añadir otro grupo RAIDZ). Fácil. Tiene consecuencias.
- Hacer crecer un vdev: ensanchar un vdev existente (por ejemplo, RAIDZ1 de 5 discos a 6 discos). Históricamente “no”, ahora “a veces sí” dependiendo del soporte de features.
- Aumentar cada disco: reemplazar discos por otros más grandes y dejar que el vdev crezca tras el último reemplazo. Clásico, seguro, lento.
1) Añadir un disco a un vdev RAIDZ existente
Hoy: Esto es posible en builds recientes de OpenZFS cuando la feature RAIDZ expansion está soportada y habilitada. Puedes adjuntar un disco adicional a un vdev RAIDZ y el vdev iniciará un proceso de expansión.
La trampa: No es instantáneo y no es gratis. Los datos existentes deben reescribirse para aprovechar la nueva geometría (más columnas). Eso significa un proceso de larga duración en segundo plano que se parece mucho a un reescrito completo del pool. Espera I/O intensivo, mucho tiempo y variabilidad en el rendimiento.
2) Reemplazar todos los discos por unidades más grandes
Hoy: Sigue siendo la forma más aburrida y correcta de aumentar la capacidad RAIDZ. Reemplazas discos uno por uno, resilver tras cada uno y el vdev se expande cuando el último dispositivo es más grande y se respeta autoexpand.
La trampa: Necesitas paciencia y discos buenos. Resilverizar en discos grandes es una decisión de estilo de vida.
3) Añadir un nuevo vdev de primer nivel (otro grupo RAIDZ, o mirrors)
Hoy: Siempre funciona. Es como ZFS fue diseñado para escalar pools: haciendo striping entre vdevs.
La trampa: Cambias permanentemente tu perfil de redundancia y la matemática del dominio de fallo. ZFS hace striping sobre vdevs de primer nivel; perder cualquiera de esos vdevs puede matar el pool. Así que si “solo añades un disco” (un vdev de un solo disco), has creado un pool que puede morir por una única falla de disco. Eso no es una expansión: es una pistola cargada.
Consejo con opinión: Si puedes usar RAIDZ expansion de forma segura (feature soportada, ventana de mantenimiento tolerable, margen de I/O), hoy es una herramienta legítima. Si no puedes, no inventes: reemplaza discos por otros más grandes o migra a un nuevo pool/layout de vdevs. Los vdevs “temporales” de un solo disco tienden a volverse permanentes hasta que se convierten en catastróficos.
Broma #1: RAIDZ expansion es como una membresía de gimnasio: técnicamente puedes progresar, pero va a exigir tiempo y cierto grado de incomodidad sostenida.
Cómo funciona la expansión RAIDZ internamente (suficiente para decidir)
RAIDZ escribe datos en “stripes” a través de los discos, con paridad. El número de discos que participan en una stripe es el “width” del vdev. Cuando añades un disco a un vdev RAIDZ (con la feature de expansión), estás cambiando ese width.
Este es el motivo por el que es difícil: los bloques antiguos están distribuidos según el width antiguo. Los bloques nuevos podrían escribirse con el width nuevo, pero entonces el vdev contendría una mezcla de distribuciones. Eso es posible, pero implica:
- El cálculo de capacidad se complica: el espacio no se libera mágicamente hasta que suficiente data sea reescrita.
- Las características de rendimiento varían según cuánto del dataset sea de “layout antiguo” vs “layout nuevo”.
- La matemática de paridad, las clases de asignación y la selección de metaslab deben cooperar sin romper la compatibilidad en disco.
Así que la expansión implica una reescritura controlada de bloques para que se puedan redistribuir en la nueva geometría. Piensa en ello como: “el pool aprende una nueva forma de andar y luego poco a poco enseña a sus datos existentes a caminar así”.
Qué esperar operacionalmente
- Un proceso de larga duración que compite con las cargas normales (lectura, escritura, metadata).
- Mayor amplificación de escritura porque los bloques se reescriben, además de la sobrecarga de paridad.
- Interacción con snapshots: los bloques referenciados por snapshots no desaparecen; la reescritura puede verse limitada por las políticas de retención. No “rebalances” alrededor de una montaña de historial inmutable sin pagar por ello.
- Estrés térmico y SMART en todo el vdev. Si tus discos ya están en el límite, vas a descubrirlo de la forma menos agradable.
Qué no arregla la expansión
- Mala elección de ashift (por ejemplo, discos 4K con ashift=9). Eso es para siempre.
- Topología fundamentalmente equivocada para tu carga (por ejemplo, RAIDZ para escrituras random síncronas intensas en una BD sensible a latencia). Un RAIDZ más ancho puede mejorar throughput, pero no lo convertirá en un mirror.
- Alta fragmentación y bloat de snapshots causados por patrones de carga. La expansión puede reducir la presión pero no el comportamiento subyacente.
Hechos e historia que explican las rarezas
Algunos puntos de contexto que explican por qué “solo añade un disco” tardó tanto en ser real en el mundo ZFS:
- ZFS nació en una era de discos grandes y caros donde planear el layout del vdev por adelantado se asumía. La cultura vino con ello: “Elige sabiamente; cambiar después es difícil”.
- El striping entre vdevs de primer nivel es fundamental: los pools ZFS son un stripe a través de vdevs. Esto hace que escalar sea fácil pero que mezclar redundancias sea riesgoso cuando la gente improvisa.
- La paridad RAIDZ no es un RAID5/6 pegado; está integrada en la asignación y punteros de bloque. Esa integración profunda es fantástica para integridad y horrible para adaptar layouts retroactivamente.
- El método “reemplazar por discos más grandes” precede a la mayoría de los forks modernos de ZFS y se convirtió en la historia canónica porque no requería reescribir todo de una vez.
- Resilverizar es basado en bloques, no en disco completo (en muchos casos). Esa es una ventaja de ZFS, pero los resilvers RAIDZ aún pueden ser largos porque la reconstrucción de paridad toca mucha data.
- La consolidación de OpenZFS importó: el desarrollo de ZFS divergió entre descendientes de Solaris y luego se reconvergió. El trabajo de features on-disk grande tiende a moverse a la “velocidad cuidadosa de un sistema de archivos”.
- Las snapshots son ciudadanos de primera clase, lo que cambia todo: “borrar y reescribir” no es simple si bloques antiguos siguen referenciados.
- Los checksums de extremo a extremo cambiaron las expectativas de fallo: no solo quieres capacidad; quieres datos correctos. Cualquier feature de expansión debe preservar integridad frente a fallos, pérdidas de energía y progreso parcial.
- Las capacidades de los discos explotaron más rápido que las ventanas de reconstrucción se redujeron: eso amplió el dolor—la gente quería expansión porque reemplazar por más grandes significaba resilvers de varios días.
Tareas prácticas: comandos, salidas y decisiones
Abajo hay tareas reales que ejecuto antes de tocar un pool en producción. Cada una incluye un comando, salida de ejemplo, qué significa y la decisión que tomas.
Tarea 1: Identificar tus versiones ZFS y kernel/userspace
cr0x@server:~$ zfs version
zfs-2.2.4-1
zfs-kmod-2.2.4-1
Qué significa: Estás en OpenZFS 2.2.x userspace y kernel module. La disponibilidad de features varía según la versión y el empaquetado de la distribución.
Decisión: Si estás en una release antigua, deja de asumir que RAIDZ expansion existe. Planifica una ventana de upgrade primero o usa las soluciones alternativas antiguas.
Tarea 2: Comprobar salud del pool y daños latentes
cr0x@server:~$ zpool status -xv
all pools are healthy
Qué significa: No hay errores conocidos en este momento.
Decisión: Si esto muestra errores, no expandas. Arregla problemas de dispositivos subyacentes primero. La expansión multiplica I/O y mostrará discos débiles.
Tarea 3: Obtener la topología exacta de vdev (esto dicta tus opciones)
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
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
errors: No known data errors
Qué significa: Un solo vdev RAIDZ2, ancho 6. Perder más de 2 discos en ese vdev mata el pool.
Decisión: Puedes (a) expandir este width de vdev (si está soportado), (b) reemplazar discos por otros más grandes, o (c) añadir otro vdev RAIDZ2. No añadas discos individuales.
Tarea 4: Confirmar ashift y alineación de sectores (no puedes “arreglarlo” después)
cr0x@server:~$ zdb -C tank | grep ashift -n
56: ashift: 12
57: asize: 599998545920
Qué significa: ashift=12 (sectores 4K) es generalmente sensato para discos modernos.
Decisión: Si ashift está mal (comúnmente 9 en discos 4K), no inviertas más tiempo en expansión. La migración suele ser la única corrección correcta.
Tarea 5: Revisar feature flags y si el pool soporta features nuevas
cr0x@server:~$ zpool get -H all tank | egrep 'feature@|compatibility'
tank compatibility off local
Qué significa: El modo compatibility está off; las feature flags pueden estar habilitadas individualmente.
Decisión: En entornos que arrancan desde medios de recuperación más antiguos o replican a hosts antiguos, habilitar features nuevas puede romper compatibilidad. Confirma que tu flota las soporta antes de girar perillas.
Tarea 6: Comprobar capacidad y fragmentación del pool (a la expansión no le gustan los pools llenos)
cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health tank
NAME SIZE ALLOC FREE CAP FRAG HEALTH
tank 21.8T 19.1T 2.7T 87% 61% ONLINE
Qué significa: 87% lleno y 61% fragmentado. Estás en la zona de “todo es más difícil ahora”.
Decisión: Si CAP > 80%, prioriza liberar espacio antes de expandir o reemplazar. El rendimiento y el comportamiento de asignación de ZFS se degradan mucho cuando está lleno.
Tarea 7: Identificar los mayores consumidores de espacio, incluidas las snapshots
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint -S used | head
NAME USED AVAIL REFER MOUNTPOINT
tank 19.1T 2.7T 256K /tank
tank/backups 11.2T 2.7T 4.1T /tank/backups
tank/backups@snap-1 2.8T - 4.0T -
tank/vm 5.6T 2.7T 5.6T /tank/vm
tank/home 1.9T 2.7T 1.9T /tank/home
Qué significa: Las snapshots pueden representar una cantidad sorprendente de «USED» y atan bloques antiguos.
Decisión: Si la expansión depende de reescribir bloques pero las snapshots los mantienen vivos, recorta la retención de snapshots primero (con aprobación de los stakeholders).
Tarea 8: Medir flags de escritura y comportamiento sync (aquí viven los malentendidos sobre SLOG)
cr0x@server:~$ zfs get -o name,property,value -s local,default sync,logbias,recordsize tank/vm
NAME PROPERTY VALUE
tank/vm sync standard
tank/vm logbias latency
tank/vm recordsize 128K
Qué significa: El dataset VM tiene sync por defecto, logbias latency y recordsize 128K.
Decisión: Si ves problemas de latencia, no asumas que “la expansión lo arregla”. Podrías tener un cuello de botella de escrituras sync que necesita ajuste de SLOG o cambios en la carga.
Tarea 9: Verificar autotrim, compresión y atime—asesinos silenciosos y salvadores
cr0x@server:~$ zfs get -o name,property,value compression,atime,relatime,autotrim tank
NAME PROPERTY VALUE
tank compression lz4
tank atime off
tank relatime off
tank autotrim off
Qué significa: Compresión activada (bien). atime apagado (a menudo bien). autotrim apagado (puede estar bien para HDD; en SSD es materia para discutir).
Decisión: La expansión aumenta escrituras; la compresión puede reducirlas. Si tu pool es SSD, considera el comportamiento de autotrim con cuidado—pero prueba primero.
Tarea 10: Línea base de I/O y latencia antes de cualquier cirugía
cr0x@server:~$ zpool iostat -v tank 5 3
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 19.1T 2.7T 85 210 1.20G 2.45G
raidz2-0 19.1T 2.7T 85 210 1.20G 2.45G
sda - - 12 35 180M 420M
sdb - - 14 36 190M 410M
sdc - - 13 34 200M 430M
sdd - - 15 35 210M 400M
sde - - 16 35 210M 410M
sdf - - 15 35 210M 380M
-------------------------- ----- ----- ----- ----- ----- -----
Qué significa: Muestra ancho de banda/ops por vdev y por disco. Buscas outliers y margen disponible.
Decisión: Si los discos ya están cerca de saturación, la expansión dañará el rendimiento. Programa una ventana tranquila o limita el proceso de expansión (cuando esté soportado) gestionando la carga.
Tarea 11: Revisar historial de errores reciente y cadencia de resilver/scrub
cr0x@server:~$ zpool status tank | sed -n '1,120p'
pool: tank
state: ONLINE
scan: scrub repaired 0B in 12:44:02 with 0 errors on Mon Dec 2 03:21:08 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
errors: No known data errors
Qué significa: El scrub terminó limpio recientemente. Buen punto de partida.
Decisión: Si no has scrubbeado en meses, hazlo antes de expandir/reemplazar. Encuentra errores latentes cuando aún tienes margen.
Tarea 12: Validar que el “nuevo” disco es realmente el que crees
cr0x@server:~$ lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE
NAME SIZE MODEL SERIAL TYPE
sda 3.64T ST4000NM0035 ZC1A1ABC disk
sdb 3.64T ST4000NM0035 ZC1A1ABD disk
sdc 3.64T ST4000NM0035 ZC1A1ABE disk
sdd 3.64T ST4000NM0035 ZC1A1ABF disk
sde 3.64T ST4000NM0035 ZC1A1ABG disk
sdf 3.64T ST4000NM0035 ZC1A1ABH disk
sdg 3.64T ST4000NM0035 ZC1A1ABJ disk
Qué significa: Tienes un disco candidato (sdg) presente. Puedes cruzar seriales con la orden de hardware del DC.
Decisión: Nunca operes sobre /dev/sdX a ciegas. Prefiere identificadores estables como /dev/disk/by-id en las configuraciones reales del pool.
Tarea 13: Comprobar SMART antes de involucrar un disco en tu matemática de redundancia
cr0x@server:~$ sudo smartctl -a /dev/sdg | egrep 'SMART overall-health|Reallocated_Sector_Ct|Current_Pending_Sector|Offline_Uncorrectable'
SMART overall-health self-assessment test result: PASSED
5 Reallocated_Sector_Ct 0x0033 100 100 010 Pre-fail Always - 0
197 Current_Pending_Sector 0x0012 100 100 000 Old_age Always - 0
198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 0
Qué significa: No hay reallocaciones/pending sectors. No es garantía, pero no está gritando problemas.
Decisión: Si hay sectores pendientes o reallocaciones crecientes, no lo añadas. Los discos fallan bajo estrés; no los invites.
Tarea 14: Simula el cambio de topología que estás considerando (en tu cabeza, con matemáticas)
cr0x@server:~$ zpool list -o name,ashift,autoexpand,size,alloc,free,cap tank
NAME ASHIFT AUTOEXPAND SIZE ALLOC FREE CAP
tank 12 off 21.8T 19.1T 2.7T 87%
Qué significa: autoexpand off. Para “reemplazar discos por otros más grandes”, normalmente querrás autoexpand on en el momento correcto.
Decisión: Decide tu camino:
- Ruta RAIDZ expansion: asegura soporte de feature, bahías de repuesto, acepta tiempo de reescritura.
- Ruta reemplazo de discos: activa autoexpand en el momento adecuado; espera resilvers seriales.
- Ruta nuevo vdev: asegura redundancia similar y características de rendimiento parecidas.
Tarea 15: Prepárate para la parte aburrida—verifica que puedes restaurar
cr0x@server:~$ zfs get -o name,property,value -s local,default copies,encryption,keylocation tank/backups
NAME PROPERTY VALUE
tank/backups copies 1
tank/backups encryption off
tank/backups keylocation none
Qué significa: Este dataset no está encriptado y tiene una copia. Está bien si tu sistema de backup está en otro lado; terrible si finges que esto es el backup.
Decisión: Antes de cambios grandes en el layout, valida backups y ejercicios de restauración. La expansión no debería ser destructiva, pero los sistemas en producción disfrutan de la ironía.
Tarea 16: Si vas por la ruta “reemplazar discos”, confirma naming por device-by-id
cr0x@server:~$ ls -l /dev/disk/by-id/ | egrep 'sd[abc]$' | head -n 3
lrwxrwxrwx 1 root root 9 Dec 25 02:10 ata-ST4000NM0035_ZC1A1ABC -> ../../sda
lrwxrwxrwx 1 root root 9 Dec 25 02:10 ata-ST4000NM0035_ZC1A1ABD -> ../../sdb
lrwxrwxrwx 1 root root 9 Dec 25 02:10 ata-ST4000NM0035_ZC1A1ABE -> ../../sdc
Qué significa: Existen identificadores estables. Bien.
Decisión: Usa estas rutas en zpool replace para evitar incidentes de “disco equivocado”.
Guía rápida de diagnóstico: encuentra el cuello de botella rápido
Cuando alguien dice “necesitamos expansión RAIDZ porque el almacenamiento está lento/lleno”, necesitas diagnosticar el cuello de botella real antes de empezar a mover discos. Este es el orden de triaje que uso.
Primero: presión de capacidad y fragmentación
- Revisa CAP y FRAG con
zpool list. - Si CAP > 80% y FRAG > ~50%, espera problemas del allocator y amplificación de escritura.
Acción: Borra o migra datos primero; ajusta la retención de snapshots; añade espacio usando el método menos riesgoso disponible. Expandir en un pool casi lleno es como reparar un motor mientras el coche aún corre.
Segundo: latencia vs throughput (no son el mismo problema)
- Usa
zpool iostat -vpara detectar discos sobrecargados o un dispositivo lento. - Correlaciona con síntomas de la aplicación: ¿se quejan de latencia IOPS o de tiempo de transferencia en bloque?
Acción: Para escrituras aleatorias sensibles a latencia, cambiar el ancho RAIDZ puede no ayudar mucho. Los mirrors o dispositivos especiales pueden ser la solución.
Tercero: escrituras sync y comportamiento del intent log
- Revisa propiedades de dataset:
sync,logbias. - Busca tipos de carga: NFS con semántica sync, bases de datos, hipervisores de VM.
Acción: Si la latencia sync es el cuello de botella, un SLOG adecuado en medio con protección contra pérdida de energía puede ayudar más que cualquier expansión. O ajusta la semántica de la aplicación si puedes.
Cuarto: tasas de error y salud de discos
- Revisa
zpool statuspor errores de read/write/cksum. - Chequea SMART en outliers.
Acción: Reemplaza discos que fallan antes de intentar expansión/rebuild. Un disco marginal bajo reescritura intensa se convierte en generador de outages.
Quinto: recordsize, volblocksize y desajuste con la carga
- Para bases de datos: recordsize demasiado grande aumenta amplificación de lectura.
- Para zvols de VM: revisa volblocksize; cambiarlo después puede requerir migración.
Acción: Corrige el desajuste carga/dataset si es posible; la expansión no corrige datasets mal configurados.
Mejores soluciones alternativas cuando no puedes (o no debes) expandir RAIDZ
Aun con RAIDZ expansion disponible, hay casos donde debes elegir otra aproximación: pool demasiado lleno, la carga no tolera reescritura sostenida en background, tu plataforma no puede habilitar flags nuevas o simplemente no confías en la ventana de mantenimiento.
Solución 1: Reemplazar discos por otros más grandes (el método “lento pero sensato”)
Clásico: reemplaza discos uno a uno, resilveriza, repite. Cuando el último dispositivo sea más grande y el pool lo reconozca, obtendrás más capacidad sin cambiar el ancho del vdev.
Para qué sirve: perfil de riesgo predecible, sin nueva topología, amigable con compatibilidad.
Coste: tiempo. Además, resilvers repetidos estresan el vdev varias veces, lo que no es trivial en flotas antiguas.
Consejo operativo: mantén al menos un spare frío onsite. Trata el reemplazo de discos como una campaña, no como una serie de heroicidades puntuales.
Solución 2: Añadir un nuevo vdev de primer nivel (pero hazlo con cabeza)
Añade otro vdev RAIDZ con el mismo nivel de paridad y rendimiento similar. Esto aumenta capacidad inmediatamente. También suele aumentar rendimiento agregado porque hay más spindles y metaslabs.
Reglas:
- Iguala la redundancia. RAIDZ2 + RAIDZ2 es razonable; RAIDZ2 + disco suelto es negligencia.
- Intenta emparejar width y clase de disco. Mezclar un RAIDZ HDD ancho con un RAIDZ SSD estrecho crea acantilados de rendimiento.
- Planifica dominios de fallo: más vdevs significa más superficies donde “cualquier vdev que falle mata el pool”. No confundas “más redundancia por vdev” con “pool invencible”.
Solución 3: Migrar a mirrors para crecimiento futuro
Si necesitas crecer en pequeños incrementos y buscas IOPS predecible, los mirrors son tus amigos. Los mirrors permiten añadir capacidad en pares y obtener latencia predecible.
El intercambio: pagas en capacidad usable. A veces está bien. A veces finanzas discutirá. Finanzas siempre discute; es su RAIDZ.
Solución 4: Construir un nuevo pool y replicar (el “corte limpio”)
Si tu layout está mal (ashift, nivel de paridad equivocado, width erróneo, tipo de vdev inapropiado), deja de parchear y migra. Construye un pool nuevo con la geometría correcta y replica datasets con zfs send | zfs receive.
Por qué suele ser lo mejor: te permite arreglar varios errores estructurales a la vez y te da un plan de rollback. La migración es trabajo, pero es trabajo que termina en un sistema en el que realmente confías.
Solución 5: Añadir special vdevs con cuidado (aceleración de metadata/pequeños bloques)
Los special vdevs pueden mover metadata (y opcionalmente bloques pequeños) a medios más rápidos. Esto puede hacer que un pool RAIDZ se sienta mucho más ágil, sobre todo en cargas con metadata intensa.
Aviso: los special vdevs no son caché. Si pierdes un special vdev que contiene metadata, puedes perder el pool. Replica los special vdevs en mirror. Trátalos como almacenamiento de primera clase, no como adorno.
Tres micro-historias corporativas desde las trincheras
Micro-historia 1: El incidente causado por una suposición equivocada
Tenían un solo vdev RAIDZ2 y se estaban quedando sin espacio. Un ingeniero bienintencionado dijo: “ZFS puede stripear entre vdevs, así que podemos añadir un disco temporalmente y mover datos después.” Sonó plausible en la forma en que muchas ideas peligrosas lo hacen.
El equipo ejecutó zpool add con un disco único. La presión de capacidad cedió al instante. El ticket se cerró. Todos se fueron a casa y disfrutaron la rara sensación de “arreglamos almacenamiento rápido”.
Dos meses después, ese “temporal” empezó a mostrar errores. No un fallo total—peor. Timeouts intermitentes y errores de escritura ocasionales. ZFS comenzó a marcar el dispositivo como degradado y luego falló. El pool murió porque un vdev de primer nivel falló. Sin paridad, sin mirror. Un disco pasó a ser un single point of failure para todo el pool.
El postmortem dolió porque el sistema se comportó exactamente como diseñado. La suposición equivocada no fue sobre ZFS ser poco fiable; fue sobre malinterpretar lo que implica “striping entre vdevs”. No añadieron capacidad—añadieron una columna frágil bajo todo el edificio.
La solución fue recuperar desde backups y reconstruir la topología del pool. También añadieron una regla: un wrapper que rechazaba zpool add a menos que el vdev añadido cumpliera una regla mínima de redundancia.
Micro-historia 2: La optimización que salió mal
Otra compañía tenía un pool RAIDZ1 para una granja de VM. “Iba bien” hasta que no: picos de latencia, VMs con stuttering, equipos de aplicaciones enfadados. El equipo de almacenamiento decidió “optimizar” haciendo el RAIDZ más ancho durante una expansión para aumentar throughput, asumiendo que más discos = más velocidad.
Expandieron capacidad añadiendo otro vdev RAIDZ ancho, y además ajustaron settings de dataset: recordsize mayor, caching más agresivo y un calendario de snapshots más intenso “por seguridad”. El sistema rindió bien en benchmarks secuenciales. La carga real de producción no era secuencial ni educada.
Bajo carga real, las escrituras sync y el churn de metadata dominaron. Un RAIDZ más ancho encareció las escrituras pequeñas. El calendario de snapshots ancló bloques y amplificó la fragmentación. Los scrubs tardaron más, los resilvers tardaron más y la cola de latencia empeoró.
No causaron pérdida de datos, pero crearon un sistema que cumplía metas de capacidad mientras fallaba en SLOs de rendimiento. El rollback fue migrar datasets de VM a vdevs mirror, dejando RAIDZ para backups y almacenamiento en bloque.
La lección no fue “RAIDZ es malo”. Fue: optimizar por la métrica equivocada es indistinguible de sabotaje, salvo que los tickets suenan mejor al principio.
Micro-historia 3: La práctica aburrida y correcta que salvó el día
Una empresa de medios ejecutaba un pool de archivo siempre cerca del lleno porque alguien consideró “espacio libre” una opción. El ingeniero de almacenamiento—silencioso, poco glamuroso, consistentemente correcto—insistía en tres prácticas: scrubs mensuales, naming de dispositivos estable y reemplazo de discos por etapas con runbook probado.
Una semana, un disco empezó a mostrar sectores pendientes. El pool seguía online. No había alarmas de aplicaciones aún. Pero el informe de scrub y la tendencia SMART eran claros: el disco se estaba convirtiendo en un incidente futuro.
Lo cambiaron durante horario laboral con un resilver controlado. Porque tenían mapping by-id estable, el riesgo de reemplazar el disco equivocado fue bajo. Porque scrubbeaban regularmente, no había errores latentes por descubrir durante el resilver. Porque mantenían 20% de espacio libre por política, las asignaciones se mantuvieron sanas y el resilver terminó sin convertirse en desastre de rendimiento.
Dos días después, otro disco en el mismo vdev falló por completo. Respiraron, vieron a ZFS hacer su trabajo de paridad y siguieron con la semana. El segundo fallo podría haber sido pérdida del pool si el primer disco se hubiera dejado pudrir.
La práctica “aburrida” no recibió aplausos. Hizo algo mejor: evitó la llamada de las 3 a.m.
Errores comunes: síntomas → causa raíz → arreglo
Error 1: “Añadimos un disco y ahora el rendimiento es peor”
Síntomas: Mayor latencia, scrubs más lentos, throughput impredecible tras actividad de expansión.
Causa raíz: Expansión/rewrite compite con I/O de producción; además el pool está fragmentado y casi lleno.
Arreglo: Crea margen (borra/migra datos), reduce retención de snapshots, programa reescritura pesada en ventanas de baja carga y toma línea base con zpool iostat -v para confirmar contención.
Error 2: “Podemos añadir un disco temporalmente”
Síntomas: El pool depende de un vdev de primer nivel no redundante; luego una falla de un disco tira todo el pool.
Causa raíz: Mala comprensión del striping entre vdevs y dominios de fallo.
Arreglo: Nunca añadas un vdev de un solo disco a un pool importante. Si ya lo hiciste, migra fuera inmediatamente o reemplázalo añadiendo redundancia (mirror) si es factible.
Error 3: “Reemplazamos todos los discos pero no obtuvimos más espacio”
Síntomas: Después del reemplazo final, zpool list sigue mostrando el tamaño antiguo.
Causa raíz: autoexpand deshabilitado, particiones no crecieron o la capacidad del dispositivo no se expuso.
Arreglo: Habilita autoexpand, confirma tamaño de particiones, exporta/importa si hace falta y verifica con zpool get autoexpand y lsblk.
Error 4: “El resilver duró una eternidad y luego falló otro disco”
Síntomas: Resilver de varios días, errores crecientes, segundo disco falla durante la reconstrucción.
Causa raíz: No scrub regular; errores latentes descubiertos durante rebuild; discos viejos bajo estrés; pool muy lleno.
Arreglo: Scrub regularmente, mantiene espacio libre, reemplaza discos por tendencias SMART y considera paridad mayor (RAIDZ2/3) para pools HDD grandes.
Error 5: “Habilitamos una feature flag nueva y ahora replicación/boot falló”
Síntomas: Otro host no puede importar el pool; la imagen de recuperación no puede montar; el target de replicación rechaza streams.
Causa raíz: Mismatch de feature flags/compatibilidad entre sistemas.
Arreglo: Estandariza versiones OpenZFS en la flota antes de habilitar features; usa propiedades de compatibilidad cuando convenga; mantiene herramientas de recuperación actualizadas.
Error 6: “Expandimos pero la capacidad no apareció inmediatamente”
Síntomas: El disco añadido aparece en la config, pero el espacio usable crece lentamente o no lo hace.
Causa raíz: Los bloques existentes siguen en la geometría antigua; las snapshots los anclan; el proceso de reescritura/expansión toma tiempo.
Arreglo: Maneja expectativas, monitorea progreso, reduce retención de snapshots y evita expandir un pool casi lleno.
Listas de verificación / plan paso a paso
Plan A: Usar RAIDZ expansion (cuando esté soportado y toleres la reescritura)
- Confirma soporte de la plataforma: versión OpenZFS en todos los importadores (nodos prod, DR, medios de rescate).
- Confirma salud del pool:
zpool statuslimpio, scrub reciente, sin banderas SMART rojas. - Crea margen: baja CAP bajo ~80% si es posible.
- Congela cambios riesgosos: sin actualizaciones de kernel simultáneas, sin roulette de firmware, sin experimentos “mientras estamos aquí”.
- Valida backups: prueba una ruta de restauración para al menos un dataset representativo.
- Identifica el disco objetivo por-id: confirma serial, slot y WWN.
- Programa la ventana: la expansión es disruptiva; planifica degradación de rendimiento y trabajos batch más largos.
- Monitorea continuamente: vigila
zpool status,zpool iostat, SMART y latencia de aplicaciones. - Scrub post-cambio: cuando el sistema se estabilice, corre un scrub para verificar integridad bajo la nueva configuración.
Plan B: Reemplazar discos por otros más grandes (amigable para producción, costoso en tiempo)
- Haz un scrub primero; arregla errores antes de comenzar.
- Reemplaza un disco a la vez. Deja completar resilver completamente.
- No reemplaces múltiples discos “para ahorrar tiempo” a menos que te guste apostar con la paridad.
- Después del reemplazo final, asegúrate de que el vdev se expanda (autoexpand, tamaño de partición).
- Valida rendimiento y capacidad; luego ajusta retención de snapshots si el objetivo real era “espacio libre”.
Plan C: Añadir un nuevo vdev (capacidad rápida, cambio de topología permanente)
- Elige redundancia para igualar o superar los vdevs existentes.
- Empareja clase de disco y ancho aproximado para rendimiento predecible.
- Documenta el nuevo dominio de fallo para on-call.
- Después de añadirlo, observa la distribución: nuevas escrituras irán al vdev nuevo; los datos antiguos permanecen a menos que se reescriban.
- Si necesitas reequilibrio, plánificalo explícitamente (send/receive o reescritura controlada), no por deseo.
Preguntas frecuentes
1) ¿Puedo añadir un disco a mi vdev RAIDZ y obtener más espacio al instante?
No instantáneamente como la gente espera. Con soporte de RAIDZ expansion puedes añadir un disco e iniciar un proceso de expansión, pero el espacio utilizable puede materializarse gradualmente a medida que se reescriben los datos.
2) ¿Es más seguro añadir un nuevo vdev RAIDZ en lugar de expandir uno existente?
“Más seguro” depende de lo que entiendas. Añadir un vdev redundante es una operación bien entendida con dominios de fallo predecibles. La expansión reescribe muchos datos y estresa discos. Si tus discos son viejos o el pool está muy lleno, añadir un vdev nuevo (correctamente redundante) puede ser la opción de menor riesgo.
3) ¿Por qué ZFS no rebalancea datos automáticamente después de añadir capacidad?
ZFS no mueve bloques antiguos solo porque añadiste espacio; asignará bloques nuevos en metaslabs nuevas. Rebalancear automáticamente implicaría I/O masivo en background y decisiones de política complejas (qué datos, cuándo, con qué prioridad).
4) Si añado un nuevo vdev, ¿las lecturas serán más rápidas?
A menudo sí para cargas paralelas, porque tienes más vdevs que pueden atender lecturas. Pero los datos calientes ya escritos en el vdev antiguo permanecen allí; “más vdevs” no teletransporta tu working set.
5) ¿Debería cambiar de RAIDZ a mirrors para crecimiento futuro?
Si necesitas expansión incremental y latencia IOPS predecible, los mirrors suelen ser la respuesta correcta. Si necesitas máxima capacidad usable por disco y la carga es más secuencial/por lotes, RAIDZ sigue siendo excelente. No elijas por fe; elige según dominios de fallo y requisitos de latencia.
6) ¿Añadir un SLOG ayuda con la expansión o la capacidad?
No para capacidad. Para rendimiento: ayuda solo para escrituras síncronas y solo si el SLOG es rápido y seguro contra pérdida de energía. Los mitos sobre SLOG son eternos; también lo son las caches de escritura que mienten.
7) ¿La expansión RAIDZ arreglará mi problema de “pool al 90%”?
Puede proporcionar más espacio, pero expandir un pool casi lleno es riesgoso y puede ser dolorosamente lento. Prioriza reducir uso, podar snapshots o añadir capacidad de una forma que no requiera un reescrito masivo bajo presión.
8) ¿Cómo sé si las snapshots están bloqueando la recuperación de espacio?
Mira la salida de zfs list incluyendo snapshots y compara REFER vs USED por dataset. Valores grandes en USED por snapshots indican bloques antiguos anclados. Si borras datos y el espacio no vuelve, las snapshots son sospecha principal.
9) ¿Puedo “deshacer” una mala elección de expansión?
No puedes eliminar un vdev de primer nivel del pool en el caso general. A veces puedes evacuar y destruir un vdev, o migrar datasets a un pool nuevo con mejor layout. Por eso las decisiones de topología merecen paranoia.
10) ¿Cuál es el hábito único mejor para prevenir dramas de expansión?
Mantén margen. Bajo ~70–80% de uso, ZFS se comporta como un sistema de archivos competente. Por encima de eso se convierte en un show cómico operativo con un reparto muy caro.
Siguientes pasos prácticos
Esto es lo que haría un lunes por la mañana si heredara tu situación de “necesitamos más capacidad RAIDZ”:
- Mide la realidad: ejecuta
zpool list,zpool iostat -vyzfs list -t snapshot. Decide si el problema es capacidad, latencia o ambos. - Compra tiempo de forma segura: poda snapshots y datos fríos primero. Si necesitas capacidad inmediata, añade un nuevo vdev redundante—nunca un disco suelto.
- Elige una estrategia de expansión:
- Si toleras un largo reescrito en background y tu plataforma lo soporta, RAIDZ expansion es ahora una opción legítima.
- Si necesitas riesgo mínimo en features y operaciones predecibles, reemplaza discos por otros más grandes.
- Si tu topología está mal (ashift, clase de discos equivocada, redundancia incorrecta), migra a un pool nuevo.
- Aplica las guardas aburridas: scrub primero, chequea SMART, valida backups y documenta el rollback.
Una idea parafraseada de Richard Cook (investigador en seguridad y operaciones): El éxito en sistemas complejos suele venir de equipos que se adaptan constantemente, no de la ausencia de problemas.
Broma #2: La forma más rápida de aprender que tu topología de pool está mal es intentar “arreglarla temporalmente” durante un freeze de cambios por vacaciones.