Estás de guardia. La base de datos está lenta. Alguien publica una captura: “¡la tasa de aciertos del ARC cayó al 72%!” y una docena de personas decide que ese es El Problema.
Casi puedes escuchar cómo se redacta la solicitud de presupuesto para más RAM.
A veces tienen razón. A menudo no. Las tasas de acierto de caché ZFS son como un pronóstico del tiempo: útiles para planificar, inútiles para señalar culpables.
Esta es la guía de campo para saber cuándo es una pista válida—sin convertir tu almacenamiento en una feria de ciencias.
Qué miden realmente las tasas de acierto de caché ZFS
ZFS tiene una caché primaria en memoria llamada ARC (Adaptive Replacement Cache). También dispone de una caché secundaria opcional en dispositivos rápidos llamada
L2ARC. Ambas cachés registran “aciertos” y “fallos”, y las herramientas calculan con gusto una ratio de aciertos que parece un KPI.
Aquí está la trampa: un “acierto” no es lo mismo que “rápido” y un “fallo” no es lo mismo que “lento”. La tasa de aciertos es una afirmación sobre desde dónde
se sirvió un dato, no sobre si el sistema cumplió objetivos de latencia, ni si la carga es saludable, ni si tu pool está saturado.
ARC no es un solo compartimento
ARC contiene tanto datos (bloques de archivo) como metadatos (dnode, bloques indirectos, entradas de directorio, etc.). Muchos
workloads viven o mueren por el caché de metadata. Por ejemplo, un sistema de archivos con millones de archivos pequeños puede sentirse “rápido”
principalmente porque los metadatos permanecen calientes, incluso si los bloques de datos están fríos.
ARC también mantiene internamente múltiples “listas” (MRU/MFU y sus variantes “ghost”) para equilibrar recencia frente a frecuencia. Eso importa porque un acierto puede ser
“lo vimos recientemente” o “lo vemos constantemente”, lo cual tiene distintas implicaciones de ajuste.
L2ARC no es una expansión mágica de RAM
L2ARC almacena bloques en SSD/NVMe para su reutilización. Suena como “RAM pero más barata”. En la práctica, es “caché SSD con sobrecarga de gestión”.
L2ARC necesita a ARC para indexarlo. Si te falta RAM, añadir L2ARC puede paradójicamente dejarte con aún más escasez de memoria.
Los aciertos se cuentan por solicitud, no por resultado de negocio
ZFS puede satisfacer una solicitud desde ARC, L2ARC o disco. También puede hacer readahead (prefetch), comprimir, deduplicar (si activaste esa particular herramienta peligrosa) y
consolidar I/O. Tu aplicación experimenta latencia de extremo a extremo influida por CPU, bloqueos, colas de I/O, commits de txg y comportamiento de sync.
La tasa de aciertos es una lente, no la verdad.
Un mantra práctico: el rendimiento es la latencia bajo carga, no porcentajes de caché.
Una cita que vale la pena pegar en un post-it: “La esperanza no es una estrategia.”
— General Gordon R. Sullivan.
Las ratios de aciertos de caché son donde la esperanza va a parecer matemática.
Cuándo importan las tasas de acierto (y son predictivas)
1) Workloads de solo lectura con conjuntos de trabajo estables
Si tu carga lee repetidamente los mismos bloques—tormentas de arranque de VM, reutilización de artefactos de CI, servicio de activos web, análisis con escaneos repetidos sobre el
mismo subconjunto “caliente”—entonces la tasa de aciertos de ARC se correlaciona fuertemente con la presión de lecturas al disco y la latencia.
En este mundo, mejorar la tasa de aciertos (más RAM, mejor alineación de recordsize, reducir churn) suele ser una ganancia directa de rendimiento.
Puedes razonar: menos lecturas a disco → menor profundidad de cola → mejor latencia.
2) Workloads dominados por metadatos
Listar directorios con millones de entradas. Recorrer árboles profundos. Construir capas de contenedores. Ejecutar operaciones git en monorepos grandes.
Estos workloads se benefician de aciertos de metadata en ARC incluso cuando los aciertos de datos siguen siendo mediocres.
Aquí, la métrica útil no es la “tasa de aciertos global”, sino “¿los fallos de metadata están causando lecturas aleatorias síncronas?” Si la respuesta es sí,
dimensionar ARC y la colocación de metadata (special vdev) puede ser transformador.
3) Pools donde los discos son el cuello de botella
Si tu pool es rotacional (HDD) o tus SSD ya están en alta utilización, los fallos de ARC duelen porque el tiempo de servicio del disco es tu factor limitante.
Las tasas de acierto importan cuando la alternativa es lenta.
4) Estás evaluando una inversión en L2ARC o special vdev
Las tasas de acierto por sí solas no bastan, pero son parte del modelo de coste:
si tu flujo de misses en ARC es mayormente lecturas aleatorias y tu conjunto de trabajo excede ligeramente la RAM, L2ARC puede ayudar.
Si los misses son lecturas secuenciales, backups o streaming, L2ARC suele ser calor caro.
Broma #1: L2ARC es como un becario con una carretilla—ocasionalmente brillante, ocasionalmente caro, siempre requiere supervisión.
5) Estás diagnosticando una regresión y las tasas de acierto cambiaron con ella
Si una actualización, un cambio de configuración o una propiedad de dataset cambiada coincide con una caída brusca en las tasas de acierto, eso puede ser una pista fuerte. No es prueba.
Es una señal para “seguir el humo”.
Cuándo las tasas de acierto no importan (y te inducirán a error)
1) Workloads con mucha escritura
ARC no es una caché de escritura en el sentido que la gente suele entender en las salas de reuniones. Sí, ZFS usa memoria para datos sucios y transaction groups, y usa
cachés para lecturas que a menudo siguen a escrituras. Pero si tu problema es la latencia de escritura o tormentas de fsync, las tasas de acierto son un espectáculo secundario.
Para escrituras, la historia importante es: sync vs async, SLOG (si existe), latencia del pool y comportamiento de txg. Una hermosa tasa de aciertos del ARC no te salvará
de un pool saturado que hace pequeñas escrituras síncronas.
2) Lecturas en streaming y escaneos de una sola pasada
Backups, copias de archivos grandes, pipelines de medios, reprocesado de logs, escaneos analíticos fríos: leen mucho una vez y ya está.
Una baja tasa de aciertos es esperada y saludable. Prefetch de ZFS puede hacer que parezca que la caché “funciona” (porque coloca bloques en ARC brevemente),
pero no cambia la física: estás fundamentalmente limitado por el throughput.
3) Cuando el cuello de botella es CPU o contención de locks
Descompresión, checksumming, cifrado, tablas de dedup, churn patológico de metadata o una aplicación mono-hilo pueden saturar en CPU.
En ese caso la tasa de aciertos de ARC puede ser excelente mientras el sistema sigue lento, porque el tiempo se consume por encima de la capa de I/O.
4) Cuando tu pool ya es lo suficientemente rápido
Si estás en NVMe moderno y tus objetivos de latencia se cumplen, puedes tolerar misses. “Más aciertos” se vuelve una métrica de vanidad. No recibes un premio
por 99% de aciertos en ARC si el servicio ya es rápido y estable.
5) Cuando la tasa de aciertos está inflada por lo que no importa
ARC puede parecer “impresionante” porque está cacheando datos que no te interesan: prefetch secuencial, bloques transitorios o datos calentados por un benchmark
que ejecutaste una vez. Mientras tanto, tu carga real falla en metadata y sufre.
Si debes recordar una regla: no ajustes en base a una sola ratio agregada. Desglosa: metadata vs datos, demanda vs prefetch,
latencia vs throughput, sync vs async. Si no, solo estarás afinando tus sentimientos.
ARC vs L2ARC: las diferencias prácticas
ARC: el más rápido, más simple y aún fácil de estropear
ARC vive en RAM. Es extremadamente rápido y puede servir lecturas sin tocar discos. Pero ARC comparte RAM con todo lo demás:
aplicaciones, page cache (en algunas plataformas), estructuras del kernel y metadata de ZFS.
Si ARC es demasiado pequeño respecto a tu conjunto de trabajo, hay thrashing: muchos fallos, evicciones frecuentes y picos de lecturas a disco.
Si ARC es demasiado grande, dejas sin memoria a las aplicaciones y al SO. Eso puede parecer “almacenamiento lento” cuando en realidad es presión de reclaim.
L2ARC: a veces genial, a veces un impuesto
L2ARC puede ser una victoria cuando:
- Tu carga es de solo lectura y reutiliza bloques.
- Tu conjunto de trabajo es mayor que la RAM pero no desmesuradamente mayor.
- Tu pool es más lento que tu dispositivo de caché (pool en HDD, o pool SSD muy ocupado).
- Tienes suficiente RAM para mantener los encabezados de L2ARC sin ahogarte.
L2ARC puede ser una pérdida cuando:
- Tu carga es mayormente lecturas en streaming (churn de caché).
- Tu dispositivo de caché no mantiene baja latencia bajo carga de escritura.
- Ya estás con restricción de memoria.
- Esperas que acelere escrituras síncronas (no lo hace).
Por qué difieren las tasas de acierto entre ARC y L2ARC
La tasa de aciertos de ARC mide las solicitudes servidas desde RAM. La tasa de aciertos de L2ARC mide las solicitudes servidas desde el dispositivo de caché.
Un “buen” porcentaje de L2ARC depende de lo que intentes lograr:
a veces incluso 10–20% de aciertos en L2ARC pueden ser significativos si esos aciertos evitan lecturas aleatorias lentas que de otro modo irían a HDD.
Además: L2ARC se rellena de forma asíncrona y históricamente no era persistente tras reboot. En muchos sistemas OpenZFS modernos,
la persistencia de L2ARC existe, pero la realidad operativa sigue importando: tiempo de calentamiento, comportamiento de evicción y desgaste del dispositivo.
Hechos interesantes y contexto histórico
- ARC fue una característica destacada del diseño de ZFS de Sun: reemplazó la división tradicional “buffer cache vs page cache” por una caché adaptativa única.
- La idea de las “ghost lists” en ARC (recordar bloques recientemente expulsados) vino de investigación académica sobre caching y ayuda a evitar el thrashing.
- L2ARC llegó más tarde cuando el flash se volvió viable; los primeros SSD eran rápidos pero frágiles, lo que moldeó un comportamiento conservador en las escrituras de caché.
- Históricamente, L2ARC no era persistente tras un reinicio: las cachés arrancaban frías, lo que importaba en “tormentas de inicio de lunes por la mañana”.
- Las estadísticas ARC se volvieron cultura: los admins comparaban las tasas de aciertos como gamers comparan FPS, incluso cuando los gráficos de latencia eran el verdadero juego.
- Los special vdev (metadata/bloques pequeños en dispositivos rápidos) cambiaron la conversación sobre caché al hacer los “fallos” menos dolorosos.
- La compresión cambió la matemática de la caché: ARC almacena bloques comprimidos en muchas configuraciones, aumentando efectivamente la capacidad por GiB de RAM.
- El comportamiento de prefetch ha evolucionado: lo que parecía “contaminación de caché” en una versión pudo ser readahead más inteligente en otra.
- La reputación de dedup como devoradora de RAM está ganada: la tabla de dedup puede dominar las necesidades de memoria y distorsionar todo lo que crees saber sobre ARC.
Guion de diagnóstico rápido
El objetivo no es admirar métricas. El objetivo es identificar el cuello de botella en menos de 15 minutos, elegir la siguiente prueba y evitar el tuning por cargo-cult.
Primero: ¿es IOPS/latencia o throughput?
- Si los usuarios se quejan de “lentitud puntual” y timeouts: sospecha latencia/IOPS.
- Si las transferencias son simplemente más lentas de extremo a extremo: sospecha límites de throughput, CPU o red.
Segundo: ¿son lecturas o escrituras, síncronas o asíncronas?
- Altas IOPS de lectura + alto await en disco: la caché podría importar.
- Altas IOPS de escritura con sync: SLOG/latencia del pool importa más que las tasas de acierto de ARC.
- Escrituras altas con bloques grandes: mira el throughput de vdev y la fragmentación.
Tercero: ¿está ARC bajo presión o se comporta normalmente?
- Tamaño de ARC fijado y evicción alta: puede que estés haciendo thrashing.
- Tamaño de ARC estable, misses estables, latencia aún mala: el cuello de botella está en otra parte.
Cuarto: ¿está el pool saturado o poco saludable?
- Revisa
zpool iostat -vpor desequilibrio de vdevs, alto encolamiento y dispositivos lentos. - Busca errores, resilvering, scrub o un disco moribundo que arrastre el vdev.
Quinto: valida con un experimento dirigido
- ¿Vaciar cachés? Suele ser mala idea en producción, pero puedes ejecutar una prueba de lectura controlada en un dataset no crítico.
- Cambia una propiedad (por ejemplo,
primarycache=metadataen un dataset de backups) y observa el comportamiento de ARC. - Usa
fioo métricas a nivel de aplicación para confirmar mejoras.
Tareas prácticas: comandos, salidas, decisiones
Estas son las comprobaciones de trabajo que espero que un SRE ejecute antes de proponer hardware y antes de tocar tunables con una larga vara.
Cada tarea incluye: comando, salida de ejemplo, qué significa y la decisión que tomas.
Task 1: Confirmar la salud del pool y trabajos de mantenimiento en curso
cr0x@server:~$ sudo zpool status
pool: tank
state: ONLINE
scan: scrub repaired 0B in 02:14:33 with 0 errors on Tue Dec 24 03:10:11 2025
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
errors: No known data errors
Significado: Si estás resilverizando, haciendo scrub o estás degradado, el rendimiento puede caer independientemente de la tasa de aciertos.
Decisión: Si hay un scan durante la hora pico, reprograma. Si está degradado, arregla el hardware primero; no “afines ARC” para compensar.
Task 2: Identificar carga de lectura vs escritura y latencia a nivel de pool
cr0x@server:~$ sudo zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 4.22T 7.58T 1.20K 3.40K 140M 220M
raidz2-0 4.22T 7.58T 1.20K 3.40K 140M 220M
sda - - 280 860 35.0M 56.0M
sdb - - 300 820 34.5M 55.0M
sdc - - 310 870 36.0M 56.5M
sdd - - 320 850 34.5M 55.0M
-------------------------- ----- ----- ----- ----- ----- -----
Significado: Esto muestra distribución por vdev y por disco. Un gran desequilibrio sugiere un disco lento o encolamiento.
Decisión: Si un disco va rezagado, investigarlo. Si todo el vdev está saturado, la caché puede ayudar lecturas—pero solo si los misses son aleatorios y reutilizables.
Task 3: Revisar propiedades de dataset que cambian directamente el comportamiento de caché
cr0x@server:~$ zfs get -o name,property,value,source recordsize,primarycache,secondarycache,compression,sync tank/data
NAME PROPERTY VALUE SOURCE
tank/data recordsize 128K local
tank/data primarycache all default
tank/data secondarycache all default
tank/data compression lz4 local
tank/data sync standard default
Significado: primarycache/secondarycache deciden qué puede entrar en ARC/L2ARC. recordsize afecta la forma de I/O y la eficiencia de caché.
Decisión: Para datasets de backup/streaming, considera primarycache=metadata para evitar contaminación de caché. Para DBs, evalúa recordsize y sync por separado.
Task 4: Inspeccionar tamaño y objetivo de ARC
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:01:01 22K 1.8K 8 980 4 740 3 120 1 64G 64G
12:01:02 21K 2.0K 9 1.1K 5 760 3 140 1 64G 64G
12:01:03 20K 1.9K 9 1.0K 5 780 4 120 1 64G 64G
Significado: arcsz es el tamaño actual de ARC; c es el objetivo. Miss% son misses por demanda. Los misses de prefetch son separados.
Decisión: Si arcsz está fijado en c y los misses son altos con latencia de lectura en aumento, puede que estés sub-cacheado. Si los misses son bajos, la caché no es tu cuello de botella.
Task 5: Separar demanda vs prefetch para detectar contaminación de caché
cr0x@server:~$ arcstat -f time,read,miss,miss%,pmis,pm%,arcsz,c 1 3
time read miss miss% pmis pm% arcsz c
12:02:10 18K 2.2K 12 1.9K 10 64G 64G
12:02:11 19K 2.1K 11 1.8K 10 64G 64G
12:02:12 18K 2.3K 12 2.0K 11 64G 64G
Significado: Altos misses de prefetch (pm%) durante lecturas en streaming es normal; altos hits de prefetch pueden expulsar datos útiles.
Decisión: Si un job de backup crea mucha actividad de prefetch y picos de latencia interactiva, aíslalo (dataset separado, limita IO, ajusta propiedades de caché).
Task 6: Comprobar presencia y efectividad de L2ARC
cr0x@server:~$ arcstat -f time,l2read,l2miss,l2hit%,l2asize,l2size 1 3
time l2read l2miss l2hit% l2asize l2size
12:03:01 6K 4K 33 420G 800G
12:03:02 7K 5K 29 421G 800G
12:03:03 6K 4K 33 421G 800G
Significado: El % de acierto de L2ARC puede parecer “meh” y aún así ser valioso si evita lecturas lentas a disco. También vigila cuánto está realmente lleno (l2asize).
Decisión: Si L2ARC se usa muy poco o el % de acierto es bajo y tus misses son de streaming, quítalo o repropón el dispositivo. Si ayuda lecturas aleatorias, mantenlo.
Task 7: Verificar presión de memoria antes de culpar al tamaño de ARC
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 256Gi 210Gi 3.1Gi 2.0Gi 43Gi 20Gi
Swap: 16Gi 9.5Gi 6.5Gi
Significado: Bajo “available” y uso activo de swap significa presión de memoria. ARC puede estar compitiendo con las aplicaciones.
Decisión: Si hay swapping, arregla la presión de memoria primero (reduce cargas, añade RAM, limita ARC) antes de perseguir ratios de aciertos.
Task 8: Medir latencia de disco directamente en Linux
cr0x@server:~$ iostat -x 1 3
Device r/s w/s r_await w_await aqu-sz %util
sda 280.0 860.0 18.2 12.4 9.10 98.0
sdb 300.0 820.0 17.9 12.1 8.80 97.5
sdc 310.0 870.0 18.5 12.7 9.30 98.3
sdd 320.0 850.0 18.0 12.2 9.00 97.9
Significado: Alto await y alto %util indican saturación/encolamiento del dispositivo. Los aciertos de caché no arreglarán escrituras saturadas.
Decisión: Si la latencia es alta por escrituras, investiga comportamiento de sync, slog y amplificación de escritura (recordsize, pequeños bloques, fragmentación).
Task 9: Ver si las escrituras síncronas dominan
cr0x@server:~$ zfs get -o name,property,value,source sync tank/db
NAME PROPERTY VALUE SOURCE
tank/db sync standard default
Significado: sync=standard significa que la aplicación decide. Las bases de datos suelen hacer muchas escrituras síncronas.
Decisión: Si la latencia se correlaciona con fsync, necesitas un SLOG adecuado (rápido, protegido contra pérdida de energía) o ajustar la app—no ajustar tasas de acierto de ARC.
Task 10: Confirmar si existe un SLOG y dónde está
cr0x@server:~$ sudo 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
logs
nvme0n1 ONLINE 0 0 0
Significado: Un log vdev es tu SLOG. Sus características de latencia y durabilidad importan para escrituras síncronas.
Decisión: Si no tienes SLOG y la latencia de escrituras síncronas te mata, considera uno. Si tienes un SSD de consumo como SLOG, reemplázalo antes de que arruine tu fin de semana.
Task 11: Detectar presión de evicción en ARC (Linux /proc)
cr0x@server:~$ egrep 'c_max|c_min|size|memory_throttle_count|deleted|evict' /proc/spl/kstat/zfs/arcstats
c_max 4 68719476736
c_min 4 17179869184
size 4 68719476736
memory_throttle_count 4 0
deleted 4 119283
evict_skip 4 0
Significado: size en c_max no es inherentemente malo. memory_throttle_count en aumento sugiere que ARC está siendo forzado a reducirse o está siendo throttled.
Decisión: Si el throttling aumenta durante la carga, busca contención de memoria y considera limitar ARC o mover cargas.
Task 12: Entender comportamiento de metadata vs datos en ARC
cr0x@server:~$ egrep 'demand_data_hits|demand_data_misses|demand_metadata_hits|demand_metadata_misses' /proc/spl/kstat/zfs/arcstats
demand_data_hits 4 99887766
demand_data_misses 4 5544332
demand_metadata_hits 4 22334455
demand_metadata_misses 4 112233
Significado: Muchos misses de datos pueden estar bien para streaming. Los misses de metadata son más sospechosos para cargas de archivos donde la interfaz “se siente lenta”.
Decisión: Si los misses de metadata suben con picos de latencia, considera un special vdev para metadata o aumentar ARC (si la memoria lo permite).
Task 13: Comprobar si existe un vdev “special” para metadata/bloques pequeños
cr0x@server:~$ sudo zpool status tank | sed -n '1,140p'
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
special
mirror-1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
Significado: El special vdev puede descargar metadata y opcionalmente bloques pequeños en dispositivos rápidos, reduciendo el dolor de los misses de caché.
Decisión: Si los misses de metadata duelen y no tienes special vdev, evalúalo. Si lo tienes, revisa esos dispositivos por desgaste/latencia.
Task 14: Identificar desajustes de política de caché a nivel de dataset
cr0x@server:~$ zfs get -r -o name,property,value primarycache tank | head
NAME PROPERTY VALUE
tank primarycache all
tank/backups primarycache all
tank/backups/daily primarycache all
tank/db primarycache all
tank/home primarycache all
Significado: Los datasets de backup por defecto cachean todo, lo que puede expulsar datos calientes sin beneficio.
Decisión: Ajusta los datasets de backup a primarycache=metadata (o incluso none en casos extremos) y deja los datasets interactivos intactos.
Task 15: Validar que recordsize coincide con la realidad del workload
cr0x@server:~$ zfs get -o name,property,value recordsize tank/db tank/vm tank/backups
NAME PROPERTY VALUE
tank/db recordsize 16K
tank/vm recordsize 64K
tank/backups recordsize 1M
Significado: I/O aleatorio pequeño de DB prefiere recordsize pequeño; backups prefieren grande. Un recordsize erróneo puede desperdiciar ARC y causar amplificación read-modify-write.
Decisión: Si la tasa de aciertos es baja porque estás cacheando registros gigantes para lecturas pequeñas, ajusta recordsize en el dataset (con cuidado, solo afecta escrituras nuevas).
Task 16: Comprobación rápida “es la app?” con I/O por proceso
cr0x@server:~$ sudo pidstat -d 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
12:05:10 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
12:05:11 PM 1001 24182 1200.00 9800.00 0.00 postgres
12:05:11 PM 0 19876 0.00 64000.00 0.00 zfs
Significado: Confirma quién está generando I/O. Si un job por lotes está machacando escrituras, las tasas de acierto son solo espectadores.
Decisión: Si un vecino ruidoso es responsable, limita/redistribuye/traslada el job antes de tocar tunables de ZFS.
Tres micro-historias corporativas desde las trincheras
Micro-historia 1: El incidente causado por una suposición errónea
Una compañía mediana ejecutaba una plataforma analítica multi-tenant. Durante una semana de lanzamiento, los dashboards se ralentizaron y algunas solicitudes hicieron timeout.
El equipo de almacenamiento vio la ratio de aciertos del ARC caer de mediados de 90 a bajos 70. La conclusión se formó al instante: “Necesitamos más RAM.”
Compraron memoria de emergencia, programaron una ventana de mantenimiento y mientras tanto intentaron “proteger la caché” desactivando prefetch y cambiando algunas
propiedades de dataset en todo el pool. Al día siguiente, el sistema estaba peor. Los picos de latencia se agudizaron y las tasas de error internas subieron.
El problema real eran escrituras síncronas. Un nuevo pipeline de ingestión usaba una librería que hacía fsync agresivamente. El pool no tenía SLOG y los vdevs ya
estaban cerca de saturación en peak. Las lecturas sufrían porque las escrituras encolaban; la ratio ARC cayó porque el sistema simplemente tardaba más en
atender los misses, no porque el caché “fallara”.
Cuando graficaron la latencia de escrituras síncronas, fue obvio. Añadieron un SLOG adecuado protegido contra pérdida de energía, arreglaron la ruta de ingestión y revirtieron
los cambios de afinamiento de caché. La ratio ARC se recuperó algo, pero más importante aún, las latencias tail volvieron a su SLO.
Lección: una caída en la tasa de aciertos puede ser un efecto, no la causa. Las métricas de caché son excelentes testigos y terribles sospechosos.
Micro-historia 2: La optimización que salió mal
Otra organización operaba un clúster de VM respaldado por ZFS. Alguien propuso L2ARC en un NVMe de consumo brillante: “Tendremos rendimiento tipo RAM sin comprar RAM.”
El cambio entró en un periodo tranquilo. Las pruebas iniciales parecieron mejorar. Todos se relajaron.
Dos semanas después, el clúster enfrentó un patrón de carga nuevo: muchas VMs de corta vida haciendo installs de paquetes y builds de CI—muchas lecturas, sí, pero también gran churn.
L2ARC empezó a llenarse con bloques que nunca se reutilizaban. ARC tuvo que mantener metadata para esos bloques cacheados, y la presión de memoria aumentó.
El hipervisor empezó a hacer swap de manera intermitente. La latencia se volvió extraña: no mala constantemente, pero impredecible en el peor sentido.
El equipo miró la tasa de aciertos de L2ARC. No era excelente, pero tampoco pésima. Discutieron si “30% de aciertos” era “bueno”.
Mientras tanto, los clientes llenaban tickets.
La solución fue dolorosamente aburrida: quitar L2ARC, limitar ARC para dejar margen para el hipervisor y guests, y separar el espacio scratch de CI en un dataset
con caché restringido a metadata. También movieron las cargas de build más ruidosas a otro pool.
Lección: L2ARC no es gratis. Si tu carga churnea, pagas sobrecarga por cachear datos que nunca volverás a ver.
Micro-historia 3: La práctica aburrida pero correcta que salvó el día
Un equipo de servicios financieros usaba ZFS para directorios home y herramientas internas. Nada glamoroso; muchos archivos pequeños, mucho recorrido de directorios,
y ocasionales quejas de “¿por qué mi checkout de repo va lento?”. Tenían una costumbre: cada trimestre revisaban propiedades de datasets y validaban que
los datasets “bulk” (backups, exports, archivos de medios) no inundaran el ARC.
Así, su dataset de backups tenía primarycache=metadata. Su dataset de archivo tenía recordsize ajustado grande. Sus datasets interactivos
permanecían con los valores por defecto. El equipo también monitorizaba latencia del pool y misses de metadata de ARC como señales de primera clase.
Un día, un nuevo job de backup apuntó por error al dataset interactivo en lugar del de backups. Empezó a hacer lecturas en streaming durante horas en horario laboral.
En la mayoría de sistemas eso habría vaciado ARC y disparado una tormenta de “almacenamiento lento” y quejas.
Aquí, el radio de impacto fue limitado. El dataset equivocado fue ruidoso, pero la mayor parte del pool se mantuvo reactiva. La ratio ARC bajó brevemente, pero
la metadata siguió caliente y la latencia para usuarios no colapsó. El equipo detectó la mala configuración desde los logs del job y lo arregló sin incidentes mayores.
Lección: higiene pequeña y consistente de caché vence al tuning heroico. El mejor outage es el que parece un error de redondeo.
Errores comunes (síntomas → causa raíz → solución)
1) “La ratio de aciertos del ARC es baja, así que el almacenamiento está lento”
Síntomas: La ratio de aciertos cae durante jobs por lotes; los usuarios se quejan; alguien propone duplicar la RAM.
Causa raíz: Lecturas en streaming o escaneos de una sola pasada están evitando la reutilización. Los misses son esperados; el throughput es la limitación.
Solución: Aísla las cargas por lotes (dataset/pool separado), pon primarycache=metadata en datasets bulk, limita con cgroups/ionice y mide throughput/latencia directamente.
2) “L2ARC solucionará nuestra latencia de escritura”
Síntomas: Latencia de fsync de DB es mala; el equipo añade L2ARC; nada mejora.
Causa raíz: L2ARC acelera lecturas, no escrituras síncronas. La latencia de escritura está regida por SLOG/pool.
Solución: Añade un SLOG apropiado para cargas con mucho sync, o cambia el comportamiento de sync de la app (si es seguro). No compres SSDs para el trabajo equivocado.
3) La tasa de aciertos es alta, pero la app sigue lenta
Síntomas: ARC hit > 95%, los usuarios aún ven timeouts.
Causa raíz: Saturación de CPU (checksums/compresión/cifrado), contención de locks o un dataset caliente que causa retrasos de txg.
Solución: Perfila la CPU, comprueba iowait vs tiempo de usuario, inspecciona txg y comportamiento de escrituras síncronas, y valida cuellos de botella a nivel de aplicación.
4) “Pondremos primarycache=none en todas partes para evitar contaminación”
Síntomas: La ratio de aciertos cae, los misses de metadata se disparan, las operaciones de directorio se vuelven terriblemente lentas.
Causa raíz: Sobrecorrección: eliminaste justo lo que hace que los workloads de sistema de archivos sean reactivos.
Solución: Usa primarycache=metadata solo para datasets bulk. Mantén all para datasets interactivos a menos que tengas una razón específica.
5) L2ARC hace el sistema menos estable
Síntomas: Swapping ocasional, latencia con jitter, presión de reclaim del kernel.
Causa raíz: No hay suficiente RAM para encabezados de L2ARC y para ARC; el dispositivo de caché fomenta más churn de caché.
Solución: Quita o reduce L2ARC, limita ARC o añade RAM. Si ejecutas hipervisores, protege primero la memoria del host.
6) “Apagamos el prefetch y empeoró”
Síntomas: El throughput de lecturas secuenciales cae, las aplicaciones hacen más lecturas síncronas.
Causa raíz: El prefetch ayudaba a tu carga real; asumiste que era contaminación por ver estadísticas de prefetch.
Solución: Vuelve a habilitar prefetch y en su lugar controla las cargas que causan streaming nocivo. Mide antes/después.
7) “Nuestro ARC es enorme; ¿por qué fallamos en metadata?”
Síntomas: Mucha RAM, pero los misses de metadata suben con recorridos de directorios.
Causa raíz: El conjunto de trabajo es realmente enorme, o falta special vdev y la metadata debe leerse desde discos lentos, haciendo los misses dolorosos.
Solución: Considera special vdev para metadata/bloques pequeños, reduce el número de archivos por directorio y asegúrate de que los datasets bulk no estén expulsando metadata.
Broma #2: Si tu única herramienta es la ratio de aciertos de ARC, todo problema de rendimiento parece “añadir RAM.” Así es como te ascienden a “la persona que pide RAM.”
Listas de verificación / plan paso a paso
Paso a paso: Decide si las tasas de acierto son accionables
- Define el dolor: latencia tail, throughput, jitter o timeouts? Obtén primero un gráfico de la app.
- Clasifica la carga: read-heavy, write-heavy, mixta; streaming vs conjunto de trabajo reutilizado.
- Revisa la salud del pool:
zpool statuspor degradado/resilver/scrub durante pico. - Revisa la latencia de dispositivos:
zpool iostat -vyiostat -x. Si discos están al máximo, las cachés no arreglarán las escrituras. - Revisa comportamiento de sync: identifica apps con fsync intensivo; verifica configuración de SLOG si es necesario.
- Inspecciona comportamiento de ARC: misses por demanda vs prefetch; misses de metadata vs datos; contadores de evicción/throttle.
- Revisa presión de memoria: swap o memoria disponible baja invalida ajustes simplistas de ARC.
- Solo entonces decide: añadir RAM, ajustar propiedades de caché del dataset, añadir special vdev, añadir/quitar L2ARC, o no tocar nada.
Checklist operacional: Evita que las cachés se vuelvan una superstición
- Particiona datasets por tipo de carga: interactivo vs bulk vs DB vs VMs.
- Configura
primarycache=metadataen datasets bulk (backups, exports) salvo que se demuestre lo contrario. - Mantén
compression=lz4por defecto salvo que la CPU sea verdaderamente tu cuello de botella. - Revisa
recordsizeen datasets DB/VM; no heredes “1M en todas partes” porque alguien leyó un blog. - Rastrea la latencia a nivel de pool y dispositivo, no solo las tasas de acierto.
- Documenta por qué existe cada tunable; elimínalo si nadie puede explicarlo.
- Prueba L2ARC con trazas reales de workload; no decidas solo por benchmarks sintéticos.
- Protege margen de memoria en hipervisores y sistemas multi-tenant; la codicia de caché es cómo convocas al swap.
Preguntas frecuentes
1) ¿Cuál es una “buena” ratio de aciertos de ARC?
No hay un número único. Para una carga de solo lectura estable, más alto suele significar menos lecturas a disco y mejor latencia.
Para lecturas en streaming, una baja ratio es normal y no es problema. Juzga por latencia y utilización de disco, no por estética.
2) ¿Por qué bajó la ratio de ARC después de agregar más RAM?
Porque la carga cambió, porque empezaste a medir diferente, o porque el sistema ahora hace más prefetch/lecturas bajo mayor concurrencia.
Además, añadir RAM puede aumentar la concurrencia (las apps hacen más trabajo), lo que cambia la dinámica de caché. Observa misses y latencia, no solo la ratio.
3) ¿La compresión mejora las tasas de acierto de caché?
A menudo sí—de forma indirecta. Con compresión como lz4, ARC puede guardar más datos lógicos por GiB de RAM (según implementación y carga).
Pero si la CPU está limitada, la compresión puede cambiar I/O por CPU y perjudicar la latencia.
4) ¿Debería poner primarycache=metadata en todo?
No. Es una sobre-reacción común. Úsalo en datasets que hacen lecturas largas en streaming (backups, archivos) para que no expulsen caché útil.
Mantén datasets interactivos en all salvo que hayas demostrado que cachear bloques de datos es dañino.
5) ¿Vale la pena L2ARC en pools NVMe?
A veces, pero la barrera es más alta. Si tu pool ya es NVMe de baja latencia, L2ARC puede no aportar mucho y añadir sobrecarga.
L2ARC brilla cuando evita misses caros—como lecturas aleatorias a HDD o SSDs ocupados—especialmente cuando el conjunto de trabajo excede ligeramente la RAM.
6) ¿Puede L2ARC perjudicar el rendimiento?
Sí. Consume RAM para encabezados y puede aumentar la presión de memoria. También puede malgastar ancho de banda de escritura del dispositivo de caché llenándose con
bloques no reutilizados. Si ves swapping o latencia con jitter tras activarlo, trata eso como una señal seria.
7) Si mi tasa de aciertos L2ARC es solo 20%, ¿debería quitarlo?
No automáticamente. Pregunta: ¿qué reemplazan esos 20% de aciertos? Si evitan lecturas aleatorias lentas a HDD, 20% puede ser enorme.
Si reemplazan lecturas ya rápidas o son mayormente prefetch, quizá sea inútil.
8) ¿ARC ayuda en escrituras?
ARC es principalmente caché de lectura. ZFS guarda datos sucios en memoria antes de commitear transaction groups y las escrituras pueden consolidarse.
Pero si tu problema es latencia de escrituras síncronas, las tasas de acierto de ARC no son la palanca. Mira SLOG y la latencia de escritura del pool.
9) ¿Por qué mis tasas de acierto se ven geniales pero los usuarios siguen quejándose?
Porque la latencia puede venir de otra parte: escrituras síncronas, saturación de CPU, problemas de red, locks en la aplicación o un dispositivo lento en un vdev.
Valida con zpool iostat -v, iostat -x y métricas de la aplicación.
10) ¿Cuál es el ajuste más simple y seguro que suele ayudar?
Separa datasets bulk y configura primarycache=metadata en ellos. Mantén compression=lz4. Verifica la alineación de recordsize para DB/VM datasets.
Todo lo demás debe justificarse con medidas.
Conclusión: qué hacer a continuación
Las tasas de acierto de caché no son el rendimiento. Son una pista. A veces una pista muy buena. Pero si las tratas como un marcador, afinarás lo equivocado
y seguirás lento—solo con gráficos más bonitos.
Pasos prácticos a seguir:
- Comienza a monitorizar latencia y utilización de pool/dispositivo junto con estadísticas de ARC/L2ARC.
- Divide datasets por carga y aplica políticas de caché deliberadamente (bulk vs interactivo vs DB/VM).
- Usa el guion de diagnóstico rápido: salud → latencia → comportamiento sync/escrituras → desglose de ARC → solo entonces tuning de caché.
- Si cambias algo, cambia una cosa a la vez y valida con métricas de aplicación, no solo con ratios de aciertos.
No necesitas tasas de acierto perfectas. Necesitas latencia predecible, throughput estable y un sistema que no te sorprenda a las 2 a.m.
ZFS puede hacerlo—si dejas de pedirle a la caché que sea tu religión.