ZFS redundant_metadata: cuando más copias de metadatos sí importan

¿Te fue útil?

ZFS tiene la habilidad de convertir conversaciones sobre “sistema de ficheros” en conversaciones sobre “arquitectura de almacenamiento”. Eso no es un fallo; es precisamente la intención. ZFS trata tus datos como un grafo de bloques, y los metadatos son el mapa. Pierdes el mapa y no estás “perdiendo un fichero”, pierdes la capacidad de demostrar qué es ese fichero. Por eso existe redundant_metadata: es una propiedad de dataset que decide cuántas copias de metadatos intenta mantener ZFS.

El problema es que “más copias” no es automáticamente “mejor”. Copias adicionales de metadatos pueden salvarte de la clase de corrupción que hace que ingenieros curtidos miren zpool status en silencio —pero también pueden añadir amplificación de escritura silenciosa y convertir una pool ya limitada por I/O en un desastre de colas. Este texto trata sobre cuándo redundant_metadata se paga por sí mismo, cuándo no, y cómo distinguirlo en producción sin adivinar.

Qué hace realmente redundant_metadata

redundant_metadata es una propiedad de dataset de ZFS que influye en cuántas copias de los metadatos almacena ZFS. Los valores más comunes que verás son:

  • all: almacenar copias redundantes de todos los metadatos (es decir, “intentar mantener copias extra”).
  • most: almacenar copias redundantes de la mayoría de los metadatos.
  • none: no almacenar copias extra de metadatos (más allá de la redundancia que ya proporciona el diseño de vdev).

Esto no es lo mismo que la propiedad copies. copies=2 duplica datos y metadatos a nivel de dataset, aumentando sustancialmente el uso de espacio. redundant_metadata se centra solo en metadatos, que normalmente son mucho más pequeños que los datos de usuario —hasta que no lo son (piensa en millones de ficheros pequeños, snapshots intensivos o cargas de trabajo con muchos metadatos como maildir, capas de contenedores, caches de build).

Matiz importante: ZFS ya tiene redundancia a nivel de vdev (mirror, RAIDZ). redundant_metadata trata sobre copias adicionales sobre eso. En mirrors ya tienes dos o más copias de cada bloque porque todo el vdev está duplicado. En RAIDZ, cada bloque está protegido por paridad, pero sigue siendo un bloque lógico por escritura. Copias extra de metadatos pueden darte instancias físicas alternas de ese bloque de metadatos, lo que cambia la historia de recuperación cuando tienes corrupción silenciosa o problemas a nivel de sector que la paridad no puede corregir (por ejemplo, errores de lectura repetidos en una región específica, o un dispositivo que devuelve datos incorrectos con la ruta de checksum forzada a reintentar).

Versión en una frase: redundant_metadata es una apuesta a que tu mayor riesgo es “los metadatos se vuelven ilegibles antes de que lo notes”, y estás dispuesto a pagar cierta sobrecarga para cubrirte.

Broma #1 (corta y pertinente): Los metadatos son como DNS: a nadie le importa hasta que se rompe, y entonces de repente es “el servicio más crítico que hemos tenido”.

¿Qué cuenta como “metadatos” aquí?

Los metadatos de ZFS incluyen cosas como punteros de bloques, bloques indirectos, dnodes (metadatos de fichero), estructuras de directorio, mapas de espacio y otras estructuras en disco usadas para localizar y verificar tus datos. Algunos metadatos son a nivel de pool (MOS y compañía), otros son específicos de dataset. En la práctica, si estás depurando una situación grave, los “metadatos” que te importan son cualquier cosa que impida que el sistema de ficheros recorra tus contenidos de forma fiable.

No todos los metadatos son iguales. El contenido corrupto de un fichero puede ser un adjunto de cliente que restauras desde un snapshot. Los metadatos corruptos pueden hacer que datasets enteros no se puedan montar o provocar fallos de recorrido que bloqueen las restauraciones (que es la verdadera pesadilla: tus backups existen, pero no puedes enumerarlos).

Por qué los metadatos son la parte que no puedes perder

ZFS es copy-on-write. Cada vez que cambia un bloque, escribe nuevos bloques y luego actualiza punteros a los nuevos bloques. Por eso ZFS es tan bueno en consistencia: no sobrescribe estructuras vivas en su sitio; construye un árbol nuevo y luego cambia un puntero raíz al final. Ese diseño tiene implicaciones:

  • La rotación de metadatos puede ser muy alta incluso cuando los datos de usuario están “estables”.
  • La “forma” de tus metadatos afecta el rendimiento (más indirección, más I/O aleatorio pequeño).
  • Los metadatos hacen posibles los snapshots, pero los snapshots también preservan metadatos históricos, lo que puede aumentar el número de bloques de metadatos que deben seguir siendo legibles.

Operativamente, las fallas de ZFS tienden a presentarse en dos sabores:

  • Fallos de dispositivo obvios: un disco muere, SMART alerta, el mirror se degrada, lo reemplazas, resilver. Molesto pero rutinario.
  • Corrupción no obvia e ilegibilidad parcial: todo parece bien hasta que un scrub o el acceso a un bloque específico produce errores de checksum o errores permanentes. Los bloques de metadatos son desproporcionadamente dolorosos aquí, porque pueden estar en caminos críticos: montaje, listado de directorios, operaciones con snapshots, send/receive, incluso scrubs.

Las copias adicionales de metadatos no te salvan de todo desastre. No pueden arreglar “ups, destruimos la pool” y no harán que RAIDZ se comporte como un mirror. Pero sí pueden cambiar un incidente de corrupción de “necesitamos una ventana de restauración y mucha cafeína” a “el scrub lo reparó y seguimos adelante”.

Cómo ZFS coloca copias extra (y dónde no puede)

ZFS tiene un mecanismo de larga data para “ditto blocks” (copias extra de metadatos). La intención es simple: si una instancia está mal, otra puede estar bien, y los checksums permiten a ZFS elegir la correcta. Conceptualmente es similar a tener réplicas múltiples, pero dentro de una sola pool y controlado por reglas del asignador.

Hay restricciones:

  • No todo se copia de la misma forma. Algunos metadatos ya se manejan de forma especial; otros pueden ser demasiado grandes o demasiado frecuentes para duplicarlos razonablemente.
  • Las copias deben caer en algún lugar. Si tu pool es pequeña, fragmentada o está limitada a un conjunto estrecho de dispositivos, las “copias extra” pueden acabar no siendo tan independientes como piensas. Dos copias en el mismo disco fallando no cuentan como redundancia; cuentan como optimismo.
  • Un vdev especial cambia las reglas. Si usas un vdev especial para metadatos, entonces la colocación y redundancia de metadatos puede volverse tanto mejor como peor: mejor porque los metadatos están en dispositivos rápidos, peor porque acabas de crear una “capa de metadatos” que debe ser apropiadamente redundante o has construido un punto único de fallo con menor latencia.

Además: redundant_metadata no reescribe tu pool retroactivamente. Influye en escrituras nuevas. Los bloques de metadatos existentes generalmente permanecen tal cual hasta que se reescriben por el churn normal, o los fuerzas a reescribirse con tácticas específicas (lo cual puede ser arriesgado y dependiente de la carga).

Mirrors, RAIDZ y la falsa sensación de “ya tenemos redundancia”

En mirrors, cada bloque está duplicado a nivel de vdev. La redundancia de metadatos es inherentemente fuerte porque cualquier lectura puede venir de cualquiera de los lados, y los checksums permiten a ZFS detectar y auto-reparar reescribiendo desde el lado bueno. En ese mundo, redundant_metadata suele ser menos crítico para la integridad (aunque a veces relevante para rendimiento por la colocación y distribución de lecturas).

En RAIDZ, la paridad te protege contra la falla de un dispositivo completo hasta el nivel de paridad, y puede corregir algunos errores de lectura. Pero la paridad no es mágica frente a todos los modos de fallo, especialmente cuando tratas con errores de sector latentes, bugs de firmware, o un dispositivo que devuelve datos malos de forma inconsistente. Copias físicas extra de metadatos pueden ayudar porque crean fuentes alternativas para la misma información lógica.

Broma #2 (corta y pertinente): La paridad de RAIDZ es como un seguro: es genial hasta que descubres que la franquicia es “reconstruir la pool durante un fin de semana”.

Cuándo más copias de metadatos realmente importan

A continuación están las situaciones donde redundant_metadata tiende a justificar su coste, basadas en cómo aparecen las fallas en sistemas reales.

1) Cargas de trabajo pesadas en metadatos (millones de ficheros, ficheros diminutos, árboles profundos)

Si ejecutas algo que crea un número enorme de objetos del sistema de ficheros —caches de CI, capas de imagen de contenedores, mirrors de paquetes, colas de correo, almacenes de artefactos, monorepos de código fuente— tus “metadatos” no son una cifra irrelevante. Se convierten en un consumidor de capacidad y rendimiento de primer orden. Este es precisamente el tipo de entorno donde la corrupción de metadatos es también especialmente disruptiva: la exploración toca muchos bloques de metadatos, y un único bloque de directorio malo puede bloquear el acceso a grandes porciones lógicas de datos.

Las copias extra son valiosas porque la probabilidad de encontrar un bloque de metadatos malo aumenta con el número de bloques de metadatos que tienes y lees. Es estadística, no superstición.

2) Retención larga de snapshots o políticas agresivas de snapshots

Los snapshots preservan versiones históricas de metadatos, no solo de datos. Cuando mantienes muchos snapshots, mantienes metadatos antiguos. Si parte de esos metadatos se vuelve ilegible, puede romper operaciones como zfs list -t snapshot, zfs destroy (sí, incluso borrar puede quedar bloqueado), y zfs send. Es como guardar años de recibos en una caja de zapatos—bien hasta que el que necesitas es el que recibió café encima.

redundant_metadata=all puede reducir la probabilidad de que un bloque de metadatos concreto sea un punto único de fallo.

3) Pools con historial de errores de checksum o hardware marginal

Todos queremos hardware empresarial. A veces heredas hardware de “mejor esfuerzo” con una historia de compra que empieza con “fue una gran oferta”. Si has visto errores de checksum intermitentes durante scrubs, o has tenido que reemplazar discos por errores de lectura más de una vez, la redundancia de metadatos puede ser un reductor de riesgo práctico.

Pero sé honesto: si ves errores de checksum rutinariamente, la primera solución suele ser hardware, cables, HBAs, firmware y energía. redundant_metadata no sustituye caminos de E/S estables; es el cinturón de seguridad, no el volante.

4) Pools RAIDZ donde las IOPS de lectura de metadatos son la restricción

Suena paradójico: “copias extra” significa más escrituras, pero también puede mejorar la resiliencia de lectura y, en algunos casos, el comportamiento de lectura ante errores. En una pool RAIDZ, un sector malo puede forzar lecturas de reconstrucción que son caras. Si ZFS puede leer una copia buena de un bloque de metadatos sin reconstrucción, puede reducir el radio de impacto de un disco marginal durante un scrub o una exploración pesada.

5) Diseños con vdev especial bien hechos

Si tienes un vdev especial compuesto por SSDs en mirror dedicado a metadatos (y opcionalmente a bloques pequeños), puedes hacer que los metadatos sean tanto más rápidos como más resilientes—siempre que el vdev especial sea a su vez apropiadamente redundante y monitorizado. En tales arquitecturas, configurar redundant_metadata=all para datasets críticos puede marcar la diferencia entre “metadatos rápidos” y “metadatos rápidos que sobreviven a un modo de fallo raro en SSD”.

Cuándo duele: compensaciones de rendimiento y espacio

redundant_metadata no es gratis. Puede morderte en tres frentes: amplificación de escritura, comportamiento de fragmentación y planificación de capacidad.

Amplificación de escritura y escrituras aleatorias pequeñas

Las escrituras de metadatos suelen ser pequeñas y aleatorias. Duplicarlas significa más escrituras pequeñas y aleatorias. En pools de HDD, así es como conviertes “latencia aceptable” en “¿por qué todo está a 200 ms?”. En pools SSD puede que no lo notes de inmediato, pero aún aumentas la carga de escritura y potencialmente afectas la resistencia y el comportamiento de recolección de basura.

Si tu carga es muy sync-heavy (bases de datos con sync=standard y muchas fsync, exportaciones NFS con semántica síncrona), la ruta de metadatos está en la cadena crítica de latencia. Escrituras extra de metadatos pueden aparecer como tiempos de commit más altos, que se traducen en latencia de cola para la aplicación. Nadie llama al equipo de almacenamiento por la latencia media.

Sobrecoste de espacio que es invisible hasta que no lo es

La sobrecarga de metadatos suele ser pequeña comparada con los datos. “Usualmente” hace mucho trabajo en esa frase. Si almacenas miles de millones de objetos pequeños, usas muchos xattrs, o mantienes historiales de snapshots profundos, los metadatos pueden ser sustanciales. Copias extra de metadatos pueden empujarte hacia una mayor utilización de la pool, y la alta utilización es donde la asignación de ZFS se vuelve menos amigable, la fragmentación aumenta y el rendimiento se degrada.

Aquí es donde la gente se sorprende: no se quedaron sin espacio por “datos”. Se quedaron sin espacio porque el sistema de archivos tuvo que gestionar los datos, y la gestión se duplicó.

No es la solución correcta para “quiero más redundancia”

Si tu objetivo real es “quiero que este dataset sobreviva a dos fallos de disco”, redundant_metadata no es la herramienta. Elige la topología mirror/RAIDZ adecuada. Copias extra de metadatos ayudan con ciertas clases de corrupción y modos de ilegibilidad localizada; no cambian tu tolerancia fundamental a fallos como lo hace la redundancia de vdev.

Hechos y contexto que puedes usar en discusiones

Estos son puntos cortos y concretos que ayudan cuando estás en una revisión de diseño y alguien dice “¿por qué siquiera hablamos de metadatos?”

  1. ZFS fue diseñado alrededor de checksums end-to-end, así que puede detectar corrupción silenciosa en lugar de servir datos malos en silencio. Esa detección solo sirve si existe una fuente alterna válida (lado del mirror, reconstrucción por paridad, o una copia extra).
  2. Copy-on-write hace la consistencia barata pero los metadatos ocupados. Incluso cambios “pequeños” pueden tocar múltiples bloques de metadatos: actualizaciones de dnode, bloques indirectos, mapas de espacio, etc.
  3. El término “ditto blocks” precede al nombre de la propiedad moderna y refleja la idea original: mantener copias extra de metadatos críticos para que un único sector malo no deje inútil el recorrido de la pool.
  4. Los scrubs no son solo “chequeos”, son flujos de reparación en vdevs redundantes: ZFS lee, verifica checksums y puede curar reescribiendo desde una copia buena. Copias extra de metadatos pueden aumentar la probabilidad de que exista una copia buena.
  5. Los metadatos tienden a ser I/O de bloque pequeño, que es precisamente el patrón peor para vdevs HDD y diseños con paridad: pequeño, aleatorio y sensible a la latencia.
  6. RAIDZ tiene un “impuesto de reconstrucción”: cuando un sector está malo, leer un bloque puede requerir leer múltiples columnas y reconstruir. Para metadatos, ese impuesto golpea operaciones frecuentes (recorridos de directorios, enumeración de snapshots).
  7. La alta utilización de la pool cambia el comportamiento del asignador, a menudo aumentando fragmentación y dispersando el I/O de metadatos. Copias extra de metadatos incrementan la presión sobre el espacio libre antes.
  8. Los vdevs especiales se introdujeron para abordar cuellos de botella de IOPS de metadatos moviendo metadatos a dispositivos más rápidos; pero también introducen un nuevo dominio de fallo que debe estar en mirror (o mejor) porque perderlo puede ser catastrófico.
  9. “Los backups existen” no es lo mismo que “la restauración es posible”. Si la corrupción de metadatos impide enumerar snapshots o leer streams de send, puedes tener bits en disco y aun así estar bloqueado operativamente.

Tres micro-historias del mundo corporativo

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

Heredamos un clúster de almacenamiento que “tenía redundancia”, según el documento de entrega. La pool era RAIDZ2, muchos discos, y los dashboards estaban en verde. La suposición del equipo era básicamente: la paridad equivale a seguridad, así que la afinación de metadatos es académica.

Entonces un evento inocuo: empezó un scrub semanal, y un día después los desarrolladores se quejaron de que un registro de contenedores “se colgaba aleatoriamente”. No caído—solo colgado. La pool no se quedó sin espacio, y no había fallos de dispositivo obvios. Pero la latencia se disparó durante operaciones con mucha metadata: listar tags, garbage collection y extraer capas antiguas. El equipo de aplicación sospechó de la red. El equipo de red sospechó del DNS. El equipo de almacenamiento sospechó de todo y de nada.

zpool status mostró errores de checksum en un disco, pero el vdev seguía ONLINE. RAIDZ2 “lo estaba manejando”. La suposición equivocada fue que “lo está manejando” significa “sin impacto en el usuario”. En realidad, cada vez que ZFS accedía a ciertos bloques de metadatos que vivían en la región marginal de ese disco, pagaba el impuesto de reconstrucción. Bajo carga de scrub, esas lecturas de metadatos se volvieron frecuentes y caras. El sistema era correcto; también era lento.

Reemplazamos el disco y los síntomas desaparecieron. Más tarde, en el postmortem cambiamos dos cosas: tratamos los errores de checksum como urgentes incluso si la redundancia los enmascaraba, y ajustamos la estrategia de metadatos para los datasets más pesados. La lección no fue “redundant_metadata hubiera evitado esto”. Fue que los metadatos son el primer lugar donde el hardware marginal se hace visible, y la paridad no hace que el rendimiento sea gratis.

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

Otro entorno: un sistema de builds que producía millones de artefactos pequeños. La pool era SSD RAIDZ, y el equipo quería exprimir la máxima capacidad. Alguien leyó que la redundancia extra de metadatos “desperdicia espacio” y puso redundant_metadata=none en los datasets de artefactos. Parecía inocuo. Los scrubs estaban limpios. Los gráficos se veían bien. Se hablaba de promociones.

Meses después, un problema de firmware (no catastrófico, solo molesto) causó errores de lectura ocasionales en un subconjunto de bloques en un SSD. Con RAIDZ, ZFS reconstruyó. Otra vez, “manejado”. Pero la carga era muy dependiente de metadatos: recorridos de directorios, tormentas de stat y operaciones de snapshot durante la limpieza de retención. Un día, un job de limpieza empezó a fallar al destruir snapshots antiguos debido a “I/O error” en un dataset. No toda la pool. Ni siquiera todos los snapshots. Solo ciertas operaciones que tocaban estructuras de metadatos específicas.

Ahora lo que salió mal: porque los metadatos no tenían copias físicas extra, las opciones de recuperación eran más limitadas. RAIDZ pudo reconstruir algunos bloques, pero un bloque se volvió permanentemente ilegible tras intentos repetidos; ZFS reportó errores permanentes ligados a metadatos. El dataset quedó parcialmente inmanejable: listar era lento y con errores, la limpieza fallaba y los sends tenían problemas. Terminamos haciendo una remediación más disruptiva: restaurar desde un target de replicación que tenía una copia limpia, lo que costó tiempo y credibilidad.

La lección no fue “siempre poner redundant_metadata=all”. Fue que la “optimización” se aplicó sin entender el modo de fallo que se intercambiaba. Optimizar capacidad es fácil de justificar; la complejidad de recuperación es más difícil de cuantificar hasta que la vives.

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

Una tercera historia, y es la menos glamorosa: un equipo que hacía scrubs rutinarios, mantenía la utilización de la pool razonable y tenía separación limpia de datasets con propiedades sensatas. También tenían una política: los datasets pesados en metadatos recibían protección extra, y usaban un vdev especial en mirror para metadatos en sus pools más concurridas.

Una mañana, un host se reinició después de un mantenimiento de energía. Arrancó, pero un par de servicios estaban lentos. Nada estaba “caído”, y ese es exactamente el tipo de situación donde la gente pierde medio día acusándose mutuamente. El ingeniero de almacenamiento lanzó un scrub y enseguida vio errores de checksum que se corrigieron. El sistema se curó solo porque tenía desde dónde curarse.

No acabó ahí: la causa raíz se rastreó a un cable HBA flojo que ocasionalmente corrompía datos en vuelo. La razón por la que no fue un incidente a gran escala fue aburrida: los checksums lo detectaron, la redundancia lo reparó y los scrubs lo sacaron a la luz rápidamente. Reemplazaron el cable, validaron y siguieron adelante. Sin heroicidades. Sin restauración de fin de semana. Sin dramática reunión de “casi lo perdimos todo”.

Esta es la verdadera condición de victoria: un sistema diseñado para que la falla parezca mantenimiento rutinario, no un evento definitorio de carrera.

Tareas prácticas: comandos e interpretación

A continuación hay tareas prácticas que puedes ejecutar en un sistema ZFS. Los comandos están escritos en un shell estilo Linux con las herramientas OpenZFS. Ajusta nombres de pool/dataset a tu entorno.

Tarea 1: Comprobar la configuración actual de redundant_metadata (y la herencia)

cr0x@server:~$ zfs get -r -o name,property,value,source redundant_metadata tank
NAME                 PROPERTY           VALUE  SOURCE
tank                 redundant_metadata all    default
tank/home            redundant_metadata all    inherited from tank
tank/registry         redundant_metadata none   local
tank/registry/blobs   redundant_metadata none   inherited from tank/registry

Interpretación: Busca overrides “local” que pueden haberse establecido como un arreglo rápido u optimización. “default” o “inherited” no es automáticamente correcto; solo significa que nadie lo tocó.

Tarea 2: Cambiar redundant_metadata de forma segura en un único dataset

cr0x@server:~$ sudo zfs set redundant_metadata=all tank/registry
cr0x@server:~$ zfs get redundant_metadata tank/registry
NAME           PROPERTY           VALUE  SOURCE
tank/registry  redundant_metadata all    local

Interpretación: Esto afecta a las escrituras de metadatos futuras para ese dataset. No reescribirá inmediatamente metadatos existentes. Si esperabas un cambio instantáneo en la distribución en disco, te decepcionarás (y esa decepción es más segura que la alternativa).

Tarea 3: Validar salud de la pool y ver si ya existen errores

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Determine if the device needs to be replaced, and clear the errors
  see: none
config:

        NAME           STATE     READ WRITE CKSUM
        tank           ONLINE       0     0     0
          raidz2-0     ONLINE       0     0     0
            sda        ONLINE       0     0    12
            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

errors: Permanent errors have been detected in the following files:

        tank/registry@daily-2025-12-01:/blobs/sha256/aa/...

Interpretación: Los errores de checksum en un dispositivo no son “están bien porque RAIDZ2”. Son un síntoma. Los errores permanentes que apuntan a una ruta de snapshot a menudo indican problemas de metadatos o bloques referenciados que afectan la vista de ese snapshot.

Tarea 4: Hacer un scrub a propósito, no por superstición

cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ zpool status tank
  pool: tank
 state: ONLINE
status: scrub in progress since Tue Dec 24 10:11:22 2025
        1.23T scanned at 510M/s, 420G issued at 173M/s, 8.11T total
        0B repaired, 5.18% done, 0:07:42 to go

Interpretación: “Scanned” vs “issued” importa. Si issued es mucho más bajo, la pool está buscando/encolando o está limitada por IOPS. Las pools pesadas en metadatos a menudo muestran fuertemente esta brecha.

Tarea 5: Comprobar la presión de espacio (porque lo cambia todo)

cr0x@server:~$ zpool list -o name,size,alloc,free,capacity,frag,health
NAME  SIZE  ALLOC  FREE  CAPACITY  FRAG  HEALTH
tank  10T   8.7T   1.3T  87%       52%   ONLINE

Interpretación: 87% lleno y 52% fragmentado es la zona donde “escrituras pequeñas aleatorias de metadatos” se vuelven más caras. Si estás afinando la redundancia de metadatos en una pool tan llena, la planificación de capacidad es parte de la solución.

Tarea 6: Identificar datasets pesados en metadatos por recuento de objetos y espacio lógico

cr0x@server:~$ zfs list -o name,used,refer,logicalused,logicalrefer,compressratio -r tank
NAME           USED  REFER  LOGICALUSED  LOGICALREFER  RATIO
tank           8.7T  128K   11.2T        128K          1.28x
tank/home      1.2T  1.2T   1.3T         1.2T          1.09x
tank/registry  6.8T  6.8T   9.4T         9.4T          1.38x

Interpretación: Esto no muestra directamente metadatos, pero ayuda a encontrar datasets donde el comportamiento lógico vs físico y el churn pueden indicar mucha actividad de punteros de bloque. Combina con el recuento de snapshots y el conocimiento de la carga.

Tarea 7: Contar snapshots y entender el riesgo de retención

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -r tank/registry | head
NAME                                USED  REFER  CREATION
tank/registry@hourly-2025-12-24-09   0B    6.8T   Tue Dec 24 09:00 2025
tank/registry@hourly-2025-12-24-08   0B    6.8T   Tue Dec 24 08:00 2025
tank/registry@daily-2025-12-23       12G   6.7T   Mon Dec 23 00:10 2025

Interpretación: Muchos snapshots significan muchos caminos históricos de metadatos. Si las operaciones sobre snapshots antiguos fallan, la redundancia de metadatos puede ser parte de la estrategia de resiliencia, pero también necesitas disciplina de scrubs y una retención sensata.

Tarea 8: Confirmar si existe un vdev especial (tier de metadata)

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

        NAME             STATE     READ WRITE CKSUM
        tank             ONLINE       0     0     0
          raidz2-0       ONLINE       0     0     0
            sda          ONLINE       0     0     0
            sdb          ONLINE       0     0     0
            sdc          ONLINE       0     0     0
            sdd          ONLINE       0     0     0
            sde          ONLINE       0     0     0
            sdf          ONLINE       0     0     0
        special
          mirror-1       ONLINE       0     0     0
            nvme0n1p1    ONLINE       0     0     0
            nvme1n1p1    ONLINE       0     0     0

Interpretación: Si tienes un vdev especial, debe ser redundante. Si es un dispositivo único, trátalo como una caída esperando a ocurrir.

Tarea 9: Comprobar hacia dónde van los metadatos (comportamiento a alto nivel)

cr0x@server:~$ zpool get -o name,property,value,source feature@spacemap_histogram tank
NAME  PROPERTY                   VALUE  SOURCE
tank  feature@spacemap_histogram active local

Interpretación: Las features varían por plataforma y versión; el punto es verificar que tu pool soporta las herramientas que planeas usar para visibilidad. Si tu plataforma tiene introspección limitada, puede que necesites confiar más en síntomas de carga y resultados de scrub.

Tarea 10: Observar presión de I/O y latencia (vista rápida)

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

avg-cpu:  %user %nice %system %iowait  %steal   %idle
           6.12  0.00    3.45   18.90    0.00   71.53

Device            r/s     w/s   rkB/s   wkB/s  await  svctm  %util
sda              32.0   210.0   820.0  4600.0  98.12   3.10  79.2
sdb              30.0   208.0   800.0  4550.0 102.55   3.20  80.1
nvme0n1         900.0   700.0 72000.0 64000.0   1.20   0.05   8.5

Interpretación: Alto await en HDDs con bajo throughput a menudo indica saturación por I/O aleatorio—dolor clásico de metadatos. Baja utilidad en NVMe special vdev sugiere que no es el cuello; alta utilidad sugiere saturación del tier de metadata o un special vdev mal dimensionado.

Tarea 11: Observar estadísticas I/O de ZFS (a nivel de pool)

cr0x@server:~$ zpool iostat -v tank 1 3
                               capacity     operations     bandwidth
pool                         alloc   free   read  write   read  write
---------------------------  -----  -----  -----  -----  -----  -----
tank                          8.7T   1.3T  2.10K  5.80K  180M   95M
  raidz2-0                    8.7T   1.3T  2.10K  5.80K  180M   95M
    sda                           -      -    350    970   30M   16M
    sdb                           -      -    350    970   30M   16M
    sdc                           -      -    350    970   30M   16M
    sdd                           -      -    350    970   30M   16M
    sde                           -      -    350    970   30M   16M
    sdf                           -      -    350    970   30M   16M
special                            -      -    900  1.10K  72M   64M
  mirror-1                         -      -    900  1.10K  72M   64M
    nvme0n1p1                      -      -    450    550   36M   32M
    nvme1n1p1                      -      -    450    550   36M   32M
---------------------------  -----  -----  -----  -----  -----  -----

Interpretación: Esto ayuda a confirmar si el tráfico de metadata/bloque pequeño está aterrizando en el special vdev o si los HDD RAIDZ están haciendo el trabajo doloroso. Si falta el special vdev, las IOPS de metadata van a los vdevs principales.

Tarea 12: Comprobar knobs de dataset que interactúan con comportamiento de metadatos

cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,atime,xattr,dnodesize,compression,redundant_metadata tank/registry
NAME           PROPERTY           VALUE
tank/registry  recordsize         128K
tank/registry  atime              off
tank/registry  xattr              sa
tank/registry  dnodesize          legacy
tank/registry  compression        zstd
tank/registry  redundant_metadata all

Interpretación: La estrategia de metadatos no vive sola. xattr=sa puede aumentar la densidad de metadatos en dnodes; dnodesize afecta cuánto metadato puede vivir “inline”. Estos ajustes cambian la cantidad de I/O de metadatos y el coste de duplicarlos.

Tarea 13: Identificar errores de checksum temprano y borrarlos solo tras la remediación

cr0x@server:~$ zpool status -x
pool 'tank' has experienced checksum errors
cr0x@server:~$ sudo zpool clear tank
cr0x@server:~$ zpool status -x
all pools are healthy

Interpretación: Borrar errores es para registro después de haber abordado la causa (reemplazar disco, arreglar cables, completar scrub). Borrarlos primero solo elimina evidencia y no enseña nada al sistema.

Tarea 14: Usar un árbol de ficheros controlado para ver costos de metadatos en microcosmos (técnica de laboratorio)

cr0x@server:~$ mkdir -p /tank/testmeta
cr0x@server:~$ time bash -c 'for i in $(seq 1 200000); do echo x > /tank/testmeta/f_$i; done'
real    2m41.772s
user    0m20.118s
sys     1m39.332s

Interpretación: Es una herramienta básica, pero hace visible el coste de los metadatos. Repite en un dataset con diferentes ajustes de redundant_metadata (en laboratorio) y compara latencia y estadísticas de I/O. No lo hagas en producción a menos que te guste dar explicaciones.

Guía rápida de diagnóstico

Este es el orden que uso cuando un sistema está lento y “podría ser almacenamiento”. El objetivo es identificar si los metadatos son el cuello de botella, y si los ajustes de redundancia están contribuyendo.

Primero: ¿La pool está sana, o estamos pagando impuesto de reconstrucción?

cr0x@server:~$ zpool status -v tank

Mira: errores de checksum, dispositivos degradados, scrub en progreso, “permanent errors”, errores de lectura repetidos en un solo dispositivo. Si ves incrementos en CKSUM, asume impacto en rendimiento incluso si la pool está ONLINE.

Segundo: ¿Estamos limitados por capacidad/fragmentación?

cr0x@server:~$ zpool list -o name,capacity,frag,alloc,free tank

Mira: capacidad > 80–85% y alta fragmentación. Si estás casi lleno, la duplicación de metadatos es más probable que haga daño, y el comportamiento del asignador puede dominar todo.

Tercero: ¿Es latencia IOPS (tipo metadatos) o throughput (tipo datos)?

cr0x@server:~$ iostat -x 1 10

Mira: alto await con bajo KB/s apunta a presión por I/O aleatorio—a menudo metadatos. Alto KB/s con alta util apunta a saturación por throughput secuencial.

Cuarto: ¿El vdev especial está haciendo su trabajo (si existe)?

cr0x@server:~$ zpool status tank
cr0x@server:~$ zpool iostat -v tank 1 5

Mira: vdev special ocupado mientras los HDDs están tranquilos (bueno: metadata offloaded) versus HDDs ocupados con I/O pequeño (metadata atascada en discos mecánicos).

Quinto: Confirmar ajustes a nivel de dataset en la ruta caliente

cr0x@server:~$ zfs get -o name,property,value,source redundant_metadata,copies,recordsize,xattr,dnodesize,primarycache tank/registry

Mira: copies accidentalmente establecido en 2+ (error común), o redundant_metadata configurado inconsistente con la carga y tolerancia al riesgo.

Sexto: Decidir: ¿arreglamos hardware, carga o configuración?

Si existen errores: arregla hardware primero. Si estás casi lleno: arregla capacidad primero. Si las IOPS de metadatos son el cuello: considera un vdev special (bien en mirror), reducir el churn de metadatos (política de snapshots, comportamiento de la app), y luego considera la redundancia de metadatos en contexto.

Errores comunes: síntomas y soluciones

Error 1: Tratar los errores de checksum como “no urgentes porque hay redundancia”

Síntoma: zpool status muestra errores CKSUM en un dispositivo, la pool permanece ONLINE, pero los scrubs se ralentizan y las operaciones de metadatos se vuelven puntuales.

Solución: Investiga y remedia la causa subyacente (disco, cable, HBA, backplane). Ejecuta un scrub tras el reemplazo. Solo entonces borra los errores.

Error 2: Usar redundant_metadata=none como optimización general de capacidad

Síntoma: Meses después ves errores permanentes ligados a rutas de snapshot o fallos de recorrido de directorios durante replicación/limpieza.

Solución: Reevalúa el riesgo. Considera redundant_metadata=most o all para datasets pesados en metadatos/críticos, especialmente en RAIDZ. Acompaña con scrubs y retención sensata de snapshots.

Error 3: Confundir redundant_metadata con copies

Síntoma: La pool se llena “misteriosamente”, la latencia de escritura aumenta, y encuentras copies=2 activado en datasets grandes.

Solución: Usa zfs get copies en el árbol y resetea donde no proceda. Reserva copies para casos muy concretos (datasets pequeños críticos en pools no redundantes, o casos especiales), no como un ajuste casual de fiabilidad.

Error 4: Construir un vdev special sin redundancia

Síntoma: Todo es rápido hasta que el dispositivo especial muere, y entonces la pool está en estado catastrófico (a menudo no importable o faltan metadatos críticos).

Solución: El vdev special debe estar en mirror (mínimo) y monitorizado como un componente de primera clase. Trátalo como parte del diseño de redundancia de la pool.

Error 5: Esperar resultados inmediatos tras cambiar la propiedad

Síntoma: Pones redundant_metadata=all y no ves cambio en errores o rendimiento, así que lo vuelves atrás y declaras que es inútil.

Solución: Recuerda: impacta las escrituras nuevas. Los beneficios se acumulan a medida que los metadatos se reescriben. Úsalo como política, no como botón de pánico.

Error 6: Ignorar utilización de pool y fragmentación mientras afinas metadatos

Síntoma: Cualquier cambio parece empeorar las cosas, especialmente en pools HDD RAIDZ; la latencia se dispara durante operaciones de snapshot y scrubs.

Solución: Recupera capacidad (borra datos, acorta retención, añade vdevs). Afinar en una pool casi llena es como reorganizar muebles en una casa en llamas: técnicamente posible, emocionalmente poco útil.

Listas de comprobación / plan paso a paso

Checklist A: Decidir qué ajustar (nivel de política)

  1. Clasifica datasets por impacto de negocio: “puede restaurarse después” vs “debe estar en línea”.
  2. Clasifica por carga: pesado en metadatos (muchos ficheros pequeños, snapshots, directorios) vs pesado en datos (ficheros secuenciales grandes).
  3. Clasifica por topología de vdev: mirror vs RAIDZ; y si existe un vdev special.
  4. Si RAIDZ + metadata-heavy + alta criticidad: inclínate hacia redundant_metadata=all (o al menos most).
  5. Si mirror + hardware sano + no es metadata-heavy: la configuración por defecto puede ser suficiente; céntrate en scrubs y monitorización.
  6. Si la pool está >85% llena: arregla capacidad antes de añadir sobrecarga.

Checklist B: Desplegar el cambio de forma segura

  1. Inventario de ajustes actuales:
cr0x@server:~$ zfs get -r -o name,property,value,source redundant_metadata tank
  1. Elige un único dataset en la ruta caliente y cámbialo primero:
cr0x@server:~$ sudo zfs set redundant_metadata=all tank/registry
  1. Rastrea la línea base de rendimiento antes/después con estadísticas de pool y dispositivo:
cr0x@server:~$ zpool iostat -v tank 1 10
cr0x@server:~$ iostat -x 1 10
  1. Ejecuta un scrub en una ventana controlada y compara errores corregidos y throughput:
cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ zpool status tank
  1. Despliega al resto de datasets solo después de entender la sobrecarga.

Checklist C: Si sospechas cuello de botella por IOPS de metadatos

  1. Confirma que es latencia/IOPS, no throughput (iostat -x).
  2. Confirma que la pool no está degradada / reconstruyéndose mucho (zpool status -v).
  3. Comprueba capacidad/frag (zpool list).
  4. Verifica si existe un vdev special y si está dimensionado/redundante (zpool status).
  5. Solo entonces afina políticas de metadatos (redundant_metadata, retención de snapshots y organización de datasets).

Preguntas frecuentes

1) ¿Debería siempre poner redundant_metadata=all?

No. Es una buena opción para datasets críticos y pesados en metadatos en pools RAIDZ, especialmente con retención larga de snapshots. En mirrors, el beneficio incremental para integridad suele ser menor, y la sobrecarga puede no valer la pena para cada dataset.

2) ¿Es redundant_metadata un sustituto de mirrors o RAIDZ2?

No. No cambia la tolerancia a fallos a nivel de vdev. Ayuda con ciertas corrupciones y escenarios de bloques ilegibles al aumentar la probabilidad de que exista un bloque alternativo de metadatos.

3) ¿Cuál es la diferencia entre redundant_metadata y copies=2?

copies duplica también bloques de datos, lo que puede ser extremadamente costoso en espacio y carga de escritura. redundant_metadata apunta solo a metadatos, típicamente mucho más barato, y suele ser la herramienta más quirúrgica.

4) ¿Cambiar redundant_metadata reescribe metadatos existentes?

No de inmediato. Afecta a metadatos recién escritos. Los bloques existentes pueden reescribirse a medida que los ficheros cambian, se crean/eliminen snapshots, o los bloques se realocan con el tiempo. Trátalo como una política orientada al futuro.

5) ¿Esto arreglará mensajes de “permanent errors have been detected”?

No directamente. Errores permanentes significan que ZFS no pudo reparar un bloque con la redundancia disponible en el momento que se necesitó. Copias extra pueden reducir la probabilidad de que eso ocurra en el futuro, pero aún necesitas remediar el daño existente (restaurar desde replicación/backup, o eliminar el snapshot/ficheros afectados si es posible).

6) ¿Un vdev special hace innecesario redundant_metadata?

No. Un vdev special mejora rendimiento de metadatos y puede mejorar resiliencia si está en mirror y sano. Pero sigue siendo hardware y puede experimentar corrupción o fallos de lectura. Copias extra de metadatos pueden complementar un vdev special; no sustituyen un buen diseño de redundancia.

7) ¿Cuáles son las señales más comunes de que los metadatos son mi cuello?

Alto I/O wait, alto await del disco con bajo throughput, listados de directorio lentos, operaciones de snapshot lentas, cargas de ficheros pequeños lentas, y scrubs con “issued” muy por debajo de “scanned”. También: rendimiento que empeora al llenar y fragmentar la pool.

8) ¿Puede redundant_metadata empeorar el rendimiento?

Sí, especialmente en pools basadas en HDD y cargas pesadas en metadatos. Añades escrituras pequeñas extra. Si ya estás limitado por IOPS, puede incrementar la latencia. Por eso se despliega por dataset y se mide.

9) Si estoy en mirrors, ¿debería ponerlo a none para rendimiento?

Quizá, pero no lo hagas por reflejo. Los mirrors ya proporcionan auto-reparación fuerte, así que el beneficio de integridad es menor; sin embargo, la sobrecarga de duplicación de metadatos puede ser también menor de lo que piensas según la carga. Prueba en un dataset representativo y no optimices seguridad por defecto a menos que sepas qué modo de fallo aceptas.

10) ¿Cuál es la configuración más “aburrida y correcta” aquí?

Para datasets críticos: mantén scrubs programados, controla la utilización, usa vdevs redundantes (mirror o RAIDZ adecuado), y define la estrategia de metadatos intencionalmente (a menudo redundant_metadata=all para datasets metadata-heavy en RAIDZ). La mayoría de desastres son una acumulación de pequeñas decisiones de “lo arreglamos luego”.

Conclusión

redundant_metadata es una de esas palancas de ZFS que parece una casilla hasta que vives un incidente relacionado con metadatos. Entonces empieza a verse como una póliza de seguro con una prima pagada en escrituras de bloque pequeño y sobrecarga de capacidad. El truco es comprar la póliza donde importa: datasets con alto churn de metadatos, historiales largos de snapshots y alto impacto de negocio—especialmente en pools RAIDZ donde la reconstrucción bajo estrés es cara.

Si extraes solo una lección operativa: no debatas la redundancia de metadatos en abstracto. Mide la salud de tu pool, capacidad y margen de IOPS; entiende si los metadatos están en la ruta crítica; y luego configura redundant_metadata intencionadamente por dataset. ZFS hará las cuentas, pero no priorizará por ti.

← Anterior
Contenedores Docker de solo lectura: Endurece sin romper tu app
Siguiente →
Proxmox “Disco no arrancable”: orden de arranque BIOS/UEFI, flags de disco y una ruta rápida de recuperación

Deja un comentario