Espejos ZFS: el diseño que hace que el I/O aleatorio se sienta como NVMe

¿Te fue útil?

Hay un tipo particular de alegría que solo obtienes en producción: cuando una carga de trabajo que antes parecía arrastrar un refrigerador por grava de repente se pone en alerta. La CPU deja de estar inactiva. La base de datos deja de quejarse. Los gráficos de latencia dejan de parecer un sismógrafo. No compraste nuevos servidores. No reescribiste la aplicación. Cambiaste la disposición del almacenamiento.

Los espejos ZFS son ese cambio, más a menudo de lo que la gente espera. No porque los espejos sean mágicos, sino porque se alinean con la física de los discos y la matemática de las colas. Los espejos convierten las lecturas aleatorias en un problema paralelizable, y la mayoría de los tickets reales de “mi almacenamiento es lento” son, debajo del hilo de Slack, un problema de latencia de lectura aleatoria. Si alguna vez has visto una pool RAIDZ hacer un trabajo hermoso con ancho de banda secuencial mientras tu base de datos sigue agotando tiempos de espera, bienvenido. Esto explica por qué los espejos pueden hacer que el I/O aleatorio se sienta como NVMe —sin pretender que realmente lo sean.

Por qué los espejos se sienten rápidos (y cuándo no)

Los espejos ganan en lecturas aleatorias por una razón aburrida pero poderosa: le dan opciones a ZFS. Para cada bloque que existe en dos (o tres) discos, ZFS puede elegir qué copia leer. Eso no es solo redundancia: es libertad de programación. Con un solo disco, las lecturas aleatorias se alinean en una cola y esperan su turno. Con un espejo, ZFS puede enviar diferentes lecturas a distintos miembros, y puede enrutar alrededor de un disco que está teniendo un mal día (o simplemente uno ocupado).

En la práctica, los vdevs espejo se comportan como “amplificadores de IOPS” para lecturas. Una pool construida a partir de múltiples vdevs espejo multiplica eso de nuevo porque ZFS distribuye datos entre vdevs. El resultado final es que una base de datos que realiza muchas lecturas pequeñas puede ver cómo la latencia se desploma cuando pasas de un vdev RAIDZ ancho a varios vdevs espejo, incluso si el conteo bruto de discos permanece igual.

Las escrituras son otra historia. Para un espejo simple de 2 vías, cada escritura debe aterrizar en ambos miembros. Eso significa que las escrituras en espejo no son más rápidas que un solo disco en el mismo vdev (ignorando el comportamiento de ZIL/SLOG). Pero el paralelismo a nivel de pool todavía ayuda: si tienes muchos vdevs espejo, tus escrituras se distribuyen entre ellos. Así que puedes obtener un gran rendimiento de escritura con muchos espejos, pero un solo vdev espejo no duplica mágicamente las IOPS de escritura.

Aquí está el modelo mental clave: el rendimiento de ZFS está dominado por el número y el tipo de vdevs, no por el número de discos. Los espejos se suelen desplegar como muchos vdevs pequeños (espejos de 2 discos, o a veces de 3), lo que aumenta el recuento de vdevs y le da a ZFS más colas independientes con las que trabajar.

¿Y cuándo no se sienten rápidos los espejos? Cuando el cuello de botella no son los discos. Si estás saturando una sola cola HBA, si tu CPU está ocupada en checksumming o compresión con una mala elección de algoritmo, si la red es el factor limitante, o si tu carga de trabajo son principalmente escrituras síncronas sin un SLOG adecuado, los espejos no te salvarán. Seguirán siendo correctos. Simplemente no serán heroicos.

Broma #1: Un espejo es como una rotación de guardias: la redundancia no hace que el trabajo desaparezca, solo asegura que otra persona pueda atender la llamada.

Hechos e historia que puedes usar a las 3 a.m.

Algunos puntos de contexto que son cortos, concretos y sorprendentemente útiles cuando estás defendiendo un cambio de diseño en una reunión donde alguien piensa que RAID5 sigue siendo la respuesta para todo:

  1. ZFS nació en Sun a mediados de los 2000 como un sistema de archivos y gestor de volúmenes de extremo a extremo, diseñado para detectar y corregir la corrupción silenciosa con checksums en todos los niveles.
  2. RAIDZ existe porque el RAID tradicional tenía un agujero de escritura: el RAID por paridad podía reconocer escrituras que no se habían comprometido por completo en una pérdida de energía, dejando inconsistencias silenciosas. El modelo transaccional de ZFS reduce esa clase de fallos.
  3. “Los vdevs son la unidad de rendimiento” no es un eslogan: es cómo ZFS programa IO. ZFS distribuye asignaciones a través de vdevs de nivel superior, no a través de discos dentro de un vdev como lo hacen los controladores RAID clásicos.
  4. Los espejos permiten la selección de lectura: ZFS puede elegir la pata del espejo menos ocupada y puede usar la latencia histórica para preferir el miembro más rápido.
  5. Los discos modernos de “sector 4K” cambiaron el juego: usar el ashift equivocado puede penalizar permanentemente las escrituras pequeñas con comportamiento de lectura-modificar-escritura. Esto perjudica también a los espejos, pero los vdevs de paridad sufren más.
  6. Las SSD hicieron que las “lecturas aleatorias” fueran normales: las bases de datos y los clusters de búsqueda empezaron a esperar almacenamiento de baja latencia, y las matrices HDD por paridad comenzaron a mostrar su edad en esas cargas.
  7. L2ARC nunca fue pensado como un nivel SSD mágico: puede ayudar a conjuntos de lectura intensiva que no caben en RAM, pero consume RAM para metadatos y no arregla la latencia de escritura.
  8. SLOG no es una caché de escritura: es un dispositivo de registro separado para escrituras síncronas; acelera la latencia de commit, no el rendimiento a granel.
  9. El comportamiento de resilver difiere: los espejos suelen resilverizar más rápido que vdevs de paridad amplios porque pueden copiar solo los bloques asignados (dependiendo de la plataforma/características) y las matemáticas de reconstrucción son más sencillas.

Arquitectura de espejos: vdevs, colas y la “matemática de IOPS”

Lo que ZFS realmente hace cuando creas espejos

Un pool ZFS (zpool) se construye a partir de uno o más vdevs de nivel superior. Esos vdevs pueden ser:

  • un disco único (no hagas esto en producción a menos que disfrutes del dolor),
  • un espejo (2 vías, 3 vías…),
  • un grupo RAIDZ (raidz1/2/3).

Cuando construyes una pool a partir de múltiples vdevs de nivel superior, ZFS distribuye las asignaciones entre ellos. Esa es la striping. No es un stripe RAID0 fijo como lo haría un controlador; es basado en asignaciones, pero el efecto es similar: más vdevs significa más colas de IO independientes.

Por qué los espejos ayudan en lecturas aleatorias

Las cargas de trabajo de lectura aleatoria (bases de datos, imágenes de VM, servidores de correo, caches de compilación, sistemas de archivos con muchos metadatos) están dominadas por seek/latencia en HDDs y por profundidad de cola/latencia en SSDs. Con un espejo, cada lectura puede ser servida por cualquiera de los miembros. ZFS puede:

  • enviar lecturas concurrentes a distintas patas del espejo,
  • preferir el disco con la cola más corta,
  • evitar un disco que esté devolviendo errores o tardando más de lo esperado.

Si tienes N vdevs espejo, tienes N colas de vdev independientes. Para lecturas aleatorias, también tienes dos posibles spindles por vdev. Así obtienes dos tipos de concurrencia: entre vdevs y dentro de cada vdev (elección de la pata). El efecto combinado puede parecer dramático comparado con un único vdev RAIDZ amplio, que tiene una sola cola de vdev y debe tocar múltiples discos para cada operación.

¿Pero los espejos “duplican las IOPS”?

En lecturas, los espejos pueden acercarse a 2× IOPS de lectura por vdev en las condiciones adecuadas, porque las lecturas pueden repartirse entre las patas. En la vida real, es menos limpio: caché, prefetch, tamaños de petición y el hecho de que algunas lecturas son secuenciales reducen la ganancia teórica. Aun así, es común ver una mejora significativa.

En escrituras, un vdev espejo 2-vías debe escribir dos veces. Así que las IOPS de escritura por vdev son aproximadamente las de un solo disco (otra vez, ignorando ZIL/SLOG). El rendimiento de escritura a nivel de pool mejora añadiendo más vdevs espejo, no al esperar que un solo espejo escriba más rápido que la física.

Comparación con RAIDZ sin teología

RAIDZ es excelente en eficiencia de capacidad y en rendimiento secuencial. También es muy bueno en la simplicidad de “un solo vdev grande”. Pero los vdevs por paridad tienen más dificultades con IO aleatorio pequeño porque:

  • una escritura pequeña puede convertirse en lectura-modificar-escribir a través de múltiples discos,
  • las lecturas aleatorias aún deben coordinarse entre discos (incluso si en algunos casos se pueden servir desde un disco, hay más sobrecarga y menos libertad de programación),
  • el vdev es una unidad de programación; un RAIDZ2 ancho sigue siendo un vdev.

Por eso las pools espejo son la respuesta por defecto para cargas sensibles a la latencia. RAIDZ no es “malo”; simplemente es más adecuado para diferentes perfiles de rendimiento.

Una nota sobre comparaciones con NVMe

No, los espejos no convierten HDDs en NVMe. Pero pueden hacer que el sistema se sienta similar a NVMe para una aplicación que está bloqueada principalmente por la latencia de cola de lectura aleatoria, especialmente cuando los aciertos de ARC son altos y las lecturas restantes en disco se distribuyen bien. La experiencia subjetiva es lo que cambia: menos bloqueos, menos pausas largas, menos “todo está bien excepto que la base de datos es lenta”.

Broma #2: Llamar a los espejos HDD “NVMe” es como llamar a una bicicleta “una motocicleta con excelente eficiencia de combustible”. Técnicamente te mueve, pero por favor no la lleves a una carrera.

Decisiones de diseño: ancho, número y qué comprar

Espejos 2-vías vs 3-vías

Espejos 2-vías son el estándar: buena redundancia, buen rendimiento de lectura y costo de capacidad aceptable.

Espejos 3-vías son para cuando el riesgo de reconstrucción y la disponibilidad importan más que la capacidad. Pueden reducir las probabilidades de que una segunda falla mate el vdev durante un resilver, y pueden mejorar aún más la selección de lectura. Te cuestan mucho en espacio utilizable, por lo que normalmente se justifican para pools calientes y pequeños (metadatos de VM, logs críticos de BD, etc.) o cuando las tasas de fallo de disco son malas y los reemplazos tardan en llegar.

Muchos espejos pequeños baten a un espejo grande

Si tienes 12 discos, la conversación de rendimiento generalmente no es “una cosa de 12 discos” sino “¿cuántos vdevs de nivel superior obtengo?”

  • 6 vdevs espejo (2-vías) te dan 6 colas de vdev y excelente escalado de lectura aleatoria.
  • 1 vdev RAIDZ2 te da 1 cola de vdev y alto rendimiento secuencial con buena capacidad.

Si tu carga es almacenamiento de VM, bases de datos, caches de CI, servidores estilo maildir, o cualquier cosa con muchos archivos pequeños: los espejos suelen ganar.

Matemática de capacidad que debes hacer antes de comprar discos

Los espejos “desperdician” la mitad de la capacidad bruta (o dos tercios para 3-vías). Pero ese desperdicio no es vanidad: te compra margen de rendimiento y margen operativo. Cuando los sistemas son lentos, los equipos hacen cosas tontas: apagan medidas de seguridad, deshabilitan sync, reducen la replicación. Pagar por espejos suele ser más barato que pagar por una semana de respuesta a incidentes.

Aun así, debes hacer las cuentas por adelantado:

  • Planifica mantenerte por debajo de ~70–80% de uso de la pool para cargas sensibles a la latencia. ZFS se vuelve más lento a medida que el espacio libre disminuye porque la asignación se vuelve más difícil y la fragmentación aumenta.
  • Presupuesta redundancia y repuestos. Si no puedes reemplazar un disco fallado rápidamente, tu espejo estará temporalmente en un solo disco. Eso no es redundancia; es esperanza.

Consideraciones sobre discos y controladoras

Los espejos exponen latencia. Eso es bueno, hasta que tu HBA o expander comienza a hacer cosas “creativas” con el encolamiento y la recuperación de errores. Algunas notas prácticas:

  • Usa HBAs en modo IT (passthrough). ZFS quiere ver los discos.
  • Evita mezclar tipos de disco muy diferentes en el mismo vdev espejo. ZFS puede enrutar lecturas, pero las escrituras deben esperar a ambos, y el tiempo de resilver sigue al miembro más lento.
  • Configura un manejo de recuperación de errores de disco sensato (TLER/ERC) para entornos tipo RAID. Las recuperaciones internas largas del disco pueden bloquear colas de IO y disparar timeouts.

Propiedades y ajustes que realmente importan

ashift: la decisión permanente

ashift establece la alineación de sectores de la pool. Equivocarte y puedes bloquear la amplificación de escritura por la vida del vdev. Para discos modernos, ashift=12 (sectores de 4K) suele ser la elección mínima sensata; muchos administradores eligen ashift=13 (8K) para algunas SSD para alinearse con páginas internas. No puedes cambiar ashift después de la creación sin reconstruir.

recordsize (y volblocksize) acorde a la carga

Para sistemas de archivos, recordsize controla el tamaño máximo de bloque que ZFS usará para datos de archivos. Registros grandes (1M) son excelentes para rendimiento secuencial (backups, media), pero pueden perjudicar el I/O aleatorio si tu aplicación lee fragmentos pequeños de bloques grandes.

Para zvols (dispositivos de bloque para iSCSI/VMs), volblocksize se establece en la creación y debe coincidir con el sistema de archivos invitado y la carga (comúnmente 8K/16K para bases de datos, 16K/32K para uso general de VM). De nuevo: no puedes cambiarlo después sin recrear el zvol.

compresión: rendimiento gratis hasta que no lo es

compression=lz4 suele ser una victoria: menos bytes leídos/escritos significa menos tiempo de disco. Para cargas de lectura aleatoria, la compresión puede reducir el tamaño de IO y mejorar la latencia. Pero la compresión consume CPU, y en sistemas ya limitados por CPU puede volverse contraproducente.

atime: muerte por mil escrituras de metadatos

atime=on actualiza tiempos de acceso en las lecturas, causando escrituras adicionales. En sistemas de archivos ocupados, esto puede convertirse en un flujo constante de pequeñas actualizaciones de metadatos con cierto comportamiento sync según la carga. Para la mayoría de las cargas de servidor, atime=off es una mejora sencilla.

escrituras sync, ZIL y SLOG

Las escrituras síncronas son una garantía contractual: el llamador quiere confirmación de que los datos están seguros en almacenamiento estable. ZFS lo satisface vía el ZIL (ZFS Intent Log). Si añades un dispositivo SLOG dedicado (rápido, baja latencia, protegido contra pérdida de energía), puedes acelerar dramáticamente la latencia de commit síncrono.

Los espejos y SLOG son un emparejamiento común: espejos para IOPS de lectura aleatoria, SLOG para latencia de escritura sync. Pero si tu carga es mayoritariamente escrituras asíncronas, SLOG no ayudará mucho. Si tu carga es mayoritariamente escrituras síncronas y no tienes SLOG, los espejos no arreglarán la cola de latencia tampoco.

Tareas prácticas con comandos (y cómo leer la salida)

Los comandos abajo asumen un sistema Linux típico con OpenZFS. Ajusta nombres de dispositivos y nombres de pool/dataset. El punto no es copiar y pegar heroicamente; es construir el hábito de verificar qué está haciendo realmente el sistema.

Tarea 1: Inspeccionar la topología del pool (confirmar que realmente construiste espejos)

cr0x@server:~$ sudo zpool status -v
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 00:17:02 with 0 errors on Sun Dec 22 02:17:05 2025
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0
          mirror-1                  ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0
            ata-WDC_WD80...-part1   ONLINE       0     0     0

errors: No known data errors

Interpretación: Quieres múltiples vdevs de nivel superior mirror-X. Si ves un único vdev RAIDZ gigante, tu historia de IO aleatorio será diferente. También confirma que el estado es ONLINE, no DEGRADED.

Tarea 2: Ver el IO por vdev en tiempo real (encuentra el vdev caliente)

cr0x@server:~$ sudo zpool iostat -v tank 1
                    capacity     operations     bandwidth
pool              alloc   free   read  write   read  write
----------------  -----  -----  -----  -----  -----  -----
tank              3.21T  4.05T    820    210  41.0M  12.3M
  mirror-0        1.60T  2.02T    610    105  30.4M   6.2M
    ata-WDC...      -      -     320     52  15.2M   3.1M
    ata-WDC...      -      -     290     53  15.2M   3.1M
  mirror-1        1.61T  2.03T    210    105  10.6M   6.1M
    ata-WDC...      -      -     110     52   5.3M   3.0M
    ata-WDC...      -      -     100     53   5.3M   3.1M
----------------  -----  -----  -----  -----  -----  -----

Interpretación: Si un espejo está haciendo la mayor parte del trabajo, puede que tengas skew (colocación de datos, un dataset caliente o un pequeño conjunto de bloques viviendo mayoritariamente en un vdev debido a la edad de la pool e historial de expansión). Los espejos te dan concurrencia, pero solo si las asignaciones están razonablemente distribuidas.

Tarea 3: Obtener la señal de 30 segundos “¿estoy limitado por caché o por disco?”

cr0x@server:~$ arcstat 1
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:01:10  12K  2.1K    17%   890   7%  1.2K  10%     0   0%  96.3G  128G
12:01:11  11K  2.4K    21%   1.1K 10%  1.3K  12%     0   0%  96.3G  128G

Interpretación: Altas tasas de aciertos de ARC a menudo enmascaran diferencias en la disposición de disco. Cuando los misses suben, la verdadera capacidad de lectura aleatoria de la pool importa. Si los misses se disparan y la latencia sube con ellos, estás limitado por disco.

Tarea 4: Comprobar propiedades de datasets que silenciosamente sabotean la latencia

cr0x@server:~$ sudo zfs get -o name,property,value -s local,default recordsize,compression,atime,sync tank
NAME  PROPERTY     VALUE
tank  recordsize   128K
tank  compression  lz4
tank  atime        off
tank  sync         standard

Interpretación: Un dataset de base de datos con recordsize=1M es un clásico auto-problemático. atime=on en un filesystem caliente crea presión de escritura en segundo plano. sync=disabled es un informe de incidente esperando ocurrir.

Tarea 5: Encontrar si las escrituras sync son tu verdadero problema

cr0x@server:~$ sudo zpool iostat -v tank 1 | head -n 20
                    capacity     operations     bandwidth
pool              alloc   free   read  write   read  write
----------------  -----  -----  -----  -----  -----  -----
tank              3.21T  4.05T    120    950  6.0M   38.0M
  mirror-0        1.60T  2.02T     70    480  3.4M   19.2M
  mirror-1        1.61T  2.03T     50    470  2.6M   18.8M
----------------  -----  -----  -----  -----  -----  -----

Interpretación: Muchas operaciones de escritura con bajo ancho de banda suelen significar muchas escrituras pequeñas. Si la aplicación exige semánticas sync (commits de BD, NFS con sync, flushes de VM), tu siguiente pregunta es: ¿tienes SLOG y está sano?

Tarea 6: Confirmar si existe un SLOG y cuál es

cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
config:

        NAME                         STATE     READ WRITE CKSUM
        tank                         ONLINE       0     0     0
          mirror-0                   ONLINE       0     0     0
            /dev/sdb1                ONLINE       0     0     0
            /dev/sdc1                ONLINE       0     0     0
          mirror-1                   ONLINE       0     0     0
            /dev/sdd1                ONLINE       0     0     0
            /dev/sde1                ONLINE       0     0     0
        logs
          nvme-SAMSUNG_MZ...-part1   ONLINE       0     0     0

Interpretación: Si te importa la latencia de escritura sync, el dispositivo de log debe ser de baja latencia y protegido contra pérdida de energía. Una SSD de consumo usada como SLOG puede fallar de formas que no aparecen en benchmarks pero sí en preguntas como “¿por qué fsync acaba de tardar 800ms?”.

Tarea 7: Crear una pool espejo correctamente (con ashift explícito)

cr0x@server:~$ sudo zpool create -o ashift=12 tank \
  mirror /dev/disk/by-id/ata-DISK_A /dev/disk/by-id/ata-DISK_B \
  mirror /dev/disk/by-id/ata-DISK_C /dev/disk/by-id/ata-DISK_D

Interpretación: Usa identificadores de dispositivos estables. El ashift explícito evita que los valores por defecto de la plataforma te muerdan después. El punto son múltiples vdevs espejo: estás comprando colas.

Tarea 8: Añadir otro vdev espejo (escalar rendimiento y capacidad)

cr0x@server:~$ sudo zpool add tank mirror \
  /dev/disk/by-id/ata-DISK_E /dev/disk/by-id/ata-DISK_F

Interpretación: Así crecen las pools espejo: añade más vdevs espejo. Generalmente no puedes “convertir” un vdev RAIDZ en espejos. La disposición es una elección de diseño en el tiempo de creación.

Tarea 9: Reemplazar un disco fallando en un espejo (la manera adulta)

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: DEGRADED
config:

        NAME        STATE     READ WRITE CKSUM
        tank        DEGRADED     0     0     0
          mirror-0  DEGRADED     0     0     0
            sdb1    ONLINE       0     0     0
            sdc1    FAULTED     12     0     0  too many errors
          mirror-1  ONLINE       0     0     0
            sdd1    ONLINE       0     0     0
            sde1    ONLINE       0     0     0

cr0x@server:~$ sudo zpool replace tank sdc1 /dev/disk/by-id/ata-NEW_DISK-part1
cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
  scan: resilver in progress since Tue Dec 24 09:12:03 2025
        312G scanned at 1.20G/s, 41.2G issued at 160M/s, 3.21T total
        41.2G resilvered, 1.26% done, 05:22:11 to go

Interpretación: zpool replace es la operación de ciclo de vida que quieres. Observa las tasas de resilver. Si el resilver está lento, puedes estar limitado por IO debido a la carga, límites del controlador o un disco sobreviviente con problemas.

Tarea 10: Poner offline/online un disco para mantenimiento (simular fallo de forma segura)

cr0x@server:~$ sudo zpool offline tank /dev/disk/by-id/ata-DISK_B
cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: DEGRADED
config:

        NAME                       STATE     READ WRITE CKSUM
        tank                       DEGRADED     0     0     0
          mirror-0                 DEGRADED     0     0     0
            ata-DISK_A             ONLINE       0     0     0
            ata-DISK_B             OFFLINE      0     0     0
          mirror-1                 ONLINE       0     0     0
            ata-DISK_C             ONLINE       0     0     0
            ata-DISK_D             ONLINE       0     0     0

cr0x@server:~$ sudo zpool online tank /dev/disk/by-id/ata-DISK_B

Interpretación: Útil para mantenimiento controlado. No dejes los espejos degradados más tiempo del necesario; estás a una sorpresa de la disponibilidad.

Tarea 11: Scrub y verificar (y ver si tu pool está sufriendo silenciosamente)

cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
  scan: scrub in progress since Tue Dec 24 10:03:41 2025
        1.20T scanned at 820M/s, 510G issued at 350M/s, 3.21T total
        0B repaired, 15.87% done, 02:22:10 to go

Interpretación: Los scrubs detectan y corrigen bloques malos usando la redundancia del espejo. Si los scrubs reparan datos rutinariamente, tus discos, cableado o ruta del controlador necesitan atención. Los espejos son indulgentes; no te dan licencia para ignorar errores.

Tarea 12: Comprobar fragmentación y espacio libre (predecir el futuro)

cr0x@server:~$ sudo zpool list -o name,size,alloc,free,frag,capacity,health
NAME  SIZE  ALLOC  FREE  FRAG  CAPACITY  HEALTH
tank  7.25T  3.21T 4.05T   18%      44%  ONLINE

Interpretación: Alta fragmentación y alto uso de capacidad se correlacionan con peor latencia. Si ya estás por encima de ~80% y la app es sensible a la latencia, ahora pagas intereses por el optimismo anterior.

Tarea 13: Encontrar los mayores consumidores de IO (contabilidad de IO por dataset)

cr0x@server:~$ sudo zfs iostat -r -v tank 1
                              capacity     operations     bandwidth
dataset                      alloc   free   read  write   read  write
---------------------------  -----  -----  -----  -----  -----  -----
tank                         3.21T  4.05T      0      0      0      0
  tank/db                    820G   1.20T    640    520  32.0M  24.0M
  tank/vm                    1.90T  2.10T    180    310  9.0M   14.0M
  tank/home                  120G   800G      5     18  200K   900K
---------------------------  -----  -----  -----  -----  -----  -----

Interpretación: Esto te dice de dónde viene el IO. Si “db” está caliente y tiene el recordsize o sync incorrecto, tienes una corrección dirigida en lugar de un pánico vago de almacenamiento.

Tarea 14: Verificar ashift en vdevs existentes

cr0x@server:~$ sudo zdb -C tank | grep -E 'ashift|vdev_tree|type: mirror' -n
15:        vdev_tree:
34:            type: 'mirror'
48:                ashift: 12
71:            type: 'mirror'
85:                ashift: 12

Interpretación: Confirma la alineación. Si descubres ashift=9 en discos de 4K, has encontrado una causa estructural de latencia. La solución es reconstruir/reemplazar vdevs, no ajustar sysctls hasta que mejore la moral.

Tarea 15: Medir la latencia indirectamente (pistas de tiempo de servicio desde iostat)

cr0x@server:~$ iostat -x 1
Linux 6.8.0 (server)  12/24/2025  _x86_64_  (32 CPU)

Device            r/s   w/s  rkB/s  wkB/s  await  svctm  %util
sdb              90.0  60.0  4600   5100    7.2   1.1    18.0
sdc              88.0  62.0  4500   5200    8.0   1.2    19.0
sdd              30.0  90.0  1400   7800   25.0   1.3    22.0
sde              28.0  92.0  1300   7900   27.5   1.4    23.0

Interpretación: await subiendo mientras %util no está al máximo puede indicar encolamiento por encima de la capa de dispositivo (controlador, filesystem, stalls por escrituras sync). Una pata de espejo mostrando consistentemente peor await es una pista: ese disco, ruta o cable puede estar degradado.

Guía rápida de diagnóstico

Este es el “entra en la sala, mira tres cosas y no te distraigas” de rutina. Está diseñado para incidentes y degradaciones donde necesitas una hipótesis rápido.

Primero: ¿Es caché, disco o sync?

  1. Tasa de aciertos de ARC: ejecuta arcstat 1 (o equivalente). Si los misses son bajos, la disposición del disco podría no ser el problema ahora.
  2. Forma del IO de la pool: ejecuta zpool iostat -v tank 1. Busca muchas pequeñas operaciones de escritura, carga sesgada en vdevs y si predominan lecturas o escrituras.
  3. Presión sync: verifica si la carga exige mucho sync (commits BD, NFS sync). Confirma si existe un SLOG vía zpool status. Si no hay SLOG y las escrituras sync dominan, probablemente hayas encontrado el culpable de latencia.

Segundo: ¿Un solo dispositivo/ruta se está comportando mal?

  1. Salud y errores: zpool status -v. ¿Algún error READ/WRITE/CKSUM? ¿Algún vdev DEGRADED?
  2. Pistas de latencia por disco: iostat -x 1. Un disco con await alto o reintentos es a menudo “el problema”, aunque la pool esté “ONLINE”.
  3. Logs del kernel: revisa por resets/timeouts de enlace.

Tercero: ¿Te quedaste sin espacio o te ahogas en fragmentación?

  1. Capacidad y frag: zpool list -o size,alloc,free,frag,capacity. Si estás por encima de ~80% y la frag es alta, el dolor de IO aleatorio es esperado.
  2. Infractores por dataset: zfs iostat -v 1 para encontrar datasets calientes, luego inspecciona sus propiedades.
  3. Trabajo en segundo plano: scrubs/resilvers pueden dominar el IO. Revisa la línea scan en zpool status.

Una vez que tengas la categoría—miss de caché, latencia de escritura sync, un solo disco/ruta malo, o pool lleno/fragmentado—puedes actuar. Sin eso, pasarás horas “afinando” un sistema que simplemente está fuera de su sobre de diseño.

Tres micro-historias del mundo corporativo

1) Incidente causado por una suposición errónea: “Las escrituras en espejo son rápidas, ¿no?”

Un equipo migró un servicio transaccional desde una base de datos gestionada a instancias autogestionadas por razones de coste. El plan de almacenamiento parecía sensato: “Usaremos espejos ZFS, así que será rápido.” Construyeron una pool de varios vdevs espejo en SSD decentes, activaron compresión y dieron por terminado el asunto. Las pruebas iniciales fueron geniales—porque las pruebas eran mayormente lecturas y cargas masivas. El servicio entró en producción un lunes, porque por supuesto lo hizo.

Para el martes por la tarde, la rotación de on-call había descubierto una nueva versión de fatiga por alertas. Picos de latencia se alineaban con ráfagas de transacciones. La base de datos no estaba limitada por CPU. La red estaba limpia. Los discos no estaban saturados en ancho de banda. Pero los commits se quedaban atascados lo suficiente como para disparar timeouts. El canal de incidentes se llenó con los sospechosos habituales: “¿Quizá ZFS es lento?” “¿Necesitamos instancias más grandes?” “¿Deshabilitar fsync?”

La suposición errónea fue sutil: pensaron que los espejos acelerarían las escrituras como aceleran las lecturas aleatorias. Pero la carga estaba dominada por commits síncronos, y el sistema no tenía SLOG dedicado. ZFS hacía lo correcto—honrar las semánticas sync confirmando en almacenamiento estable—pero el perfil de latencia de los dispositivos de la pool principal (y la amplificación de escritura por escrituras sync pequeñas) lo hizo feo bajo presión.

La solución no fue un sysctl misterioso. Añadieron un dispositivo de SLOG de baja latencia y protegido contra pérdida de energía como espejo (porque sí, los dispositivos de log también pueden fallar), verificaron que la latencia de escritura sync bajó, y volvieron a probar con patrones reales de transacciones. El servicio se estabilizó. El postmortem no trató de ZFS como “lento”. Trató de alinear la disposición con la forma de IO y entender que los espejos son un arma para latencia de lectura, no una poción universal de rendimiento.

La lección que quedó: los espejos les dieron el margen de lectura aleatoria que querían, pero sin SLOG seguían teniendo cola de latencia en escrituras síncronas. Comenzaron a tratar “sync-heavy” como un requisito de primera clase, no como un pensamiento posterior.

2) Optimización que salió mal: “Subamos recordsize y apaguemos sync”

Esta empieza como muchas tragedias de almacenamiento: con una captura de dashboard y una frase confiada. Un desarrollador mostró que la aplicación hacía mucho IO, y alguien sugirió “optimizar” el filesystem. La propuesta fue simple: aumentar recordsize a 1M “para throughput” y poner sync=disabled “porque fsync es caro.” El equipo quería que sus gráficos se vieran mejor. Consiguieron su deseo.

Durante unas dos semanas el rendimiento se vio genial. Luego una ventana de mantenimiento incluyó un ciclo de energía que tardó más de lo esperado. Cuando los sistemas volvieron, los datos de la aplicación tenían inconsistencias. No fue un fallo dramático de “todo desapareció”: peor. Un pequeño número de transacciones recientes faltaban y algunos registros estaban aplicados parcialmente. El tipo de corrupción que se convierte en una semana larga de conciliaciones y disculpas.

Deshabilitar sync eliminó la garantía contractual sobre la que la aplicación confiaba. ZFS hizo exactamente lo que le dijeron: tratar las escrituras síncronas como asíncronas. El diseño de espejo no fue el villano. La “optimización” sí. Aumentar recordsize también tuvo un costo: la base de datos ahora leía y reescribía bloques más grandes de los necesarios, lo que hizo que el IO aleatorio fuera más propenso a picos bajo carga, especialmente cuando ARC no lo estaba captando.

El plan de recuperación implicó restaurar desde backups y reproducir lo que pudieron desde logs upstream. El cambio duradero fue cultural: las propiedades del sistema de archivos pasaron a control de cambios, y el trabajo de rendimiento requirió un plan de pruebas representativo de la carga. El equipo aprendió a temer cualquier optimización que comience con “probablemente podemos desactivar la seguridad; estará bien”.

Los espejos no los salvaron de sí mismos. Pero el rediseño posterior sí: revirtieron sync a standard, usaron un SLOG apropiado para las partes pesadas en sync, ajustaron recordsize por dataset, y mantuvieron los espejos porque el perfil de lectura aleatoria era la necesidad real a largo plazo.

3) Práctica aburrida pero correcta que salvó el día: reemplazar discos antes de que “fallen”

En un entorno corporativo grande, el trabajo más heroico suele ser silencioso. Una flota de almacenamiento tenía una política: si un disco empieza a registrar errores medios o muestra una tasa de errores en ascenso, reemplazarlo en horario laboral—antes de que haga que un vdev pase a degradado. No era dramático. También era ocasionalmente impopular porque parecía gastar dinero “temprano”.

Un trimestre, comenzaron a ver picos de latencia esporádicos en una pool que soportaba CI interno y almacenamiento de artefactos. Nada alarmante en zpool status. Ningún vdev DEGRADED. Solo picos de latencia en cola que hacían inestables las compilaciones y molestos a los desarrolladores. En lugar de culpar a la red o “Kubernetes siendo Kubernetes”, el on-call ejecutó el tríaje estándar: zpool iostat -v mostró una pata de espejo con carga desigual y peores tiempos de servicio. iostat -x indicó que un disco ocasionalmente se quedaba atascado.

Recogieron datos SMART y encontraron signos tempranos de problemas—nada que activara un ticket de falla inmediata, pero suficiente para correlacionar con los stalls. Reemplazaron el disco en una ventana planificada usando zpool replace, vieron completar el resilver y los picos de latencia desaparecieron. Sin interrupción. Sin postmortem. Solo un bucle cerrado entre observación y mantenimiento.

Semanas después, otro disco en otro espejo falló en forma contundente. El equipo se encogió de hombros, lo reemplazó y siguió. Lo importante: porque mantuvieron la pool saludable y tenían una cultura de reemplazo proactivo, la “falla real” no coincidió con un segundo disco marginal, una cola de scrubs y una pool llena. Los espejos hicieron su trabajo porque las operaciones hicieron el suyo.

Errores comunes: síntomas y correcciones

Error 1: Construir un vdev RAIDZ gigante para una carga de IO aleatorio

Síntomas: Los benchmarks secuenciales se ven bien. Las apps reales (BD/VMs) muestran alta latencia y bajas IOPS. zpool iostat muestra un vdev haciendo todo porque solo hay uno.

Corrección: Para IO aleatorio sensible a latencia, diseña con múltiples vdevs espejo. Si ya construiste RAIDZ, la corrección suele ser migrar a una nueva disposición de pool (send/receive, replicación, rebuild). No existe un atajo seguro “convertir en sitio” que preserve el mismo vdev.

Error 2: ashift incorrecto

Síntomas: Las escrituras pequeñas son inexplicablemente lentas. CPU y ancho de banda están bien, pero la latencia persiste. Ves mucho comportamiento read-modify-write a nivel de dispositivo.

Corrección: Verifica con zdb -C. Si está mal, planifica una reconstrucción: reemplaza vdevs con los correctamente alineados o migra a una nueva pool. No pierdas tiempo persiguiendo “tuning” para un problema de geometría.

Error 3: Apagar sync para “arreglar” rendimiento

Síntomas: Los gráficos de rendimiento mejoran. Luego un apagado no limpio lleva a datos recientes faltantes o inconsistencias a nivel de aplicación.

Corrección: Mantén sync=standard a menos que puedas probar que la aplicación no requiere durabilidad (raro). Si necesitas rendimiento sync, añade un SLOG correcto y confirma que realmente se está usando (y que es de baja latencia y con PLP).

Error 4: Usar una SSD de consumo como SLOG

Síntomas: La latencia de escritura sync es inestable; stalls ocasionales largos. El SLOG muestra errores o resets. A veces el rendimiento empeora con el tiempo mientras la GC interna del dispositivo te pelea.

Corrección: Usa un dispositivo empresarial con protección contra pérdida de energía. Considera espejar el SLOG. Móntoréalo como si importara—porque importa.

Error 5: Llenar la pool hasta el tope

Síntomas: La latencia aumenta a medida que la pool se acerca a alta utilización. La asignación se vuelve costosa. La fragmentación sube. Todo se siente “blando” e impredecible.

Corrección: Mantén margen de espacio libre (a menudo 20–30% para pools calientes). Añade vdevs temprano. Si ya estás lleno, migra datos fríos a otro lugar o expande; el tuning no creará espacio libre.

Error 6: Ignorar un disco “ligeramente extraño”

Síntomas: La pool está ONLINE pero hay picos de latencia en cola. Un disco muestra await más alto o errores esporádicos. Los scrubs tardan más de lo habitual.

Corrección: Trata el hardware marginal como un bug de rendimiento. Reemplaza discos sospechosos y arregla cables/rutas inestables. Los espejos ocultan fallos; también ocultan advertencias tempranas a menos que las mires.

Error 7: Mezclar tamaños o velocidades de disco dentro de un espejo

Síntomas: Solo obtienes la capacidad igual al disco más pequeño en cada espejo. El resilver y la latencia de escritura siguen al miembro más lento. El rendimiento es inconsistente.

Corrección: Espeja “like-with-like” cuando sea posible. Si debes mezclar, hazlo intencionalmente y acepta las limitaciones (y documenta para que el Tú del futuro no lo “optimice” hasta el caos).

Listas de verificación / plan paso a paso

Paso a paso: diseñando una pool espejo para I/O aleatorio

  1. Clasifica la carga: lectura aleatoria intensiva (BD/VM), escritura sync intensiva (logs transaccionales, NFS sync), secuencial (backups/media), mixta.
  2. Elige la estrategia de vdev de nivel superior:
    • IO aleatorio + sensibilidad a latencia: múltiples vdevs espejo 2-vías.
    • Requisitos extremos de disponibilidad: considera espejos 3-vías para la capa caliente.
    • Primero capacidad + secuencial: RAIDZ2/3 puede ser apropiado, pero comprende los tradeoffs en IO aleatorio.
  3. Decide el patrón de crecimiento: los espejos crecen agregando vdevs espejo. Confirma que el negocio puede comprar discos en pares (o tríos) más adelante.
  4. Elige ashift: usualmente 12. Sé explícito.
  5. Planifica para escrituras sync: si tienes una carga sync-heavy, diseña SLOG desde el principio (y presupuestea un dispositivo con PLP).
  6. Establece valores por defecto de datasets: compression=lz4, atime=off, y recordsize sensatos por dataset (no talla única para todo).
  7. Política operacional: calendario de scrubs, monitorización SMART, inventario de repuestos, playbook de reemplazo.

Paso a paso: validar que los espejos entreguen la latencia que esperas

  1. Confirma la topología con zpool status y verifica que existan múltiples vdevs espejo.
  2. IO de referencia: mide con carga representativa de la aplicación, no solo tests sintéticos secuenciales.
  3. Observa la distribución: zpool iostat -v 1 debe mostrar trabajo repartido entre vdevs.
  4. Verifica el comportamiento de caché: arcstat para ver si realmente estás golpeando disco.
  5. Prueba modo fallo: pon offline un disco en una ventana controlada, observa el comportamiento y vuelve a ponerlo online. Asegura que las alertas de monitorización funcionen.
  6. Documenta los ajustes “conocidos buenos”: recordsize/volblocksize, semánticas sync, tipo de dispositivo SLOG, ashift.

Paso a paso: cuando ya tienes RAIDZ y quieres espejos

  1. Admite que es una migración: no estás “afinando” hasta espejos. Estás moviendo datos.
  2. Construye una nueva pool con vdevs espejo y ashift correcto.
  3. Usa replicación: zfs send/zfs receive para datasets; mantiene snapshots consistentes.
  4. Haz el corte en una ventana planificada, valida y luego desmantela la pool vieja.

Preguntas frecuentes

1) ¿Son los espejos ZFS siempre más rápidos que RAIDZ?

No. Los espejos suelen ser más rápidos para lecturas aleatorias y cargas mixtas sensibles a latencia. RAIDZ puede ser excelente para rendimiento secuencial y eficiencia de capacidad. Elige según la forma de IO y las restricciones operativas.

2) ¿Cuántos vdevs espejo necesito?

Los suficientes para que tu carga pueda repartirse entre colas de vdev. Como heurística operativa: más vdevs de nivel superior generalmente significa más IOPS y menor contención. Pero controladoras, CPU y red pueden convertirse en el nuevo cuello de botella, así que mide y no sobreconstruyas a ciegas.

3) ¿Debo usar espejos 2-vías o 3-vías?

Usa 2-vías por defecto. Usa 3-vías cuando la disponibilidad y el riesgo de reconstrucción dominen y puedas permitir el costo de capacidad—especialmente para datasets pequeños y críticos.

4) ¿Los espejos ayudan la latencia de escritura?

No directamente por vdev. Las escrituras deben ir a todos los miembros de un espejo. El rendimiento de escritura a nivel de pool mejora teniendo múltiples vdevs espejo, pero la latencia de escritura síncrona suele resolverse con un SLOG apropiado, no solo con espejos.

5) ¿Cuál es la configuración única más importante “no la cagues”?

ashift. Alinea el sector correctamente al crear la pool. Un ashift equivocado puede degradar permanentemente el rendimiento de escrituras pequeñas y es doloroso de corregir luego.

6) ¿Se requiere SLOG para pools espejo?

No. Solo se requiere si tienes carga significativa de escrituras síncronas y te importa la latencia. Si tu carga es mayoritariamente asíncrona, un SLOG a menudo aporta poco beneficio.

7) ¿Por qué mi pool espejo es rápida en benchmarks pero lenta en producción?

Los benchmarks suelen probar throughput secuencial o profundidades de cola poco realistas. El dolor en producción es frecuentemente latencia en cola por escrituras sync, un disco/ruta con problemas, una pool casi llena, o un desajuste de propiedades de dataset (recordsize/volblocksize).

8) ¿Puedo ampliar un vdev espejo añadiendo un tercer disco más tarde?

En muchos entornos OpenZFS puedes adjuntar un dispositivo adicional a un espejo para convertirlo en 3-vías, pero el soporte operativo varía por plataforma y política. Incluso cuando es posible, trátalo como un cambio con riesgo real: prueba en laboratorio, confirma monitorización y asegúrate de que los procedimientos de reemplazo gestionan la nueva topología.

9) ¿Los espejos reducen el tiempo de resilver?

A menudo sí. Los resilvers de espejo suelen ser más simples que la reconstrucción por paridad. Dependiendo de características y comportamiento de la plataforma, ZFS puede resilverizar solo bloques asignados, lo que puede hacer la recuperación más rápida que “copiar todo el disco”. Pero la velocidad de resilver aún depende de la carga, la salud de los discos y límites del controlador.

10) ¿Y si quiero tanto eficiencia de capacidad como rendimiento de IO aleatorio?

Separa por niveles. Usa espejos para datasets calientes de IO aleatorio y RAIDZ para datos fríos/secundarios—o pools separados por completo. Intentar que una sola disposición satisfaga todas las cargas es como obtener un rendimiento medio y incidentes por encima del promedio.

Conclusión

Los espejos ZFS no engañan a la física. La explotan. El I/O aleatorio es un problema de colas, y los espejos le dan a ZFS más opciones: más colas, más paralelismo y más oportunidades para evitar el disco que silenciosamente arruina tu latencia de cola. Cuando construyes una pool con múltiples vdevs espejo, no solo duplicas datos: compras libertad de programación.

La recompensa operacional es mayor que los benchmarks. Los espejos hacen que el manejo de fallos sea sencillo, que los scrubs tengan sentido y que el rendimiento sea más predecible bajo cargas mixtas. Combínalos con propiedades sensatas, espacio libre suficiente y (cuando sea necesario) un SLOG real, y obtendrás el equivalente de almacenamiento de una rotación on-call bien gestionada: nada glamoroso, pero de repente todo deja de ser una emergencia.

← Anterior
Correo: Fuerza bruta en IMAP/SMTP — protégelo sin dejarte fuera
Siguiente →
Servidores Ubuntu 24.04: Snap vs apt — dónde Snap causa dolor silencioso (y qué hacer)

Deja un comentario