Resilver secuencial en ZFS: por qué la velocidad de reconstrucción no es solo «MB/s de disco»

¿Te fue útil?

Reemplazas un disco fallado, inicias un resilver y esperas ver un flujo uniforme de cientos de MB/s. En su lugar obtienes una reconstrucción que empieza rápido, luego se arrastra y después oscila como si estuviera regulada por un comité invisible. Mientras tanto, la latencia de tu aplicación se dispara y la dirección pregunta por qué «el disco nuevo es lento».

La verdad incómoda es ésta: la velocidad de resilver es un problema de sistema. Los resilvers de ZFS no ocurren en el vacío. Compiten con cargas reales, atraviesan metadatos reales y están limitados por la geometría del vdev, el historial de asignación y la física de lecturas aleatorias pequeñas—incluso cuando el lado de escritura parece «secuencial».

Qué significa realmente “resilver secuencial” (y qué no significa)

Cuando la gente dice “resilver secuencial” suelen querer decir: «ZFS reconstruirá leyendo grandes bloques contiguos desde los discos sanos y escribiendo grandes bloques contiguos en el disco de reemplazo». Ese es el sueño. Y a veces sucede.

Pero el resilver secuencial no es una promesa de que el patrón de E/S subyacente sea puramente secuencial de punta a punta. Es una estrategia: escanear preferentemente mapas de espacio y metadatos de asignación para reconstruir solo lo asignado, y hacerlo de una manera que tienda a agrupar trabajo para reducir seeks.

Qué es:

  • Un método para reconstruir datos asignados, no todo el espacio de direcciones del dispositivo (como las reconstrucciones de RAID clásicas).
  • Un intento de buena fe para minimizar I/O aleatorio al recorrer metaslabs y árboles de asignación en un orden amigable con la localidad.
  • Una carga de trabajo que a menudo está limitada por lecturas en los dispositivos sobrevivientes y por la trayectoria de metadatos, incluso si las escrituras hacia el disco nuevo parecen secuenciales.

Qué no es:

  • No es «copiar todo el disco desde LBA 0 hacia adelante». ZFS no reconstruye el espacio libre, y no tiene por qué hacerlo.
  • No es «un hilo, un flujo». El resilver está en pipeline y es concurrente: lecturas, verificación de checksums, descompresión, reconstrucción de paridad (RAIDZ) y escrituras.
  • No es «inmune a la fragmentación». ZFS puede ser secuencial en teoría y aun así verse forzado a lecturas dispersas porque los datos están dispersos.

El tiempo de resilver es el tiempo que toma encontrar los bloques que importan, leerlos de forma fiable, reconstruirlos correctamente y escribirlos de forma que la pool quede consistente. “MB/s de disco” es solo una variable, y rara vez es la limitante cuando las cosas se ponen feas.

Por qué «MB/s de disco» es la unidad equivocada para planificar un resilver

Los benchmarks de rendimiento secuencial asumen que estás haciendo algo como dd sobre un dispositivo limpio. Un resilver hace algo más cercano a:

  • descubrimiento guiado por metadatos (space maps, punteros de bloque, bloques indirectos)
  • lecturas de tamaños mixtos (registros, registros parciales, bloques pequeños de metadatos)
  • verificación de checksum por cada bloque leído
  • descompresión opcional (ruta de lectura) y compresión (ruta de escritura)
  • cálculo de paridad RAIDZ (CPU + ancho de banda de memoria)
  • colas y planificación entre múltiples miembros del vdev
  • asignación de escritura y actualizaciones de metaslab en el destino

Por eso dos pools construidos con discos idénticos pueden resilverizar a velocidades radicalmente distintas:

  • Pool A: 40% lleno, baja fragmentación, recordsize ajustado a la carga, mirrors amplios, margen de IOPS suficiente. El resilver parece «secuencial».
  • Pool B: 85% lleno, años de churn, muchos bloques pequeños, RAIDZ con amplificación de lectura patológica y una carga de trabajo pesada en primer plano. El resilver parece una escena del crimen.

Incluso en la misma pool, la velocidad de resilver puede cambiar hora a hora porque el cuello de botella se mueve: primero lees extensiones de datos grandes rápidamente, luego alcanzas regiones pesadas en metadatos y de repente estás limitado por IOPS. La barra de progreso sigue moviéndose, pero tus expectativas no deberían hacerlo.

Broma #1: Si crees que la velocidad de resilver es «solo MB/s de disco», tengo un array que da 10 GB/s en benchmarks—hasta que lo usas.

Entonces, ¿qué deberías planificar en lugar de MB/s? Piensa en restricciones:

  • Techo de IOPS de lectura de los miembros vdev sobrevivientes (a menudo el limitador).
  • Comportamiento con bloques pequeños (metadatos, tablas de dedup, aciertos/fallos en special vdev).
  • Historial de asignación (fragmentación, distribución del espacio libre, tamaños de metaslab).
  • Concurrencia (hilos de resilver, pipeline ZIO, comportamiento del ARC).
  • Presupuesto operativo: cuánto aumento de latencia puedes tolerar en producción mientras corre.

Datos interesantes y pequeño contexto histórico

  1. ZFS popularizó “reconstruir solo datos asignados” como objetivo de diseño de primera clase, evitando el comportamiento tradicional de «reconstruir todo el disco» común en controladoras RAID clásicas.
  2. Scrubs y resilvers comparten la misma maquinaria, pero el resilver tiene que escribir y actualizar estado, lo que cambia los patrones de contención en la canalización de I/O.
  3. El resilver en RAIDZ es inherentemente amplificado en lecturas porque reconstruir un bloque suele requerir leer múltiples columnas; los mirrors frecuentemente pueden leer desde una sola copia.
  4. Los checksums de los punteros de bloque son centrales: las lecturas de ZFS se verifican extremo a extremo, así que «corrupción rápida y silenciosa» no está en el menú.
  5. Las decisiones de ashift se volvieron más críticas a medida que los discos pasaron a sectores físicos de 4K; el desalineamiento puede convertir trabajo «secuencial» en ciclos extra de lectura-modificación-escritura.
  6. Los space maps evolucionaron para seguir mejor rangos libres/asignados, y esa contabilidad afecta directamente cuán eficientemente ZFS puede recorrer el espacio asignado durante la reconstrucción.
  7. Mejoras en eliminación de dispositivos y resilver secuencial en los ecosistemas OpenZFS hicieron las reconstrucciones menos punitivas que los enfoques tempranos de «escanear todo»—cuando el diseño de la pool coopera.
  8. Los special vdev cambiaron el juego para pools pesados en metadatos: la velocidad de resilver puede mejorar drásticamente si las lecturas de metadatos se sirven rápido, pero solo si el special vdev está sano y dimensionado correctamente.

Los verdaderos cuellos de botella: dónde pasa tiempo el resilver

1) Los discos sobrevivientes hacen la parte difícil

El disco de reemplazo normalmente no es el factor limitante. Durante el resilver, la pool tiene que leer todos los bloques que pertenecían al dispositivo fallado desde los miembros sobrevivientes. Esas lecturas suelen ser:

  • distribuidas a lo largo del espacio de direcciones del vdev (fragmentación)
  • de tamaños mixtos, incluyendo muchas lecturas de metadatos pequeñas
  • en competencia con tu carga de trabajo de producción

Así que puedes poner un disco nuevo y rápido, y no importará porque los discos viejos están buscando por todo el plato como si fuera 2007.

2) La reconstrucción de paridad en RAIDZ amplifica las lecturas

Con mirrors, ZFS a menudo necesita una copia buena para reconstruir un bloque. Con RAIDZ, reconstruir un bloque generalmente requiere leer las otras columnas en la franja. Por eso «mismo TB bruto, mismos discos» no significa «mismo tiempo de resilver». RAIDZ intercambia eficiencia de capacidad por comportamiento de reconstrucción más complejo, y en el resilver pagas esa factura.

3) La fragmentación convierte la intención secuencial en realidad aleatoria

El resilver secuencial intenta recorrer las asignaciones en orden, pero si tus datos se escribieron con un patrón de churn (imágenes de VM, bases de datos con reescrituras frecuentes, stores de objetos con borrados), el «siguiente bloque» puede no estar cerca del anterior en disco.

Dos consecuencias prácticas:

  • Tus lecturas se vuelven limitadas por IOPS, no por throughput.
  • Tu pool puede mostrar «pocos MB/s» mientras está saturada (alta utilización, alta latencia).

4) Los metadatos pueden dominar la cola final

La primera mitad de un resilver suele verse más rápida porque estás copiando extensiones más grandes y contiguas. El final se pone extraño: bloques minúsculos, bloques indirectos, dnodes, spill blocks, actualizaciones de spacemap. Ahí es cuando el porcentaje de progreso se mueve despacio y todos empiezan a acusar a los discos.

5) Compresión, checksums y CPU no son gratis

En CPUs modernas, la sobrecarga de checksum y compresión suele ser manejable, hasta que deja de serlo. Si estás haciendo cálculo de paridad RAIDZ más compresión alta y una máquina ocupada, la CPU puede volverse el cuello de botella. Esto se manifiesta como:

  • discos no plenamente utilizados (bajo %util) mientras el resilver es lento
  • alto uso de CPU del sistema, tiempo de kernel o softirq según la plataforma
  • presión en el ARC que causa lecturas adicionales desde disco

6) La pool es un recurso compartido; el resilver compite

Si permites que un resilver se ejecute “a tope” durante horas pico, la pool puede convertirse en rehén de I/O. ZFS intenta ser justo, pero justo no es lo mismo que «tu base de datos sigue feliz». Necesitas decidir qué optimizas: tiempo de reconstrucción más rápido, o latencia de producción aceptable. Intentar obtener ambos sin medición es la forma de quedarse sin ninguno.

Broma #2: Un resilver es como obras viales: siempre se programa justo cuando ya vas tarde.

Una idea de fiabilidad que vale la pena colgar en la pared

La esperanza no es una estrategia. — James Cameron

No es específico de ZFS, pero es dolorosamente relevante: no esperes que tu resilver sea rápido. Mide, diseña y practica.

Guía rápida de diagnóstico

Este es el camino de triaje cuando alguien te escribe: «el resilver está lento». No empieces a tocar parámetros a ciegas. Encuentra el limitador.

Primero: confirma qué tipo de lentitud tienes

  • Pocos MB/s pero alta utilización del disco? Probablemente estás limitado por IOPS/seeks (fragmentación, bloques pequeños, lecturas RAIDZ).
  • Pocos MB/s y baja utilización del disco? Probablemente estás limitado por CPU, throttling o bloqueado en otra cosa (fallos de ARC, special vdev, scheduler, tunables).
  • Picos de latencia altos en clientes? El resilver compite con la carga de producción; necesitas presupuestar I/O.

Segundo: aísla si limitan las lecturas o las escrituras

  • Si los discos sanos muestran muchas operaciones de lectura y alta latencia: el lado de lectura es el limitador.
  • Si el disco nuevo muestra alta latencia de escritura o errores: la ruta de escritura del objetivo es limitante (disco malo, cableado, HBA, comportamiento SMR).

Tercero: busca patologías

  • ¿Aparecen errores de checksum durante el resilver? Deja de asumir «problema de rendimiento». Puede que tengas un problema de fiabilidad.
  • ¿Hay discos SMR, firmware raro o quirks de gestión de energía? El comportamiento de reconstrucción puede colapsar bajo escrituras sostenidas.
  • ¿Pool casi llena o muy fragmentada? Espera latencia en la cola final y un final lento.

Cuarto: decide el objetivo operativo

  • Objetivo A: terminar el resilver lo antes posible (aceptar impacto a usuarios).
  • Objetivo B: mantener la producción estable (aceptar resilver más largo).

Toma esa decisión explícitamente y luego ajusta. Si no, oscilarás entre «demasiado lento» y «los usuarios gritan» y fingirás que es un misterio.

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

A continuación están las tareas prácticas que uso en producción. Cada una incluye (1) comando, (2) qué significa la salida, (3) la decisión que tomas.

Task 1: Confirmar estado de resilver y ritmo de escaneo

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: DEGRADED
status: One or more devices is currently being resilvered.
scan: resilver in progress since Tue Dec 24 11:02:12 2025
        1.23T scanned at 410M/s, 612G issued at 204M/s, 3.10T total
        148G resilvered, 19.11% done, 0 days 03:41:22 to go
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        DEGRADED     0     0     0
          raidz2-0                  DEGRADED     0     0     0
            sda                     ONLINE       0     0     0
            sdb                     ONLINE       0     0     0
            sdc                     ONLINE       0     0     0
            sdd                     ONLINE       0     0     0
            sde                     ONLINE       0     0     0
            sdf                     ONLINE       0     0     0
            sdg                     ONLINE       0     0     0
            sdh                     ONLINE       0     0     0
            sdi                     ONLINE       0     0     0
            sdj                     ONLINE       0     0     0
            sdk                     ONLINE       0     0     0
            sdl                     ONLINE       0     0     0
            sdm                     ONLINE       0     0     0
            sdn                     ONLINE       0     0     0
            sdo                     ONLINE       0     0     0
            sdp                     ONLINE       0     0     0
            sdq                     ONLINE       0     0     0
            sdr                     ONLINE       0     0     0
            sds                     ONLINE       0     0     0
            sdt                     ONLINE       0     0     0
            sdu                     ONLINE       0     0     0
            sdv                     ONLINE       0     0     0
            sdw                     ONLINE       0     0     0
            sdx                     ONLINE       0     0     0
            sdy                     ONLINE       0     0     0
            sdz                     ONLINE       0     0     0
            sdaa                    ONLINE       0     0     0
            sdab                    ONLINE       0     0     0
            sdac                    ONLINE       0     0     0
            sdad                    ONLINE       0     0     0
            sdae                    ONLINE       0     0     0
            sdaf                    ONLINE       0     0     0
            sdag                    ONLINE       0     0     0
            sdah                    ONLINE       0     0     0
            sdai                    ONLINE       0     0     0
            sdaj                    ONLINE       0     0     0
            sdak                    ONLINE       0     0     0
            sdal                    ONLINE       0     0     0
            sdam                    ONLINE       0     0     0
            sdan                    ONLINE       0     0     0
            sdao                    ONLINE       0     0     0
            sdap                    ONLINE       0     0     0
            sdaq                    ONLINE       0     0     0
            sdar                    ONLINE       0     0     0
            sdas                    ONLINE       0     0     0
            sdat                    ONLINE       0     0     0
            sdau                    ONLINE       0     0     0
            sdav                    ONLINE       0     0     0
            sdaw                    ONLINE       0     0     0
            sdax                    ONLINE       0     0     0
            sday                    ONLINE       0     0     0
            sdaz                    ONLINE       0     0     0
            sdbb                    ONLINE       0     0     0
            sdbc                    ONLINE       0     0     0
            sdbd                    ONLINE       0     0     0
            sdbe                    ONLINE       0     0     0
            sdbf                    ONLINE       0     0     0
            sdbg                    ONLINE       0     0     0
            sdbh                    ONLINE       0     0     0
            sdbi                    ONLINE       0     0     0
            sdbj                    ONLINE       0     0     0
            sdbk                    ONLINE       0     0     0
            sdbl                    ONLINE       0     0     0
            sdbm                    ONLINE       0     0     0
            sdbn                    ONLINE       0     0     0
            sdbo                    ONLINE       0     0     0
            sdbp                    ONLINE       0     0     0
            sdbq                    ONLINE       0     0     0
            sdbr                    ONLINE       0     0     0
            sdbs                    ONLINE       0     0     0
            sdbt                    ONLINE       0     0     0
            sdbu                    ONLINE       0     0     0
            sdbv                    ONLINE       0     0     0
            sdbw                    ONLINE       0     0     0
            sdbx                    ONLINE       0     0     0
            sdby                    ONLINE       0     0     0
            sdbz                    ONLINE       0     0     0
            sdc0                    ONLINE       0     0     0
            sdc1                    ONLINE       0     0     0
            sdc2                    ONLINE       0     0     0
            sdc3                    ONLINE       0     0     0
            sdc4                    ONLINE       0     0     0
            sdc5                    ONLINE       0     0     0
            sdc6                    ONLINE       0     0     0
            sdc7                    ONLINE       0     0     0
            sdc8                    ONLINE       0     0     0
            sdc9                    ONLINE       0     0     0
            sdd0                    ONLINE       0     0     0
            sdd1                    ONLINE       0     0     0
            sdd2                    ONLINE       0     0     0
            sdd3                    ONLINE       0     0     0
            sdd4                    ONLINE       0     0     0
            sdd5                    ONLINE       0     0     0
            sdd6                    ONLINE       0     0     0
            sdd7                    ONLINE       0     0     0
            sdd8                    ONLINE       0     0     0
            sdd9                    ONLINE       0     0     0
            sde0                    ONLINE       0     0     0
            sde1                    ONLINE       0     0     0
            sde2                    ONLINE       0     0     0
            sde3                    ONLINE       0     0     0
            sde4                    ONLINE       0     0     0
            sde5                    ONLINE       0     0     0
            sde6                    ONLINE       0     0     0
            sde7                    ONLINE       0     0     0
            sde8                    ONLINE       0     0     0
            sde9                    ONLINE       0     0     0
            sdf0                    ONLINE       0     0     0
            sdf1                    ONLINE       0     0     0
            sdf2                    ONLINE       0     0     0
            sdf3                    ONLINE       0     0     0
            sdf4                    ONLINE       0     0     0
            sdf5                    ONLINE       0     0     0
            sdf6                    ONLINE       0     0     0
            sdf7                    ONLINE       0     0     0
            sdf8                    ONLINE       0     0     0
            sdf9                    ONLINE       0     0     0
            sdg0                    ONLINE       0     0     0
            sdg1                     ONLINE       0     0     0
            replacing-1              ONLINE       0     0     0
              sdxX                   ONLINE       0     0     0
              sdnew                  ONLINE       0     0     0

errors: No known data errors

Significado: “scanned” vs “issued” te indica cuánto recorrido de metadatos está ocurriendo frente a la reconstrucción real de datos. Si scanned es alto pero issued es bajo, estás haciendo mucha contabilidad y muchos seeks.

Decisión: Si “issued” está muy por debajo de lo que los discos pueden hacer, busca limitadores de IOPS/latencia (fragmentación, bloques pequeños, RAIDZ). Si aparecen errores, cambia de modo rendimiento a modo integridad de datos inmediatamente.

Task 2: Vigilar I/O por vdev durante el resilver

cr0x@server:~$ zpool iostat -v tank 1
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        51.2T  13.8T  8.12K  1.90K   812M   162M
  raidz2-0                  51.2T  13.8T  8.12K  1.90K   812M   162M
    sda                         -      -    310     75  31.2M  6.1M
    sdb                         -      -    298     72  30.8M  6.0M
    sdc                         -      -    315     76  31.4M  6.2M
    ...
    sdnew                       -      -     12    980   1.1M  98.4M
--------------------------  -----  -----  -----  -----  -----  -----

Significado: Los discos sanos están haciendo muchas lecturas; el disco nuevo está mayormente en escrituras. Si las ops de lectura son altas pero los MB/s de lectura por disco son bajos, estás limitado por IOPS y buscando.

Decisión: Si el MB/s de lectura por disco es anémico pero las ops son altas, deja de esperar rendimiento lineal. Considera limitar el resilver para proteger latencia, o programarlo fuera de horas; ajustar para “velocidad” no vencerá a la física.

Task 3: Comprobar latencia y saturación a nivel de disco

cr0x@server:~$ iostat -x 1 3
Device            r/s     w/s   rkB/s   wkB/s  await  aqu-sz  %util
sda             310.0    70.0  32000    6200   28.4    8.2   99.0
sdb             295.0    68.0  30800    6000   30.1    8.5   98.7
sdnew            10.0   980.0   1100  102000   12.7    2.1   72.4

Significado: Los discos viejos están al ~99% de util con ~30ms de await. Eso es limitación clásica por seeks/IOPS. El disco nuevo no está saturado.

Decisión: Tu cuello de botella es el comportamiento de lectura de los discos sobrevivientes. Si la latencia de producción importa, limita la agresividad del resilver en lugar de perseguir el throughput del disco nuevo.

Task 4: Inspeccionar salud de la pool y contadores de errores

cr0x@server:~$ zpool status tank
  pool: tank
 state: DEGRADED
scan: resilver in progress since Tue Dec 24 11:02:12 2025
config:

        NAME        STATE     READ WRITE CKSUM
        tank        DEGRADED     0     0     0
          raidz2-0  DEGRADED     0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     2
            sdnew   ONLINE       0     0     0

errors: No known data errors

Significado: Errores CKSUM en un disco sobreviviente durante el resilver son una bandera roja. Aunque ZFS pueda corregirlos, cuestan tiempo y riesgos.

Decisión: Extrae SMART, logs de cableado y HBA. Si los errores aumentan, deja de “optimizar velocidad” y empieza a prepararte para otra falla y posible pérdida de datos.

Task 5: Revisar SMART del reemplazo y de los sobrevivientes estresados

cr0x@server:~$ sudo smartctl -a /dev/sdnew | sed -n '1,80p'
=== START OF INFORMATION SECTION ===
Device Model:     ST18000NM000J
Firmware Version: SN05
User Capacity:    18,000,207,937,536 bytes
Sector Sizes:     512 bytes logical, 4096 bytes physical
SMART overall-health self-assessment test result: PASSED
...
ID# ATTRIBUTE_NAME          VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  5 Reallocated_Sector_Ct   100   100   010    Pre-fail  Always       -       0
197 Current_Pending_Sector  100   100   000    Old_age   Always       -       0
199 UDMA_CRC_Error_Count    200   200   000    Old_age   Always       -       12

Significado: Los errores CRC suelen implicar cableado/backplane/HBA. Bajo resilver, la inestabilidad del enlace puede parecer “lentitud aleatoria”.

Decisión: Si los contadores CRC aumentan bajo carga, vuelve a insertar/reemplaza cables o cambia bahías. No sigas resilverizando sobre un enlace inestable.

Task 6: Identificar ashift y diseño del vdev de nivel superior

cr0x@server:~$ zdb -C tank | egrep -A3 'ashift|vdev_tree|type'
        vdev_tree:
            type: 'root'
            id: 0
            ashift: 12

Significado: ashift=12 implica sectores de 4K. Si esto está mal (p. ej., 9 en unidades de 4K), el resilver puede sufrir penalizaciones de alineación y E/S extra.

Decisión: Si ashift es incorrecto, la “solución” suele ser una reconstrucción/migración, no un ajuste rápido. Planea la migración; no discutas con la geometría.

Task 7: Comprobar fragmentación y grado de llenado de la pool

cr0x@server:~$ zpool list -o name,size,alloc,free,frag,health tank
NAME  SIZE  ALLOC  FREE  FRAG  HEALTH
tank  65.0T 51.2T  13.8T   42%  DEGRADED

Significado: Alta frag aumenta lecturas con seeks. Un alto porcentaje de asignación reduce el espacio contiguo disponible y puede empeorar el comportamiento de asignación al escribir.

Decisión: Si frag es alta y alloc es alto, espera colas finales lentas en el resilver. Considera añadir capacidad o rebalancear mucho antes del próximo fallo.

Task 8: Inspeccionar propiedades de dataset que cambian la forma del bloque

cr0x@server:~$ zfs get -o name,property,value -s local recordsize,compression,checksum tank/vmstore
NAME          PROPERTY     VALUE
tank/vmstore  recordsize   128K
tank/vmstore  compression  lz4
tank/vmstore  checksum     on

Significado: recordsize afecta cuántos bloques existen y qué tamaño tienen. Bloques pequeños incrementan metadatos y necesidad de IOPS; bloques grandes pueden mejorar la secuencialidad para cargas de streaming.

Decisión: Si este dataset aloja I/O aleatorio pequeño (VMs, BD), recordsize puede no coincidir; pero cambiarlo a mitad de vida no reescribirá bloques existentes. Planea migración o ventana de reescritura si necesitas otro perfil de bloque.

Task 9: Revisar special vdev y su salud (aceleración de metadata)

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

        NAME            STATE     READ WRITE CKSUM
        tank            DEGRADED     0     0     0
          special       ONLINE       0     0     0
            nvme0n1p1    ONLINE       0     0     0
            nvme1n1p1    ONLINE       0     0     0
          raidz2-0      DEGRADED     0     0     0
            ...

Significado: Un special vdev puede afectar dramáticamente el rendimiento del resilver al servir metadatos rápidamente. Si está ausente o en mal estado, las lecturas de metadatos vuelven a HDDs y la cola final se vuelve brutal.

Decisión: Si tu carga es heavy en metadatos y no tienes special vdev, considera diseñar uno para la próxima renovación de hardware. Si tienes uno, protégelo como si fuera información crítica de producción.

Task 10: Confirmar presión del ARC y memoria disponible

cr0x@server:~$ arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
11:10:01  6120  1480     24   820  55    60   4   600  41   112G   128G
11:10:02  5988  1622     27   910  56    72   4   640  39   112G   128G
11:10:03  6210  1588     25   880  55    55   3   653  41   112G   128G

Significado: Altas tasas de miss durante el resilver pueden forzar lecturas adicionales desde disco. Eso ralentiza el resilver e incrementa la latencia para todo lo demás.

Decisión: Si el ARC es demasiado pequeño para el working set, no puedes «tunar» para solucionarlo permanentemente. Añade memoria, reduce churn de carga o mueve metadatos a dispositivos más rápidos.

Task 11: Vigilar saturación de CPU y tiempo de kernel

cr0x@server:~$ mpstat -P ALL 1 2
Linux 6.8.0 (server)  12/24/2025  _x86_64_  (32 CPU)

Average:     CPU   %usr  %sys  %iowait  %idle
Average:     all   18.2  42.7     6.1    33.0
Average:      0    21.0  55.0     3.0    21.0
Average:      1    16.0  51.0     4.0    29.0

Significado: Alto %sys durante un resilver RAIDZ puede indicar sobrecarga por paridad/checksum y overhead de la pila I/O. Si los discos no están saturados pero %sys es alto, la CPU es sospechosa.

Decisión: Considera reducir la concurrencia del resilver para aliviar la CPU si la producción sufre, o programa ventanas intensivas cuando haya CPU libre.

Task 12: Revisar eventos zed y logs del kernel por resets de enlace

cr0x@server:~$ sudo dmesg -T | tail -n 20
[Tue Dec 24 11:22:14 2025] ata12: hard resetting link
[Tue Dec 24 11:22:15 2025] ata12: SATA link up 6.0 Gbps (SStatus 133 SControl 300)
[Tue Dec 24 11:22:15 2025] sd 11:0:0:0: [sdb] tag#18 timing out command, waited 180s
[Tue Dec 24 11:22:15 2025] blk_update_request: I/O error, dev sdb, sector 1987654321 op 0x0:(READ)

Significado: Resets de enlace y timeouts de comandos no son «rendimiento». Son eventos de fiabilidad que se manifiestan como colapso de rendimiento.

Decisión: Reemplaza cables/backplane/puerto HBA, posiblemente el disco. No continúes un resilver con una ruta intermitente salvo que te guste vivir peligroso.

Task 13: Confirmar tunables de scrub/resilver (Linux/OpenZFS)

cr0x@server:~$ sudo sysctl -a | egrep 'zfs_scan|resilver|scrub' | head
kstat.zfs.misc.scan.state = 2
kstat.zfs.misc.scan.pass = 1
kstat.zfs.misc.scan.start_time = 1735038132

Significado: No todos los sistemas exponen los mismos tunables via sysctl, pero aún puedes verificar el estado del scan y correlacionar tiempos. Si tu plataforma usa parámetros de módulo, los mirarás luego.

Decisión: No cambies tunables porque un blog lo dijo. Solo modifícalos cuando sepas si estás presupuestando latencia o maximizando velocidad, y puedas revertir.

Task 14: Identificar discos SMR (un asesino silencioso del rebuild)

cr0x@server:~$ lsblk -d -o NAME,MODEL,ROTA
NAME  MODEL              ROTA
sda   ST18000NM000J         1
sdb   ST18000NM000J         1
sdnew ST18000NM000J         1

Significado: Esto no te dice directamente SMR vs CMR, pero te da el modelo para verificar internamente. Si mezclaste SMR sin saberlo, las escrituras sostenidas durante resilver pueden hundir el rendimiento.

Decisión: Mantén una lista aprobada de modelos para pools. Si sospechas SMR, para y verifica el comportamiento del modelo; «funciona la mayoría de las veces» no es una estrategia de almacenamiento.

Tres micro-historias del mundo corporativo

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

La empresa ejecutaba un gran clúster analítico sobre ZFS en RAIDZ2. Cuando un disco falló, el ingeniero on-call lo sustituyó y dijo a todos que la pool estaría sana «para el almuerzo» porque cada unidad podía hacer 250 MB/s en escrituras secuenciales. Ese número venía de una hoja de datos del proveedor y un benchmark rápido en un disco vacío.

El resilver empezó a cientos de MB/s, lo que parecía validarlo. Luego se ralentizó a un jittery 30–60 MB/s “issued”, mientras que scanned se mantenía alto. Las consultas de producción empezaron a fallar por tiempo, no porque la red fuera lenta, sino porque la latencia de lectura de la pool se disparó. Los usuarios llenaron tickets. La dirección llenó el calendario de reuniones.

La suposición equivocada no fue «ZFS es lento». La suposición equivocada fue creer que la velocidad de escritura secuencial del disco de reemplazo determina el tiempo de reconstrucción. La pool estaba al 80% con años de churn. Reconstruir la columna faltante forzó lecturas dispersas desde todos los discos sobrevivientes. Esos discos ahora estaban realizando muchas lecturas aleatorias de alta IOPS mientras también servían la carga en vivo.

La solución fue aburrida: limitar el resilver durante horas laborales, reanudar agresivamente en la noche y añadir una política que prohíba pools por encima de un umbral de llenado definido. Después de eso, las promesas de almuerzo cesaron. Las pools no se volvieron mágicamente más rápidas, pero el negocio dejó de sorprenderse.

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

Otro equipo quería resilvers más rápidos, así que fueron a buscar tunables. Aumentaron la concurrencia del scan y volvieron el resilver «más paralelo», esperando que la pool procesara trabajo más rápido. En papel, sí: más operaciones I/O por segundo.

En realidad, la latencia de la aplicación se duplicó. La base de datos no estaba limitada por ancho de banda; estaba por tail-latency. La mayor concurrencia del resilver provocó colas más profundas en los HDDs. El «throughput medio» se veía mejor en un dashboard mientras las consultas reales de usuarios se volvían más lentas. El equipo reaccionó añadiendo más reintentos en la aplicación, lo que incrementó la carga de lectura y agravó las colas. Clásico.

Revirtieron el afinado y tomaron una decisión que suena casi ofensiva: dejaron que el resilver fuera más lento. Pero fijaron un máximo de latencia aceptable para la base de datos y ajustaron la agresividad del resilver para mantenerse dentro de ese límite. La reconstrucción tardó más, pero el negocio dejó de notarlo.

La lección del traspié: tunear el resilver no es un almuerzo gratis. Si tu pool está limitado por seeks, más concurrencia solo significa más seeks pendientes. No obtienes “más rápido”. Obtienes “más ruidoso”.

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

Una plataforma de servicios financieros ejecutaba mirrors ZFS para datos transaccionales y RAIDZ para almacenamiento frío. Nada exótico. Su arma secreta eran prácticas sobrias: scrubs programados, tendencia SMART y una política que dice que cualquier disco con UDMA_CRC creciente se mueve a otra bahía antes de volver a la pool.

Una semana, un disco en un mirror falló durante el pico de procesamiento. El resilver arrancó y parecía normal. Una hora después, otro disco en el mismo chasis empezó a lanzar CRC y el kernel registró resets de enlace. Aquí muchas empresas «esperan y rezan» a que el resilver termine primero.

Ellos no esperaron. Pausaron, movieron el disco sospechoso a una bahía conocida buena, reemplazaron el cable y reanudaron. El resilver terminó sin una segunda falla. El sistema de transacciones se mantuvo dentro de los SLOs de latencia porque el equipo también tenía un procedimiento estándar: durante el pico, limitar el impacto del resilver; por la noche, dejarlo correr.

La práctica que les salvó no fue un tunable milagroso. Fue higiene disciplinada y la disposición a tratar enlaces inestables como incidentes de producción, no como «rendimiento raro».

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

Error 1: «El resilver empieza rápido y luego se frena hasta arrastrarse»

Síntoma: MB/s iniciales altos, luego la cola final tarda una eternidad; los discos muestran alta util pero bajo throughput.

Causa raíz: Fragmentación + cola final dominada por metadatos; el trabajo restante son muchos bloques pequeños dispersos, limitados por IOPS.

Solución: Acepta la física; no ajustes en pánico. Mantén las pools por debajo de umbrales de llenado altos, prefiere mirrors para cargas con churn y considera special vdev para casos pesados en metadatos.

Error 2: «El disco nuevo es rápido, pero el resilver es lento»

Síntoma: Escritura en disco de reemplazo moderada; discos sobrevivientes saturados en lecturas.

Causa raíz: El lado de lectura es el limitador (amplificación de lectura RAIDZ, lecturas con seeks, contención por la carga).

Solución: Diagnostica latencia por disco; limita el resilver para proteger producción; diseña futuros vdevs teniendo en cuenta el comportamiento de reconstrucción (mirrors vs ancho RAIDZ).

Error 3: «La velocidad del resilver colapsa de forma impredecible»

Síntoma: Barridos periódicos; enormes picos de latencia; los logs del kernel muestran resets/timeouts.

Causa raíz: Inestabilidad de enlace (cables, backplane, expander, HBA), o un disco marginal bajo carga sostenida.

Solución: Trátalo como incidente de hardware. Revisa dmesg, SMART CRC, logs HBA; cambia bahía/puerto; reemplaza componentes sospechosos.

Error 4: «Afiné el resilver para velocidad; los usuarios se quejan»

Síntoma: Resilver termina antes pero la latencia y los timeouts de apps aumentan.

Causa raíz: Profundidad de cola y justicia: más concurrencia del resilver aumenta tail latency y roba IOPS del foreground.

Solución: Ajusta con un SLO, no con un cronómetro. Limita agresividad del resilver en horas pico y programa ventanas agresivas fuera de horario.

Error 5: «Aparecen errores de checksum durante el resilver; el rendimiento cae»

Síntoma: Incremento en CKSUM; resilver se ralenta; posibles reintentos de lectura.

Causa raíz: Problemas de medio, cableado defectuoso o un segundo disco fallando; ZFS está corrigiendo (si puede), lo que cuesta tiempo.

Solución: Deja de enfocarte en la velocidad. Estabiliza el hardware, identifica el dominio de fallo y considera reemplazo preventivo del miembro sospechoso.

Error 6: «La pool está al 90% y el resilver es terrible»

Síntoma: Resilver tarda mucho más que eventos pasados; la asignación se ve caótica.

Causa raíz: El espacio libre está fragmentado; las metaslabs tienen menos extensiones contiguas; lecturas y escrituras se vuelven menos eficientes.

Solución: Añade capacidad con anticipación. Si no puedes, migra datasets, reduce churn y deja de tratar 90% como operación normal.

Listas de verificación / plan paso a paso

Paso a paso: manejar una falla de disco con el mínimo drama

  1. Congela la historia: captura zpool status -v, zpool iostat -v 1 (30 segundos), iostat -x 1 (30 segundos). Esto es tu verdad antes/después.
  2. Confirma el dominio de falla: ¿es un disco, un cable, una bahía, una línea de expander? Revisa SMART CRC y logs del kernel.
  3. Reemplaza el dispositivo correctamente: usa zpool replace y confirma el mapeo correcto GUID/dispositivo. Los errores humanos aman las bahías de discos.
  4. Decide el modo operativo: “terminar rápido” vs “proteger latencia”. Escríbelo en el ticket. Sé responsable.
  5. Monitorea salud primero: ¿aumentan READ/WRITE/CKSUM? Si sí, pausa ajustes de rendimiento y estabiliza hardware.
  6. Monitorea cuellos de botella: util y await por disco; si los discos viejos están al límite, deja de fingir que el disco nuevo importa.
  7. Protege a los usuarios: si eres sensible a latencia, reduce la agresividad del resilver durante ventanas pico en vez de forzar throughput.
  8. Después del resilver: ejecuta un scrub (o asegúrate de que el siguiente scrub programado ocurra pronto) para confirmar que no quedan problemas silenciosos.
  9. Postmortem de la causa raíz: no “un disco murió”, sino “por qué murió y qué más comparte ese dominio de fallo”.
  10. Seguimiento de capacidad/fragmentación: si estabas >80% lleno, trata eso como un factor contribuyente al incidente y planea remediación.

Checklist de diseño: construir pools que no conviertan el resilver en una carrera

  • Elige tipos de vdev según el churn: mirrors para I/O aleatorio con churn alto; RAIDZ para datos más fríos, secuenciales y con menos reescrituras.
  • Mantén margen en las pools: no vivas en la zona 85–95% y te sorprendas cuando las reconstrucciones sean terribles.
  • Estandariza modelos de discos: evita mezclar comportamientos SMR desconocidos en pools con escrituras intensas.
  • Planifica para metadatos: special vdev puede ayudar, pero solo si está espejado, correctamente dimensionado y monitorizado.
  • Practica fallos: ensaya procedimientos de replace/resilver; documenta nombres de dispositivos y mapeo de bahías; confirma que el alerting funciona.

Preguntas frecuentes (FAQ)

1) ¿Un resilver siempre es más rápido que una reconstrucción RAID tradicional?

A menudo sí, porque ZFS reconstruye bloques asignados en lugar de todo el dispositivo. Pero si tu pool está muy llena y fragmentada, la ventaja disminuye y la cola final puede seguir siendo brutal.

2) ¿Por qué “scanned” difiere de “issued” en zpool status?

“Scanned” es cuánto espacio de direcciones/recorrido de metadatos se ha caminado; “issued” es el I/O real emitido para la reconstrucción. Grandes brechas suelen significar trabajo intensivo en metadatos o patrones de acceso ineficientes.

3) ¿Mirrors o RAIDZ para resilvers más rápidos?

Los mirrors generalmente resilverizan más rápido y con menos amplificación de lectura. Los resilvers en RAIDZ pueden ser significativamente más lentos porque la reconstrucción suele requerir leer múltiples columnas por cada bloque.

4) ¿Puedo simplemente limitar el resilver para mantener la producción estable?

Sí, y a menudo deberías hacerlo. El riesgo es un estado degradado más largo. Para servicios sensibles a latencia, un resilver controlado y lento suele ser más seguro que uno rápido que provoca timeouts y fallas en cascada.

5) ¿Agregar un disco de reemplazo más rápido acelera el resilver?

A veces, pero comúnmente no. El factor limitante suele ser las IOPS de lectura y la latencia de los discos sobrevivientes, no el throughput de escritura del objetivo.

6) ¿Por qué el resilver se ralentiza al final?

La cola final contiene más bloques pequeños y trabajo pesado en metadatos. Las lecturas aleatorias pequeñas dominan, lo que colapsa el throughput aunque el sistema esté «ocupado».

7) ¿La fragmentación es un problema del dataset o de la pool?

Ambos. La fragmentación la impulsa el patrón de asignación y la distribución del espacio libre a nivel de pool, pero los datasets con churn la amplifican. La pool paga el precio durante el resilver.

8) ¿Son normales los errores de checksum durante el resilver?

No. ZFS puede corregirlos si hay redundancia, pero indican una falla real: medio, cable, ruta HBA u otro dispositivo en problemas. Trátalo como un incidente de fiabilidad.

9) ¿La compresión ayuda o perjudica la velocidad del resilver?

Puede ayudar si reduce bytes físicos leídos/escritos, pero puede perjudicar si la CPU se convierte en cuello de botella o si la carga es dominada por metadatos/IOPS. Mide CPU y utilización de disco antes de culpar a la compresión.

10) ¿Puedo forzar un “resilver secuencial”?

No en el sentido que la mayoría piensa. ZFS emplea estrategias para reducir I/O aleatorio, pero la realidad de asignación en disco y el diseño del vdev dictan cuán secuencial puede ser.

Próximos pasos prácticos

Si estás lidiando con un resilver lento hoy:

  1. Ejecuta zpool status -v, zpool iostat -v 1 y iostat -x 1. Decide si estás limitado por IOPS, CPU o patologías de hardware.
  2. Revisa dmesg y contadores SMART CRC. Si los enlaces flaquean, arregla el hardware antes de tocar tunables.
  3. Elige un objetivo: terminar rápido o producción estable. Limita/acelera según corresponda y documenta la decisión.

Si estás diseñando para la próxima falla (el momento correcto para preocuparse):

  1. Deja de sobrellenar pools. El margen es seguro de rendimiento y fiabilidad.
  2. Elige vdevs según el churn. Los mirrors cuestan capacidad; te compran cordura en reconstrucciones.
  3. Invierte en observabilidad: latencia por disco, contadores de error ZFS y mapeo claro de bahías a IDs de dispositivo.

El mejor resilver es el que terminas antes de que alguien lo note. No es magia. Es diseño, medición y negarse a tratar «MB/s de disco» como un plan.

← Anterior
La VM de Proxmox no arranca tras cambiar el tipo de CPU: pasos de recuperación que funcionan
Siguiente →
Captura de fallos con Kdump en Debian 13: configúralo y demuestra que funciona (caso #17)

Deja un comentario