La deduplicación de ZFS es el equivalente en almacenamiento de un botón de “Dinero Gratis”. Parece inofensiva, funciona bien en demostraciones y ha arruinado más de un fin de semana de on-call. La promesa seduce: almacenar bloques idénticos una sola vez, referenciarlos muchas veces, recuperar montones de espacio y parecer un mago en la temporada de presupuestos.
La realidad es más parecida a esto: cambias disco por memoria, y si no pagas esa factura de memoria, ZFS cobra intereses en forma de latencia, thrash y comportamiento aterrador del pool. Dedup puede ser una herramienta válida, pero no debe ser la opción por defecto. Este artículo trata sobre cómo ejecutarla en producción sin engañarte a ti mismo.
Tabla de contenido
- Qué hace realmente dedup (y qué no hace)
- Por qué dedup devora RAM: el DDT y el impuesto que no puedes evitar
- Hechos y contexto histórico (lo que la gente olvida)
- Cuándo funciona dedup (raro, real y específico)
- Cuándo falla dedup (común, caro, previsible)
- Tres microhistorias corporativas desde las trincheras
- Tareas prácticas: comandos, salidas y cómo interpretarlos
- Guía de diagnóstico rápido: encuentra el cuello de botella antes de que te encuentre
- Errores comunes: síntomas y soluciones
- Listas de verificación / plan paso a paso
- Preguntas frecuentes
- Conclusión
Qué hace realmente dedup (y qué no hace)
La deduplicación de ZFS es dedup a nivel de bloque. Cuando activas dedup=on para un dataset, ZFS calcula un hash de cada bloque a medida que se escribe. Si ya existe un bloque con ese hash en el pool, ZFS evita escribir una segunda copia y crea otra referencia al bloque existente.
Esto no es deduplicación a nivel de archivo, no es “encontrar ISO idénticas” y no es un trabajo en segundo plano que puedas pausar cuando la base de datos está sensible. Dedup es en línea: sucede en la ruta de escritura. Eso significa que cada escritura incluye trabajo extra: calcular la suma, buscarla y posiblemente actualizar metadatos de dedup. No puedes “deduplicar después” a menos que reescribas los datos después—más sobre esa molestia en breve.
También: dedup no es compresión. La compresión reduce bloques codificándolos de forma más eficiente. Dedup evita almacenar bloques duplicados por completo. Pueden complementarse, pero la compresión suele ser la primera palanca porque es barata, predecible y a menudo mejora el I/O al reducir bytes en disco.
Una frase que debería ir en una pegatina: ZFS dedup es un problema de metadatos disfrazado de característica de capacidad.
Broma #1: Dedup es como comprar una trituradora de papel para ahorrar espacio en el archivador—técnicamente correcto, hasta que te das cuenta de que funciona con electricidad y solo tienes un enchufe.
Por qué dedup devora RAM: el DDT y el impuesto que no puedes evitar
El corazón palpitante de dedup es la DDT: la Deduplication Table. Conceptualmente, es un mapeo checksum de bloque → puntero(s) físico(s) y contadores de referencias. En cada escritura a un dataset con dedup activado, ZFS necesita determinar si ya existe un bloque idéntico. Eso requiere una búsqueda en la DDT.
Si la DDT está caliente en memoria, dedup puede ser solo “algo de sobrecarga”. Si la DDT no está en memoria, dedup se convierte en “lecturas aleatorias de metadatos mientras intentas escribir datos”, que es como convertir un sistema de almacenamiento respetable en una pieza de arte interpretativa de rendimiento.
ARC, L2ARC y por qué “solo agregar SSD” no es un plan
ZFS usa ARC (Adaptive Replacement Cache) en RAM para el cacheo. Dedup quiere la DDT en ARC porque se accede constantemente. Cuando ARC es lo suficientemente grande, la vida está bien. Cuando ARC no lo es, ZFS debe traer entradas de DDT desde disco. Esas son lecturas pequeñas y dispersas que son lo peor para discos giratorios y aún molestas en SSDs bajo carga.
Algunos entornos intentan “arreglar” esto con L2ARC (cache secundaria en SSD). L2ARC puede ayudar, pero no es magia. L2ARC es más lento que RAM y tiene su propia sobrecarga de metadatos. Si ya tienes poca memoria, agregar L2ARC puede empeorar las cosas al consumir más RAM para encabezados de L2ARC mientras sigue sin ofrecer latencias comparables a la RAM.
Special vdev: mejor, pero no gratis
En OpenZFS más recientes, un special vdev puede almacenar metadatos (y opcionalmente bloques pequeños) en dispositivos rápidos. Si tu DDT y otros metadatos viven en un special vdev espejo NVMe, las búsquedas de dedup son mucho menos dolorosas. Este es el primer enfoque que se siente como una arquitectura real en lugar de un mecanismo de afrontamiento. Pero tiene un filo afilado: si pierdes el special vdev, puedes perder el pool. Trátalo como tratarías a tu vdev más sagrado, porque lo es.
Por qué existe el folklore de “RAM por TB”
Escucharás reglas empíricas como “1–5 GB de RAM por TB de datos dedupeados”. La respuesta real depende de recordsize, carga de trabajo, cuánto se duplican los datos y cuán grande se hace la DDT. Pero el folklore existe porque el modo de fallo es consistente: una vez que la DDT no cabe en memoria, la latencia se dispara y el rendimiento cae por un acantilado.
Y hay una segunda trampa: no necesitas que ARC quepa todo el pool, necesitas que ARC quepa el working set de la DDT. Si tu conjunto de trabajo de entradas DDT es grande (alta rotación, muchos bloques únicos), puedes tener mucha RAM y aun así pasarlo mal.
Hechos y contexto histórico (lo que la gente olvida)
Dedup no se volvió “controvertida” porque esté rota. Se volvió controvertida porque es fácil de activar y difícil de operar de forma segura. Algunos puntos de contexto a tener en cuenta:
- ZFS dedup lleva mucho tiempo existiendo, y las implementaciones tempranas se ganaron la reputación de castigar el uso de memoria porque los sistemas de entonces tenían menos recursos y las capas metálicas de SSD eran raras.
- Dedup es por dataset, no por pool, pero la DDT vive a nivel de pool. Un único dataset con dedup activado puede imponer sobrecarga en el comportamiento de todo el pool.
- No puedes “apagar” dedup retroactivamente. Ajustar
dedup=offsolo afecta las escrituras nuevas. Los bloques existentes permanecen dedupeados hasta que se reescriban. - Dedup interactúa con snapshots: los bloques dedupeados pueden ser referenciados a través de snapshots y clones, incrementando contadores de referencia y haciendo la contabilidad de espacio más sutil.
- Dedup hace que ciertos modos de fallo sean más lentos: resilver, scrub y algunas reparaciones pueden tardar más porque hay que recorrer más metadatos y referencias.
- La compresión a menudo entrega la mayor parte del beneficio con menos riesgos, especialmente en logs, JSON, imágenes de VM y páginas de bases de datos que no son idénticas pero sí compresibles.
- Las imágenes golden de VM son el ejemplo clásico de ganancias por dedup, pero las pilas modernas de VM a menudo usan cloning/linked clones o capas de imagen que ya evitan duplicación.
- El crecimiento de la DDT puede sorprender cuando recordsize es pequeño o las cargas generan muchos bloques únicos (bases de datos, datos encriptados, blobs ya comprimidos).
- Los datasets cifrados reducen la oportunidad de dedup: el cifrado tiende a randomizar bloques, eliminando patrones de bloques idénticos a menos que dedup ocurra antes del cifrado en la ruta de datos (a menudo no es así).
Cuándo funciona dedup (raro, real y específico)
Dedup puede ser la herramienta correcta cuando todas las siguientes condiciones son verdaderas:
- Tus datos son genuinamente idénticos a nivel de bloque entre muchos archivos o imágenes. No “similares”, no “compresibles”, sino bloques idénticos a la recordsize que uses.
- Tu working set es estable, o al menos predecible. Dedup odia la alta rotación donde el working set de la DDT cambia constantemente.
- Puedes pagar la factura de metadatos: suficiente RAM y/o una capa de metadatos rápida (special vdev) para evitar que las búsquedas de DDT sean accesos a disco.
- Has probado con datos parecidos a producción. Las pruebas sintéticas mienten; dedup es especialmente sensible a cómo se organizan los datos en la vida real.
Los entornos donde he visto dedup tener éxito sin drama suelen parecerse a:
1) Destinos de backup con copias completas repetidas (con matices)
Si tienes muchas copias completas que contienen bloques idénticos (por ejemplo, una granja de máquinas similares) y escribes flujos secuenciales grandes, dedup puede entregar grandes ahorros de espacio. Pero si tu software de backup ya deduplica a nivel de aplicación, dedup de ZFS es redundante y a veces dañino. Además, las escrituras de backup suelen ser bursty—lo que significa que la DDT debe sobrevivir al pico de ingestión, no al promedio.
2) VDI / plantillas VM (solo si no usas clones)
Cientos de escritorios o VMs creados desde la misma plantilla pueden compartir muchos bloques idénticos. Pero muchas plataformas ya usan cloning copy-on-write que evita duplicación sin dedup de ZFS. Si ya estás en ZFS, los clones y snapshots de ZFS pueden ofrecer la mayor parte del beneficio con menos riesgo.
3) Datasets mayormente de solo lectura con artefactos idénticos
Pensemos en grandes flotas distribuyendo capas de contenedores idénticas, repositorios de paquetes o artefactos de build—siempre que esos artefactos sean realmente idénticos a nivel de bloque y no se vuelvan a firmar o re-fechar de formas que cambien bloques. Esto es más raro de lo que la gente supone.
Cuándo falla dedup (común, caro, previsible)
Dedup falla de la forma que a los SREs les disgusta: lentamente al principio, luego de golpe, y generalmente a las 2 a.m.
1) Bases de datos y cualquier cosa con alta rotación
Las bases de datos reescriben páginas. Incluso si el contenido lógico es similar, los bloques difieren y el patrón de escritura agita metadatos. Si aumentan los DDT misses y la DDT no puede permanecer caliente en ARC, verás latencias puntuales y una caída del rendimiento. También corres el riesgo de convertir mantenimientos rutinarios (scrubs, resilvers) en operaciones de varios días.
2) Datos ya comprimidos o cifrados
Video comprimido, archivos, muchos formatos binarios y blobs cifrados suelen tener baja deduplicación. Pagas la sobrecarga y obtienes poco espacio a cambio. Este es el peor trato en almacenamiento: sobrecarga sin beneficio.
3) Cargas mixtas en un pool compartido
Un equipo habilita dedup en un dataset. La DDT a nivel de pool crece. Otro equipo que ejecuta cargas sensibles a la latencia en un dataset distinto comienza a abrir tickets por “pausas aleatorias”. Nadie conecta los puntos hasta que grafiqueas misses de ARC y ves la DDT peleando por memoria.
4) “Ya agregaremos RAM después”
Esto no es un interruptor reversible. Si activas dedup y ingestas semanas de datos, luego descubres que la DDT es demasiado grande, desactivar dedup no elimina las entradas de la DDT. Ahora estás en el negocio de reescribir datos o migrar, que es el equivalente de almacenamiento de descubrir que tu “cinta” temporal es ahora estructural.
Broma #2: ZFS dedup es la única característica que conozco que puede convertir “ahorramos 20% de disco” en “perdimos 80% de rendimiento” con el mismo entusiasmo.
Tres microhistorias corporativas desde las trincheras
Microhistoria 1: El incidente causado por una suposición errónea
Una empresa mediana operaba un clúster de virtualización privado sobre ZFS. Un nuevo responsable de almacenamiento heredó una solicitud cara de expansión y decidió “ser inteligente” antes de comprar más discos. Activó dedup en el dataset que almacenaba discos de VM, esperando una duplicación basada en plantillas.
La suposición errónea: “Las VMs son todas similares, así que dedup será enorme”. En realidad, el entorno había derivado. Las plantillas estaban obsoletas, muchas VMs habían recibido parches durante años y la plataforma ya usaba cloning para despliegues iniciales. Había duplicación, pero nada cerca de lo que la hoja de cálculo imaginó.
Los primeros síntomas fueron sutiles: picos ocasionales de latencia durante las tormentas de login matinales. Luego el helpdesk empezó a reportar “VMs lentas” y “congelamientos aleatorios”. IOPS en promedios parecían bien, pero la latencia p99 de escritura era fea. Los scrubs también comenzaron a tardar más—más recorrido de metadatos, más presión de cache.
El equipo on-call lo trató como un problema de hipervisor hasta que alguien correlacionó los picos con misses de cache de DDT. La DDT era mucho mayor de lo esperado, ARC expulsaba constantemente datos útiles para hacer espacio a metadatos de dedup y el pool hacía pequeñas lecturas aleatorias solo para decidir cómo escribir.
Desactivaron dedup en el dataset esperando una solución inmediata. El rendimiento mejoró ligeramente (menos búsquedas nuevas de dedup), pero la DDT permaneció masiva porque los datos existentes seguían dedupeados. La solución final fue una migración controlada: replicar datasets a un nuevo pool sin dedup y cortar. El “ahorro de disco” terminó costando semanas de planificación y muchas reuniones donde nadie podía decir “te lo dije”.
Microhistoria 2: La optimización que salió mal
Una compañía SaaS usaba ZFS como backend para un almacén interno de artefactos. La carga era principalmente escrituras durante picos de CI y lecturas durante despliegues. El crecimiento de espacio preocupaba y alguien notó que muchos artefactos compartían capas base idénticas.
Hicieron una prueba rápida en un subconjunto pequeño, vieron buenas ratios de dedup y lo desplegaron masivamente. La optimización falló porque el conjunto de prueba estaba sesgado: contenía salidas de build mayormente idénticas de un único proyecto que reutilizaba capas intensamente. El entorno más amplio contenía muchos proyectos con dependencias ligeramente distintas y rebuilds frecuentes que cambiaban bloques lo suficiente para derrotar a dedup.
En un mes, el sistema de artefactos comenzó a incumplir SLAs en horas pico. No porque los discos estuvieran llenos, sino porque las búsquedas de metadatos estaban ahora en la ruta crítica para cada escritura. ARC estaba hambriento; el sistema pasaba su tiempo trayendo entradas DDT. El equipo intentó añadir L2ARC para “cachear la tabla”, lo cual aumentó la presión de RAM y poco ayudó a la latencia pico.
La solución fue aburrida: revertir dedup, activar compresión y rediseñar las políticas de retención. La compresión dio ahorros predecibles con menos dolor de metadatos. El rediseño de retención cortó el crecimiento de la cola larga. Dedup no era exactamente el villano—era la herramienta equivocada para una carga con alta variabilidad y sin una capa de metadatos apropiada.
Microhistoria 3: La práctica correcta y aburrida que salvó el día
Una firma de servicios financieros operaba una plataforma de backups basada en ZFS. Los tentó dedup porque los backups estaban “llenos de repeticiones”. El ingeniero de almacenamiento—callado, metódico y alérgico a sorpresas—insistió en una lista de verificación preflight antes de activar nada.
Tomaron una muestra representativa: una semana de backups reales, no sintéticos, y la volcaron en un pool de staging. Midieron ratio de compresión, ratio de dedup, tamaño de DDT, comportamiento de ARC y rendimiento pico de ingestión. También simularon un scrub y una ventana de resilver mientras el sistema estaba con carga moderada, porque las peores fallas ocurren cuando el mantenimiento se solapa con tráfico.
Los datos mostraron que dedup ayudaría, pero solo si los metadatos vivían en dispositivos rápidos. Así que construyeron el pool con un special vdev espejo dimensionado para el crecimiento de metadatos y lo trataron como infraestructura crítica (monitorización, repuestos, control estricto de cambios). También limitaron la concurrencia de ingest para evitar thrash de DDT en picos.
Cuando un incidente de hardware forzó un resilver durante una semana ocupada, el sistema se mantuvo estable. No fue emocionante—nadie ganó un trofeo—pero evitó la historia clásica de dedup: “ahorramos espacio y luego perdimos el fin de semana”. La práctica correcta no fue ingeniosa; fue probar disciplinadamente y construir para la ruta de metadatos, no solo para la ruta de datos.
Tareas prácticas: comandos, salidas y cómo interpretarlos
A continuación hay tareas concretas que puedes ejecutar en un sistema típico OpenZFS (Linux con zfsutils). Algunos comandos difieren en FreeBSD/Illumos, pero el modelo mental se mantiene. El objetivo no es memorizar flags; es hacer el comportamiento de dedup medible.
Task 1: Identify which datasets have dedup enabled
cr0x@server:~$ sudo zfs get -r -o name,property,value,source dedup tank
NAME PROPERTY VALUE SOURCE
tank dedup off default
tank/vmstore dedup on local
tank/backups dedup off inherited from tank
Interpretación: Dedup es por dataset. Si ves aunque sea un dataset crítico con dedup=on, asume que existe sobrecarga de DDT a nivel de pool. Rastrea quién lo activó y por qué.
Task 2: Check the actual dedup ratio at pool level
cr0x@server:~$ sudo zpool list tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 54.5T 38.2T 16.3T - - 21% 70% 1.08x ONLINE -
Interpretación: DEDUP 1.08x significa que ahorras ~8% de espacio lógico con dedup. Eso puede no justificar la sobrecarga. Si está por debajo de ~1.2x, deberías sospechar salvo que tengas una razón muy específica.
Task 3: Check DDT size and how “hot” it is
cr0x@server:~$ sudo zpool status -D tank
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
dedup: DDT entries 48239124, size 34.1G on disk, 19.6G in core
bucket allocated referenced
______ ______________________________ ______________________________
refcnt blocks LSIZE PSIZE DSIZE blocks LSIZE PSIZE DSIZE
1 36.2M 9.44T 8.81T 8.81T 36.2M 9.44T 8.81T 8.81T
2 8.7M 2.31T 2.16T 2.16T 18.1M 4.62T 4.32T 4.32T
4 1.2M 353G 331G 331G 5.0M 1.38T 1.30T 1.30T
Interpretación: La línea clave es “size X on disk, Y in core.” Si “in core” es grande en relación con tu RAM, o si no puede permanecer en ARC, vas hacia problemas. Observa también cuántos bloques están referenciados solo una vez: si la mayoría son refcnt=1, estás pagando la sobrecarga de dedup por bloques que no se deduplicaron.
Task 4: Estimate dedup “waste” by looking at reference counts
cr0x@server:~$ sudo zdb -DD tank | head -n 25
DDT-sha256-zap-duplicate: 48239124 entries, size 34972804096 on disk, 21043748864 in core
DDT histogram (aggregated over all DDTs):
bucket allocated referenced
______ ______________________________ ______________________________
refcnt blocks LSIZE PSIZE DSIZE blocks LSIZE PSIZE DSIZE
1 36.2M 9.44T 8.81T 8.81T 36.2M 9.44T 8.81T 8.81T
2 8.7M 2.31T 2.16T 2.16T 18.1M 4.62T 4.32T 4.32T
Interpretación: Si la mayoría de los bloques son refcnt=1, dedup no está cumpliendo. Si tienes una concentración fuerte en contadores mayores (8, 16, 32), ahí dedup empieza a parecer negocio.
Task 5: Check ARC size and memory pressure signals
cr0x@server:~$ cat /proc/spl/kstat/zfs/arcstats | egrep '^(size|c |c_min|c_max|misses|hits|demand_data_misses|demand_metadata_misses) '
size 4 34325131264
c 4 36507222016
c_min 4 4294967296
c_max 4 68719476736
hits 4 1183749821
misses 4 284993112
demand_data_misses 4 84129911
demand_metadata_misses 4 162104772
Interpretación: Altos demand_metadata_misses bajo carga es un olor a dedup. Dedup es intensivo en metadatos; si los misses de metadatos suben, el pool hará más lecturas pequeñas y la latencia lo seguirá.
Task 6: Observe real-time latency and IOPS per vdev
cr0x@server:~$ sudo zpool iostat -v tank 2
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 38.2T 16.3T 110 980 11.2M 84.5M
raidz2-0 38.2T 16.3T 110 980 11.2M 84.5M
sda - - 18 165 1.9M 14.2M
sdb - - 19 164 1.8M 14.0M
sdc - - 17 162 1.7M 14.1M
sdd - - 18 163 1.9M 14.1M
sde - - 19 163 1.9M 14.0M
sdf - - 19 163 2.0M 14.1M
Interpretación: Esto muestra la distribución de carga. Si dedup está forzando lecturas aleatorias de metadatos, puedes ver subir IOPS de lectura incluso cuando la aplicación está principalmente escribiendo. Empareja esto con herramientas de latencia para confirmar.
Task 7: On Linux, catch ZFS-induced stalls via pressure metrics
cr0x@server:~$ cat /proc/pressure/memory
some avg10=0.32 avg60=0.18 avg300=0.07 total=12873631
full avg10=0.09 avg60=0.05 avg300=0.02 total=2219481
Interpretación: La presión de memoria se correlaciona fuertemente con el dolor de dedup. Si ARC está peleando con el kernel y las aplicaciones por RAM, verás subir la presión “full” durante picos.
Task 8: Check dataset recordsize and why it matters for DDT growth
cr0x@server:~$ sudo zfs get -o name,property,value recordsize tank/vmstore
NAME PROPERTY VALUE
tank/vmstore recordsize 128K
Interpretación: Un recordsize más pequeño significa más bloques para los mismos datos, lo que implica más entradas DDT. La sobrecarga de dedup escala con el número de bloques, no solo con los bytes totales.
Task 9: Measure compression ratio before reaching for dedup
cr0x@server:~$ sudo zfs get -o name,property,value,source compression,compressratio tank/vmstore
NAME PROPERTY VALUE SOURCE
tank/vmstore compression lz4 local
tank/vmstore compressratio 1.52x -
Interpretación: Si ya obtienes 1.5x de compresión, la ganancia incremental de dedup puede ser pequeña—especialmente por su coste. Si la compresión está desactivada, arréglalo primero salvo que tengas una razón fuerte para no hacerlo.
Task 10: Find whether a dataset is paying dedup overhead without benefit
cr0x@server:~$ sudo zfs get -o name,property,value written,logicalused,usedrefreserv usedbydataset tank/vmstore
NAME PROPERTY VALUE
tank/vmstore written 19.3T
tank/vmstore logicalused 27.8T
tank/vmstore usedrefreserv 0B
tank/vmstore usedbydataset 31.1T
Interpretación: logicalused vs used real pueden ayudarte a razonar sobre la eficiencia del espacio, pero dedup complica la contabilidad debido a bloques compartidos. Usa el ratio de dedup a nivel pool y los histogramas DDT para decidir si dedup está “funcionando”, no solo los valores del dataset.
Task 11: Disable dedup for new writes (and set expectations correctly)
cr0x@server:~$ sudo zfs set dedup=off tank/vmstore
cr0x@server:~$ sudo zfs get -o name,property,value dedup tank/vmstore
NAME PROPERTY VALUE
tank/vmstore dedup off
Interpretación: Esto detiene dedup en escrituras nuevas solamente. Los bloques existentes permanecen. El rendimiento puede mejorar si tu carga es muy escritora y la tasa de búsquedas DDT baja, pero el pool sigue cargando la DDT y su complejidad asociada.
Task 12: Remove deduped data the only way that truly works: rewrite or migrate
cr0x@server:~$ sudo zfs snapshot tank/vmstore@migration-start
cr0x@server:~$ sudo zfs send -R tank/vmstore@migration-start | sudo zfs receive -u tank2/vmstore
cr0x@server:~$ sudo zfs set dedup=off tank2/vmstore
cr0x@server:~$ sudo zfs mount tank2/vmstore
Interpretación: Enviar un snapshot replica bloques. Si dedup se preserva depende de cómo esté configurado el receptor y la naturaleza del stream send/receive. La forma operativamente segura es: migrar a un pool/dataset limpio con dedup off y validar. Si tu objetivo es “deshacer la DDT”, típicamente necesitas mover datos a un pool que nunca tuvo dedup activado o reescribirlos en sitio (lo cual rara vez es divertido).
Task 13: Confirm whether you have a special vdev for metadata
cr0x@server:~$ sudo zpool status tank
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
nvme0n1p2 ONLINE 0 0 0
nvme1n1p2 ONLINE 0 0 0
Interpretación: Un special vdev espejo es un gran mitigador para la latencia de metadatos de dedup. No elimina las necesidades de RAM, pero puede mantener el sistema en pie cuando ARC está presionado.
Task 14: Watch ZFS transaction group behavior (a proxy for “is storage stalling?”)
cr0x@server:~$ grep -E "txg_sync|txg_quiesce" /proc/spl/kstat/zfs/* 2>/dev/null | head
/proc/spl/kstat/zfs/tank/txgs:txg_sync 4 9123
/proc/spl/kstat/zfs/tank/txgs:txg_quiesce 4 9123
Interpretación: Si los tiempos de txg sync se inflan durante picos de dedup, el pool está teniendo problemas para comprometer cambios. Dedup añade actualizaciones de metadatos que pueden exacerbar la presión de sync.
Guía de diagnóstico rápido: encuentra el cuello de botella antes de que te encuentre
Este es el orden que uso cuando alguien alerta “ZFS está lento” y dedup podría estar involucrado. El punto es converger rápido, no ser filosóficamente completo.
Step 1: Is dedup even enabled, and is it meaningful?
- Revisa datasets:
zfs get -r dedup POOL - Revisa ratio del pool:
zpool list - Revisa tamaño de DDT:
zpool status -D POOL
Decisión: Si el ratio de dedup es bajo (< ~1.2x) y la DDT es grande, probablemente tengas “coste sin beneficio”. Planifica salir de dedup en lugar de ajustar alrededor.
Step 2: Is the DDT fitting in memory (or at least staying hot)?
- Estadísticas ARC:
cat /proc/spl/kstat/zfs/arcstats - Mira los metadata misses y los misses generales subiendo con la carga.
- Revisa presión de memoria del SO:
/proc/pressure/memory
Decisión: Si la presión de memoria es alta y los metadata misses suben, espera que las búsquedas de dedup golpeen disco. Esa es tu latencia.
Step 3: Is metadata I/O landing on slow devices?
- Confirma special vdev:
zpool status - Observa IOPS de lectura durante cargas intensas de escritura:
zpool iostat -v 2
Decisión: Si no tienes special vdev y estás en HDDs, dedup a escala rara vez termina felizmente.
Step 4: Are you actually CPU-bound on hashing?
- Revisa CPU del sistema:
top/mpstat(dependiendo de la plataforma) - Correlaciona alto uso de CPU con throughput de escritura y latencia estable.
Decisión: La sobrecarga de hashing existe, pero la mayoría de desastres reales por dedup son limitados por memoria/I/O de metadatos, no por CPU. No persigas al dragón equivocado.
Step 5: Rule out “not dedup” issues quickly
- Salud del pool:
zpool status -x - Actividad de scrub/resilver:
zpool status - Pool casi lleno y fragmentación:
zpool list(CAP), y vigila FRAG.
Decisión: Un pool con alta capacidad y alta fragmentación tendrá mal rendimiento aunque no haya dedup. Dedup puede amplificar el dolor, pero no siempre es la causa raíz.
Errores comunes (síntomas y correcciones)
Mistake 1: Enabling dedup because “we have a lot of similar data”
Síntoma: El ratio de dedup se queda cerca de 1.00x–1.15x mientras la latencia empeora.
Corrección: Activa compresión (si no está activada), mide la oportunidad real de dedup en una muestra representativa y considera dedup a nivel de aplicación o estrategias de cloning. Si dedup ya está activado y duele, planifica migración/reescritura; no esperes que dedup=off deshaga el historial.
Mistake 2: Underestimating DDT growth due to small recordsize
Síntoma: Las entradas DDT explotan; suben los misses de metadatos en ARC; aparecen IOPS de lectura aleatoria durante escrituras intensas.
Corrección: Reevalúa recordsize para el dataset. Para imágenes VM y almacenamiento de propósito general, 128K es común; tamaños más pequeños pueden ser necesarios para ciertas cargas pero tienen costes de metadatos. Si debes usar bloques pequeños, dedup se vuelve más caro.
Mistake 3: Relying on L2ARC to “solve” dedup
Síntoma: Añades SSD cache y aún ves parones; aumenta el uso de RAM; el sistema se siente peor en picos.
Corrección: Trata L2ARC como suplemento, no sustituto de RAM. Si dedup es necesario, prioriza suficiente RAM y considera un special vdev para metadatos. Valida con pruebas basadas en la carga.
Mistake 4: Enabling dedup on a mixed-use pool without isolation
Síntoma: Una carga cambia y servicios no relacionados ven picos de latencia. La gente empieza a culpar a la red.
Corrección: Si dedup es necesaria, aíslala: pool dedicado, o al menos hardware separado y una capa de metadatos dimensionada para ello. Un pool compartido es un radio de impacto compartido.
Mistake 5: Forgetting that dedup increases operational complexity
Síntoma: Scrubs/resilvers tardan más de lo planeado; las ventanas de mantenimiento se extienden; los ejercicios de recuperación son lentos.
Corrección: Mide el comportamiento de scrub/resilver en staging con dedup activado. Monitorea y presupuestar tiempo. Si RTO/RPO importan, sopesa este coste seriamente.
Mistake 6: Expecting an easy rollback
Síntoma: Pones dedup=off y nada mejora lo suficiente; la DDT sigue grande.
Corrección: Acepta la física: los bloques dedupeados permanecen dedupeados hasta reescribirlos. La salida limpia es migrar a un pool/dataset sin dedup, o una reescritura controlada de los datos (a menudo mediante send/receive, copia estilo rsync, o rehidratación a nivel de aplicación).
Listas de verificación / plan paso a paso
Checklist A: “Should we enable dedup?” (preflight)
- Define el objetivo: ¿Se trata de retrasar una compra de discos, reducir la huella de backups o habilitar una funcionalidad específica?
- Mide la compresión primero: Activa
compression=lz4en un dataset de prueba y midecompressratio. - Muestra datos reales: Usa un subconjunto representativo (no un directorio elegido) y prueba dedup en staging.
- Mide ratio de dedup y tamaño de DDT: Recopila
zpool status -Dyzdb -DD. - Modela ingestión en peor caso: Ejecuta la carga de escritura pico, no el día promedio.
- Prueba un scrub bajo carga: Confirma que aún puedes cumplir latencia y throughput.
- Decide sobre tier de metadatos: Si dedup es realmente necesario, planifica un special vdev espejo y RAM suficiente.
- Escribe el plan de rollback: Incluye cómo migrarás fuera de dedup si decepciona, y cuánto tardará.
Checklist B: If dedup is already enabled and you’re suffering
- Detén la hemorragia: Pon
dedup=offen los datasets afectados para prevenir más crecimiento de DDT por escrituras nuevas (a menos que dedup sea esencial para esos datos). - Cuantifica el impacto de la DDT: Usa
zpool status -Dy estadísticas ARC para confirmar misses de metadatos y presión de memoria. - Reduce la concurrencia temporalmente: Si la carga lo permite (ingest de backups, jobs por lotes), limita escritores paralelos para reducir presión de búsquedas.
- Añade RAM si es factible: Es la palanca más rápida para “estabilizar ahora”, aunque no siempre posible de inmediato.
- Considera añadir un special vdev: Si es soportado y puedes hacerlo con seguridad, mueve metadatos a dispositivos espejados rápidos. Esto puede transformar lecturas aleatorias de metadatos de “muerte” a “molestia”.
- Planifica la solución real: Migra datasets a un nuevo pool con dedup off, o reescribe datos de forma controlada.
- Valida con pruebas de carga: No declares victoria tras la primera hora tranquila.
Checklist C: “Dedup, but safely” (operational guardrails)
- Monitorea tamaño de DDT y huella “in core” regularmente.
- Alerta sobre rises en metadata misses y presión de memoria sostenida.
- Mantén la capacidad del pool razonable; evita operar al límite.
- Programa scrubs con conocimiento de las ventanas de carga pico.
- Documenta qué datasets usan dedup y por qué, con un responsable.
Preguntas frecuentes
1) Is ZFS dedup “bad”?
No. Es especializada. Es mala como opción por defecto porque la desventaja es pronunciada y el rollback es difícil. En la carga correcta y con el hardware adecuado (RAM y metadatos rápidos), puede ser excelente.
2) How much RAM do I need for dedup?
Suficiente para mantener el working set de la DDT caliente. Existen reglas empíricas, pero la única respuesta segura es: mide el tamaño “in core” de la DDT y observa el comportamiento de misses de metadatos bajo carga pico. Si el sistema está thrashing, no tienes suficiente.
3) Can I disable dedup and get my RAM back?
Desactivar dedup detiene las operaciones de dedup nuevas. No elimina la DDT existente para bloques ya dedupeados. Reduces el crecimiento futuro, pero no borras el pasado sin reescribir/migrar datos.
4) Does dedup help with VM storage?
A veces. Si tienes muchas imágenes VM casi idénticas y no usas cloning/snapshots de forma efectiva, dedup puede ahorrar espacio. Pero las cargas VM también generan rotación, y la “similitud” suele desvanecerse con el tiempo. Prueba con discos VM reales y una ventana temporal realista.
5) Is compression a safer alternative?
Normalmente, sí. compression=lz4 se usa ampliamente porque a menudo mejora el rendimiento efectivo (menos bytes escritos/leídos) con coste CPU mínimo en sistemas modernos. También es más fácil de razonar y no requiere tablas de metadatos masivas.
6) Does encryption ruin dedup?
A menudo. Si los datos están cifrados antes de que ZFS los vea, los bloques parecen aleatorios y no se deduplican. Si ZFS cifra el dataset, el comportamiento de dedup depende de detalles de implementación y de cuándo ocurre dedup respecto al cifrado. En muchas configuraciones prácticas, el cifrado reduce significativamente las ganancias de dedup.
7) Can a special vdev “fix” dedup?
Puedes reducir drásticamente el dolor manteniendo metadatos en dispositivos rápidos, lo que ayuda cuando las búsquedas DDT fallan en ARC. No elimina las necesidades de RAM ni la complejidad operativa. Además, se convierte en infraestructura crítica: perderlo puede implicar perder el pool.
8) Why is my pool slow even though the dedup ratio is high?
Un ratio alto significa que los bloques se comparten, pero no garantiza que la DDT quepa en memoria o que la ruta de metadatos sea rápida. Puedes tener fuertes ahorros por dedup y aun así estar limitado por búsquedas DDT, presión de txg sync o dispositivos de metadatos lentos. Mide misses de metadatos en ARC y “in core” de la DDT frente a RAM.
9) What’s the safest way to get rid of dedup once enabled?
Migración a un nuevo pool (o al menos a un nuevo dataset en un pool que nunca usó dedup) con dedup desactivado, seguido de validación y cutover. La limpieza in-place suele ser un ejercicio de reescritura, operacionalmente más difícil de controlar.
10) Should I enable dedup on a shared storage pool used by many teams?
Sólo si quieres que el radio de impacto de dedup incluya a todos. Si dedup es necesaria, aíslala: pool dedicado, tier de metadatos dedicado, propiedad clara y plan de rollback.
Conclusión
ZFS dedup no es algo “bonito de tener”. Es una elección arquitectónica con una firma permanente en los metadatos de tu pool y en tu vida operativa. Si la tratas como una casilla más, tratará tu RAM como consumible y tu presupuesto de latencia como una sugerencia.
Cuando dedup funciona, lo hace porque los datos son realmente duplicados y el sistema está construido para servir metadatos rápidamente—RAM primero, luego un tier serio de metadatos. Cuando dedup falla, falla porque alguien asumió que similaridad equivale a duplicación, o asumió que podría deshacerlo más tarde, o intentó resolver un problema de RAM con un parche SSD. Tu mejor movimiento es disciplinado: prueba con datos reales, dimensiona la ruta de metadatos y ten un plan de salida antes de necesitarlo.