Análisis de registros ZFS: detectar lentitudes antes de que sean cortes de servicio

¿Te fue útil?

ZFS rara vez “cae” en una conflagración dramática. Se vuelve más lento. Silenciosamente. El gráfico se mueve. La latencia se estira.
Las aplicaciones empiezan a agotar tiempos. Alguien abre un ticket sobre “lentitud intermitente”. Y entonces —porque el universo odia la humildad— tu
siguiente despliegue aterriza encima del problema y se lleva la culpa por todo.

El truco es detectar la degradación del rendimiento de ZFS mientras sigue siendo una ventana de mantenimiento, no un postmortem. Esta es una guía de campo para
leer los registros y la verdad adyacente (mensajes del kernel, errores de dispositivos, flujos de eventos de ZFS) para detectar lentitudes pronto y decidir
qué hacer después—rápido, con precisión y sin rituales de culto al cargo.

La mentalidad: los registros son una línea de tiempo, no una sensación

Los “registros” de ZFS son plurales. Está el flujo de eventos de ZFS, el buffer de anillo del kernel, el journal de systemd, los registros SMART/dispositivo,
y la propia idea de ZFS sobre la salud del pool. El objetivo no es coleccionar más texto. El objetivo es alinear las líneas de tiempo:
qué se volvió más lento, cuándo y qué más cambió.

Esta es la postura operativa que te mantiene fuera de problemas:

  • Prefiere latencia sobre throughput. Los usuarios sienten la latencia del percentil 99. Los paneles que sólo muestran MB/s te mentirán.
  • Asume que ZFS es honesto sobre la integridad de datos y conservador respecto al rendimiento. Cuando se ralentiza, suele estar protegiéndote de algo peor.
  • Sospecha de narrativas “empezó después de X”. Los problemas de ZFS a menudo incuban durante semanas: un disco débil, un recordsize mal dimensionado, una ruta de escrituras síncronas que olvidaste que existía.
  • Correlaciona a nivel de dispositivo. La mayoría de “problemas de rendimiento de ZFS” son latencia del dispositivo, encolamiento o una ruta de escritura síncrona haciendo exactamente lo que le pediste.

Una línea de registro es una pista, no un veredicto. Aún tienes que reconciliarla con la realidad: zpool iostat, arcstat, iostat,
y lo que tus aplicaciones realmente están haciendo.

Hechos interesantes y contexto histórico (para que dejes de adivinar)

  1. ZFS nació en la era de Solaris con un modelo de integridad de datos end-to-end—checksums por todas partes—porque la “corrupción silenciosa” ya existía, aunque no fuera un tema popular.
  2. El intent log (ZIL) no es una caché de escritura. Es un mecanismo para reproducir la semántica síncrona después de un crash. La mayoría de las escrituras nunca viven en “el log” a largo plazo.
  3. SLOG es un dispositivo, no una característica mágica. Añadir un dispositivo de log separado (SLOG) sólo ayuda a las escrituras síncronas y puede perjudicar si es lento o está mal configurado.
  4. Los scrubs fueron diseñados como auditoría proactiva, no como una herramienta de “reparar cuando está roto”. Son cómo ZFS demuestra que tus datos siguen siendo tuyos.
  5. El comportamiento de resilver evolucionó. Los resilvers modernos de OpenZFS pueden ser secuenciales y más inteligentes sobre qué copiar, pero aún pagas en contención de I/O.
  6. La sintonía de ARC/L2ARC tiene una larga historia de malos consejos. Muchas “guías de rendimiento” de hace una década optimizaban para cargas y ratios RAM-disco distintos.
  7. ashift es para siempre. Una suposición equivocada del tamaño de sector al crear el pool puede inmovilizarte en amplificación de escritura—silenciosamente costosa, ruidosamente dolorosa.
  8. La compresión se convirtió en estándar en operaciones ZFS porque la CPU se abarató y el I/O no. Pero la ganancia depende de la forma de tus datos, no de tus esperanzas.

Qué significa realmente “ZFS lento”: el mapa de cuellos de botella

“ZFS está lento” es como decir “la ciudad está congestionada”. ¿Qué calle? ¿Qué hora? ¿Qué carril cerrado?
En la práctica, las lentitudes de ZFS se agrupan en unas pocas categorías. Tus registros normalmente apuntarán a una:

1) Latencia de dispositivo y recuperación de errores

Un disco marginal puede bloquear un vdev. En RAIDZ y mirrors, el hijo más lento a menudo se convierte en el coche marcando el ritmo.
Los logs del kernel de Linux pueden mostrar reinicios de enlace, timeouts de comandos o eventos de “cola congelada”. ZFS puede mostrar errores de lectura/escritura/checksum.
Incluso si el disco “se recupera”, los costes de reintento se pagan en tiempo real por tu aplicación.

2) Ruta de escritura síncrona: dolor ZIL/SLOG

Si tu carga hace escrituras síncronas (bases de datos, NFS, cierto almacenamiento de VMs, cualquier cosa que llame a fsync mucho),
entonces la latencia del ZIL importa. Con un SLOG, tu latencia síncrona suele ser la latencia del SLOG.
Sin SLOG, las escrituras síncronas golpean el pool y heredan la latencia del pool. Los registros no dirán “fsync es tu problema” con esas palabras,
pero el patrón aparece: aumento de await, ráfagas alineadas con txg sync, y muchas quejas durante periodos de commits intensos.

3) Picos en el tiempo de sync de transaction group (txg)

ZFS agrupa cambios en transaction groups. Cuando un txg se confirma (“sync”), el sistema puede ver tormentas cortas de I/O de escritura.
Si el tiempo de sync crece, todo lo que depende de esos commits se vuelve más lento. Esto puede aparecer como pausas periódicas, NFS “no responde”,
o picos de latencia en la aplicación cada pocos segundos.

4) Problemas de metadatos y fragmentación

La fragmentación no es una falta moral; es física más tiempo. Ciertas cargas (imágenes de VM, bases de datos, escrituras aleatorias pequeñas)
pueden convertir el pool en un festival caro de seeks. Los logs de ZFS no imprimirán “estás fragmentado”, pero tus patrones de iostat sí lo harán,
y los tiempos de scrub/resilver empeorarán.

5) Presión de memoria: thrash de ARC

Cuando la tasa de aciertos del ARC cae, las lecturas van al disco. Eso no es automáticamente malo—a veces el conjunto de trabajo simplemente es mayor que la RAM.
Pero un colapso súbito del ARC puede ocurrir tras un despliegue hambriento de memoria, un cambio en la densidad de contenedores o una mala configuración de L2ARC.
La señal suele ser: más lecturas de disco, mayor latencia y un kernel que se ve… ocupado.

Una idea parafraseada a menudo atribuida a John Allspaw encaja aquí: La fiabilidad viene de aprender y adaptarse, no de pretender que podemos predecirlo todo. (idea parafraseada).
ZFS es adaptable. Tu trabajo es aprender lo que te está diciendo antes de que empiece a gritar.

Guía rápida de diagnóstico (primeras/segundas/terceras comprobaciones)

Si estás de guardia, no tienes tiempo para danza interpretativa. Necesitas una secuencia que reduzca el espacio de búsqueda.
Esta guía asume Linux + OpenZFS, pero la lógica se aplica más ampliamente.

Primero: ¿está el pool sano ahora mismo?

  • Ejecuta zpool status -x. Si dice cualquier cosa distinta a “all pools are healthy”, detente e investiga eso primero.
  • Revisa zpool events -v en busca de fallos de dispositivo recientes, reinicios de enlace o errores de checksum.
  • Busca scrubs/resilvers en ejecución. Un pool “sano” puede seguir lento si se está reconstruyendo.

Segundo: ¿es un problema de dispositivo o de carga/Sync?

  • Ejecuta zpool iostat -v 1 y observa la distribución de latencia por vdev. ¿Un disco lento? ¿Un mirror lento? Ese es tu sospechoso.
  • Ejecuta iostat -x 1 y revisa await, svctm (si está presente) y %util. Await alto + util alta = saturación de dispositivo/cola.
  • Comprueba si la latencia se correlaciona con ráfagas de escrituras síncronas: busca escrituras altas con throughput relativamente bajo pero await alto.

Tercero: confirma el modo de fallo con logs y contadores

  • Journal/kernel: journalctl -k para timeouts, reinicios, errores NCQ, errores de transporte, comandos abortados.
  • SMART: smartctl para sectores reasignados, sectores pendientes, Offline_Uncorrectable, CRC errors (a menudo cable/backplane).
  • Estadísticas de ZFS: comportamiento ARC (arcstat si está disponible), mensajes de txg sync (según tu build), e historial de eventos.

Regla de una frase: si puedes nombrar el componente más lento, normalmente puedes arreglar el outage.
Si no puedes, sigues adivinando—sigue estrechando.

Tareas prácticas: comandos, salidas y decisiones (12+)

Estas son las tareas que ejecuto en producción cuando ZFS se ralentiza. Cada una incluye qué significa la salida y qué decisión tomar después.
Copiar/pegar está permitido. Entrar en pánico no lo está.

Tarea 1: Comprobación rápida de salud del pool

cr0x@server:~$ sudo zpool status -x
all pools are healthy

Significado: No hay fallos conocidos, no hay vdevs degradados, ni errores activos. Esto no garantiza rendimiento, pero elimina una gran clase de emergencias.
Decisión: Pasa al diagnóstico de latencia (zpool iostat, iostat) en lugar de operaciones de reparación.

Tarea 2: Estado completo con contadores de error y trabajo en curso

cr0x@server:~$ sudo zpool status
  pool: tank
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
  scan: scrub repaired 0B in 02:14:33 with 0 errors on Mon Dec 23 03:12:18 2025
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-SAMSUNG_SSD_860-1   ONLINE       0     0     0
            ata-SAMSUNG_SSD_860-2   ONLINE       0     0     3

errors: No known data errors

Significado: El pool está online, pero un dispositivo tiene errores de checksum. ZFS los corrigió usando redundancia, pero ahora tienes un olor a fiabilidad y rendimiento.
Decisión: Investiga esa ruta de dispositivo (SMART, cableado, backplane, HBA). No hagas “zpool clear” como terapia; limpia sólo después de entender por qué ocurrieron los errores.

Tarea 3: Vigilar latencia por vdev en vivo

cr0x@server:~$ sudo zpool iostat -v 1
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        4.12T  3.15T    210    980  23.1M  61.4M
  mirror-0                  2.06T  1.57T    105    510  11.6M  30.7M
    ata-SAMSUNG_SSD_860-1      -      -     60    250  6.7M  15.2M
    ata-SAMSUNG_SSD_860-2      -      -     45    260  4.9M  15.5M
--------------------------  -----  -----  -----  -----  -----  -----

Significado: Una carga balanceada en el mirror se ve aproximadamente simétrica a lo largo del tiempo. Si un miembro muestra muchas menos ops pero mayor latencia (no mostrado en esta vista básica),
o si las ops de un vdev colapsan mientras la demanda del pool permanece, eso es una pista de que el dispositivo está bloqueándose o reintentando errores.
Decisión: Si el desequilibrio persiste, correlaciona con kernel y SMART; considera offlining/reemplazando el dispositivo sospechoso si los errores coinciden.

Tarea 4: Añadir columnas de latencia (donde se soporte)

cr0x@server:~$ sudo zpool iostat -v -l 1
                              capacity     operations     bandwidth    total_wait     disk_wait
pool                        alloc   free   read  write   read  write   read  write    read  write
--------------------------  -----  -----  -----  -----  -----  -----  ----- -----    ----- -----
tank                        4.12T  3.15T    220   1020  24.0M  63.2M   3ms   28ms     2ms   24ms
  mirror-0                  2.06T  1.57T    110    520  12.0M  31.6M   2ms   30ms     2ms   27ms
    ata-SAMSUNG_SSD_860-1      -      -     55    260  6.1M  15.8M   2ms   8ms      2ms   7ms
    ata-SAMSUNG_SSD_860-2      -      -     55    260  5.9M  15.8M   2ms   90ms     2ms   85ms
--------------------------  -----  -----  -----  -----  -----  -----  ----- -----    ----- -----

Significado: Un disco tiene picos de disk_wait (85–90ms) mientras el otro se mantiene bajo. Ese es tu “coche marcando el ritmo”.
Decisión: Extrae evidencia del kernel + SMART. Si es un cable/ruta HBA, arréglalo. Si es el SSD en sí, programa el reemplazo antes de que “se recupere” en tu siguiente outage.

Tarea 5: Comprobar contención por scrub/resilver

cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
  scan: resilver in progress since Thu Dec 26 08:11:02 2025
        312G scanned at 1.24G/s, 48.2G issued at 192M/s, 7.11T total
        48.2G resilvered, 0.68% done, 10:27:11 to go
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

errors: No known data errors

Significado: Hay un resilver en curso. Tu pool está haciendo lecturas/escrituras adicionales, y la latencia normalmente empeorará.
Decisión: Si esto es un sistema de producción expuesto a usuarios, decide si limitar el resilver/scrub (donde sea posible),
o desplazar temporalmente la carga. También confirma que la falla original está totalmente resuelta—no dejes que un segundo disco falle durante el resilver.

Tarea 6: Leer el flujo de eventos recientes de ZFS

cr0x@server:~$ sudo zpool events -v | tail -n 30
TIME                           CLASS
Dec 26 2025 08:10:58.123456789 ereport.fs.zfs.vdev.io
    pool = tank
    vdev_path = /dev/disk/by-id/ata-SAMSUNG_SSD_860-2
    vdev_guid = 1234567890123456789
    errno = 5
    size = 131072
    offset = 9876543210
    flags = 0x180

Dec 26 2025 08:10:58.223456789 ereport.fs.zfs.vdev.checksum
    pool = tank
    vdev_path = /dev/disk/by-id/ata-SAMSUNG_SSD_860-2
    vdev_guid = 1234567890123456789

Significado: ZFS está registrando errores de I/O y problemas de checksum contra un dispositivo específico.
Decisión: Trata esto como triage de ruta de hardware: SMART, cables, HBA, chasis. Si se repite, reemplaza el dispositivo.
Si se detiene al recolocar un cable, sigue vigilando; los errores CRC intermitentes suelen volver.

Tarea 7: Revisar logs del kernel por reinicios de transporte y timeouts

cr0x@server:~$ sudo journalctl -k --since "2 hours ago" | egrep -i "ata|nvme|scsi|reset|timeout|error" | tail -n 40
Dec 26 09:01:14 server kernel: ata7.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
Dec 26 09:01:14 server kernel: ata7.00: failed command: READ FPDMA QUEUED
Dec 26 09:01:14 server kernel: ata7: hard resetting link
Dec 26 09:01:18 server kernel: ata7: link is slow to respond, please be patient (ready=0)
Dec 26 09:01:20 server kernel: ata7: SATA link up 6.0 Gbps (SStatus 133 SControl 300)
Dec 26 09:01:20 server kernel: ata7.00: configured for UDMA/133

Significado: Eventos de reinicio de enlace. Incluso cuando “se recuperan”, el tiempo de reintento crea picos de latencia y puede bloquear un vdev.
Decisión: Revisa cableado/backplane, alimentación y firmware del HBA. Si es una bahía de disco única, mueve el disco a otro slot para aislar la ruta del chasis.

Tarea 8: Triage SMART (dispositivos SATA/SAS)

cr0x@server:~$ sudo smartctl -a /dev/sdb | egrep -i "Reallocated|Pending|Offline_Uncorrectable|CRC_Error_Count|Power_On_Hours"
  9 Power_On_Hours          0x0032   094   094   000    Old_age   Always       -       23874
197 Current_Pending_Sector  0x0012   100   100   000    Old_age   Always       -       8
198 Offline_Uncorrectable   0x0010   100   100   000    Old_age   Offline      -       2
199 UDMA_CRC_Error_Count    0x003e   200   200   000    Old_age   Always       -       0

Significado: Sectores pendientes y Offline_Uncorrectable son problemas reales de medio. Un CRC count en cero sugiere que esto no es “sólo un cable”.
Decisión: Planifica el reemplazo. Si el pool es redundante, reemplaza proactivamente. Si es disco único (no lo hagas), haz backup primero y luego reemplaza cuanto antes.

Tarea 9: Salud NVMe y registro de errores

cr0x@server:~$ sudo nvme smart-log /dev/nvme0 | egrep -i "critical_warning|media_errors|num_err_log_entries|percentage_used"
critical_warning                    : 0x00
media_errors                        : 12
num_err_log_entries                 : 398
percentage_used                     : 87%

Significado: Errores de medio y un alto porcentaje de uso pueden correlacionar con latencia creciente e inminente fallo.
Decisión: Si este NVMe es un SLOG o un vdev especial, trátalo como urgente—esos roles pueden degradar el rendimiento drásticamente cuando el dispositivo falla.

Tarea 10: Identificar cargas pesadas en sync vía propiedades de dataset

cr0x@server:~$ sudo zfs get -o name,property,value -s local sync,logbias,primarycache,recordsize tank/app tank/vm
NAME      PROPERTY      VALUE
tank/app  sync          standard
tank/app  logbias       latency
tank/app  primarycache  all
tank/app  recordsize    128K
tank/vm   sync          always
tank/vm   logbias       latency
tank/vm   primarycache  metadata
tank/vm   recordsize    16K

Significado: sync=always fuerza semántica síncrona incluso si la app no la pide. Eso puede ser correcto, o puede ser un incidente de rendimiento autoinfligido.
Decisión: Verifica por qué está sync=always. Si es para una base de datos que ya gestiona durabilidad, podrías estar pagando doble. Si es para NFS/VMs, mantenlo y apuesta por un SLOG adecuado.

Tarea 11: Confirmar presencia de SLOG y diseño básico

cr0x@server:~$ sudo zpool status tank | sed -n '1,80p'
  pool: tank
 state: ONLINE
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            sda                     ONLINE       0     0     0
            sdb                     ONLINE       0     0     0
        logs
          nvme-SAMSUNG_MZVLB1T0-1   ONLINE       0     0     0

errors: No known data errors

Significado: Existe un SLOG de un solo dispositivo. Eso es común, pero también es un punto único de rendimiento y (según tu tolerancia) riesgo para la latencia de escrituras síncronas.
Decisión: Para cargas síncronas críticas, prefiere SLOGs en espejo. Y asegúrate de que el SLOG realmente tenga baja latencia en condiciones seguras ante pérdida de energía.

Tarea 12: Comprobar si el sistema está ahogado por colas de I/O

cr0x@server:~$ iostat -x 1 3
Linux 6.5.0 (server)   12/26/2025  _x86_64_  (32 CPU)

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  %util
sda              12.0   340.0    480   14560      83.2     18.4    52.6     3.1     54.4   99.2
sdb              10.0   332.0    420   14400      85.7      1.2     3.7     2.8      3.8   34.5
nvme0n1           0.0    25.0      0    2048     163.8      0.4    15.8     0.0     15.8   40.1

Significado: sda está al 99% de uso con una cola profunda y await alto, mientras sdb está bien. En un mirror, eso puede arrastrar al vdev.
NVMe muestra await moderado; si ese es tu SLOG, 15ms puede ser demasiado lento para expectativas de “fsync rápido”.
Decisión: Investiga por qué sda está lento: errores, firmware, thermal throttling, problemas de controlador. Si es miembro de un mirror, considera offline temporal para ver si la latencia mejora (con conciencia del riesgo).

Tarea 13: Revisar comportamiento del ARC (si arcstat está disponible)

cr0x@server:~$ arcstat 1 5
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
09:12:01  3120   980     31   220    7   710   23    50    1  96.2G  96.0G
09:12:02  2980   940     31   240    8   650   22    50    1  96.2G  96.0G
09:12:03  3050   970     32   210    7   710   23    50    1  96.2G  96.0G
09:12:04  3105   995     32   230    7   715   23    50    1  96.2G  96.0G
09:12:05  3002   960     32   220    7   690   23    50    1  96.2G  96.0G

Significado: Una tasa de misses ~31–32% puede ser aceptable o terrible según tu storage y carga. Si miss% salta de repente respecto al baseline,
los discos verán más lecturas y la latencia subirá.
Decisión: Compáralo con la línea base de la semana pasada. Si ARC está limitado (c igual a arcsz) y tienes RAM libre, considera aumentar el máximo de ARC.
Si ARC está siendo reducido por otra cosa, arregla la presión de memoria en lugar de “tunear ZFS” hasta dejarlo en una esquina.

Tarea 14: Revisar compresión del dataset y I/O lógico vs físico

cr0x@server:~$ sudo zfs get -o name,property,value compression,compressratio tank/app
NAME      PROPERTY       VALUE
tank/app  compression    lz4
tank/app  compressratio  1.62x

Significado: La compresión funciona y probablemente ahorra I/O. Si compressratio es ~1.00x, estás pagando sobrecarga de CPU sin beneficio de I/O (generalmente pequeño con lz4, pero no cero).
Decisión: Si la CPU es un cuello de botella y los datos son incompresibles, considera desactivar la compresión en ese dataset. Si no, deja lz4 como está; es uno de los pocos “por defecto” que realmente merece la pena.

Tarea 15: Averiguar quién está pegando al pool ahora mismo

cr0x@server:~$ sudo iotop -oPa
Total DISK READ: 45.20 M/s | Total DISK WRITE: 112.30 M/s
  PID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
18342 be/4  postgres    2.10 M/s   65.40 M/s  0.00 %  84.21 % postgres: checkpointer
20111 be/4  root        0.00 B/s   28.20 M/s  0.00 %  62.10 % zfs send -w tank/app@snap
 9321 be/4  libvirt-qemu 1.10 M/s  12.80 M/s  0.00 %  20.33 % qemu-system-x86_64

Significado: Tienes un checkpointer haciendo escrituras intensas, un zfs send empujando datos y VMs leyendo/escribiendo. Esto es un mapa de contención.
Decisión: Si la latencia es visible para usuarios, pausa o reprograma la transferencia masiva (zfs send) o limita su velocidad. No discutas con la física.

Broma #1: El almacenamiento es el único lugar donde “está bien en promedio” se acepta justo hasta el momento en que deja de estarlo.

Tres mini-historias corporativas (anonimizadas, dolorosamente plausibles)

Mini-historia 1: El incidente causado por una suposición equivocada

Una empresa SaaS mediana ejecutaba Postgres de clientes sobre almacenamiento de VMs respaldado por ZFS. Había sido estable durante meses, y el equipo estaba orgulloso:
SSDs en espejo, compresión activada, scrubs semanales, monitorización básica. Lo único que no monitorizaron fue la latencia de escrituras síncronas. Porque, en su cabeza,
“los SSDs son rápidos”.

Llegó un nuevo requisito de cumplimiento: asegurar semánticas de durabilidad para un subconjunto de cargas. Un ingeniero puso sync=always en el dataset que alojaba
las imágenes de VM. La suposición era simple: “Esto será más seguro y sólo un poco más lento.” Tenían media razón.

A la mañana siguiente, los clientes reportaron timeouts esporádicos. El pool parecía sano. La CPU estaba bien. La red estaba bien. Los gráficos de throughput estaban bien.
Pero la latencia de escritura del percentil 99 se disparó. Los logs del kernel no mostraban nada dramático. Los logs de ZFS no mostraban errores. Todos empezaron a mirar la capa de aplicación,
porque eso es lo que haces cuando el almacenamiento no confiesa.

El arma humeante estaba en zpool iostat -l: el dispositivo SLOG (un NVMe de consumo sin protección ante pérdida de energía) tenía latencia de escritura alta y errática bajo carga sinc.
No estaba “roto”. Simplemente le pidieron que proporcionara commits de baja latencia consistentes y educadamente se negó.

La solución fue aburrida y cara: reemplazar el SLOG por un dispositivo diseñado para latencia sostenida en escrituras síncronas y ponerlo en espejo.
El postmortem dejó una lección digna de tatuaje: no cambies las semánticas de sync sin medir la ruta de sync.

Mini-historia 2: La optimización que salió mal

Un equipo de plataforma interno de una empresa ejecutaba un pool ZFS para artefactos de CI e imágenes de contenedores. Eran principalmente archivos grandes, muchas lecturas paralelas
y escrituras grandes ocasionales. El sistema estaba “bien”, pero una iniciativa de rendimiento bien intencionada exigió “más throughput”.

Alguien encontró una nota de tuning antigua y decidió que el pool debía usar un “special vdev” separado para metadatos para acelerar el recorrido de directorios y lecturas pequeñas.
Añadieron un par de SSDs pequeños y rápidos como special vdev. Los benchmarks iniciales fueron geniales. La dirección sonrió. Todos siguieron con su trabajo.

Meses después, el rendimiento se volvió raro. No sólo más lento—con picos. Durante horas pico de CI, las builds se detenían por segundos.
zpool status seguía verde. Pero zpool iostat -v -l contaba una historia más fea: el special vdev se convirtió en el cuello de botella de latencia.
Esos “SSDs pequeños y rápidos” ahora estaban siendo muy escritos, se estaban desgastando y a veces se estaban limitando.

El problema no fue la característica. Fue el dimensionamiento y el pensamiento sobre el ciclo de vida. Metadatos y bloques pequeños pueden ser un imán de I/O.
Cuando el special vdev hace picos, todo el pool se siente tambaleado. Los logs del kernel mostraban advertencias NVMe leves, no suficientes para disparar alertas,
pero suficientes para explicar las paradas cuando se correlacionaban con los picos de latencia.

El plan de remediación: reemplazar el special vdev por dispositivos apropiadamente durables, ampliar capacidad para reducir amplificación de escritura,
y añadir monitorización específica para latencia y desgaste del special vdev. La moraleja: cada estructura de aceleración se vuelve una dependencia.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Una entidad de servicios financieros ejecutaba ZFS como backend NFS sirviendo directorios home y salidas de build compartidas. Nada sexy. Sin tunings heroicos.
Lo que sí tenían era disciplina: scrubs mensuales, alertas en cambios de zpool status, y un runbook que obligaba a los ingenieros a comprobar
errores de transporte del kernel antes de tocar las perillas de ZFS.

Un martes, la latencia subió. Los usuarios lo notaron. El de guardia siguió el runbook: comprobar salud del pool, eventos y logs del kernel.
En minutos encontró reinicios repetidos de enlace SATA en una bahía de discos. Aún no había errores de ZFS—sólo reintentos.

Reemplazaron el cable/componente del backplane en una micro-ventana programada, antes de que el disco empezara a tirar errores de checksum.
La latencia volvió a la línea base. No fue necesario resilver. Ningún riesgo de datos. Ningún fin de semana consumido por arrepentimiento.

La práctica que los salvó no fue genial. Fue consistencia: scrubs para detectar problemas latentes, y correlación de logs para atrapar degradación de la ruta de hardware temprano.
Lo aburrido está subestimado en ingeniería de almacenamiento porque funciona.

Broma #2: Si quieres una carrera emocionante en almacenamiento, ignora tu calendario de scrubs; el pager te creará la emoción por ti.

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

1) “El pool está ONLINE pero la latencia es horrible”

Síntoma: zpool status parece limpio; las aplicaciones hacen timeout; iostat muestra await alto.

Causa raíz: Reintentos de dispositivo, reinicios de enlace o un solo disco lento arrastrando un mirror/RAIDZ vdev.

Solución: Revisa journalctl -k por reinicios/timeouts; revisa SMART/NVMe. Reemplaza el dispositivo sospechoso o repara la ruta de transporte. No ajustes ZFS para compensar hardware que miente.

2) “Cada pocos segundos tenemos una pausa”

Síntoma: Picos periódicos de latencia; NFS se traba; bases de datos muestran stalls de commit.

Causa raíz: Txg sync tardando demasiado, a menudo porque el pool está saturado, la fragmentación es alta o un dispositivo lento está bloqueando flushes.

Solución: Usa zpool iostat -l para identificar el vdev lento y reduce la carga de escritura concurrente. Si es intensivo en sync, arregla la latencia del SLOG o reconsidera sync=always.

3) “Añadimos un SLOG y el rendimiento empeoró”

Síntoma: Carga intensiva en sync se vuelve más lenta tras añadir dispositivo de log.

Causa raíz: El SLOG tiene peor latencia que el pool o sufre throttling; un SLOG único se convierte en cuello.

Solución: Verifica con iostat -x y zpool iostat -l. Reemplaza por dispositivo de baja latencia y protección ante pérdida de energía, idealmente en espejo. Si la carga es mayormente async, quita el SLOG y deja de esperar magia.

4) “Los errores de checksum siguen apareciendo, pero los scrubs los reparan”

Síntoma: Los contadores CKSUM aumentan; los scrubs reparan; no hay errores de datos visibles—aún.

Causa raíz: A menudo cableado/backplane/HBA (errores CRC), a veces fallo de medio en el disco.

Solución: Revisa contadores SMART CRC y logs de transporte del kernel. Reasienta/reemplaza cable/backplane; actualiza firmware; reemplaza disco si los indicadores de medio son malos. Luego haz un scrub y confirma que los contadores se mantengan estables.

5) “El resilver terminará en 2 horas… durante los próximos 3 días”

Síntoma: ETA de resilver crece; el pool está lento.

Causa raíz: Carga competitiva + pool fragmentado + dispositivo lento. El resilver compite por I/O y puede ser depriorizado o starveado por tus aplicaciones.

Solución: Reduce la carga, programa resilver en horas de baja actividad cuando sea posible, y busca un dispositivo débil que prolongue el proceso. Confirma que ashift y diseño de vdev no estén causando amplificación de escritura patológica.

6) “La tasa de aciertos del ARC se desplomó tras desplegar algo no relacionado”

Síntoma: Aumento súbito de lecturas de disco; latencia sube; cambios en uso de memoria.

Causa raíz: Presión de memoria por nuevos servicios, densidad de contenedores o comportamiento del page cache del kernel; ARC limitado por configuración o exprimido por otros consumidores.

Solución: Mide memoria, no adivines. Si tienes RAM disponible, aumenta el tope de ARC. Si no, reduce la presión de memoria o mueve la carga. No añadas L2ARC como sustituto de no tener suficiente RAM a menos que entiendas los patrones de lectura/escritura.

7) “Afinamos recordsize y ahora las escrituras son más lentas”

Síntoma: Tras cambiar recordsize, el throughput baja y la latencia sube.

Causa raíz: Desajuste de recordsize con la carga (por ejemplo, demasiado grande para bloques aleatorios de DB, demasiado pequeño para streaming secuencial).

Solución: Ajusta recordsize por dataset y tipo de carga. Imágenes de VM y bases de datos suelen preferir bloques más pequeños (p. ej., 16K), mientras archivos secuenciales grandes se benefician de bloques mayores (128K–1M según uso). Valida con trazas reales de I/O, no con sensaciones.

Listas de verificación / plan paso a paso

Checklist A: Cuando los usuarios reportan “lentitud intermitente”

  1. Confirma si es latencia de almacenamiento: revisa p95/p99 a nivel de app y wait I/O en hosts.
  2. Ejecuta zpool status -x. Si no está sano, trátalo como incidente.
  3. Ejecuta zpool status y busca scrub/resilver en curso.
  4. Ejecuta zpool iostat -v -l 1 durante 60–120 segundos. Identifica el vdev/dispositivo más lento por latencia.
  5. Ejecuta journalctl -k filtrado por reinicios/timeouts. Confirma si el dispositivo lento tiene errores coincidentes.
  6. Revisa SMART/NVMe del dispositivo sospechoso.
  7. Decide: aislar (offline/reemplazar), reparar la ruta (cable/backplane/HBA), o reducir la contención de carga.

Checklist B: Cuando se sospechan escrituras síncronas (bases de datos/NFS/VMs)

  1. Revisa propiedades del dataset sync y logbias para los datasets relevantes.
  2. Confirma si tienes un SLOG y cuál es (single vs mirror).
  3. Mide la latencia del SLOG usando iostat -x en el dispositivo SLOG durante la ventana de lentitud.
  4. Si la latencia del SLOG es peor que la del pool, no lo debatas: reemplaza o retíralo según las necesidades de sync.
  5. Si no existe SLOG y la latencia sync es dolorosa, considera añadir un SLOG en espejo apropiado—después de validar que la carga es realmente sync-heavy.

Checklist C: Cuando aparecen errores pero el pool “sigue funcionando”

  1. Captura la salida de zpool status y zpool events -v para el registro del incidente.
  2. Revisa logs del kernel alrededor de los mismos timestamps por problemas de transporte.
  3. Revisa indicadores SMART/NVMe y contadores de errores de medio.
  4. Arregla la ruta o reemplaza hardware. Sólo entonces limpia errores con zpool clear.
  5. Ejecuta un scrub tras la remediación y confirma que los contadores de error se mantengan planos.

Checklist D: Baseline para detectar regresiones

  1. Registra baseline de zpool iostat -v -l durante horas “conocidas buenas”.
  2. Registra baseline de estadísticas ARC (hit rate, tamaño ARC, indicadores de presión de memoria).
  3. Rastrea duración de scrubs y resilvers (son advertencias tempranas de fragmentación y envejecimiento de dispositivos).
  4. Alerta sobre errores de transporte del kernel, no sólo sobre fallos de ZFS.

Preguntas frecuentes

1) ¿Son suficientes los registros de ZFS para diagnosticar problemas de rendimiento?

No. ZFS te dirá sobre señales de integridad (errores, fallos, eventos), pero el diagnóstico de rendimiento necesita contexto de dispositivo y kernel.
Siempre empareja eventos de ZFS con logs del kernel y iostat/zpool iostat.

2) Si zpool status está limpio, ¿puedo descartar hardware?

Rotundamente no. Muchos problemas de hardware/transporte aparecen como reintentos y reinicios de enlace mucho antes de que ZFS incremente un contador.
Los logs del kernel y SMART a menudo muestran los “pre-síntomas”.

3) ¿Agregar un SLOG siempre mejora el rendimiento?

Sólo para escrituras síncronas. Para cargas asíncronas es mayormente irrelevante. Y un SLOG lento puede empeorar el rendimiento síncrono.
Trata al SLOG como un componente crítico de latencia, no como una casilla para marcar.

4) ¿Cuál es la forma más rápida de detectar un único disco malo en un mirror?

Usa zpool iostat -v -l 1 y busca un miembro con latencia de espera de disco dramáticamente mayor.
Luego confirma con journalctl -k y logs SMART/NVMe.

5) ¿Los errores de checksum siempre significan que el disco se está muriendo?

A menudo es la ruta: cable, backplane, HBA, firmware. Los errores SMART CRC y los reinicios de transporte del kernel son tu pista.
Los errores de medio (pending/reallocated/uncorrectable) implican el disco más directamente.

6) ¿Por qué el pool se ralentiza durante un scrub si los scrubs son “background”?

Los scrubs son background en intención, no en física. Consumen I/O real y pueden elevar la latencia.
Si los scrubs causan dolor a usuarios, prográmalos mejor, limita su velocidad donde sea posible y verifica que tu pool tenga margen de rendimiento.

7) ¿Debo poner sync=disabled para arreglar la latencia?

Eso no es arreglar; es negociar con la realidad y esperar que no lo note. Estás cambiando garantías de durabilidad por velocidad.
Si los datos importan, arregla la ruta de sync (SLOG/latencia de dispositivo) en su lugar.

8) ¿La alta fragmentación siempre es la razón de las lentitudes?

No. La fragmentación es común, pero el culpable habitual primero es la latencia del dispositivo o un pool degradado/reconstruyéndose.
La fragmentación tiende a mostrarse como una tendencia a largo plazo: scrubs/resilvers más largos, I/O aleatorio más caro, y latencia más fácil de activar.

9) ¿Cuándo debo limpiar errores de ZFS con zpool clear?

Después de haber arreglado la causa subyacente y capturado la evidencia. Limpiar demasiado pronto borra tu rastro y facilita repetir el incidente.

10) ¿Qué pasa si ZFS está lento pero iostat muestra %util bajo?

Entonces el cuello de botella puede estar en otro lugar: CPU (compresión/cifrado), presión de memoria, throttling, o un stall en la ruta de sync.
También confirma que estás midiendo los dispositivos correctos (multipath, capas dm-crypt, HBAs).

Conclusión: próximos pasos prácticos

Los outages de rendimiento de ZFS suelen ser fallos de hardware en cámara lenta, sorpresas de escrituras síncronas o contención por reconstrucción/scrub que nadie trató como un evento de producción.
La buena noticia: puedes verlos venir—si miras en los lugares correctos y mantienes una línea base.

Haz lo siguiente:

  1. Establece línea base de zpool iostat -v -l y iostat -x durante horas saludables, y guarda esos números donde tu yo futuro los encuentre.
  2. Alerta sobre errores de transporte del kernel (reinicios, timeouts) además de cambios en el estado del pool ZFS.
  3. Audita datasets por configuraciones de sync e identifica qué cargas son realmente sync-heavy.
  4. Decide si tu SLOG (si existe) está realmente a la altura: baja latencia, seguro ante pérdida de energía y, idealmente, en espejo para entornos críticos.
  5. Mantén scrubs programados y monitorizados. No porque sea divertido, sino porque es cómo capturas temprano la “corrupción silenciosa y hardware débil”.

Tu objetivo no es crear el sistema ZFS perfecto. Es hacer que las lentitudes sean previsibles, diagnosables y solucionables—antes de que se conviertan en cortes de servicio con una invitación a reunión.

← Anterior
Docker: Secretos sin filtraciones — deja de poner contraseñas en .env
Siguiente →
WireGuard: la configuración de cliente más sencilla en Windows/macOS/Linux (y las trampas habituales)

Deja un comentario