Hoja de ruta maestra de ZFS: desde la primera pool hasta producción sin arrepentimientos

¿Te fue útil?

La primera vez que ZFS te hace pasar un mal rato, normalmente no es porque sea “inestable”. Es porque lo trataste como un sistema de ficheros genérico,
mezclaste unos cuantos “consejos de rendimiento” de un hilo de foro y lo subiste a producción con toda la ceremonia de mover una planta de interior.

Esta hoja de ruta es para construir ZFS como si te fueran a llamar a las 03:12, el almacenamiento estuviera lleno, el CEO estuviera en la Wi‑Fi de la demo
y tuvieras que diagnosticar el cuello de botella antes de que se enfríe tu café.

Modelo mental de ZFS: qué estás realmente construyendo

ZFS no es “un sistema de ficheros”. Es un sistema de almacenamiento con opiniones. La pool (zpool) es tu dominio de fallo y tu envoltura de rendimiento.
Los datasets son límites de política. Los zvols son dispositivos de bloque con aristas cortantes. El ARC es tu mejor amigo hasta que se convierte en tu excusa
más cara para “era rápido en staging”.

Lo más importante para interiorizar: ZFS es copy-on-write. Nunca sobrescribe bloques en su sitio. Así es como aporta checksumming,
snapshots y un estado consistente en disco sin journaling en el sentido tradicional. También es por esto que la fragmentación, el crecimiento de metadatos
y la amplificación de escritura pueden aparecer en lugares sorprendentes si no modelas las cargas.

Piensa en capas:

  • vdev: un grupo de redundancia único (mirror, raidz). Si un vdev muere, la pool se va.
  • pool: un conjunto de vdevs en stripe. La capacidad y los IOPS son agregados—hasta que no lo son.
  • dataset: un límite administrativo para propiedades (compression, recordsize, atime, cuotas, reservas).
  • snapshot: una referencia en un punto temporal; no es una “copia de seguridad”, es una máquina del tiempo atascada en el mismo chasis.
  • send/receive: cómo obtienes copias reales, replicación, migraciones y arrepentimientos en otro sistema.

Tu hoja de ruta trata principalmente de seleccionar la geometría de vdev correcta, ajustar las propiedades de los datasets para que coincidan con el I/O real,
y construir un ritmo operativo: scrub, monitorizar, probar restauración, repetir.

Hechos y contexto que cambian las decisiones

La ingeniería de almacenamiento mejora cuando recuerdas que la “mejor práctica” de hoy suele ser el informe de incidentes de ayer.
Aquí hay algunos puntos de contexto que vale la pena mantener en la cabeza:

  1. ZFS se originó en Sun Microsystems a mediados de los 2000 como un sistema de almacenamiento de extremo a extremo, no un sistema de ficheros adjunto.
  2. Copy-on-write fue una elección de diseño por consistencia: la pérdida de energía durante actualizaciones de metadatos no debería requerir fsck teatral.
  3. Checksumming de extremo a extremo significa que ZFS puede detectar corrupción silenciosa incluso cuando el disco devuelve datos erróneos con aparente normalidad.
  4. RAIDZ no es “RAID5/6” en detalles de implementación: evita el write hole por diseño, pero paga con matemática de paridad y comportamiento de stripe variable.
  5. Las primeras versiones de ZFS tuvieron fama de hambrientas de RAM; las implementaciones modernas son más configurables, pero ARC sigue escalando con la ambición.
  6. lz4 se convirtió en el valor por defecto por una razón: normalmente es “velocidad gratis” porque menos bytes llegan al disco.
  7. Alineación de sectores 4K (ashift) es una decisión permanente: una vez que creas un vdev con un ashift demasiado pequeño, no puedes arreglarlo in situ.
  8. SLOG y L2ARC fueron sobrevendidos históricamente como botones mágicos de rendimiento; en muchos sistemas reales no hacen nada o empeoran la situación.
  9. OpenZFS se convirtió en el punto de convergencia multiplataforma tras la división de licencias original; las características aterrizan a ritmos distintos según el SO.

Una idea parafraseada de John Allspaw (operaciones/confiabilidad): la confiabilidad viene de habilitar el aprendizaje, no de fingir que los fallos no sucederán.
Construye tu configuración de ZFS para que puedas aprender rápido cuando se comporte mal.

Etapa 0: decide qué tipo de fallo estás comprando

Antes de los comandos, decide las tres cosas que realmente definen tu resultado:
tolerancia a fallos, perfil de IO y riesgo de reconstrucción.
A la gente le encanta hablar de throughput bruto. Los sistemas de producción mueren por latencia en la cola y pánico operativo.

Mirror vs RAIDZ: elige según tu peor día

  • Mirrors: mejor para I/O aleatorio pequeño, resilver más rápido (especialmente en discos grandes), expansión futura más fácil. Cuesta más en capacidad.
  • RAIDZ1: tentador en teoría, frecuentemente lamentado en discos grandes. A un fallo de disco de la semana muy emocionante.
  • RAIDZ2: elección común para sistemas de capacidad; protección decente, escrituras aleatorias pequeñas más lentas que los mirrors.
  • RAIDZ3: para vdevs muy grandes y entornos donde las ventanas de reconstrucción dan miedo.

Si la pool soporta cargas sensibles a latencia (VMs, bases de datos, runners CI), los mirrors suelen ser la respuesta menos equivocada.
Si es una carga mayoritariamente secuencial de objetos/archivo, RAIDZ2 puede comportarse bien.

La regla “un vdev es un radio de explosión”

Si cualquier vdev de nivel superior falla, la pool falla. Por eso mezclar clases de dispositivo dentro de un vdev es un pasatiempo peligroso.
También es por eso que “añadir un disco más después” no es un plan—la geometría del vdev importa.

Chiste #1: ZFS no pierde tus datos. Solo programa una reunión entre tus suposiciones y la física.

Etapa 1: crea la primera pool (correctamente)

Esta etapa trata principalmente de no hornear errores irreversibles en tu pool: dispositivos equivocados, ashift incorrecto, layout erróneo.
Trata la creación de la pool como diseño de esquema. No “lo cambias después”.

Tarea 1: identifica discos por IDs estables (no la ruleta /dev/sdX)

cr0x@server:~$ ls -l /dev/disk/by-id/ | head
total 0
lrwxrwxrwx 1 root root  9 Dec 26 10:11 ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4XXXXXXXXX -> ../../sda
lrwxrwxrwx 1 root root  9 Dec 26 10:11 ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4YYYYYYYYY -> ../../sdb
lrwxrwxrwx 1 root root 10 Dec 26 10:11 wwn-0x5000c500abcdef01 -> ../../nvme0n1
lrwxrwxrwx 1 root root 10 Dec 26 10:11 wwn-0x5000c500abcdef02 -> ../../nvme1n1

Qué significa: tienes nombres estables (ata-*, wwn-*). ZFS almacenará rutas; quieres rutas que sobrevivan reinicios y cambios de HBA.
Decisión: construye vdevs usando /dev/disk/by-id (o by-partuuid si particionas).

Tarea 2: comprueba tamaños de sector antes de comprometer ashift

cr0x@server:~$ sudo lsblk -d -o NAME,MODEL,SIZE,PHY-SeC,LOG-SeC
NAME  MODEL                     SIZE PHY-SEC LOG-SEC
sda   SAMSUNG MZ7L31T9HBLT-00A 1.8T    4096    512
sdb   SAMSUNG MZ7L31T9HBLT-00A 1.8T    4096    512
nvme0n1 INTEL SSDPE2KX040T8      3.7T    4096   4096
nvme1n1 INTEL SSDPE2KX040T8      3.7T    4096   4096

Qué significa: algunos discos son 512e (lógico 512, físico 4K). ZFS debe usar alineación 4K.
Decisión: establece ashift=12 para 4K. Si tienes hardware con sectores 8K/16K, considera ashift más alto. No adivines.

Tarea 3: crea una pool mirror con ashift explícito y valores sensatos

cr0x@server:~$ sudo zpool create -o ashift=12 -O compression=lz4 -O atime=off -O xattr=sa -O acltype=posixacl tank mirror \
/dev/disk/by-id/ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4XXXXXXXXX \
/dev/disk/by-id/ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4YYYYYYYYY

Qué significa: creaste tank con un vdev mirror. Las propiedades aplican al dataset raíz.
Decisión: si esta pool va a albergar ficheros generales y VMs, los mirrors son un comienzo defendible. Si necesitas capacidad, diseña RAIDZ2 ahora—no “migres después.”

Tarea 4: verifica salud y layout de la pool

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: ONLINE
  scan: none requested
config:

        NAME                                                       STATE     READ WRITE CKSUM
        tank                                                       ONLINE       0     0     0
          mirror-0                                                 ONLINE       0     0     0
            ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4XXXXXXXXX             ONLINE       0     0     0
            ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4YYYYYYYYY             ONLINE       0     0     0

errors: No known data errors

Qué significa: sin errores; la topología coincide con lo que pretendías.
Decisión: si la topología parece incorrecta, destruye y recrea ahora (zpool destroy tank) antes de que lleguen datos y la política se entrometa.

Tarea 5: confirma que las propiedades realmente quedaron

cr0x@server:~$ sudo zfs get -o name,property,value -s local compression,atime,xattr,acltype tank
NAME  PROPERTY     VALUE
tank  compression  lz4
tank  atime        off
tank  xattr        sa
tank  acltype      posixacl

Qué significa: las propiedades están establecidas localmente en el dataset raíz.
Decisión: mantiene las propiedades de “política” a nivel de dataset; evita ajustes globales que no puedas explicar luego.

Tarea 6: establece un punto de montaje y confirma que está montado

cr0x@server:~$ sudo zfs set mountpoint=/tank tank
cr0x@server:~$ mount | grep tank
tank on /tank type zfs (rw,xattr,posixacl)

Qué significa: el dataset está montado en una ubicación predecible.
Decisión: mantén los mountpoints aburridos y explícitos. Nadie quiere “¿dónde montó ZFS eso?” durante una restauración.

Etapa 2: datasets, propiedades y valores por defecto sensatos

Las pools son para hardware. Los datasets son para humanos. Creas datasets para separar políticas:
opciones de compresión, recordsize, calendario de snapshots, cuotas y “esto puede ser ruidoso”.

Layout de datasets que sobrevive el crecimiento

Una estructura práctica (ajusta nombres a tu mundo):

  • tank/sys para cosas tipo OS y configuraciones
  • tank/home para usuarios (las cuotas ayudan)
  • tank/apps para datos de aplicaciones
  • tank/vm para discos de VM (consideraciones de recordsize)
  • tank/backup para replicación entrante (políticas de snapshot diferentes)

Tarea 7: crea datasets y aplica propiedades por carga de trabajo

cr0x@server:~$ sudo zfs create tank/apps
cr0x@server:~$ sudo zfs create tank/home
cr0x@server:~$ sudo zfs create tank/vm
cr0x@server:~$ sudo zfs set compression=lz4 tank/apps tank/home tank/vm
cr0x@server:~$ sudo zfs set atime=off tank/apps tank/vm
cr0x@server:~$ sudo zfs set recordsize=16K tank/vm

Qué significa: creaste datasets separados y ajustaste recordsize para I/O aleatorio tipo VM.
Decisión: no pongas recordsize=16K en todas partes “por rendimiento”. Úsalo donde coincida con el I/O (discos de VM, algunas bases de datos).

Tarea 8: valida la herencia de propiedades y las sobreescrituras locales

cr0x@server:~$ sudo zfs get -r -o name,property,value,source compression,recordsize,atime tank | head -n 20
NAME      PROPERTY     VALUE  SOURCE
tank      compression  lz4    local
tank      recordsize   128K   default
tank      atime        off    local
tank/apps compression  lz4    local
tank/apps recordsize   128K   inherited from tank
tank/apps atime        off    local
tank/home compression  lz4    local
tank/home recordsize   128K   inherited from tank
tank/home atime        off    inherited from tank
tank/vm   compression  lz4    local
tank/vm   recordsize   16K    local
tank/vm   atime        off    local

Qué significa: puedes ver la herencia y lo que intencionalmente sobreescribiste.
Decisión: mantiene las sobreescrituras escasas. Si todo está sobreescrito, nada es explicable.

Tarea 9: usa cuotas y reservas para prevenir vecinos ruidosos

cr0x@server:~$ sudo zfs set quota=500G tank/home
cr0x@server:~$ sudo zfs set reservation=200G tank/apps
cr0x@server:~$ sudo zfs get -o name,property,value tank/home quota
NAME       PROPERTY  VALUE
tank/home  quota     500G

Qué significa: tank/home no puede crecer más allá de 500G; tank/apps mantiene 200G reservados.
Decisión: las cuotas detienen el crecimiento descontrolado; las reservas mantienen cargas críticas fuera de la presión de “logs temporales”.

Etapa 3: ajustes de rendimiento que puedas defender

El ajuste de rendimiento en ZFS es 30% configuración y 70% no mentirte sobre tu carga de trabajo.
Empieza midiendo. Luego haz lo más simple que aborde el cuello de botella.
“Afinar todo” es como crear un sistema que solo una persona puede operar—y esa persona está de vacaciones.

ARC, memoria y por qué “más RAM” es verdad y perezoso

ARC cachea lecturas y metadatos. Puede enmascarar discos lentos y también competir por memoria con aplicaciones.
Si ejecutas bases de datos o hypervisors, debes decidir conscientemente dónde vive el cache:
en la app, en la caché de página del SO, en ARC o en una capa dedicada.

Tarea 10: inspecciona ARC y presión de memoria (ejemplo Linux)

cr0x@server:~$ grep -E 'c_max|c |size|hits|misses' /proc/spl/kstat/zfs/arcstats | head
c_max                           4    34359738368
c                               4    26843545600
size                            4    25769803776
hits                            4    182736451
misses                          4    24372611

Qué significa: ARC está ~24–25GiB, target ~25GiB, max 32GiB; hits vs misses te dicen si la caché está ayudando.
Decisión: si ARC es enorme y las apps están intercambiando, limita ARC. Si los misses son altos y los discos están ocupados, más ARC puede ayudar.

Recordsize: el silencioso que decide destinos

recordsize es para sistemas de ficheros (datasets). Es el tamaño máximo de bloque que ZFS usará para datos de ficheros.
Recordsize grande es genial para lecturas secuenciales y ratio de compresión. Recordsize pequeño reduce la sobrecarga de read-modify-write en I/O aleatorio pequeño.
Pero demasiado pequeño puede aumentar la sobrecarga de metadatos y la fragmentación.

Zvols: cuando quieres un dispositivo de bloque y también sufrir un poco

Los zvols pueden ser adecuados para iSCSI o backends de VM, pero requieren disciplina extra: establece volblocksize al crear,
alinea particiones invitadas y monitoriza amplificación de escritura. No cambies tamaños de bloque a la ligera—no puedes.

Tarea 11: crea un zvol con un volblocksize intencional

cr0x@server:~$ sudo zfs create -V 200G -o volblocksize=16K -o compression=lz4 tank/vm/vm-001
cr0x@server:~$ sudo zfs get -o name,property,value tank/vm/vm-001 volblocksize
NAME            PROPERTY      VALUE
tank/vm/vm-001  volblocksize  16K

Qué significa: un zvol de 200G respaldado por ZFS, con bloques de 16K.
Decisión: ajusta volblocksize al I/O esperado (a menudo 8K–16K para muchos patrones de VM). No uses valores por defecto a ciegas.

SLOG y escrituras sync: la parte donde la gente gasta dinero y aún pierde

Un dispositivo SLOG solo ayuda las escrituras síncronas. Si tu carga es mayoritariamente async, no moverá la aguja.
Si tu carga es intensiva en sync (bases de datos con fsync, NFS con sync, journaling de VM), SLOG puede reducir latencia y proteger logs de intención en medio rápido.
Pero un SLOG malo (sin protección contra pérdida de energía) puede convertir “mejora de rendimiento” en “historia de corrupción misteriosa”.

Tarea 12: comprueba si tu carga realmente emite escrituras sync

cr0x@server:~$ sudo zpool iostat -v tank 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        1.02T   650G    210   1800   42.1M  155M
  mirror-0  1.02T   650G    210   1800   42.1M  155M
    ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4XXXXXXXXX     -      -    105    900   21.0M  77.5M
    ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4YYYYYYYYY     -      -    105    900   21.1M  77.5M

Qué significa: ves actividad intensiva de escritura. Esto por sí solo no prueba sync vs async, pero dice dónde está la carga.
Decisión: si clientes sensibles a latencia se quejan durante operaciones sync-heavy, investiga la propiedad sync y añade SLOG solo si está justificado.

Tarea 13: inspecciona ajustes sync y evita la trampa “sync=disabled”

cr0x@server:~$ sudo zfs get -o name,property,value,source sync tank tank/apps tank/vm
NAME      PROPERTY  VALUE  SOURCE
tank      sync      standard  default
tank/apps sync      standard  inherited from tank
tank/vm   sync      standard  inherited from tank

Qué significa: estás usando semánticas POSIX normales.
Decisión: mantén sync=standard a menos que te guste explicar a auditores por qué “durable” significaba “más o menos vibes”.

Tarea 14: verifica fragmentación y margen de capacidad antes de culpar a ZFS

cr0x@server:~$ sudo zpool list -o name,size,alloc,free,capacity,frag,health
NAME  SIZE  ALLOC  FREE  CAPACITY  FRAG  HEALTH
tank  1.81T 1.02T  650G      61%   18%  ONLINE

Qué significa: 61% lleno, fragmentación 18%. No es alarmante.
Decisión: si la capacidad es >80–85% y la frag es alta, espera caídas de rendimiento. Arregla la ocupación primero; el ajuste llega después.

Compresión: normalmente activada, ocasionalmente desactivada

lz4 es el “adulto por defecto”. Reduce escrituras físicas y a menudo mejora throughput.
Desactiva la compresión solo cuando los datos ya están comprimidos (cierto media, ciertos blobs cifrados) y hayas verificado que la CPU es un factor.

Tarea 15: estima la eficacia de compresión desde datos reales

cr0x@server:~$ sudo zfs get -o name,property,value -r compressratio tank/apps | head
NAME      PROPERTY       VALUE
tank/apps compressratio  1.62x

Qué significa: ahorras ~38% de espacio en promedio, a menudo con menos escrituras al disco.
Decisión: si compressratio está cerca de 1.00x y la CPU es limitada, considera desactivar la compresión solo para ese dataset.

Etapa 4: protección: scrubs, snapshots, replicación

ZFS te da checksums. No te da invulnerabilidad. Los scrubs encuentran errores latentes en discos. Los snapshots te dan reversión.
La replicación te da una segunda copia que no comparte tu dominio de fallo.

Scrubs: no son opcionales, ni un botón de pánico

Un scrub lee todos los datos y verifica checksums, reparando desde la redundancia cuando es posible. Es cómo encuentras un disco que está muriendo lentamente
antes de que pase a “inlegible durante el resilver”.

Tarea 16: inicia un scrub y verifica el progreso

cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
  scan: scrub in progress since Fri Dec 26 10:42:01 2025
        312G scanned at 3.20G/s, 120G issued at 1.23G/s, 1.02T total
        0B repaired, 11.71% done, 0:11:23 to go
config:

        NAME                                                       STATE     READ WRITE CKSUM
        tank                                                       ONLINE       0     0     0
          mirror-0                                                 ONLINE       0     0     0
            ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4XXXXXXXXX             ONLINE       0     0     0
            ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4YYYYYYYYY             ONLINE       0     0     0

errors: No known data errors

Qué significa: el scrub está en ejecución; muestra tasa de escaneo, tasa emitida y ETA.
Decisión: programa scrubs (mensual es común). Si los scrubs tardan “una eternidad”, investiga rendimiento de disco, cableado y layout de pool.

Snapshots: un bisturí, no un vertedero

Los snapshots son baratos al principio. Luego los guardas para siempre, renombras datasets tres veces y te preguntas por qué los borrados no liberan espacio.
La estrategia de snapshots es una política de retención más pruebas de restauración. Sin ambas, es solo un directorio de falsa esperanza.

Tarea 17: crea y lista snapshots; interpreta uso de espacio

cr0x@server:~$ sudo zfs snapshot tank/apps@pre-upgrade-001
cr0x@server:~$ sudo zfs list -t snapshot -o name,used,refer,creation -s creation | tail -n 3
NAME                         USED  REFER  CREATION
tank/apps@pre-upgrade-001     12M  220G   Fri Dec 26 10:55 2025

Qué significa: USED es espacio exclusivo del snapshot (bloques retenidos por este snapshot); REFER es tamaño referenciado.
Decisión: si los snapshots se acumulan y el espacio no se libera, inspecciona USED y poda por política, no por emoción.

Replicación: la versión adulta de los snapshots

Si el controlador de la pool se fríe, los snapshots en esa pool son tan útiles como una llave de repuesto dentro del mismo coche.
La protección real significa send/receive a otra máquina, otro rack, o al menos otro dominio de fallo.

Tarea 18: ejecuta un send/receive incremental a una pool de backup

cr0x@server:~$ sudo zfs snapshot tank/apps@replica-001
cr0x@server:~$ sudo zfs send -c tank/apps@replica-001 | ssh backup01 sudo zfs receive -uF backup/tank/apps

Qué significa: enviaste un stream comprimido (-c) a backup01 y lo recibiste en backup/tank/apps, no montado (-u), forzando rollback si es necesario (-F).
Decisión: usa automatización después, pero primero házlo a mano para saber cómo es el “éxito” y cómo falla.

Tarea 19: verifica el dataset en el lado receptor y el último snapshot

cr0x@server:~$ ssh backup01 sudo zfs list -o name,used,avail,refer,mountpoint backup/tank/apps
NAME             USED  AVAIL  REFER  MOUNTPOINT
backup/tank/apps  220G  4.10T  220G  none

Qué significa: el dataset de backup existe y no está montado (bueno para seguridad).
Decisión: mantiene los receives de backup sin montar por defecto. Monta solo para pruebas de restauración y luego desmonta de nuevo.

Etapa 5: observabilidad y guardarraíles operativos

ZFS falla en voz alta cuando falla en voz alta. Los fallos más desagradables son silenciosos: un cable marginal, un disco que hace timeout una vez al día,
una pool que se llena lentamente hasta que la fragmentación se vuelve personalidad.
Tu trabajo es aprender de estos antes que los usuarios.

Tarea 20: establece líneas base de contadores de error y vigila cambios

cr0x@server:~$ sudo zpool status -v
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 0:26:41 with 0 errors on Fri Dec 26 11:08:49 2025
config:

        NAME                                                       STATE     READ WRITE CKSUM
        tank                                                       ONLINE       0     0     0
          mirror-0                                                 ONLINE       0     0     0
            ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4XXXXXXXXX             ONLINE       0     0     0
            ata-SAMSUNG_MZ7L31T9HBLT-00A07_S4YYYYYYYYY             ONLINE       0     0     0

errors: No known data errors

Qué significa: READ/WRITE/CKSUM están a cero. Buena línea base.
Decisión: alerta cuando se muevan. Un error de checksum es “investigar”. Una tendencia es “programar mantenimiento”.

Tarea 21: comprueba SMART de los discos en el vdev

cr0x@server:~$ sudo smartctl -a /dev/sda | egrep -i 'Model|Serial|Reallocated|Pending|CRC|Power_On_Hours'
Model Family:     Samsung based SSDs
Serial Number:    S4XXXXXXXXX
Power_On_Hours:   18422
Reallocated_Sector_Ct: 0
Current_Pending_Sector: 0
UDMA_CRC_Error_Count: 2

Qué significa: los errores CRC suelen apuntar a problemas de cableado/backplane/HBA, no al NAND en sí.
Decisión: si CRC incrementa, vuelve a asentar/reemplaza el cable o cambia de bahía antes de sustituir un disco aparentemente sano.

Tarea 22: verifica autotrim (SSDs) y decide si lo activas

cr0x@server:~$ sudo zpool get -o name,property,value autotrim tank
NAME  PROPERTY  VALUE
tank  autotrim  off

Qué significa: autotrim está apagado. En pools SSD, TRIM puede ayudar el rendimiento sostenido de escrituras.
Decisión: considera zpool set autotrim=on tank para pools basadas en SSD tras validar que el firmware del disco se comporta.

Tarea 23: inspecciona señales de amplificación de escritura a nivel de dataset (lógico vs físico)

cr0x@server:~$ sudo zfs get -o name,property,value logicalused,used tank/vm
NAME     PROPERTY     VALUE
tank/vm  logicalused  380G
tank/vm  used         295G

Qué significa: la compresión está ayudando (used físico es menor que logical). Si fuera al revés, sospecharías copias, padding o mismatch de volblocksize.
Decisión: cuando logical y used divergen en la dirección equivocada, revisa propiedades del dataset y supuestos de carga.

Tarea 24: ensaya una restauración (la única prueba que cuenta)

cr0x@server:~$ ssh backup01 sudo zfs clone backup/tank/apps@replica-001 backup/tank/apps-restore-test
cr0x@server:~$ ssh backup01 sudo zfs set mountpoint=/mnt/restore-test backup/tank/apps-restore-test
cr0x@server:~$ ssh backup01 mount | grep restore-test
backup/tank/apps-restore-test on /mnt/restore-test type zfs (rw,xattr,posixacl)

Qué significa: creaste un clone escribible desde un snapshot y lo montaste.
Decisión: programa pruebas de restauración. Si no lo haces, tu primera restauración será durante un outage, lo cual es una elección audaz.

Guion de diagnóstico rápido

Cuando el rendimiento cae en picado, quieres un camino que converja rápido. No una danza interpretativa de una semana con gráficas.
Este guion asume herramientas Linux/OpenZFS, pero la lógica vale en otros sitios.

Primero: ¿está la pool sana y se está reconstruyendo algo?

  • Comprobar: zpool status -v
  • Buscar: scrub/resilver en progreso, vdevs DEGRADED, errores de checksum, dispositivos lentos
  • Decisión: si está resilverizando, espera rendimiento degradado; prioriza terminar la reconstrucción de forma segura sobre “afinar”.

Segundo: ¿estás sin espacio o muy fragmentado?

  • Comprobar: zpool list -o size,alloc,free,capacity,frag
  • Buscar: capacidad > 80–85%, frag > ~50% (depende del contexto)
  • Decisión: si está lleno/fragmentado, libera espacio y borra snapshots (con cuidado). No persigas sysctls arcanos primero.

Tercero: ¿cuál es el cuello de botella: disco, CPU, memoria o latencia de sync?

  • Disco: zpool iostat -v 1 muestra un dispositivo saturado o mucho más lento que sus pares.
  • CPU: compresión/checksum puede estar limitada por CPU en núcleos pequeños; valida con herramientas de CPU del sistema.
  • Memoria: thrashing de ARC o swapping del sistema: comprueba tamaño de ARC y actividad de swap.
  • Escrituras sync: picos de latencia durante cargas con fsync; SLOG puede ayudar si está bien diseñado.

Cuarto: identifica el dataset y patrón de carga

  • Comprobar: qué dataset está caliente (logs de aplicación, discos VM, ingest de backup)
  • Buscar: recordsize incorrecto para la carga, demasiados snapshots reteniendo espacio, comportamiento inesperado de sync
  • Decisión: afina en el límite del dataset. Evita cambios a nivel de pool salvo que arreglen un problema de pool entero.

Tres mini-historias corporativas (las que se recuerdan)

Incidente: la suposición equivocada (pensando en 512 bytes en un mundo 4K)

Una empresa SaaS mediana construyó un nuevo clúster de análisis sobre discos HDD grandes detrás de un HBA reputado. El arquitecto usó ZFS por checksums
y snapshots, y porque la pila de almacenamiento antigua tenía la personalidad de cartón húmedo. La creación de la pool estaba automatizada. “Funcionó”.

Seis meses después, la latencia de escritura fue aumentando. No catastróficamente—suficiente para que los jobs batch no cumplieran ventana. Luego el tiempo de resilver
en un solo reemplazo de disco se convirtió en un evento de varios días. Durante el resilver, el rendimiento cayó en picado y no se recuperó. El equipo asumió “las reconstrucciones en discos grandes son lentas”
y aceptó el dolor como precio por la capacidad.

Alguien finalmente sacó una línea base completa: tamaños de sector, ashift y alineación física real. La pool se había creado con ashift=9 porque los discos
reportaban sectores lógicos de 512 y nadie comprobó el tamaño físico real. Cada escritura se traducía en un ciclo read-modify-write en el disco.
ZFS hizo lo que le dijeron; los discos hicieron lo que requería la física.

Migraron los datos a una nueva pool con ashift=12. El rendimiento se normalizó. Los resilvers fueron dramáticamente más rápidos.
El informe del incidente fue dolorosamente simple: “Asumimos que el disco decía la verdad.” La acción correctiva también fue simple:
“Comprobaremos PHY-SeC y estableceremos ashift explícitamente.” La lección: ZFS preservará fielmente tus errores.

Optimización que salió mal: la era “sync=disabled”

Otra compañía ejecutaba una granja de VM sobre mirrors ZFS. Los desarrolladores se quejaban de picos de latencia ocasionales durante horas pico de despliegue.
Alguien buscó en Google. Alguien encontró el ajuste. Alguien dijo, “No necesitamos escrituras síncronas; tenemos UPS.”
sync=disabled se aplicó a nivel de dataset para el almacenamiento de VM.

Los picos desaparecieron. Los tickets se cerraron. Hubo high-fives en el canal de Slack compartido donde la optimismo va a morir.
Dos meses después, un host se reinició inesperadamente tras un kernel panic. El UPS estuvo bien. Los discos estuvieron bien. Las VMs no estuvieron bien.
Un puñado volvió con sistemas de ficheros corruptos. No todas. Suficientes para que el incidente se sintiera como un fantasma.

El postmortem fue crudo pero claro: se habían deshabilitado las semánticas síncronas, así que las escrituras reconocidas no eran necesariamente durables.
El crash ocurrió en una ventana donde varios invitados creían que sus datos estaban en almacenamiento estable. No lo estaban. ZFS hizo exactamente lo que se configuró.

Revirtieron a sync=standard, midieron de nuevo y resolvieron el problema real: un camino de escritura saturado más una mala cola durante las tormentas de deploy.
Añadieron capacidad y suavizaron los picos de I/O. La moraleja no es “nunca optimices”. Es “optimiza con un plan de reversión y una definición clara de corrección.”

Chiste #2: Deshabilitar escrituras sync es como quitar el detector de humo porque hace ruido. Más silencioso, sí. Más inteligente, no.

Práctica aburrida pero correcta que salvó el día: scrubs mensuales y buena higiene de alertas

Un equipo de servicios financieros ejecutaba un servicio de ficheros modesto respaldado por ZFS. Nada sofisticado: vdevs mirror, compresión lz4, políticas conservadoras de dataset.
Tenían un hábito del que nadie presumía: scrubs mensuales y alertas que disparaban en nuevos errores de checksum o vdevs degradados.
La rotación on-call odiaba muchas cosas, pero no eso.

Un jueves por la tarde, saltó una alerta: un puñado de errores de checksum en un disco, luego más. La pool permaneció ONLINE. Los usuarios no notaron nada.
El ingeniero de guardia no “esperó a ver”. Miró SMART, vio CRC incrementando y sospechó cable o bahía.
Programó una ventana de mantenimiento y movió el disco a otra ranura. Los CRC dejaron de aumentar.

Dos semanas después, otro disco empezó a arrojar errores de medio real, y ZFS los reparó durante un scrub. El equipo reemplazó ese disco en horario laboral.
Sin emergencia. Sin outage prolongado. El sistema siguió siendo aburrido.

El secreto no fue genialidad. Fue un bucle: scrub regularmente, alerta pronto, trata contadores de error pequeños como humo y valida la ruta (cables, HBAs, firmware),
no solo el disco. En almacenamiento, lo aburrido es una característica que puedes entregar.

Errores comunes: síntomas → causa raíz → solución

1) “Los borrados no liberan espacio”

  • Síntomas: la aplicación borra datos, pero el uso de la pool se mantiene; df no cambia.
  • Causa raíz: snapshots retienen bloques referenciados; a veces los clones también.
  • Solución: lista snapshots por espacio usado y poda por política.
cr0x@server:~$ sudo zfs list -t snapshot -o name,used -s used | tail
tank/apps@daily-2025-12-20   18.2G
tank/apps@daily-2025-12-21   21.4G
tank/apps@daily-2025-12-22   25.7G

2) “I/O aleatorio es horrible en RAIDZ”

  • Síntomas: latencia VM, IOPS más bajos de lo esperado; las escrituras se sienten “pegajosas”.
  • Causa raíz: sobrecarga de paridad en RAIDZ más escrituras pequeñas aleatorias; mismatch de recordsize; pool demasiado llena.
  • Solución: mirrors para cargas sensibles a latencia, o separar RAIDZ para capacidad; afina recordsize en el dataset caliente; mantén margen de capacidad.

3) “El scrub tarda una eternidad y el sistema se arrastra”

  • Síntomas: scrubs duran días; servicios lentos; iostat muestra throughput bajo.
  • Causa raíz: disco lento o fallando, HBA/cableado malo, discos SMR escondidos, o carga concurrente pesada.
  • Solución: identifica dispositivo lento con zpool iostat -v; valida SMART; reemplaza hardware problemático; programa scrubs fuera de pico.

4) “Añadimos L2ARC y nada fue más rápido”

  • Síntomas: compraste caché SSD; latencia sin cambios; estadísticas ARC parecidas.
  • Causa raíz: la carga no es cacheable en lectura, o L2ARC es demasiado pequeño/lento, o el sistema está limitado por CPU/memoria.
  • Solución: mide tasas de acierto de caché; prioriza RAM/ARC y mejor layout de vdev antes de añadir L2ARC.

5) “El resilver es peligrosamente lento”

  • Síntomas: reemplazo de disco tarda mucho; rendimiento terrible durante resilver.
  • Causa raíz: HDDs grandes, geometría RAIDZ, alta utilización de pool, comportamiento SMR, o un disco enfermo arrastrando el vdev.
  • Solución: prefiere mirrors para reconstrucción rápida; mantén pool por debajo de ~80%; reemplaza discos sospechosos proactivamente; no mezcles dispositivos lentos/rápidos en un vdev.

6) “Aparecen errores de checksum pero los discos ‘están bien’”

  • Síntomas: zpool status muestra errores CKSUM; SMART parece normal.
  • Causa raíz: cableado/backplane/HBA/firmware; errores transitorios de transporte.
  • Solución: comprueba contadores SMART CRC; reseat/reemplaza cables; prueba otras bahías; actualiza firmware del HBA; luego limpia errores y monitoriza.

7) “No podemos expandir nuestro vdev RAIDZ como esperábamos”

  • Síntomas: añadiste un disco, la capacidad cambió poco o la expansión no fue posible.
  • Causa raíz: la geometría del vdev superior es fija; expandes añadiendo vdevs completos (o mediante características de expansión más nuevas según plataforma/versión, con restricciones).
  • Solución: planifica el ancho del vdev desde el día 0; para crecer, añade otro vdev de clase de rendimiento similar; evita pools Frankenstein.

Listas de verificación / plan paso a paso

Plan A: primera pool a “suficientemente segura” en producción en 10 pasos

  1. Inventario de hardware: confirma tipo de disco, tamaños de sector, modelo de HBA y si tienes protección contra pérdida de energía en SSDs.
  2. Elige topología: mirrors para latencia, RAIDZ2/3 para capacidad; evita RAIDZ1 en discos grandes salvo que disfrutes el azar.
  3. Nombra dispositivos con sentido: usa rutas /dev/disk/by-id; documenta el mapeo de bahías.
  4. Crea la pool explícitamente: establece ashift y propiedades del dataset raíz (compression, atime, xattr).
  5. Crea datasets por carga: apps vs VMs vs usuarios; ajusta recordsize y política sync intencionalmente.
  6. Establece guardarraíles de capacidad: cuotas para “humanos”, reservas para “no debe fallar”.
  7. Calendario de scrub: mensual como base; más frecuente si discos son sospechosos o el entorno es hostil.
  8. Política de snapshots: por ejemplo, horarias por 24h, diarias por 30d, mensuales por 12m—ajusta a necesidades de negocio y presupuesto de almacenamiento.
  9. Replicación: send/receive a un sistema distinto; prueba restauraciones clonando snapshots.
  10. Monitorización: alertas en DEGRADED, errores de checksum, incremento SMART CRC/realloc/pending, umbrales de capacidad de pool y fallos de scrub.

Plan B: migrar de “existe” a “es operable” sin fantasías de downtime

  1. Deja de hacer ajustes a nivel de pool. Empieza a medir y documentar el estado actual: zpool status, zpool list, zfs get all (filtrado).
  2. Separa datasets por carga para poder afinar y snapshotear de forma independiente.
  3. Implementa una política de retención y poda snapshots que ya no sirven a objetivos de recuperación.
  4. Configura replicación y ejecuta una prueba de restauración. Pruébalo por ti mismo con un clone montado.
  5. Planifica las “correcciones irreversibles” (ashift equivocado, topología equivocada) como una migración a una nueva pool. No hay interruptor mágico.

Cadencia operativa (qué haces cada semana/mes/trimestre)

  • Semanal: revisa alertas, busca nuevos contadores de error, confirma que jobs de snapshot funcionan, valida proyecciones de capacidad.
  • Mensual: scrub, revisa tendencias de duración de scrub, verifica al menos una prueba de restauración desde replicación.
  • Trimestral: ensaya un escenario “fallo de disco + restauración”, revisa propiedades de datasets frente a cambios de carga, valida líneas base de firmware.

Preguntas frecuentes

1) ¿Debo elegir mirrors o RAIDZ para almacenamiento de VM?

Mirrors, salvo que tengas una razón fuerte y un perfil de carga probado. Las VMs suelen hacer I/O aleatorio pequeño y castigan la sobrecarga de paridad de RAIDZ.
Si debes usar RAIDZ, mantén anchos de vdev razonables, conserva margen y ajusta recordsize para datasets de VM.

2) ¿RAIDZ1 es aceptable alguna vez?

En discos pequeños y datos no críticos, tal vez. En discos modernos grandes, RAIDZ1 aumenta el riesgo de que un segundo problema durante el resilver deje la pool abajo.
Si no toleras downtime y tiempo de restauración, no uses paridad simple.

3) ¿Qué compresión debo usar?

lz4 para casi todo. Desactívala solo en datasets donde los datos ya están comprimidos o cifrados y hayas medido el impacto en CPU.

4) ¿Cuánto puedo dejar llena una pool?

Intenta mantenerte por debajo de ~80% para un rendimiento saludable, especialmente en RAIDZ y cargas mixtas. Por encima de eso, la fragmentación y el comportamiento de asignación
pueden incrementar la latencia. El punto exacto depende de la carga, pero “la llevamos al 95%” es una frase familiar previa a un outage.

5) ¿Necesito un SLOG?

Solo si tienes escrituras síncronas significativas y te importa su latencia. Si tu carga es mayoritariamente async, un SLOG no ayudará.
Si añades uno, usa dispositivos de alta resistencia con protección contra pérdida de energía. SSDs de consumidor baratos no son dispositivos de diario; son generadores de sorpresas.

6) ¿Necesito L2ARC?

Normalmente no como primer paso. Empieza con RAM (ARC) y topología de pool correcta. L2ARC puede ayudar en cargas de lectura con working set mayor que RAM,
pero también consume memoria para metadatos y añade complejidad.

7) ¿Puedo cambiar ashift después de crear la pool?

No. No in situ. Arreglas un ashift equivocado migrando datos a una pool nueva creada correctamente. Por eso la validación del tamaño de sector es tarea de día 0.

8) ¿Cómo sé si los snapshots son la razón por la que el espacio no se libera?

Lista snapshots y ordénalos por used. Si hay snapshots grandes, están reteniendo bloques. Borra los snapshots (con cuidado, en orden de política),
luego monitoriza cambios de espacio. También revisa clones.

9) ¿ZFS es “una copia de seguridad” porque tiene snapshots?

No. Los snapshots son puntos de recuperación locales. Las copias de seguridad requieren dominios de fallo separados. Usa replicación send/receive (u otro sistema de backup) y prueba restauraciones.

10) ¿Cuál es el mejor hábito para evitar arrepentimientos?

Ejecutar pruebas de restauración desde la replicación según calendario. Todo lo demás es gestión de probabilidades; las pruebas de restauración son la verdad.

Conclusión: siguientes pasos prácticos

Si quieres “producción sin arrepentimientos”, no persigas flags exóticos. Toma tres buenas decisiones estructurales (topología, ashift, límites de dataset),
luego ejecuta un bucle operativo aburrido (scrub, snapshot, replicar, probar restauración, monitorizar errores).

Siguientes pasos que puedes hacer esta semana:

  • Escribe en una frase la topología de tu pool y la tolerancia a fallos. Si no puedes, no tienes diseño aún.
  • Crea datasets para tus tres cargas principales y define propiedades intencionalmente (compression, recordsize, atime, cuotas).
  • Ejecuta un scrub y registra cuánto tardó. Esa tendencia de duración será una señal de salud.
  • Configura replicación con send/receive a otro sistema y realiza una prueba de restauración vía clone-y-mount.
  • Convierte tus comprobaciones base en alertas: salud de pool, capacidad, errores de checksum e indicadores SMART de transporte/medio.

ZFS te dará integridad de datos y palanca operativa. También preservará gustosamente cada suposición errónea que le des.
Elige tus suposiciones como si fueras tú quien recibe la pantalla de llamada. Porque lo eres.

← Anterior
Los logs de Docker se están desbordando: arregla la rotación antes de que falle el host
Siguiente →
Email “550 rejected”: qué significa realmente y cómo desbloquearlo

Deja un comentario