Plan híbrido ZFS: datos en HDD + metadatos en SSD + caché NVMe, bien hecho

¿Te fue útil?

Compraste HDDs grandes y baratos para capacidad. Luego vino la producción: un millón de archivos pequeños, bases de datos ruidosas, imágenes de VM
que no encajan con el recordsize, y usuarios que tratan el “almacenamiento compartido” como “IOPS infinitos”. El pool está “sano”, los scrubs pasan,
y sin embargo los picos de latencia convierten tu cola de tickets en un sitio arqueológico.

Un diseño híbrido ZFS puede arreglar esto—si dejas de pensar en términos de marketing (“¡caché!”) y empiezas a pensar en dominios de fallo, rutas de escritura,
y en lo que ZFS hace realmente con los metadatos. Este es el plano que yo desplegaría cuando necesito economía de HDD sin la miseria de los HDD.

El modelo mental: rutas de IO de ZFS, no sensaciones

El trabajo sobre rendimiento en ZFS es 80% entender dónde se gasta el tiempo y 20% ajustar propiedades. La gente invierte eso, y luego se pregunta
por qué su “caché NVMe” no arregló una carga lenta de metadatos. Si mantienes un solo modelo mental, que sea este:

  • Lecturas: ARC en RAM primero, luego (opcionalmente) L2ARC en medios rápidos, y por último los vdevs principales (tu pool de HDD).
  • Escrituras (async): aterrizan en memoria, se agregan en grupos de transacción (TXGs) y luego se vacían a los vdevs principales.
  • Escrituras (sync): deben confirmarse solo después de que sean durables. Si tienes un SLOG, “durable” significa “en el SLOG”, luego se vuelcan a HDDs.
  • Metadatos: entradas de directorio, bloques indirectos, dnodes—estas cosas pueden dominar el IO para archivos pequeños y patrones aleatorios.

El plano híbrido trata de poner el tipo correcto de IO en el tipo correcto de dispositivo:
datos secuenciales y voluminosos en HDDs; metadatos calientes (y opcionalmente pequeños bloques) en SSD mediante un special vdev; intención de escritura sync
en un SLOG NVMe de baja latencia; alivio de amplificación de lectura via L2ARC cuando el ARC no es suficiente.

Aquí está la verdad aburrida: la mayoría de los problemas con “caché ZFS” son en realidad problemas de “no hay suficiente RAM”. El ARC es el único caché
que siempre es correcto, siempre es de baja latencia, y no requiere una novela para explicar en una revisión de cambios.

Una cita que vale la pena dejar en un post-it:
idea parafraseada de Werner Vogels: “You build it, you run it” no es cultura—es la forma en que aprendes lo que tu sistema realmente hace.

Hechos interesantes y contexto histórico (breve y concreto)

  1. ZFS nació en Sun para arreglar la corrupción silenciosa de datos y el dolor administrativo; los checksums de extremo a extremo fueron una característica central, no un extra.
  2. ARC es anterior al hype actual de cachés; es un caché residente en memoria de reemplazo adaptativo diseñado para superar al LRU simple en cargas mixtas.
  3. Copy-on-write cambió la historia de fallos: ZFS no sobrescribe bloques vivos; escribe nuevos y actualiza punteros, reduciendo problemas de “torn write”.
  4. SLOG no es una caché de escritura; históricamente se introdujo para acelerar escrituras sync mediante el registro de intención, no para absorber throughput masivo.
  5. L2ARC tiene un “impuesto de encabezado”: necesita metadatos en ARC para indexar el contenido de L2ARC, por eso añadir L2ARC puede reducir el ARC efectivo.
  6. Los special vdevs son relativamente nuevos en la historia de OpenZFS; formalizaron el patrón “poner metadatos en SSD” sin hacks.
  7. ashift se volvió un limitador de carrera: los admins de ZFS aprendieron que una alineación de sectores equivocada puede limitar permanentemente IOPS en discos de 4K.
  8. La compresión se volvió estándar no solo porque ahorra espacio (que lo hace), sino porque leer menos bytes suele vencer a la velocidad del disco sin comprimir.

Arquitectura de referencia: datos en HDD + metadatos en SSD + caché NVMe

Definamos el objetivo: un pool donde los datos grandes y fríos permanecen en HDDs, mientras que los patrones de IO que penalizan la latencia de HDD—búsquedas de metadatos,
lecturas aleatorias pequeñas, latencia de escrituras sync—se redirigen a medios rápidos de forma que no comprometan la seguridad ni la operabilidad.

Supuestos básicos (dílos en voz alta)

  • Los HDDs son para capacidad y throughput secuencial. Son terribles en latencia de IO aleatoria. Eso es física, no un problema del proveedor.
  • Los SSDs/NVMe son para latencia e IOPS. También fallan; simplemente fallan más rápido y a veces de formas más creativas.
  • La RAM es la palanca de rendimiento primaria. Si no conoces tu ratio de aciertos ARC, estás afinando a ciegas.
  • Estás usando OpenZFS en Linux (los ejemplos asumen rutas tipo Ubuntu/Debian). Ajusta según sea necesario.

Un layout “híbrido” sensato (ejemplo)

Este es un patrón común y apto para producción:

  • Data vdevs: RAIDZ2 de HDDs (o mirrors si necesitas IOPS más que eficiencia de capacidad)
  • Special vdev: SSDs en espejo para metadatos (y opcionalmente bloques pequeños)
  • SLOG: dispositivos NVMe en espejo (o al menos NVMe empresariales con protección ante pérdida de energía) para latencia de escrituras sync
  • L2ARC: NVMe opcional (a menudo de la misma clase que el SLOG pero no los mismos dispositivos) para cargas de lectura que superan el ARC

¿Por qué espejo para special vdev y SLOG? Porque esos componentes no son “agradables de tener”. Pasan a ser parte de la historia de disponibilidad del pool.
Pierde el special vdev y puedes perder el pool. Pierde el SLOG y pierdes aceleración de escrituras sync (y posiblemente las garantías de intención en vuelo durante un fallo),
pero con espejo y medios con PLP evitas que un corte de energía se convierta en un evento de escritura masiva al reiniciar.

Broma #1: Si alguien propone “un single SSD special vdev para ahorrar presupuesto”, pregúntales si también prefieren saltar en paracaídas con un solo paracaídas para ahorrar peso.

Metadatos en SSD bien hechos: diseño de special vdev

Qué hacen realmente los special vdevs

Un special vdev puede almacenar metadatos, y opcionalmente bloques pequeños, en medios más rápidos. Eso significa que los recorridos de directorio, búsquedas de atributos,
lecturas de bloques indirectos y muchas lecturas pequeñas aleatorias dejan de martillar tus HDDs.

La ganancia es más dramática cuando:

  • tienes muchos archivos pequeños (artefactos de CI, capas de contenedores, repositorios de código, buzones de correo, caches de compilación)
  • tienes árboles de directorio profundos y frecuentes stats/opens
  • tu working set es mayor que el ARC pero los metadatos son relativamente compactos

Regla innegociable: espeja el special vdev

El special vdev forma parte del pool. Si falla y no tienes redundancia, puede que no estés “degradado”. Puede que estés “hecho”. Trátalo como tratas la redundancia de tu vdev principal: sin puntos únicos de fallo.

Cómo decidir si almacenar bloques pequeños en special vdev

ZFS puede colocar bloques menores que un umbral en special vdevs mediante special_small_blocks. Esto es poderoso y peligroso—a la manera de dar
a tus SSDs de metadatos un trabajo extra como tier de datos de lectura aleatoria.

Úsalo cuando:

  • tus vdevs de HDD están limitados por latencia en lecturas aleatorias pequeñas
  • tienes una carga conocida dominada por pequeños bloques (muchos archivos bajo 64K, muchas lecturas de objetos pequeños)
  • tu special vdev tiene resistencia y margen de capacidad suficientes

Evítalo cuando:

  • no puedes estimar con precisión el crecimiento del footprint de pequeños bloques
  • tus SSDs son de grado consumidor con resistencia cuestionable y sin PLP
  • ya te cuesta mantener el special vdev por debajo de ~50–60% de utilización

Dimensionar special vdevs sin mentirte

Guía aproximada que funciona en la práctica:

  • Special vdev solo metadatos: suele ser unos pocos por ciento del espacio usado en el pool, pero puede dispararse con snapshots, records diminutos y churn intenso.
  • Metadatos + bloques pequeños: puede convertirse en “la mayor parte de tus datos calientes”. Planifica la capacidad en serio.

Regla práctica: dimensiona los special vdevs para que, en estado estable, se mantengan cómodamente por debajo del 70% de uso. Los SSDs se ralentizan cuando están llenos,
la asignación de metaslabs de ZFS se vuelve más selectiva, y tu “tier rápido” se convierte en un tier estrangulado.

SLOG NVMe: qué es y qué no es

Qué hace un SLOG

El Separate Intent Log (SLOG) es un dispositivo usado para almacenar el ZFS Intent Log (ZIL) para escrituras sync. Reduce la latencia de reconocimiento
de escrituras sync al escribir un registro mínimo de intención en almacenamiento rápido, y luego comprometer el TXG completo a los vdevs principales.

No es una caché de escritura general. Si tu carga es mayoritariamente escrituras async, el SLOG no moverá la aguja. Si tu carga es intensamente sync (NFS con
semántica sync, bases de datos con fsync(), almacenamiento de VM que fuerza sync), el SLOG puede ser la diferencia entre “usable” y “¿por qué es 1998 otra vez?”.

Requisitos del medio para SLOG (sé exigente)

  • Baja latencia bajo escritura sync (sostenida, no solo picos de benchmark)
  • Protección ante pérdida de energía (PLP) para que las escrituras reconocidas sobrevivan un evento de pérdida de energía
  • Endurance apropiada para cargas sync con muchas escrituras
  • Espejarlo si te importa la disponibilidad y el comportamiento predecible ante fallos de dispositivo

Dimensionamiento del SLOG: pequeño, rápido, aburrido

Normalmente no necesitas un SLOG enorme. Necesitas uno que pueda sostener tu tasa pico de escrituras sync durante el tiempo entre commits de TXG (típicamente segundos)
y el comportamiento de flush del dispositivo. Sobredimensionar no te trae mucho. Subespecificarlo te trae acantilados de latencia.

Broma #2: Un NVMe de consumidor sin PLP usado como SLOG es como un cinturón de seguridad hecho de espaguetis—técnicamente presente, espiritualemente ausente.

L2ARC NVMe: cuándo ayuda y cuándo engaña

El argumento honesto para L2ARC

L2ARC es una caché de lectura de segundo nivel. Ayuda cuando:

  • tienes una carga de lectura intensiva con un working set mayor que el ARC
  • tu patrón de acceso tiene reutilización (lecturas cacheables, no scans de una sola pasada)
  • tu cuello de botella es la latencia/IOPS de lectura de HDDs, no CPU o red

Por qué L2ARC decepciona a la gente

L2ARC no es gratis.:

  • consume memoria ARC para encabezados e indexado
  • se calienta con el tiempo (no se llena instantáneamente tras un reinicio salvo que esté configurado para ello)
  • puede ser inefectivo para lecturas en streaming, scans secuenciales grandes o datasets con baja localidad

Consejo práctico

Si te falta RAM, compra RAM antes que L2ARC. Si ya tienes RAM bien provisionada y aún estás limitado por latencia de lectura, L2ARC puede ser una palanca
sólida. Pero mide, no supongas.

Ajuste de datasets que realmente importa

Compresión: activada por defecto salvo que tengas razón para lo contrario

compression=lz4 suele ser una ganancia: menos bytes que leer de los HDDs, a menudo más rápido en conjunto. Si tus datos ya están comprimidos
(archivos multimedia, blobs encriptados), puede que no reduzca mucho el tamaño—pero normalmente no perjudica salvo que la CPU sea un recurso escaso.

recordsize: alinea con cómo lees, no con cómo almacenas

Para sistemas de archivos generales, recordsize=128K está bien. Para bases de datos, a menudo quieres records más pequeños (como 16K) para reducir
la amplificación de lectura. Para imágenes de VM, considera 64K o 128K dependiendo de la carga. Para zvols, ajusta volblocksize en el momento de creación
(no se puede cambiar después).

sync y logbias: no “arregles latencia” eliminando seguridad

Establecer sync=disabled no es tuning. Es una decisión de mentir a las aplicaciones sobre durabilidad. A veces la gente lo hace bajo presión.
A veces aprenden qué significa “consistente ante crash” por las malas.

Si necesitas optimizar cargas sync, usa un SLOG real y considera logbias=latency para datasets donde la latencia sync importe.
Usa logbias=throughput solo cuando explícitamente quieras que ZFS favorezca escrituras al pool principal sobre el comportamiento del ZIL—y lo hayas probado.

atime: pequeña mejora, bajo riesgo

Desactivar atime (atime=off) reduce escrituras de metadatos para cargas de solo lectura. Rara vez es controversial en entornos modernos.

Tareas prácticas con comandos: qué ejecutar, qué significa, qué decides

Estas son tareas que realmente ejecuto en sistemas reales. Cada una incluye: el comando, un fragmento plausible de salida, qué significa y qué decisión tomar.
Úsalas como bloques para tus propios runbooks.

Task 1: Confirmar la topología del pool (¿tienes realmente lo que crees tener?)

cr0x@server:~$ sudo 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
            ata-ST12000NM0008-1A-0001     ONLINE       0     0     0
            ata-ST12000NM0008-1A-0002     ONLINE       0     0     0
            ata-ST12000NM0008-1A-0003     ONLINE       0     0     0
            ata-ST12000NM0008-1A-0004     ONLINE       0     0     0
            ata-ST12000NM0008-1A-0005     ONLINE       0     0     0
            ata-ST12000NM0008-1A-0006     ONLINE       0     0     0
          special
            mirror-1                      ONLINE       0     0     0
              nvme-SAMSUNG_MZ1LB960HAJQ-0001  ONLINE   0     0     0
              nvme-SAMSUNG_MZ1LB960HAJQ-0002  ONLINE   0     0     0
        logs
          mirror-2                        ONLINE       0     0     0
            nvme-INTEL_SSDPED1D280GA-0001  ONLINE       0     0     0
            nvme-INTEL_SSDPED1D280GA-0002  ONLINE       0     0     0
        cache
          nvme-SAMSUNG_MZ1LB960HAJQ-0003   ONLINE       0     0     0

errors: No known data errors

Qué significa: Tienes RAIDZ2 de HDD para datos, un special vdev en espejo, un SLOG en espejo y un dispositivo L2ARC.

Decisión: Si special o logs son dispositivos únicos, corrígelo antes de llamar al sistema “apto para producción”.

Task 2: Revisar ashift (alineación) y tamaños de sector

cr0x@server:~$ sudo zdb -C tank | grep -E "ashift|path" -n | head
34:            ashift: 12
102:            path: '/dev/disk/by-id/ata-ST12000NM0008-1A-0001'

Qué significa: ashift: 12 = sectores de 4K. Bueno para HDDs/SSDs modernos. Si ves 9 (512B) en medios de 4K, el rendimiento puede quedar dañadamente bajo.

Decisión: Ashift incorrecto significa reconstruir/recrear. No negocies con la física.

Task 3: Ver cuánto hay en special vdev (chequeo de riesgo de capacidad)

cr0x@server:~$ sudo zpool list -v tank
NAME        SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank       65.4T  40.1T  25.3T         -    18%    61%  1.00x  ONLINE  -
  raidz2   65.4T  39.4T  26.0T         -    18%    60%      -  ONLINE
  special   1.7T   0.7T   1.0T         -    12%    41%      -  ONLINE
  logs       279G   4.2G   275G        -     1%     1%      -  ONLINE
  cache      894G   812G    82G        -    22%    90%      -  ONLINE

Qué significa: El special vdev está al 41%—bien. L2ARC está al 90% “usado”, lo cual es normal; se llena por diseño.

Decisión: Si el special vdev se acerca al 70–80% con special_small_blocks activado, planifica ampliación antes de que sea tu causa de outage.

Task 4: Confirmar propiedades del dataset (¿te saboteas sin querer?)

cr0x@server:~$ sudo zfs get -o name,property,value -s local,received compression,atime,recordsize,sync,logbias,special_small_blocks tank/data
NAME       PROPERTY              VALUE
tank/data  compression           lz4
tank/data  atime                 off
tank/data  recordsize            128K
tank/data  sync                  standard
tank/data  logbias               latency
tank/data  special_small_blocks  16K

Qué significa: Valores sensatos para muchas cargas mixtas. Bloques pequeños <=16K van al special vdev.

Decisión: Si la resistencia del special vdev es una preocupación, sube o desactiva special_small_blocks. Si la latencia sync es un problema, mantén logbias=latency e invierte en calidad de SLOG.

Task 5: Determinar si tu carga es sync-heavy (test de relevancia SLOG)

cr0x@server:~$ sudo zpool iostat -v tank 1 5
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        40.1T  25.3T    220   1800  38.2M  145M
  raidz2                    39.4T  26.0T    120    240  34.1M  120M
  special                    0.7T   1.0T     90   1550   4.0M  25.0M
  mirror (logs)              4.2G   275G      0   1600      0  22.0M
  cache                         -      -      -      -      -      -
--------------------------  -----  -----  -----  -----  -----  -----

Qué significa: Las escrituras están aterrizando fuertemente en logs y special. Eso suele indicar tráfico sync y actividad de metadatos/bloques pequeños.

Decisión: Si los logs muestran cero mientras tienes un “problema de latencia de base de datos”, puede que no estés atado a sync; persigue otra cosa (misses de ARC, colas en HDD, CPU).

Task 6: Revisar comportamiento del ARC (¿la RAM está haciendo su trabajo?)

cr0x@server:~$ sudo arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:01:10   420    35      8     9    2    26    6     0    0   62G   64G
12:01:11   410    40     10    12    3    28    7     0    0   62G   64G
12:01:12   395    33      8     8    2    25    6     0    0   62G   64G

Qué significa: Tasa de miss ARC ~8–10% es decente. Si miss% está constantemente alto, los HDDs serán golpeados y L2ARC podría ayudar—tras asegurar RAM adecuada.

Decisión: Si arcsz está fijado en c y miss% es alto, considera más RAM o reducir presión de memoria en otros procesos.

Task 7: Validar efectividad de L2ARC (¿realmente sirve lecturas?)

cr0x@server:~$ sudo arcstat -f time,read,miss,l2hits,l2miss,l2read 1 3
    time  read  miss  l2hits  l2miss  l2read
12:02:21   500    70     120      40     160
12:02:22   480    65     110      35     145
12:02:23   510    68     130      38     168

Qué significa: L2ARC está recibiendo hits. Si l2hits está cerca de cero, tu L2ARC no ayuda (o no se ha calentado, o tu carga no tiene reutilización).

Decisión: Si L2ARC no ayuda, retíralo o repurposa el dispositivo; no mantengas complejidad como accesorio decorativo.

Task 8: Inspeccionar presión de IO en special vdev (saturación del nivel de metadatos)

cr0x@server:~$ sudo iostat -x 1 3 /dev/nvme0n1 /dev/nvme1n1
Linux 6.8.0 (server)  12/26/2025  _x86_64_  (32 CPU)

Device            r/s     w/s   rMB/s   wMB/s  avgrq-sz avgqu-sz   await  %util
nvme0n1          820.0   540.0    42.0    31.5     94.0     2.10    1.8   92.0
nvme1n1          815.0   530.0    41.5    30.9     93.5     2.05    1.9   91.0

Qué significa: Los SSDs del special vdev están cerca de saturación (%util ~90+) pero aún con baja latencia (await ~2ms). Eso está bien… hasta que no lo está.

Decisión: Si await sube (por ejemplo 10–20ms) bajo carga, el special vdev es tu cuello de botella. Considera SSDs más rápidos, más vías, o elevar special_small_blocks.

Task 9: Confirmar ruta de latencia de escrituras sync (salud y presión del dispositivo SLOG)

cr0x@server:~$ sudo iostat -x 1 3 /dev/nvme2n1 /dev/nvme3n1
Device            r/s     w/s   rMB/s   wMB/s  avgqu-sz   await  %util
nvme2n1            0.0  2200.0     0.0    28.0      0.60    0.4   55.0
nvme3n1            0.0  2180.0     0.0    27.8      0.58    0.4   54.0

Qué significa: Las escrituras al SLOG son rápidas y sostenidas. Si await salta, el rendimiento de escrituras sync está limitado por la latencia del SLOG.

Decisión: Si la latencia del SLOG es mala, reemplaza por NVMe empresarial con PLP. No “tunes alrededor” de medios malos.

Task 10: Identificar si los vdevs HDD están haciendo cola (dolor clásico RAIDZ para IOs pequeños)

cr0x@server:~$ sudo zpool iostat -v tank 1 3
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        40.1T  25.3T    900    600   110M   80M
  raidz2                    39.4T  26.0T    860    560   106M   76M
    ata-ST12000...0001         -      -    140     95  18.0M  12.7M
    ata-ST12000...0002         -      -    145     92  18.2M  12.4M
    ata-ST12000...0003         -      -    142     93  18.1M  12.5M
    ata-ST12000...0004         -      -    143     96  18.0M  12.8M
    ata-ST12000...0005         -      -    145     92  18.3M  12.4M
    ata-ST12000...0006         -      -    145     92  18.2M  12.4M
--------------------------  -----  -----  -----  -----  -----  -----

Qué significa: Muchas operaciones por disco sugieren IO aleatorio. RAIDZ2 puede ser adecuado, pero las escrituras pequeñas aleatorias son caras (cálculo de paridad + read-modify-write).

Decisión: Si este es un pool de VM o DB y la latencia importa, los mirrors suelen superar a RAIDZ en IOPS. O mueve bloques pequeños/metadatos al special vdev con criterio.

Task 11: Rastrear comportamiento de TXG y presión de commit (pistas de picos de latencia)

cr0x@server:~$ sudo cat /proc/spl/kstat/zfs/txgs
dmu_tx_assign  0
txg_sync       0
txg_quiesce    0
txg_birth      0
txg_state      0
txg_timeout    5
txg_synctime_ms  312

Qué significa: TXG timeout es 5s, synctime ~312ms ahora mismo. Si synctime se dispara a segundos, el pool tiene problemas para vaciar.

Decisión: Si synctime sube correlacionado con latencia de aplicación, enfócate en throughput de escritura y latencia de dispositivo—a menudo saturación de vdev HDD o presión en special vdev.

Task 12: Verificar que autotrim esté configurado apropiadamente (longevidad y rendimiento SSD)

cr0x@server:~$ sudo zpool get autotrim tank
NAME  PROPERTY  VALUE     SOURCE
tank  autotrim  on        local

Qué significa: TRIM está activado, ayudando a los SSDs a mantener rendimiento y reducir amplificación de escritura.

Decisión: Para special vdevs, logs y L2ARC basados en SSD, autotrim=on suele ser la decisión correcta.

Task 13: Revisar contadores de error de dispositivos y degradación lenta

cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 05:12:33 with 0 errors on Sun Dec 21 04:00:31 2025
config:

        NAME                              STATE     READ WRITE CKSUM
        tank                              ONLINE       0     0     0
          raidz2-0                        ONLINE       0     0     0
            ata-ST12000NM0008-1A-0003     ONLINE       0     0     0
            ata-ST12000NM0008-1A-0004     ONLINE       0     0     0
          special
            mirror-1                      ONLINE       0     0     0
              nvme-SAMSUNG_MZ1LB960HAJQ-0001  ONLINE   0     0     0
              nvme-SAMSUNG_MZ1LB960HAJQ-0002  ONLINE   0     0     0

errors: No known data errors

Qué significa: Los scrubs están limpios; no hay conteos de error en aumento.

Decisión: Si READ/WRITE/CKSUM empiezan a incrementarse en special vdev o dispositivos SLOG, trátalo como urgente. “Sigue funcionando” no es una estrategia.

Task 14: Confirmar que la asignación special se usa realmente (evitar diseños placebo)

cr0x@server:~$ sudo zdb -bbbs tank | grep -E "Special|special" | head
    Special allocation class: 734.22G used, 1.01T available

Qué significa: Se están asignando datos en la clase special. Si es cercano a cero en un sistema pesado en metadatos, tu diseño no se está ejercitando.

Decisión: Valida special_small_blocks y confirma que creaste el special vdev correctamente; no asumas que “SSD presente” significa “SSD usado”.

Guía rápida de diagnóstico: qué revisar primero/segundo/tercero

Cuando un pool ZFS híbrido está “lento”, no necesitas un día de debate filosófico. Necesitas un bucle estrecho: identifica qué capa está saturada, y luego
mapea eso a una clase de dispositivo y tipo de IO.

Primero: ¿es un problema de caché/RAM?

  • Revisa tamaño ARC y miss% (arcstat).
  • Si miss% es alto y ARC está limitado: probablemente estás limitado por disco porque la RAM no mantiene el working set.
  • Decisión: añade RAM, reduce presión de memoria o acepta que los HDDs verán lecturas (y luego considera L2ARC).

Segundo: ¿es un problema de latencia de escrituras sync?

  • Revisa si los logs están activos (zpool iostat -v muestra escrituras en logs).
  • Revisa latencia del dispositivo SLOG (iostat -x en dispositivos SLOG).
  • Decisión: si es sync-heavy y los awaits del SLOG son altos, mejora/reemplaza el SLOG; no toques sync=disabled a menos que disfrutes de post-mortems.

Tercero: ¿es presión de metadatos/bloques pequeños en special vdev?

  • Revisa utilización e IO del special vdev (zpool list -v, iostat -x).
  • Comprueba si special está casi lleno o muestra latencia creciente.
  • Decisión: expande special vdev (añade otro special vdev espejado), usa dispositivos más rápidos o ajusta special_small_blocks.

Cuarto: ¿es saturación clásica de vdev HDD?

  • Revisa ops por vdev y por disco (zpool iostat -v).
  • Ops altas y bajo ancho de banda en HDDs = dolor por IO aleatorio; RAIDZ lo sentirá.
  • Decisión: cambia el layout de la carga (pool separado para VMs/DBs), mueve datasets calientes a un pool SSD, o acepta mirrors para tiers orientados a IOPS.

Quinto: revisa las partes no ZFS (porque la realidad)

  • Latencia de red (para NFS/SMB), robo de CPU (steal), saturación de IRQ, profundidad de cola del HBA y límites de virtualización pueden disfrazarse de “almacenamiento”.
  • Decisión: verifica con métricas del sistema; no culpes a ZFS por un cuello de botella de 1GbE.

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

1) “Añadimos NVMe cache y nada cambió.”

Síntomas: Misma latencia de lectura, mismas ops en HDD, tasa de aciertos L2ARC cerca de cero.

Causa raíz: La carga tiene baja reutilización (streaming), o el ARC es demasiado pequeño y la sobrecarga de encabezados L2ARC lo empeoró, o L2ARC nunca se calentó.

Solución: Mide con arcstat. Añade RAM primero. Si el patrón es streaming, retira L2ARC y céntrate en layout de vdev y throughput secuencial.

2) “El special vdev se está llenando y estamos asustados.”

Síntomas: El uso de la clase special crece más rápido de lo previsto; el desgaste del SSD sube; picos de latencia bajo churn de metadatos.

Causa raíz: special_small_blocks configurado demasiado alto, bloques pequeños dominan, los snapshots amplifican metadatos, o el special vdev está subdimensionado.

Solución: Baja special_small_blocks (solo para nuevas asignaciones), añade otro special vdev espejado, y mantén special por debajo del ~70% de uso.

3) “Las escrituras sync son lentas incluso con SLOG.”

Síntomas: Alta latencia en commits de base de datos; el dispositivo SLOG muestra await alto; la aplicación se bloquea durante ráfagas.

Causa raíz: El SLOG carece de PLP, tiene mala latencia sostenida, está compartido con otras cargas, o no se está usando realmente.

Solución: Verifica actividad de logs con zpool iostat -v. Usa NVMe empresariales dedicados con PLP. Espejalos.

4) “Pusimos sync=disabled y mejoró. ¿Por qué no dejarlo?”

Síntomas: El rendimiento mejora inmediatamente; la dirección está contenta; SRE está actualizando su currículum en silencio.

Causa raíz: Cambiaste durabilidad por velocidad. Las aplicaciones que esperan durabilidad de fsync ahora están siendo engañadas.

Solución: Vuelve a sync=standard. Despliega un SLOG apropiado y ajusta propiedades de datasets para que coincidan con la carga.

5) “El pool está sano pero hay picos de latencia cada pocos segundos.”

Síntomas: Paradas periódicas; las gráficas muestran latencia de escritura en sierra; quejas de usuarios en picos.

Causa raíz: Presión de sincronización TXG: los HDDs no pueden vaciar suficientemente rápido; special vdev saturado; fragmentación y pool cercano a lleno lo agravan.

Solución: Revisa TXG synctime, utilización de vdev, y llenado del pool. Añade vdevs, reduce amplificación de escritura (la compresión ayuda) y mantén el pool por debajo del ~80% en entornos con muchas escrituras.

6) “Usamos un special vdev único porque es ‘solo metadatos’.”

Síntomas: Falla repentina del pool o bloques de metadatos perdidos tras la muerte del SSD; las opciones de recuperación son pobres.

Causa raíz: El special vdev no es opcional; está en la ruta de datos.

Solución: Siempre espeja special vdevs. Si ya desplegaste un special de disco único, planifica una migración: backup, reconstrucción correcta y restauración. No hay retrofit limpio que arregle el riesgo sin mover datos.

Tres microhistorias corporativas (anonimizadas, plausibles, técnicamente exactas)

Incidente por una suposición equivocada: “Los metadatos no pueden tumbar el pool, ¿no?”

Una compañía SaaS mediana ejecutaba una canalización con muchos archivos: artefactos de build, capas de contenedor y montones de JSON pequeños. Su equipo de
almacenamiento hizo algo “ingenioso”: RAIDZ2 de HDD para lo voluminoso, más un único “SSD de metadatos” porque la reunión de presupuesto fue un deporte de contacto.

Funcionó de maravilla durante meses. Listados de directorio ágiles. Builds sin timeouts. La gente empezó a usar el mismo pool para más cosas porque el éxito atrae scope.

Entonces el SSD murió. No dramáticamente—sin humo, simplemente desapareció del bus PCIe. El pool no se “degradó” educadamente. Entró en pánico. Bloques de metadatos
que ZFS esperaba… no estaban. Los servicios se reiniciaron con fallos que parecían corrupción aleatoria del sistema de archivos.

El instinto inicial fue tratarlo como fallo de caché: reiniciar, rescan, reinsertar. Eso desperdició horas. La solución real fue dolorosa y honesta:
restaurar desde backups a un pool correctamente diseñado con special vdevs espejados. Recuperaron el sistema, y además una nueva política:
“si está en la topología del pool, es redundante”.

La lección no fue “ZFS es frágil”. La lección fue que ZFS es literal. Si le dices que los metadatos viven en ese dispositivo, ZFS te creerá con la devoción de un golden retriever.

Optimización que salió mal: “Activemos special_small_blocks en todas partes”

Una gran plataforma de analytics tenía cargas mixtas: archivos de data lake (grandes), archivos temporales de ETL (medios) y un enjambre de logs e índices pequeños.
Añadieron special vdevs SSD espejados y vieron mejoras inmediatas. Bien hasta aquí.

Alguien propuso entonces poner special_small_blocks=128K en la mayoría de datasets. La razón sonaba limpia: “Si la mayoría de bloques va a SSD,
los HDDs quedan solo para capacidad. Los SSDs son rápidos. Todos ganan.” El cambio pasó porque mostró una gráfica de latencia bonita en la primera hora.

Semanas después, los SSDs estaban más llenos de lo esperado y la latencia de escritura empezó a tambalearse. No fue un fallo constante—peor: stalls intermitentes
que ocurrían en ventanas de lotes. Los scrubs seguían limpios. SMART parecía “bien”. El on-call empezó a desarrollar opiniones.

La causa fue predecible en retrospectiva: el special vdev se convirtió discretamente en el tier de datos primario para la mayoría de datasets activos. Absorbió
amplificación de escritura, churn de snapshots y lecturas aleatorias. Al acercarse a alta utilización, la recolección de basura interna de los SSDs y el comportamiento
de asignación de ZFS se combinaron en picos de latencia. Los HDDs fueron inocentes testigos.

La solución fue aburrida y efectiva: redujeron special_small_blocks a un valor conservador para datasets generales, reservaron valores agresivos solo
para los árboles con muchos archivos pequeños, y añadieron capacidad a la clase special. El rendimiento se estabilizó. Las gráficas dejaron de ser emocionantes.

Práctica aburrida pero correcta que salvó el día: “Mide, haz scrubs y rehearsa”

Un equipo de servicios financieros ejecutaba NFS respaldado por ZFS para aplicaciones internas. Nadie fuera del equipo quería saber detalles del almacenamiento,
que es el mejor estado posible: invisible.

Tenían una rutina casi pintoresca: ventanas mensuales de scrub, simulacros trimestrales de restauración y un dashboard que rastreaba hit rate del ARC, uso del special vdev,
latencia del SLOG y fragmentación del pool. También una política que decía que la utilización del special vdev no debía superar un umbral conservador.

Un trimestre, un despliegue de nueva aplicación aumentó el churn de archivos pequeños. El dashboard lo detectó temprano: la asignación al special vdev subió y la latencia
de escritura de SSD aumentó durante los lotes. Nada estaba “roto” todavía; simplemente la tendencia era mala.

Como lo vieron a tiempo, la solución fue quirúrgica: añadir otro par de special vdevs espejados en una ventana de mantenimiento planificada, ajustar
special_small_blocks en un par de datasets y mantener el pool por debajo del límite de utilización acordado.

Sin outage. Sin bridge de incidente. Sin fin de semana. El equipo no recibió elogios, que en operaciones es señal de haberlo hecho bien.

Listas de verificación / plan paso a paso

Paso a paso: construir el pool híbrido (mente de producción)

  1. Elige el layout de vdev primero. Si necesitas IOPS y latencia consistente para VMs/DBs, prefiere mirrors. Si necesitas eficiencia de capacidad y IO mayoritariamente secuencial, RAIDZ2 está bien.
  2. Elige SSDs para special vdev. Espejalos. Prefiere resistencia y latencia consistente sobre IOPS pico de portada.
  3. Elige NVMe para SLOG. Usa NVMe empresariales con PLP. Espejalos. Mantenlos dedicados.
  4. Decide L2ARC al final. Solo después de medir misses de ARC y confirmar localidad de lectura.
  5. Crea el pool con ashift correcto. Usa nombres persistentes de dispositivo en /dev/disk/by-id. No uses /dev/sdX en producción.
  6. Configura propiedades base. compression=lz4, atime=off, recordsize sensato por dataset.
  7. Activa autotrim. Especialmente cuando hay SSDs en la topología.
  8. Configura monitorización. Rastrea miss% de ARC, latencia SLOG, uso de special vdev, resultados de scrub y errores de dispositivo.
  9. Ensaya fallos. Arranca un dispositivo en staging. Confirma alertas. Confirma comportamiento de resilver. Confirma la memoria muscular del equipo.

Checklist operativo: mantenerlo sano

  • Mantén la utilización del pool por debajo del ~80% para cargas con muchas escrituras.
  • Scrubea en horario y revisa resultados, no solo “se ejecutó”.
  • Vigila desgaste y uso del special vdev; trátalo como un tier que puede llenarse.
  • No compartas dispositivos SLOG con cargas aleatorias; la latencia es el producto.
  • Mantén firmware y drivers estables; las pilas de almacenamiento no disfrutan actualizaciones sorpresa.

Checklist de migración: convertir un pool HDD existente a híbrido

  • Confirma que puedes añadir un special vdev sin violar la política de redundancia (sí puedes, pero debe ser redundante).
  • Estima footprint de metadatos/bloques pequeños; planifica capacidad special con holgura.
  • Añade special vdev espejado; luego establece special_small_blocks solo donde sea necesario.
  • Añade SLOG espejado si la latencia sync es relevante.
  • Valida con mediciones antes/después (misses ARC, iostat, latencia de app).

Preguntas frecuentes

1) ¿Necesito SLOG y L2ARC?

No. SLOG ayuda a escrituras sync. L2ARC ayuda a lecturas cuando el ARC no es suficiente y la carga tiene reutilización. Muchos sistemas no necesitan ninguno si la RAM y el layout de vdev son correctos.

2) ¿Puedo usar un NVMe para SLOG y L2ARC?

Puedes, pero normalmente no deberías. SLOG quiere latencia baja y predecible; L2ARC quiere ancho de banda y puede generar escrituras en segundo plano. Mezclarlos puede crear jitter justo donde menos lo quieres.

3) ¿Un special vdev es “solo un caché”?

No. Es asignación, no caché. Los datos colocados allí son parte del pool. Si pierdes un special vdev no redundante, puedes perder el pool.

4) ¿Qué valor debería poner en special_small_blocks?

Empieza conservador: 0 (solo metadatos) o 16K. Incrementa solo para datasets probados como dominados por pequeños bloques, y solo si la capacidad y endurance del special vdev están dimensionadas para ello.

5) ¿SLOG mejora el throughput?

Mejora la latencia de escrituras sync, lo que puede mejorar el throughput a nivel de aplicación cuando la app está limitada por la latencia de commit. No convierte HDDs en NVMe para escrituras masivas.

6) ¿Debería poner sync=always por seguridad?

Solo si aceptas el coste de rendimiento y tienes un buen SLOG. Muchas aplicaciones ya ejecutan fsync donde hace falta. Forzar todo sync puede ser dolor autoinfligido.

7) ¿Mirrors vs RAIDZ para los vdevs HDD en un diseño híbrido?

Los mirrors son la jugada por latencia/IOPS; RAIDZ es la jugada por eficiencia de capacidad. Los special vdevs ayudan a pools RAIDZ con metadatos/lecturas pequeñas, pero no eliminan el coste de paridad para escrituras aleatorias.

8) ¿Cómo sé si L2ARC me está perjudicando?

Observa la presión sobre ARC y miss%. Si añadir L2ARC reduce ARC y no produce hits L2 significativos, añadiste complejidad y robaste RAM para nada. Mide con arcstat.

9) ¿Puedo añadir un special vdev después de crear el pool?

Sí. Pero los metadatos existentes no migrarán automáticamente. Verás beneficios a medida que ocurran nuevas asignaciones, y puedes provocar reescrituras mediante replicación o movimientos a nivel de fichero si hace falta.

10) ¿Es dedup una buena idea en este blueprint híbrido?

Usualmente no, salvo que tengas una carga muy específica amigable con dedup y presupuesto de RAM/CPU acorde. La compresión es la ganancia por defecto y más segura.

Siguientes pasos prácticos

Si quieres que el blueprint híbrido funcione en producción, no empieces comprando “caché”. Empieza por escribir los hechos de tu carga: sync vs async,
tamaño medio de IO, localidad de lectura, intensidad de metadatos y crecimiento. Luego diseña la topología del pool para que el fallo no sea una novela de suspenso.

  1. Ejecuta las tareas de topología y ARC arriba en tu sistema actual. Identifica si estás limitado por misses de lectura, latencia sync o metadatos.
  2. Si metadatos/archivos pequeños dañan rendimiento: añade un special vdev espejado y manténlo cómodamente por debajo del 70% de uso.
  3. Si las escrituras sync duelen: añade un SLOG NVMe PLP espejado y comprueba que realmente se usa.
  4. Si las lecturas duelen después de saneada la RAM: considera L2ARC y valida con tasas de acierto y latencia real de la app.
  5. Fija prácticas aburridas: scrubs, monitorización, simulacros de restauración y una política escrita para utilización del pool y redundancia por clase de dispositivo.

ZFS híbrido no es una bolsa de trucos. Es un plan de enrutamiento de IO con consecuencias. Hazlo bien y los HDD vuelven a ser lo que mejor saben hacer: capacidad barata y aburrida.
Hazlo mal y aprenderás cuál de tus SSDs tiene la personalidad más dramática.

← Anterior
MySQL vs Redis: Redis no es tu base de datos — pero puede reducir la carga de MySQL en un 80%
Siguiente →
MySQL vs MariaDB: Interbloqueos — ¿Cuál es más fácil de depurar cuando el sitio arde?

Deja un comentario