Prioridad de Resilver en ZFS: Reconstruir Rápido Sin Colapsar IO de Producción

¿Te fue útil?

No hay nada que ponga a prueba tu diseño de almacenamiento como el momento en que un disco falla a las 14:00 un martes y tu pool empieza a resilver mientras el negocio sigue en pleno funcionamiento. Quieres que la reconstrucción termine rápido—porque el riesgo se compone con cada minuto que permaneces degradado—pero tampoco quieres que tus bases de datos parezcan que corren en una disquetera.

La “prioridad” de resilver en ZFS es en realidad un conjunto de perillas: planificación, concurrencia, profundidad de cola y cuán agresivamente ZFS procesa regiones sucias y metadatos. Si lo haces bien, el resilver es una quema controlada. Si lo haces mal, te crearás un outage propio, de forma educada, desde dentro.

Qué significa realmente la prioridad de resilver (y qué no)

En términos de ZFS, un resilver es el proceso de reconstrucción de redundancia después de reemplazar o volver a conectar un dispositivo, o tras un dispositivo que desaparece temporalmente y regresa. Está relacionado con un scrub, pero no es el mismo trabajo.

La gente dice “subir la prioridad de resilver” como si existiera un único control deslizante llamado Hazlo Rápido. No lo hay. La velocidad de resilver y el impacto en producción dependen de:

  • Qué elige ZFS copiar: un resilver suele ser incremental, guiado por metadatos de ZFS sobre qué necesita reconstruirse, no una copia ciega de disco entero (aunque ciertos diseños y condiciones pueden hacer que se comporte más parecido a eso).
  • Cuántas E/S de reconstrucción concurrentes emite ZFS: demasiado pocas y subutilizas los discos; demasiadas y saturas las colas y destrozas la latencia.
  • Dónde está realmente el cuello de botella: a menudo no es la “velocidad del disco” sino amplificación de E/S aleatoria, contención de metadatos, fragmentación o un único vdev atascado.
  • Comportamiento del scheduler y colas en el SO: Linux vs FreeBSD difieren; los schedulers modernos, NVMe y capas de virtualización pueden cambiar las reglas.
  • Trabajo en competencia: scrubs, escrituras intensas, cargas sync y lecturas aleatorias de bloques pequeños luchan por los mismos discos.

Prioridad, en la práctica, significa decidir quién tiene permiso para ser molesto: el resilver o tus clientes. Normalmente puedes encontrar un punto intermedio donde el resilver sea lo suficientemente agresivo para reducir el riesgo, mientras la producción mantiene su p99 por debajo de “llamar al CEO”.

Una cita para tener en el monitor

Idea parafraseada (Werner Vogels, ingeniería enfocada en fiabilidad): “Todo falla, todo el tiempo—diseña y opera asumiendo que así será.”

Hechos e historial que explican el comportamiento actual

El comportamiento del resilver no es arbitrario; es producto de decisiones de diseño y un par de décadas de cicatrices. Aquí algunos hechos cortos y concretos que te ayudan a razonar sobre lo que ves.

  1. ZFS se diseñó alrededor de checksums de extremo a extremo y copy-on-write, lo que significa que “reconstruir” no es un clon ingenuo de sectores; es reconstrucción basada en lo que el pool considera vivo y válido.
  2. Los rebuilds tradicionales de RAID eran históricamente lecturas de dispositivo completo, por eso los administradores veteranos aún asumen que un resilver debe leer cada sector. ZFS a menudo puede hacer menos.
  3. El scrub precede a muchos discos modernos de alta capacidad; las tasas de error modernas y los discos multi-TB convirtieron “degradado por un día” en “degradado por una semana” si no ajustas.
  4. Los RAIDZ anchos se hicieron populares en parte para ahorrar bahías; la contrapartida es tiempos de reconstrucción más largos y más presión de E/S durante el resilver, especialmente bajo cargas de escritura aleatoria.
  5. “Resilver secuencial” y mejoras relacionadas (implementación variable según plataforma/versión) buscan reducir las tormentas de seek emitiendo E/S en un orden más amigable para discos.
  6. ZFS debe reconstruir metadatos correctamente, no solo bloques. Pools con mucha metadata (archivos pequeños, snapshots, muchos datasets) pueden resilverizar en un patrón que parece “aleatorio y lento” incluso en discos rápidos.
  7. Los dispositivos especiales (metadata/pequeños bloques) pueden hacer gritar a un pool cuando está sano—and gritar de otra forma cuando está degradado, porque las lecturas críticas se concentran.
  8. La compresión y las elecciones de recordsize cambian la forma de E/S del resilver. Registros grandes y datos comprimidos pueden reducir lecturas físicas; registros diminutos pueden hacer que el resilver parezca un millón de cortes.

Broma #1: Un resilver es como un ascensor: si lo miras, se mueve más lento. Si lo graficas, se mueve todavía más lento.

Modelo de riesgo: por qué “lo más rápido posible” no siempre es lo más seguro

La velocidad de resilver es una perilla de control de riesgo. Tu pool está degradado; otra falla puede convertirse en pérdida de datos (o al menos en una recuperación forzada). Así que sí, terminar rápido importa. Pero “terminar rápido” no significa “saturar todo hasta que la producción se caiga”.

Aquí está el triángulo de riesgo que estás equilibrando:

  • Tiempo en riesgo: cuánto tiempo estás con redundancia reducida.
  • Impacto al cliente: latencia y presupuesto de errores durante la reconstrucción.
  • Estrés de hardware: los rebuilds agresivos pueden mantener los discos al 100% durante días, aumentando la probabilidad de fallo—especialmente en spinners más viejos.

La postura correcta en la mayoría de entornos de producción es: agresivo pero limitado. Quieres que el resilver mantenga progreso aún bajo carga, mientras previenes que empuje la espera de E/S y la latencia hacia una espiral de muerte.

Un modelo mental útil: un resilver es un job batch en segundo plano con una fecha límite de seguridad. Trátalo como un job por lotes que puedes priorizar temporalmente—pero no a costa de volver el sistema inusable.

Guía de diagnóstico rápido

Si tu resilver es lento o tus apps están sufriendo, no empieces por girar tunables. Empieza por encontrar el cuello de botella. Ese es el camino más corto para acertar.

Primero: confirma qué trabajo está corriendo y en qué estado está el pool

  • ¿Es realmente un resilver, o un scrub, o ambos?
  • ¿Está el pool degradado por un disco ausente, un disco fallado, o un replace en curso?
  • ¿El disco nuevo es más lento (sorpresa SMR, puente USB, firmware incorrecto)?

Segundo: identifica el vdev limitante y la forma de E/S

  • ¿Qué vdev está haciendo la mayor parte del trabajo?
  • ¿Estás limitado por lecturas aleatorias, escrituras aleatorias o escrituras sync?
  • ¿Están dominando los metadatos (alta IOPS, bajo throughput)?

Tercero: comprueba colas y latencia, no solo ancho de banda

  • ¿Cuál es la profundidad de cola del disco y el tiempo await?
  • ¿Estás saturando un único path HBA?
  • ¿Está cayendo la tasa de aciertos del ARC, haciendo que todo vaya al disco?

Cuarto: decide el intercambio que deseas hacer

  • ¿Necesitas el resilver más rápido posible (alto riesgo de negocio, redundancia pobre), aun si perjudica?
  • ¿O necesitas proteger la latencia p99 (sistemas orientados al cliente), aceptando un resilver más largo?

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

Estos son los comandos que realmente ejecuto cuando un pool está degradado y de repente todos recuerdan que el almacenamiento existe. Cada tarea incluye: comando, salida de muestra, qué significa y la decisión que tomas.

Tarea 1: Ver si estás resilverizando, haciendo scrub o ambos

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: DEGRADED
status: One or more devices is currently being resilvered.
action: Wait for the resilver to complete.
  scan: resilver in progress since Wed Dec 25 09:12:04 2025
        1.24T scanned at 1.10G/s, 412G issued at 365M/s, 3.80T total
        412G resilvered, 10.57% done, 0 days 02:31:18 to go
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        DEGRADED     0     0     0
          mirror-0                  DEGRADED     0     0     0
            ata-WDC_WD80...         ONLINE       0     0     0
            replacing-1             DEGRADED     0     0     0
              ata-WDC_WD80...       OFFLINE      0     0     0
              ata-ST8000...         ONLINE       0     0     0
errors: No known data errors

Significado: Es un resilver, no solo un scrub. “Issued” es el trabajo que realmente se está haciendo; “scanned” puede ser mayor porque ZFS puede recorrer metadatos más rápido de lo que puede reconstruir bloques.

Decisión: Si la ETA es razonable y la producción está estable, no toques nada. Si la latencia se dispara o “issued” avanza a paso de tortuga, continúa con el diagnóstico.

Tarea 2: Comprobar si hay un scrub también en curso (y pararlo si hace falta)

cr0x@server:~$ zpool status tank | sed -n '1,25p'
  pool: tank
 state: DEGRADED
  scan: resilver in progress since Wed Dec 25 09:12:04 2025
        1.24T scanned at 1.10G/s, 412G issued at 365M/s, 3.80T total

Significado: Solo el resilver está activo. Si ves “scrub in progress” al mismo tiempo (posible en algunas secuencias operativas), estás haciendo trabajo extra.

Decisión: Si un scrub compite durante un incidente, para el scrub y deja que el resilver termine primero.

cr0x@server:~$ sudo zpool scrub -s tank

Tarea 3: Mostrar E/S por vdev para encontrar el punto caliente

cr0x@server:~$ zpool iostat -v tank 2 3
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        22.1T  13.5T  18.2K  6.4K   520M   140M
  mirror-0  7.40T  5.10T  12.1K  3.1K   340M    70M
    sda         -      -  6.1K   1.6K   170M    35M
    sdb         -      -  6.0K   1.5K   170M    35M
  mirror-1  7.40T  4.90T  3.9K   1.7K   110M    40M
    sdc         -      -  2.0K     850   55M    20M
    sdd         -      -  1.9K     840   55M    20M
  mirror-2  7.40T  3.50T  2.2K   1.6K    70M    30M
    sde         -      -  1.1K     820   35M    15M
    sdf         -      -  1.1K     810   35M    15M

Significado: mirror-0 está haciendo la mayoría de las lecturas. Ese probablemente sea el vdev que está resilverizando o el vdev con la mayor cantidad de bloques referenciados.

Decisión: Enfócate en el vdev caliente. Afinar el vdev equivocado es solo cosplay de rendimiento.

Tarea 4: Confirmar que el disco de reemplazo no sea el lento (o SMR)

cr0x@server:~$ lsblk -o NAME,MODEL,SIZE,ROTA,TRAN,SERIAL
NAME  MODEL            SIZE ROTA TRAN SERIAL
sda   WDC WD80...      7.3T    1 sata WD-AAA
sdb   WDC WD80...      7.3T    1 sata WD-BBB
sdc   WDC WD80...      7.3T    1 sata WD-CCC
sdd   WDC WD80...      7.3T    1 sata WD-DDD
sde   WDC WD80...      7.3T    1 sata WD-EEE
sdf   ST8000DM004      7.3T    1 sata ZDHFFF

Significado: Un disco es de modelo distinto. Eso puede estar bien—o puede ser un disco SMR que convierte las reconstrucciones en melaza bajo escrituras sostenidas.

Decisión: Si el reemplazo es un modelo SMR en una carga que escribe durante el resilver, para y cámbialo por CMR. Sí, aunque procurement se queje.

Tarea 5: Comprobar salud del disco rápidamente (SMART)

cr0x@server:~$ sudo smartctl -H /dev/sdf
smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.8.0] (local build)
SMART overall-health self-assessment test result: PASSED

Significado: “PASSED” no es “saludable”, es “no está obviamente muerto”. Aún quieres revisar contadores de errores.

Decisión: Si SMART falla o los atributos lucen feos (sectores reasignados/pending), no confíes en el disco para terminar un resilver. Reemplázalo de nuevo.

Tarea 6: Vigilar latencia y profundidad de cola a nivel SO durante el resilver

cr0x@server:~$ iostat -x 2 3
Linux 6.8.0 (server)  12/25/2025  _x86_64_  (32 CPU)

avg-cpu:  %user %nice %system %iowait  %steal   %idle
           6.02  0.00    3.11   18.40    0.00   72.47

Device            r/s     w/s   rkB/s   wkB/s  rrqm/s  wrqm/s %util aqu-sz  await
sda            320.1   110.4 165000   42000     0.0     2.1  99.0  41.3  110.2
sdf            310.6   115.2 160000   45000     0.0     2.0  98.7  39.8  105.9

Significado: %util ~99, profundidad de cola ~40, await ~100ms. En spinners, eso es “estamos saturándolos y todo lo demás esperará”.

Decisión: Si la producción sufre, necesitas reducir la E/S concurrente o darle forma (afinar resilver, limitar throughput o mover carga). Si estás en SSD/NVMe, 100ms es una sirena roja.

Tarea 7: Comprobar presión del ARC (fuente oculta de “todo se volvió lento”)

cr0x@server:~$ grep -E 'c_max|c_min|size|arc_meta_used|hits|misses' /proc/spl/kstat/zfs/arcstats | head
c_max                           4    25769803776
c_min                           4    6442450944
size                            4    24191070208
arc_meta_used                   4    4246732800
hits                            4    392004112
misses                          4    48122103

Significado: ARC está cercano a c_max; el uso de metadatos es alto. Durante el resilver, los recorridos de metadatos pueden expulsar caché útil e incrementar lecturas de disco para la producción.

Decisión: Si el ARC está thrashando (misses subiendo rápido) y tienes RAM disponible, considera aumentar el máximo de ARC (con cuidado) o reducir presión de memoria en otro lado. Si no, debes afinar E/S, no memoria.

Tarea 8: Confirmar diseño del pool y ashift (el tiempo de resilver depende en parte de la geometría)

cr0x@server:~$ zdb -C tank | grep -E 'vdev|ashift' -n | head -n 20
45:        vdev_tree:
46:            type: 'root'
47:            id: 0
58:                    type: 'mirror'
59:                    ashift: 12
78:                    type: 'mirror'
79:                    ashift: 12

Significado: ashift=12 (sectores de 4K). Si tienes ashift=9 en discos nativos 4K, pagarás una penalización de amplificación de escritura para siempre, y los resilvers serán peores.

Decisión: Si ashift es incorrecto, arréglalo reconstruyendo el pool (sí, doloroso). No intentes salir de una descoincidencia de geometría con tunings.

Tarea 9: Ver si estás limitado por un único HBA o enlace

cr0x@server:~$ lsscsi -t
[0:0:0:0]    disk    ata:WDC_WD80...   /dev/sda  sata:0:0:0
[0:0:1:0]    disk    ata:WDC_WD80...   /dev/sdb  sata:0:0:1
[0:0:2:0]    disk    ata:WDC_WD80...   /dev/sdc  sata:0:0:2
[0:0:3:0]    disk    ata:WDC_WD80...   /dev/sdd  sata:0:0:3
[1:0:0:0]    disk    ata:WDC_WD80...   /dev/sde  sata:1:0:0
[1:0:1:0]    disk    ata:ST8000DM004   /dev/sdf  sata:1:0:1

Significado: Discos repartidos en dos controladores. Si todo está en un HBA (o un único enlace de expander), puedes saturarlo durante el resilver.

Decisión: Si encuentras un cuello de botella único, reduce la concurrencia o planifica una corrección hardware. El tuning no puede crear ancho de banda que no tienes.

Tarea 10: Observar patrones internos de E/S de ZFS vía zpool iostat con latencia (según característica OpenZFS)

cr0x@server:~$ zpool iostat -l -v tank 2 2
                           capacity     operations     bandwidth    total_wait     disk_wait
pool                     alloc   free   read  write   read  write   read  write   read  write
-----------------------  -----  -----  -----  -----  -----  -----  -----  -----  -----  -----
tank                     22.1T  13.5T  18.0K  6.5K   510M   145M   12ms   18ms    8ms   15ms
  mirror-0               7.40T  5.10T  12.0K  3.2K   335M    72M   14ms   21ms   10ms   18ms
    sda                      -      -  6.0K   1.6K   168M    36M    0ms    0ms    0ms    0ms
    sdb                      -      -  6.0K   1.6K   167M    36M    0ms    0ms    0ms    0ms

Significado: “total_wait” incluye tiempo esperando en ZFS; “disk_wait” es tiempo en el dispositivo. Total_wait alto con disk_wait bajo indica contención en el lado de ZFS; disk_wait alto significa que los dispositivos son el muro.

Decisión: Si disk_wait domina, limita velocidad. Si total_wait domina, busca CPU, contención de locks o cargas patológicas de metadatos.

Tarea 11: Ajustar la agresividad del resilver en Linux (parámetros del módulo)

En Linux OpenZFS, el comportamiento del resilver está influido por parámetros del módulo como zfs_resilver_delay y cortes de tiempo min/max de scan. La disponibilidad exacta depende de la versión; comprueba primero y luego cambia.

cr0x@server:~$ modinfo zfs | grep -E 'resilver|scan' | head -n 20
parm:           zfs_resilver_delay:How long to delay resilvering next extent (int)
parm:           zfs_scan_idle:Idle scan delay (int)
parm:           zfs_scan_min_time_ms:Minimum scan time per txg (ulong)
parm:           zfs_scan_max_time_ms:Maximum scan time per txg (ulong)

Significado: Las perillas existen en este sistema. Bien. Ahora puedes afinar intencionalmente en vez de aplicar sysctls de forma ritual desde un post escrito en la era jurásica del spinning rust.

Decisión: Si la latencia de producción sufre, aumenta delays o reduce tiempo de scan. Si el resilver es demasiado lento y tienes margen de E/S, haz lo contrario.

cr0x@server:~$ cat /sys/module/zfs/parameters/zfs_resilver_delay
2

Significado: El delay actual es 2 (las unidades dependen de la implementación; piensa “retroceso entre extentos”). Valores menores empujan más.

Decisión: Para producción diurna, mantén un delay no nulo. Para fuera de horas o modo emergencia “terminar ahora”, reduce con cuidado, vigilando la latencia.

Tarea 12: Ralentizar temporalmente el trabajo de scan de ZFS (Linux)

cr0x@server:~$ cat /sys/module/zfs/parameters/zfs_scan_max_time_ms
30000

Significado: ZFS puede dedicar hasta 30 segundos a escanear por ciclo de txg. Más alto significa scan/resilver más agresivo; más bajo cede con más frecuencia a otro trabajo.

Decisión: Si la producción está expirando, reduce este valor en pequeños pasos y valida con métricas. No lo cambies de 30000 a 1000 y luego te preguntes por qué la ETA del resilver pasó a “algún día del próximo trimestre”.

cr0x@server:~$ echo 10000 | sudo tee /sys/module/zfs/parameters/zfs_scan_max_time_ms
10000

Tarea 13: Montar una vigilancia estable y de bajo ruido del progreso

cr0x@server:~$ watch -n 10 'zpool status tank | sed -n "1,20p"'
Every 10.0s: zpool status tank

  pool: tank
 state: DEGRADED
  scan: resilver in progress since Wed Dec 25 09:12:04 2025
        1.46T scanned at 1.05G/s, 501G issued at 360M/s, 3.80T total
        501G resilvered, 13.01% done, 0 days 02:12:03 to go

Significado: Estás siguiendo issued y ETA, no solo scanned. Ese es el número que suele correlacionar con “cuánto hasta que la redundancia vuelva”.

Decisión: Si “scanned” avanza pero “issued” se atasca, probablemente estás bloqueado en I/O de reconstrucción real o contención, no en el recorrido del scan.

Tarea 14: Verificar que no estás creando una tormenta de sync autoinfligida

cr0x@server:~$ zfs get -o name,property,value -r sync tank | head
NAME           PROPERTY  VALUE
tank           sync      standard
tank/db        sync      standard
tank/vmstore   sync      always

Significado: Un dataset con sync=always forzará más escrituras síncronas. Durante un resilver, eso puede llevar a los spinners a la miseria.

Decisión: Si sync=always está establecido por buenas razones (bases de datos sin barreras adecuadas, cumplimiento), no lo “arregles” cambiando sync. En su lugar: asegura que el SLOG esté sano y rápido, o mueve la carga durante el resilver.

Tarea 15: Comprobar si falta o es lento un dispositivo SLOG (y está perjudicando escrituras sync)

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

        NAME                        STATE     READ WRITE CKSUM
        tank                        DEGRADED     0     0     0
          mirror-0                  DEGRADED     0     0     0
            sda                     ONLINE       0     0     0
            sdb                     ONLINE       0     0     0
          logs
            nvme0n1p2               ONLINE       0     0     0

Significado: SLOG está presente y online. Si faltara/fallara, las cargas sync derramarían hacia el pool principal, compitiendo más con el resilver.

Decisión: Si SLOG está degradado, arréglalo primero para cargas sync intensas. Un resilver rápido no sirve de mucho si tu log de transacciones está en soporte vital.

Estrategia de ajuste: reconstruir rápido sin aplastar la latencia

Seamos realistas: la “mejor” prioridad de resilver depende de lo que estás protegiendo. Para un destino de backup puedes ir a todo gas. Para un pool de base de datos primario necesitas protecciones.

Comienza con palancas operativas, no con tunables

El tuning más limpio es el que no haces en sysfs en absoluto.

  • Mueve o reduce carga: limita jobs por lotes, pausa reindexados, traslada analítica fuera de la máquina, retrasa send/receive de snapshots.
  • Para trabajo de fondo opcional: scrubs, borrados masivos de snapshots, replicación, grandes zfs destroy.
  • Prefiere ventanas de finalización de resilver: si puedes, programa reemplazos para la noche. No es truco; es sentido común.

Entiende qué está optimizando ZFS durante un resilver

ZFS debe mantener la corrección. También intenta mantener el pool usable. Algunos valores por defecto de la plataforma son conservadores porque el peor caso es feo: el resilver puede generar enorme I/O aleatorio, especialmente en pools fragmentados con muchos snapshots.

Dos resultados prácticos:

  • El ancho de banda no es la única métrica. Puedes mostrar 800MB/s “scanned” mientras la latencia de producción muere porque en realidad haces lecturas/escrituras pequeñas y aleatorias y colas.
  • Incremental no siempre es barato. Si un pool está muy fragmentado o con mucha rotación, la estrategia de “solo copiar bloques vivos” aún toca muchas regiones dispersas.

Elige una política: horario laboral vs modo emergencia

Recomiendo definir dos modos y practicarlos:

  • Modo horario laboral: agresividad de resilver moderada, latencia predecible, ETA más largo.
  • Modo emergencia: cuando la redundancia es críticamente baja (segundo disco mostrando errores, RAIDZ bajo estrés, o lote conocido de discos malos), aceptas mayor impacto para terminar más rápido.

Broma #2: Afinar resilver es como la cafeína—hay una dosis productiva, y luego está “oigo colores” y nada se hace.

Perillas de Linux OpenZFS: qué tienden a hacer en el mundo real

Los nombres y semántica exactos varían por versión de OpenZFS, pero estos son temas comunes:

  • Perillas de delay (como zfs_resilver_delay): introducen una breve pausa entre fragmentos de resilver. Esto suele reducir mucho la latencia cola alta en pools HDD porque rompe la monopolización de la cola.
  • Perillas de time-slice (como zfs_scan_min_time_ms, zfs_scan_max_time_ms): cuánto tiempo por ciclo ZFS dedica al scan/resilver. Valores más bajos ceden más a I/O normal.
  • Comportamiento de scan en idle (como zfs_scan_idle): intenta detectar inactividad y subir scan cuando el sistema está tranquilo.

Qué evitar: empujar la concurrencia tan alto que las colas de disco estén siempre llenas. Así transformas un “resilver más lento” en un “resilver que nunca termina porque todo expira y se reinicia”.

Perillas en FreeBSD y enfoque general

En FreeBSD normalmente usarás controles vía sysctl y confiarás en el comportamiento del scheduler del kernel. La filosofía es similar: modelar el trabajo de scan/resilver para que ceda a I/O de primer plano. Los detalles difieren; el flujo no: medir, cambiar una cosa, observar p99 y tasa issued de resilver.

Cuando más rápido es en realidad más lento: la trampa del seek-storm

En pools HDD, el resilver puede convertirse en un generador de I/O aleatorio. Si subes la agresividad, incrementas E/S pendientes y el disco hace más seeking, lo que reduce el throughput efectivo. Verás la tasa “issued” aplanarse mientras await sube. Esa es la señal de que alcanzaste el muro de seek.

En pools SSD/NVMe la trampa es distinta: puedes saturar las colas del controlador y robar presupuesto de I/O a lecturas sensibles a latencia. Aquí, una modestísima limitación puede preservar p99 con solo un pequeño impacto en el tiempo de reconstrucción.

Scrub vs resilver: arbitraje y planificación

Un scrub lee datos y verifica checksums; un resilver reconstruye redundancia. Ambos son operaciones de la “clase scan” en ZFS. Si las ejecutas juntas, básicamente estás pidiendo a los mismos discos que hagan dos grandes trabajos de fondo mientras también sirven producción. Eso no es valentía. Es horas extra no pagadas para tu subsistema de E/S.

Reglas que sigo

  • Nunca ejecutes un scrub durante un resilver activo a menos que tengas una razón muy específica (como investigar corrupción silenciosa en un pool con hardware conocido defectuoso) y hayas aceptado el impacto de rendimiento.
  • Después de un resilver, considera un scrub si tu política operativa lo requiere, pero prográmalo cuando la carga sea menor.
  • No dejes que la automatización acumule trabajos: si tienes scrubs semanales, asegúrate de que se pausen cuando el pool esté degradado o resilverizando.

Por qué ZFS puede parecer “ocupado” incluso cuando el throughput es bajo

Scrub/resilver pueden estar ligados a metadatos: muchas E/S pequeñas, verificación de checksum y gestión. En un pool fragmentado, esto puede ser un trabajo con muchas IOPS y MB/s poco impresionantes. Eso es normal. Lo que no es normal es dejar que eso prioritice y deje sin servicio tus lecturas de primer plano.

Tres mini-historias corporativas desde la trinchera

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

La empresa tenía una flota mixta: algunos nodos de almacenamiento eran mirror vdevs en SSD y otros RAIDZ2 en HDD. Operaciones los trataba como “el mismo ZFS”. El dashboard de monitorización incluso tenía un único panel “tasa de resilver” para todos los nodos. Se veía ordenado. También mentía por omisión.

Una tarde, un disco en un vdev RAIDZ2 HDD falló. El ingeniero de guardia lo reemplazó y decidió “acelerar las cosas” aplicando los mismos parámetros de resilver que funcionaban de maravilla en los nodos SSD. Las profundidades de cola subieron, pero la velocidad “scanned” se veía fantástica, así que todos se relajaron.

En menos de una hora, la API cara al cliente empezó a mostrar timeouts intermitentes. La base de datos no se cayó; simplemente estaba lo suficientemente lenta para disparar timeouts upstream. La causa raíz no fue falta de ancho de banda. Fue una tormenta de seeks. Los HDD quedaron clavados en utilización casi constante, con await alto. Las lecturas de primer plano se encolaban detrás del I/O de reconstrucción y escrituras sync pequeñas.

La suposición equivocada fue sutil: “Si al SSD le gusta más concurrencia, al HDD también le gustará.” El HDD no. El HDD quiere secuencialidad, respirar y que no le pidan 40 cosas a la vez.

La solución fue aburrida: revertir a límites de scan conservadores, parar el scrub que también había arrancado por programación y mover temporalmente un job por lotes a otro clúster. El resilver tardó más que en “modo rápido”, pero el incidente terminó porque la latencia p99 volvió a control.

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

Otra organización tenía la costumbre: siempre que un pool estaba degradado, pausaban inmediatamente el procesamiento normal y dejaban que el resilver corriera a máxima velocidad. La lógica: minimizar tiempo en riesgo. En papel, suena bien.

Luego se pusieron ingeniosos. Construyeron automatización que detectaba un pool degradado, aumentaba la agresividad del resilver y además disparaba limpieza paralela de datasets (“liberar espacio para facilitar a ZFS”). Esa limpieza incluía borrados intensivos de snapshots—mucho trabajo de metadatos y frees—mientras el resilver recorría las mismas estructuras de metadatos.

El resultado fue una tormenta perfecta: el pool gastó mucho CPU en gestión de metadatos, mientras los discos eran golpeados con I/O aleatorio. La tasa issued del resilver en realidad cayó, aunque el sistema “parecía ocupado”. La automatización mantuvo el estado horas porque solo se detenía cuando el resilver terminaba.

No causaron pérdida de datos, pero provocaron dolor al cliente evitable y alargaron la ventana degradada. La optimización falló porque combinó dos operaciones intensivas en E/S y metadatos en un período en que el pool era menos capaz de tolerarlo.

La solución fue de política: durante un resilver, no ejecutes borrados de snapshots, grandes zfs destroy ni operaciones tipo reequilibrado. Si debes liberar espacio, hazlo antes de estar degradado, no durante.

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

Un equipo de servicios financieros usaba ZFS para almacenamiento de VM. Su SLO de rendimiento era simple: mantener la latencia de almacenamiento dentro de una banda estrecha durante horas de trading. También tenían una regla de fiabilidad: nunca dejar un pool degradado más tiempo del necesario. Esos objetivos confligían. Así que lo documentaron como un playbook operativo explícito.

Cuando un disco falló, el de guardia hizo tres cosas por memoria muscular. Primero: confirmar si era un problema de path transitorio o una falla real de disco. Segundo: iniciar el reemplazo y resilver inmediatamente. Tercero: cambiar el pool a tuning “modo horario laboral” y congelar trabajo por lotes no esencial.

También tenían una entrada en el runbook: si la p99 cruza un umbral por más de 10 minutos, reducir scan max time en pasos y reevaluar. Eso era todo. Sin heroísmos. Sin arqueología de sysctl a las 2am.

El resilver tardó más de lo que habría en modo todo-fuerza, pero los sistemas de trading se mantuvieron estables. Después de horas, cambiaron a “modo emergencia” y dejaron que el resilver terminara más agresivamente durante la noche.

La práctica aburrida fue documentar, ensayar los toggles—más la disciplina de no cambiar cinco cosas a la vez. Les salvó de convertir una falla hardware en un incumplimiento de SLA.

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

Esto no es teórico. Son las maneras en que la gente accidentalmente prende fuego a su almacenamiento y luego culpa al fuego por estar caliente.

1) Síntoma: “Resilver está atascado en 0% issued pero scanned sigue avanzando”

  • Causa raíz: el recorrido de metadatos continúa, pero la E/S de reconstrucción real está bloqueada por errores de dispositivo, disco de reemplazo lento o contención extrema.
  • Solución: revisa zpool status -v por errores; verifica salud y enlace del dispositivo de reemplazo; mira await en iostat -x; reduce agresividad de scan y para trabajos competidores.

2) Síntoma: “Las apps hacen timeout; discos muestran 99% util; la ‘velocidad’ del resilver parece alta”

  • Causa raíz: monopolización de colas/seek storm; la métrica scanned es engañosa; I/O de primer plano espera detrás de I/O de reconstrucción.
  • Solución: aumenta resilver delay / reduce scan max time; para scrub; reduce escrituras por lotes; vigila latencia p99, no solo MB/s.

3) Síntoma: “El disco de reemplazo sigue fallando durante el resilver”

  • Causa raíz: disco malo, cable/backplane marginal o problemas de alimentación; el resilver es el primer estrés sostenido que sufre.
  • Solución: reemplaza el disco otra vez, cambia slot/cable, revisa logs SMART y logs del controlador. No sigas reintentando con la misma ruta inestable.

4) Síntoma: “Resilver dolorosamente lento en un pool casi lleno”

  • Causa raíz: alta fragmentación y estrés del allocator; ZFS tiene menos libertad para colocar bloques reconstruidos eficientemente; la sobrecarga de metadatos crece.
  • Solución: mantén pools por debajo de utilización sensata (regla: evita vivir por encima de ~80% para muchas cargas); añade vdevs antes de estar desesperado; no inicies liberaciones masivas durante resilver.

5) Síntoma: “La velocidad de resilver varía salvajemente hora a hora”

  • Causa raíz: patrones de carga en competencia (ventana de backups, compactación, envíos de snapshots, checkpoints de BD) y detección idle de ZFS que escala.
  • Solución: correlaciona con el calendario de cargas; fija agresividad de scan a ajustes previsibles en horas laborales; opcionalmente aumenta agresividad durante ventanas tranquilas conocidas.

6) Síntoma: “El resilver se volvió más lento tras añadir un dispositivo especial”

  • Causa raíz: el dispositivo especial concentra metadatos/bloques pequeños; si es más lento, sobresuscrito o también está degradado, se vuelve el cuello de botella.
  • Solución: asegura que los dispositivos especiales sean redundantes y rápidos; monitoriza su latencia por separado; evita que se llenen; trátalos como almacenamiento de primera clase, no como “un SSD extra”.

7) Síntoma: “Afinamos para resilver rápido, pero el resilver tardó más”

  • Causa raíz: concurrencia demasiado agresiva causa thrash; penalización de seeks en HDD; retries incrementados; contención del scheduler de I/O.
  • Solución: reduce agresividad hasta que la tasa issued aumente y await baje; mide, no adivines.

Listas de verificación / plan paso a paso

Plan paso a paso: cuando un disco falla en producción

  1. Confirma el modo de fallo. ¿Es una falla real de disco o un hiccup de path/controlador? Revisa zpool status -v y logs del SO.
  2. Reemplaza el disco y comienza el resilver. No esperes a una invitación a reunión para aprobar la física.
  3. Para tareas de fondo en competencia. Pausa scrubs, replicación intensa, borrados de snapshots y mantenimiento a granel.
  4. Mide el impacto en producción. Usa latencia de apps y await de disco; no te fíes solo de MB/s del resilver.
  5. Elige un modo: tuning horario laboral vs modo emergencia, según riesgo de redundancia y SLOs de cliente.
  6. Ajusta una perilla a la vez. Cambia scan max time o resilver delay en pasos pequeños; observa 10–15 minutos.
  7. Verifica progreso hacia adelante. Bytes issued y resilvered deben avanzar; contadores de error deben permanecer quietos.
  8. Al completarse, valida salud. El pool debe quedar ONLINE, sin errores nuevos; programa un scrub si la política lo exige.

Checklist: modo horario laboral (proteger latencia)

  • Scrub parado o aplazado
  • Jobs por lotes pausados o limitados
  • Resilver delay no nulo
  • Scan max time reducido moderadamente
  • Vigilar latencia p95/p99, await de disco y tasa issued

Checklist: modo emergencia (terminar rápido)

  • Confirma que el riesgo de redundancia lo justifica (múltiples avisos, RAIDZ bajo estrés, lote fallando)
  • Aumenta scan max time y reduce delays
  • Opcionalmente pausa servicios no críticos brevemente para acelerar la finalización
  • Asegura refrigeración adecuada; vigila temperaturas de disco y errores de controlador

Preguntas frecuentes

1) ¿Un resilver de ZFS siempre es incremental?

A menudo sí: ZFS puede reconstruir solo los bloques que importan según metadatos. Pero el diseño del pool, la fragmentación y cómo se eliminó el dispositivo pueden hacer que se comporte más como una operación de dispositivo completo en la práctica.

2) ¿Por qué “scanned” avanza más rápido que “issued” durante el resilver?

El escaneo es recorrido de metadatos; emitir es la E/S de reconstrucción real. Si emitir va retrasado, estás limitado por I/O de disco, contención o problemas de dispositivo.

3) ¿Debería pausar la carga de producción para acelerar el resilver?

Si es un sistema orientado al cliente, prefiera dar forma al resilver primero. Pausar la carga puede ayudar, pero es un instrumento contundente. Úsalo cuando el riesgo de redundancia sea alto o cuando puedas drenar tráfico de forma segura.

4) ¿Es seguro afinar zfs_scan_max_time_ms y zfs_resilver_delay en caliente?

Normalmente sí en Linux vía parámetros del módulo en sysfs, pero trátalo como gestión de cambios: incrementos pequeños, medir impacto y registrar lo que cambias para revertir.

5) ¿Por qué el resilver se hizo más lento cuando el pool tiene >80% de ocupación?

La flexibilidad del allocator baja y la fragmentación tiende a subir, lo que incrementa I/O aleatorio y sobrecarga de metadatos. No es falta moral; es geometría y entropía.

6) ¿Los mirrors resilverizan más rápido que RAIDZ?

Usualmente. Los mirrors tienen reconstrucción más sencilla y a menudo mejor paralelismo. El resilver en RAIDZ puede implicar más cálculos de paridad y más amplificación de I/O, según la carga y fragmentación.

7) ¿Debo ejecutar un scrub justo después de que termine el resilver?

Si tu política operativa exige scrubs periódicos, prográmalo—solo no inmediatamente si el sistema sigue caliente y la carga de producción es alta. Dale al pool tiempo para recuperarse.

8) ¿Cuál es la métrica única más importante para vigilar?

Para el riesgo: tiempo restante hasta que se restaure la redundancia (progreso issued/resilvered). Para el impacto al cliente: latencia p99 y await/ profundidad de cola del disco.

9) ¿Puedo acelerar el resilver añadiendo L2ARC?

No de forma fiable. L2ARC ayuda la caché de lectura pero puede añadir tráfico de escritura y sobrecarga de metadatos. Durante un resilver, el cuello de botella suele ser la E/S de disco y la reconstrucción, no “más caché”.

10) ¿Un SLOG hace que el resilver sea más rápido?

Indirectamente. Un buen SLOG puede proteger la latencia de escrituras sync para que la producción sufra menos, lo que te permite mantener un resilver más agresivo sin romper aplicaciones. No acelera mágicamente la reconstrucción en sí.

Conclusión: pasos siguientes que puedes hacer esta semana

La prioridad de resilver no es un ajuste mágico; es operación con límite de velocidad. El objetivo es simple: restaurar redundancia lo bastante rápido para reducir riesgo, manteniendo la E/S de producción lo bastante predecible para que tu incidente no tenga una secuela.

Pasos siguientes que rinden de inmediato:

  1. Escribe dos modos (horario laboral vs emergencia) con tus ajustes de scan/resilver elegidos y cuándo usarlos.
  2. Añade monitorización que grafique progreso issued/resilvered junto a p99 de latencia y await de disco.
  3. Audita tu flota por sorpresas SMR, pools casi llenos y scrubs programados que ignoran estados degradados.
  4. Practica una vez en un pool no crítico: reemplaza un disco, observa comportamiento, ajusta una perilla y registra resultados.
← Anterior
Docker “too many open files”: aumentar límites correctamente (systemd + contenedor)
Siguiente →
El reenvío de correo rompe DMARC — Arréglalo con SRS (y otras opciones)

Deja un comentario