ZFS usando NVMe como L2ARC: cuando ARC no es suficiente

¿Te fue útil?

En algún punto, todo administrador de ZFS se enfrenta al mismo villano: un working set que no cabe en RAM. El síntoma es familiar: picos de latencia, discos que se quejan, usuarios afirmando “el almacenamiento está lento” con la certeza moral de quien nunca miró iostat.

Usar NVMe como L2ARC suena como la solución obvia: añadir un dispositivo de caché rápido y seguir con la vida. A veces es brillante. A veces es una forma cara de desgastar tu NVMe mientras el rendimiento permanece tercamente mediocre. Este artículo trata de saber en qué mundo estás antes de aprenderlo en producción.

Qué es L2ARC (y qué no es)

ZFS tiene una caché primaria llamada ARC (Adaptive Replacement Cache). Vive en RAM y es extremadamente buena haciendo lecturas repetidas económicas. Cuando ARC es demasiado pequeña para tu working set, ZFS puede extender el cache hacia un dispositivo rápido: L2ARC, el “Level 2 ARC”. L2ARC es caché de lectura. No es un buffer de escritura, no es un acelerador de journaling, no es una varita mágica.

Qué ocurre en la práctica:

  • ARC sigue lo que está caliente. Si ARC no puede mantenerlo, ZFS puede empujar parte de esos datos a L2ARC.
  • En un fallo de lectura en ARC, ZFS puede mirar en L2ARC. Si se encuentra, se lee desde NVMe en lugar de desde discos giratorios o SSDs más lentos.
  • El contenido de L2ARC se popula con el tiempo. Históricamente no persistía entre reinicios; las implementaciones más nuevas pueden persistirlo (más adelante verás más).

Qué L2ARC no hace:

  • No acelera escrituras síncronas (eso es territorio de SLOG, y aun así: solo para cargas específicas).
  • No arregla un pool lento por fragmentación, diseño de vdev pobre o un cuello de botella de CPU.
  • No elimina la necesidad de dimensionar correctamente la RAM. L2ARC todavía necesita metadatos en RAM para ser útil.

Verdad operativa seca: L2ARC es una herramienta para abaratar un tipo específico de latencia de lectura. Si tu problema es “las lecturas aleatorias me matan y los datos se vuelven a leer”, puede brillar. Si tu problema es “todo es aleatorio y nunca se repite”, no servirá.

Una cita que debería estar en cada turno de guardia: La esperanza no es una estrategia — atribuida al General Gordon R. Sullivan. Trata a L2ARC igual: mide, luego decide.

Hechos e historia interesante (corto, útil y algo opinado)

  • ARC precede a la mayoría de las prácticas de “almacenamiento en la nube”. ZFS y ARC vienen de la ingeniería de la era Solaris donde la memoria era cara y los discos lentos, así que la política de caché era asunto serio.
  • L2ARC fue diseñado para caché de lectura, no para durabilidad. Las implementaciones tempranas perdían la caché al reiniciar; eso moldeó las expectativas operativas por años.
  • L2ARC necesita RAM para describir lo que hay en él. Cada bloque cacheado necesita metadatos en ARC. Un L2ARC gigantesco puede robar silenciosamente RAM que tu ARC necesita desesperadamente.
  • NVMe hizo a L2ARC menos embarazoso. Los primeros dispositivos L2ARC eran a menudo SSDs SATA; las mejoras de latencia fueron reales, pero no siempre dramáticas. La baja latencia de NVMe cambia los trade-offs.
  • Prefetch y L2ARC tienen una relación complicada. Las lecturas secuenciales pueden inundar las cachés con cosas que nunca volverás a tocar. ZFS añadió controles (como l2arc_noprefetch) porque la gente seguía cacheando sus arrepentimientos.
  • Hay un “impuesto de calentamiento”. L2ARC se llena gradualmente, no instantáneamente. Las primeras horas (o días) pueden verse peor que “sin L2ARC”, especialmente si lo dimensionaste mal.
  • La tasa de alimentación de la caché está deliberadamente limitada. ZFS limita cuán agresivamente escribe en L2ARC para evitar convertir tu sistema en una fábrica de escritura de caché.
  • L2ARC no es una característica sin coste. Consume CPU, memoria y escrituras hacia tu NVMe. Ese desgaste es real; plánificalo como planeas la retención de logs.
  • L2ARC persistente existe ahora en implementaciones modernas de ZFS. Reduce el dolor de calentamiento tras reinicios, pero no es universal y no es gratis.

Cuándo NVMe L2ARC realmente ayuda

L2ARC es para cargas con lecturas repetidas que fallan en ARC pero podrían servirse más rápido que lo que proporciona tu pool.

Buenos candidatos

  • Hosts de VM con bloques “calientes” estables entre muchos invitados: bibliotecas compartidas, archivos de arranque, binarios comunes, repositorios de parches.
  • Bases de datos con patrones de solo lectura donde el working set es un poco más grande que la RAM (o donde te niegas a comprar más RAM por finanzas).
  • Caches de CI/build donde las mismas toolchains se usan repetidamente y tu pool está en HDD.
  • Clusters de analytics que vuelven a escanear las mismas particiones “recientes”, pero no de forma puramente secuencial.

La condición clave: L2ARC debe ser más rápido que lo que reemplaza

Si tu pool ya es NVMe o un espejo SSD poderoso, L2ARC puede ser redundante. Si tu pool es HDD RAIDZ con lecturas aleatorias, L2ARC puede parecer un milagro — asumiendo que realmente estás releyendo los mismos bloques.

Broma #1: L2ARC es como una segunda nevera—genial si guardas sobras, inútil si solo comes comida para llevar.

Cuándo L2ARC es una trampa

La mayoría de las historias “L2ARC fue decepcionante” se reducen a una de estas:

1) Tu carga no vuelve a leer

Ingesta de backups, escaneos fríos de analytics, copias de archivos únicas, procesamiento secuencial de medios grandes—estos tienden a fluir por la caché y desaparecer. L2ARC se convierte en tráfico de escritura hacia NVMe con poco retorno en tasa de aciertos.

2) Tu ARC queda hambriento, y L2ARC lo empeora

L2ARC requiere metadatos en RAM. Si tu sistema ya tiene presión de memoria, añadir un L2ARC grande puede reducir el tamaño efectivo de ARC e incrementar los fallos. Felicidades, cacheaste más en NVMe mientras perdiste lo que hace que la caché sea rápida: RAM.

3) Tu problema no son las lecturas

Si el dolor son escrituras síncronas, pequeñas escrituras aleatorias o contención de metadata, L2ARC podría no hacer casi nada. A menudo la solución correcta es un layout de vdev diferente, un vdev especial para metadata/bloques pequeños, más RAM o ajustar la aplicación.

4) Acabas de construir una caché que hace thrashing

Thrash significa que los bloques se escriben en L2ARC y se expulsan antes de ser reutilizados. Eso puede pasar porque el working set es demasiado grande, la tasa de alimentación de la caché es demasiado alta, o el patrón es una ventana rodante mayor que ARC+L2ARC.

Elegir NVMe para L2ARC: latencia, resistencia y por qué “rápido” no basta

Para L2ARC, quieres baja latencia bajo carga mixta, no solo un rendimiento secuencial heroico que nunca alcanzarás en una caché. Los números de marketing no muestran la latencia cola-coda cuando el dispositivo está caliente, parcialmente lleno y haciendo garbage collection en segundo plano. Ese es tu mundo real.

Latencia y comportamiento de colas

Los aciertos en L2ARC son lecturas aleatorias. Tu NVMe debería manejar altas IOPS sin convertir la latencia p99 en una sorpresa semanal. Las unidades con rendimiento consistente (a menudo modelos “enterprise-ish”) importan aquí. Los discos de consumo pueden estar bien, pero el riesgo es un comportamiento más brusco cuando la caché SLC se agota o bajo escrituras sostenidas por llenado de caché.

Endurance es una característica, no una nota al pie

L2ARC se popula mediante escrituras. Algunas cargas causan churn constante: los bloques se escriben en caché, se reemplazan, se escriben otra vez. Eso puede agotar las calificaciones TBW de las unidades de consumo más rápido de lo que espera tu equipo de compras.

Regla práctica: si no puedes explicar con seguridad tu tasa de escritura de caché, no compres el NVMe más barato. Compra uno que puedas reemplazar sin una discusión de carrera.

Protección contra pérdida de energía (PLP)

L2ARC es una caché; no se requiere que sea durable. Pero el comportamiento ante pérdida de energía aún importa porque un dispositivo que se comporta mal durante apagones puede colgar el bus PCIe, bloquear rutas I/O o desencadenar resets de controlador. PLP no es obligatorio para L2ARC, pero el “comportamiento empresarial aburrido” es valioso en producción.

Dimensionamiento de L2ARC: matemática simple, restricciones reales

La gente dimensiona L2ARC como dimensiona almacenamiento de objetos: “más es mejor.” Así terminas con una caché de 4 TB delante de un sistema con 64 GB de RAM y un ARC que jadea.

La realidad del overhead en RAM

L2ARC necesita metadatos en ARC para cada bloque cacheado. El overhead exacto varía por implementación y recordsize, pero debes asumir un coste real y no trivial en RAM. Si ARC ya está ajustado, un L2ARC grande puede perjudicar. Quieres suficiente RAM para mantener los metadatos más valiosos y los datos de uso frecuente en ARC, mientras L2ARC atrapa lo que se desborda.

Empieza pequeño y demuestra valor

Puntos de partida operativamente sensatos:

  • Elige un tamaño de L2ARC que sea no más que algunos múltiplos de la RAM para sistemas típicos, a menos que hayas medido y puedas justificar más.
  • Prefiere NVMe “bien dimensionado” sobre “el más grande disponible.” Una caché que nunca se calienta es un monumento al optimismo.
  • Mide ratios de acierto y mejoras de latencia antes de escalar.

Recordsize y compresión importan

ZFS cachea bloques. Si tus datasets usan recordsize de 1M para escrituras secuenciales grandes, eso puede cambiar el comportamiento de caché comparado con 16K típico de algunas bases de datos. La compresión también afecta cuánto “lógico” cabe en la caché y puede mejorar la capacidad efectiva de la caché —a veces dramáticamente.

Controles de ajuste que importan (y los que mayormente no)

La mayor parte del tuning de L2ARC se trata de reducir el caché inútil y prevenir que el relleno de caché se convierta en su propia carga de trabajo.

Prefiere cachear lecturas bajo demanda sobre prefetch

Prefetch es ZFS intentando ayudar para acceso secuencial. Para L2ARC puede ser activamente perjudicial porque llena la caché con datos que se leyeron una vez, de forma secuencial, y que nunca volverán a leerse.

Enfoque común: habilita L2ARC pero evita cachear prefetch. En Linux/OpenZFS, esto suele controlarse con l2arc_noprefetch. Los valores por defecto y el comportamiento pueden variar por versión; mide en tu build.

Controla la tasa de alimentación

L2ARC se popula desde la expulsión de ARC. Hay tunables que controlan cuánto se escribe por intervalo y cuán rápido se escala. Si empujas demasiado, tú:

  • Aumentas la carga de escritura en NVMe (golpe a la endurance).
  • Gastas CPU en bookkeeping de caché.
  • Potencialmente compites con I/O del workload real.

L2ARC persistente: agradable, pero no lo idolatres

L2ARC persistente reduce el calentamiento tras reboot guardando cabeceras y contenido de caché entre reinicios. Puede ser una gran ganancia para sistemas que se reinician por parches y necesitan rendimiento predecible post-reboot. Pero la persistencia puede aumentar la complejidad y el comportamiento de escaneo en el arranque. Trátala como cualquier otra característica: prueba, luego despliega.

Tareas prácticas: comandos, salidas y las decisiones que tomas

Estas son tareas reales que puedes ejecutar en un host Linux OpenZFS. Las salidas son representativas. Tus números variarán; tus decisiones no deberían ser basadas en corazonadas.

Task 1: Verificar la salud del pool antes de tocar la caché

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 02:11:43 with 0 errors on Sun Dec 22 03:10:12 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
            sde                     ONLINE       0     0     0
            sdf                     ONLINE       0     0     0

errors: No known data errors

Qué significa: No estás en llamas. Si ves errores de checksum o vdevs degradados, arregla eso primero.

Decisión: Solo añade L2ARC a un pool estable. Un dispositivo de caché no rescatará un pool enfermo.

Task 2: Comprueba si ya existe un L2ARC

cr0x@server:~$ sudo zpool list -v tank
NAME         SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank        65.4T  41.2T  24.2T        -         -    22%    63%  1.00x  ONLINE  -
  raidz2   65.4T  41.2T  24.2T        -         -    22%    63%
    sda        -      -      -        -         -      -      -
    sdb        -      -      -        -         -      -      -
    sdc        -      -      -        -         -      -      -
    sdd        -      -      -        -         -      -      -
    sde        -      -      -        -         -      -      -
    sdf        -      -      -        -         -      -      -

Qué significa: No se muestra una sección cache, por lo que no hay L2ARC.

Decisión: Procede a seleccionar y adjuntar un NVMe, o detente si puedes resolver el problema con RAM o layout en su lugar.

Task 3: Confirma la identidad y salud del dispositivo NVMe (antes de que ZFS lo toque)

cr0x@server:~$ lsblk -o NAME,MODEL,SIZE,ROTA,TYPE,MOUNTPOINT | grep -E 'nvme|NAME'
NAME        MODEL                 SIZE ROTA TYPE MOUNTPOINT
nvme0n1     Samsung SSD 980 PRO  931.5G    0 disk

Qué significa: Estás a punto de usar /dev/nvme0n1, 1 TB, no rotacional.

Decisión: Confirma que no estás apuntando al disco del SO. Si este NVMe también contiene root, detente. Compartir es posible pero rara vez sensato.

Task 4: Comprueba SMART y los indicadores de endurance del NVMe

cr0x@server:~$ sudo smartctl -a /dev/nvme0n1 | sed -n '1,35p'
smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.8.0] (local build)
=== START OF INFORMATION SECTION ===
Model Number:                       Samsung SSD 980 PRO 1TB
Serial Number:                      S5GXNF0R123456A
Firmware Version:                   5B2QGXA7
PCI Vendor/Subsystem ID:            0x144d
IEEE OUI Identifier:                0x002538
Total NVM Capacity:                 1,000,204,886,016 [1.00 TB]
Unallocated NVM Capacity:           0
Controller ID:                      6
Number of Namespaces:               1
Namespace 1 Size/Capacity:          1,000,204,886,016 [1.00 TB]

SMART/Health Information (NVMe Log 0x02)
Critical Warning:                   0x00
Temperature:                        44 Celsius
Available Spare:                    100%
Available Spare Threshold:          10%
Percentage Used:                    2%
Data Units Written:                 14,512,331
Data Units Read:                    22,900,112

Qué significa: La unidad está sana, bajo desgaste (Percentage Used).

Decisión: Si el desgaste ya es alto, no ofrezcas este dispositivo para churn de caché. Si debes hacerlo, limita la tasa de alimentación y monitoriza las escrituras.

Task 5: Observa el tamaño actual de ARC y la presión

cr0x@server:~$ arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsize  c
12:10:01  8160  1432     17   902   11   420    5   110    1     46G  58G
12:10:02  7992  1470     18   961   12   401    5   108    1     46G  58G
12:10:03  8421  1522     18  1002   12   413    5   107    1     46G  58G

Qué significa: ARC es ~46G, target/limit ~58G. Tasa de fallos ~18%. Eso puede estar bien o ser terrible según la latencia del pool.

Decisión: Si ARC está muy por debajo de su objetivo porque el SO lo está estrangulando, arregla la presión de memoria primero. L2ARC no sustituye a la RAM.

Task 6: Mide de dónde vienen tus lecturas ahora mismo

cr0x@server:~$ sudo zpool iostat -v tank 1 3
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        41.2T  24.2T   8900    420   195M  6.8M
  raidz2    41.2T  24.2T   8900    420   195M  6.8M
    sda         -      -   1500     70  33.0M  1.2M
    sdb         -      -   1490     72  32.8M  1.1M
    sdc         -      -   1520     71  33.5M  1.1M
    sdd         -      -   1475     68  32.4M  1.1M
    sde         -      -   1460     69  32.1M  1.1M
    sdf         -      -   1455     70  31.9M  1.1M

Qué significa: Las lecturas están golpeando fuertemente los vdevs HDD. Si la latencia es alta y el working set se relee, L2ARC puede ayudar.

Decisión: Si los discos están saturados y las lecturas son aleatorias, una caché es plausible. Si las lecturas son pequeñas y centradas en metadata, considera un vdev especial en su lugar.

Task 7: Adjuntar NVMe como L2ARC

cr0x@server:~$ sudo zpool add tank cache /dev/nvme0n1
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
        cache
          nvme0n1                   ONLINE       0     0     0

Qué significa: NVMe es ahora un dispositivo de caché (L2ARC).

Decisión: No declares victoria. Ahora monitoriza calentamiento, ratio de aciertos y escrituras NVMe.

Task 8: Verifica que L2ARC se esté usando (tasas de acierto y tamaño)

cr0x@server:~$ arcstat 1 5 | sed -n '1,6p'
    time  read  miss  miss%  ...  l2hit  l2miss  l2miss%  l2bytes  arcsize  c
12:18:01  9010  1210     13  ...   2200     980       31     190G     47G  58G
12:18:02  9155  1198     13  ...   2350     960       29     191G     47G  58G
12:18:03  9033  1160     12  ...   2480     910       27     192G     47G  58G
12:18:04  9199  1205     13  ...   2605     920       26     194G     47G  58G
12:18:05  9122  1188     13  ...   2710     890       25     195G     47G  58G

Qué significa: L2ARC tiene ~195G poblados y está sirviendo aciertos (l2hit). El porcentaje de fallos L2 está cayendo a medida que se calienta.

Decisión: Si l2bytes se mantiene pequeño durante horas bajo carga constante, algo anda mal: tasa de alimentación, workload, o simplemente no estás expulsando bloques útiles.

Task 9: Vigila I/O del NVMe para asegurar que el llenado de caché no esté destrozando la latencia

cr0x@server:~$ iostat -x 1 3 | sed -n '1,25p'
Linux 6.8.0 (server)  12/26/2025  _x86_64_  (32 CPU)

Device            r/s     w/s   rMB/s   wMB/s  await  svctm  %util
nvme0n1         3200.0  180.0   125.0    40.0   0.7    0.2   68.0
sda              250.0   12.0     4.1     0.3  18.4    2.2   55.0
sdb              240.0   11.0     4.0     0.3  19.1    2.2   54.0

Qué significa: NVMe está ocupada, pero la latencia (await) es baja. Los HDD muestran await más alto, típico.

Decisión: Si el await del NVMe sube a varios ms y compite con el I/O de la aplicación, reduce la escritura a L2ARC o revalúa. Tu caché no debe convertirse en el dispositivo más caliente.

Task 10: Confirma las propiedades del dataset que influyen en el comportamiento de la caché

cr0x@server:~$ sudo zfs get -o name,property,value,source recordsize,primarycache,secondarycache,compression tank/vmstore
NAME          PROPERTY        VALUE     SOURCE
tank/vmstore  recordsize      128K      local
tank/vmstore  primarycache    all       default
tank/vmstore  secondarycache  all       default
tank/vmstore  compression     lz4       local

Qué significa: Tanto ARC como L2ARC están permitidos (primarycache=all, secondarycache=all).

Decisión: Si un dataset tiene secondarycache=none, L2ARC no lo cacheará. Eso puede ser correcto para backups en streaming, o una configuración silenciosa equivocada.

Task 11: Excluir datasets de streaming del L2ARC para evitar contaminación

cr0x@server:~$ sudo zfs set secondarycache=none tank/backups
cr0x@server:~$ sudo zfs get -o name,property,value,source secondarycache tank/backups
NAME         PROPERTY        VALUE  SOURCE
tank/backups secondarycache  none   local

Qué significa: El dataset de backups no pobl·ará L2ARC.

Decisión: Haz esto cuando tengas grandes lectores/escritores secuenciales que expulsarían bloques cacheados útiles. Reserva la caché para las cargas que “pagan renta”.

Task 12: Inspeccionar parámetros del módulo relacionados con L2ARC (Linux OpenZFS)

cr0x@server:~$ sudo sysctl -a 2>/dev/null | grep -E 'l2arc_|zfs\.arc_' | head
zfs.l2arc_noprefetch = 1
zfs.l2arc_write_max = 8388608
zfs.l2arc_write_boost = 33554432
zfs.arc_max = 62277025792
zfs.arc_min = 15569256448

Qué significa: El prefetch no se cachea en L2ARC, y los límites de escritura están establecidos (bytes por intervalo).

Decisión: Si l2arc_noprefetch es 0 y tienes workloads secuenciales, considera activarlo. Si el llenado de caché es demasiado agresivo, ajusta l2arc_write_max con cuidado y valida.

Task 13: Cambiar un tunable de L2ARC de forma segura (temporal) y validar impacto

cr0x@server:~$ sudo sysctl -w zfs.l2arc_write_max=4194304
zfs.l2arc_write_max = 4194304

Qué significa: Se redujo la tasa máxima de escritura hacia L2ARC (aquí a 4 MiB por intervalo; el intervalo depende de la implementación).

Decisión: Usa esto si las escrituras NVMe compiten con lecturas/escrituras sensibles a latencia. Revisa iostat y la latencia p99 de la aplicación tras el cambio.

Task 14: Confirma que no confundes SLOG con L2ARC

cr0x@server:~$ sudo zpool status tank | sed -n '1,35p'
  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
        cache
          nvme0n1                   ONLINE       0     0     0

Qué significa: Solo hay un vdev de cache presente. No hay sección logs, lo que significa que no hay SLOG.

Decisión: Si tu dolor son escrituras síncronas (NFS con sync, bases de datos con patrones fsync-intensos), L2ARC no lo arreglará. Considera SLOG—con cuidado—solo después de medir.

Task 15: Eliminar L2ARC (si no ayuda) sin drama

cr0x@server:~$ sudo zpool remove tank nvme0n1
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

Qué significa: L2ARC se ha desenganchado. El pool no cambia estructuralmente (los vdevs cache no guardan datos únicos).

Decisión: Si el rendimiento no cambia o mejora después de eliminarlo, tu caché era ruido o daño. Deja de intentar hacerlo funcionar y arregla el verdadero cuello de botella.

Task 16: Evaluar la presión de memoria y comportamiento de reclaim (Linux)

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           128Gi        94Gi       4.1Gi       1.2Gi        30Gi        26Gi
Swap:           16Gi       2.3Gi        13Gi

Qué significa: RAM está muy usada, disponible es 26Gi, swap está en uso.

Decisión: La actividad de swap en una caja de almacenamiento suele ser señal de que ARC está exprimido o el host está sobrecomprometido (VMs, contenedores). Antes de añadir L2ARC, considera añadir RAM o reducir workloads co-ubicados. El overhead de metadatos de L2ARC no ayudará a un host que está haciendo swap.

Playbook de diagnóstico rápido: encuentra el cuello de botella en minutos

Este es el orden que ahorra tiempo en producción. El objetivo no es “recopilar todas las métricas.” El objetivo es “identificar el recurso limitante y la solución más simple”.

Primero: determina si tienes un problema de latencia de lectura o otra cosa

  • Revisa I/O del pool y proxies de latencia: zpool iostat -v 1, iostat -x 1.
  • Si los discos no están ocupados y la latencia es baja, tu problema puede ser CPU, red, locks de aplicación o comportamiento de escrituras síncronas.

Segundo: comprueba la efectividad de ARC y la presión de memoria

  • Usa arcstat para evaluar la tasa de fallos y la estabilidad del tamaño de ARC.
  • Usa free -h y observa swap. Si el host está haciendo swap, arregla eso. L2ARC no cura la inanición de memoria.

Tercero: confirma que la carga tiene localidad temporal

  • Busca lecturas repetidas: comportamiento de buffer cache de DB, tormentas de arranque de VM, builds de CI repetidos.
  • Si es principalmente streaming, L2ARC será un generador de desgaste.

Cuarto: prueba un L2ARC pequeño y mide

  • Añade NVMe L2ARC y observa l2hit, l2miss y la latencia p95/p99 de la aplicación.
  • El calentamiento importa; evalúa sobre un ciclo de trabajo, no 10 minutos.

Quinto: si es intensivo en metadata, considera un diseño distinto

  • I/O aleatorio de metadata en pools HDD a menudo responde mejor a un vdev especial que a L2ARC.
  • Si la latencia de escrituras síncronas es el problema, mídelo y considera SLOG (con el dispositivo correcto y expectativas reales).

Tres mini-historias del mundo corporativo desde el frente

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

Tenían un cluster de virtualización ocupado sobre HDD RAIDZ2. Los usuarios se quejaban de “lentitud aleatoria”, sobre todo los lunes por la mañana. El equipo de storage vio IOPS de lectura en el pool y decidió “arreglarlo bien” con un gran NVMe L2ARC—varios terabytes, porque compras ama los números redondos.

Se instaló limpiamente. Los gráficos parecían emocionantes: la utilización de NVMe saltó y las IOPS de lectura del pool bajaron. Todos se sintieron inteligentes por un día.

Luego la latencia empezó a trepar. No en el pool HDD—en el host. El tamaño de ARC se encogió. El hipervisor empezó a hacer swap bajo carga. Las tormentas de arranque de VM empeoraron, no mejoraron, y el helpdesk aprendió vocabulario nuevo.

La suposición equivocada fue simple: “L2ARC es caché extra, así que no puede empeorar la memoria.” En realidad, el L2ARC gigante consumió metadatos de ARC y redujo la caché efectiva en RAM. El sistema cambió aciertos rápidos en RAM por aciertos más lentos en NVMe y más fallos. Removieron el L2ARC, añadieron RAM a los hosts, y reintrodujeron una caché más pequeña después, dirigida a datasets específicos. El rendimiento se normalizó y se mantuvo aburrido.

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

Un equipo de plataforma de datos corría analytics en un pool ZFS respaldado por SSDs. Querían dashboards más rápidos, y alguien sugirió L2ARC en un NVMe de consumidor sobrante. “Es solo caché; si falla, nada se rompe.” Eso era técnicamente cierto en el sentido más estrecho.

Afilaron los parámetros de escritura de L2ARC agresivamente para “calentarlo más rápido.” Se calentó más rápido. También escribió constantemente, porque el workload escaneaba grandes ventanas de datos con poca reutilización. L2ARC se convirtió en una cinta de correr de escritura.

Unas semanas después, el NVMe empezó a tirar errores de medio. No catastrófico, pero suficiente para generar alertas y pequeñas perturbaciones I/O. Durante un incidente, el reset del dispositivo causó stalls temporales que parecían un outage de almacenamiento a nivel de cluster. La gente culpó a ZFS. ZFS sobrellevo; el dispositivo estaba teniendo un mal día.

El postmortem fue incómodo porque la “optimización” no mejoró el p99 del dashboard de todos modos. La solución fue aburrida: remover L2ARC, ajustar consultas para reducir churn, y más tarde añadir un vdev especial pequeño para metadata y bloques pequeños. Los dashboards mejoraron y el NVMe dejó de morirse por una característica que nadie pudo cuantificar.

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

Una firma de servicios financieros corría ZFS para almacenamiento de VM y servicios internos. Tenían L2ARC en NVMe en espejo (sí, en espejo—porque tenían ranuras y les gustaba dormir tranquilos). Su política de cambios era dolorosamente estricta: cada cambio en storage requería una línea base pre-cambio, un plan de rollback y una métrica de éxito explícita.

El parcheo trimestral requería reinicios, y antes habían visto dips de rendimiento post-reboot mientras las cachés se calentaban. Probaron L2ARC persistente en staging, confirmaron el comportamiento de arranque y lo desplegaron con tunables cuidadosamente elegidos y un camino documentado para “desactivar persistencia”.

Luego vino una semana fea: un deploy de aplicación aumentó la amplificación de lectura e hizo las cachés menos efectivas. Porque tenían líneas base, pudieron probar que no era “el storage envejeciendo”. Ajustaron las políticas de caché del dataset para la carga ruidosa y protegieron la caché de la contaminación. Sin heroísmos. Sin llamadas a proveedores. Solo competencia.

No fue glamoroso, pero previno el clásico bucle de sala de guerra: “el storage está lento” → “añadir caché” → “sigue lento” → “añadir más caché.” Su proceso aburrido salvó días de fricción.

Broma #2: Lo único más persistente que L2ARC es un stakeholder preguntando si podemos “simplemente añadir más NVMe”.

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

1) Síntoma: la tasa de aciertos de L2ARC permanece cerca de cero

Causa raíz: La carga es streaming o tiene baja localidad de re-lectura; o el dataset tiene secondarycache=none; o la caché es demasiado pequeña y hace thrash inmediato.

Solución: Verifica propiedades del dataset con zfs get secondarycache. Excluye datasets de streaming. Si la localidad es baja, elimina L2ARC e invierte en otra cosa.

2) Síntoma: el tamaño de ARC se reduce después de añadir L2ARC, aumentan los misses

Causa raíz: El overhead en RAM por metadatos L2ARC reduce la capacidad de ARC; el host tiene presión de memoria; L2ARC sobredimensionado.

Solución: Reduce el tamaño de L2ARC (usa una partición/dispositivo más pequeño), añade RAM o elimina L2ARC. Confirma con arcstat y free -h.

3) Síntoma: alta utilización de NVMe, picos de latencia, la aplicación empeora

Causa raíz: Tasa de alimentación de L2ARC demasiado agresiva; NVMe es un disco de consumo con mal comportamiento sostenido; el llenado de caché compite con el workload.

Solución: Baja l2arc_write_max/l2arc_write_boost. Usa un NVMe con rendimiento consistente. Considera excluir datasets ruidosos de L2ARC.

4) Síntoma: el rendimiento es genial… hasta el reinicio, luego horrible por horas

Causa raíz: L2ARC no persistente requiere calentamiento; la carga depende fuertemente de aciertos en caché.

Solución: Evalúa soporte de L2ARC persistente en tu versión de ZFS. Si no está disponible o no es deseable, planifica reinicios y pre-calienta, o incrementa RAM para reducir la dependencia en L2ARC.

5) Síntoma: esperabas escrituras más rápidas, pero nada cambió

Causa raíz: L2ARC es caché de lectura. Las escrituras están condicionadas por ZIL/SLOG, el layout del pool y semánticas sync.

Solución: Mide escrituras síncronas. Si es necesario, evalúa SLOG con el dispositivo correcto y prueba. No cargo-cultes “NVMe = más rápido”.

6) Síntoma: L2ARC ayuda algunas cargas, pero los backups ralentizan todo

Causa raíz: Contaminación de caché y presión de expulsión por lecturas/escrituras secuenciales de backups.

Solución: Pon secondarycache=none (y a veces primarycache=metadata) en datasets de backup. Mantén la caché para workloads interactivos/calientes.

7) Síntoma: mucho uso de CPU en kernel bajo carga tras habilitar L2ARC

Causa raíz: Overhead de bookkeeping de caché más actividad elevada de expulsión; posiblemente demasiados bloques pequeños o feed agresivo.

Solución: Reduce la tasa de escritura de L2ARC; asegúrate de no cachear prefetch; considera aumentar recordsize donde corresponda o repensar el patrón I/O del workload.

8) Síntoma: NVMe se desgasta más rápido de lo esperado

Causa raíz: Churn constante por baja localidad; caché sobredimensionada con alta rotación; tunables de escritura agresivos.

Solución: Mide la tasa de escritura, limita la alimentación, excluye datasets de streaming, o elimina L2ARC. Compra dispositivos de mayor endurance cuando la carga lo justifique.

Listas de verificación / plan paso a paso

Plan A: Decide si deberías añadir L2ARC en absoluto

  1. Confirma que es un problema de lectura. Si tu pool está limitado por escrituras o por sync, para y diagnostica eso en su lugar.
  2. Mide la tasa de fallos de ARC y el headroom de RAM. Si el host tiene presión de memoria, prioriza RAM y colocación de workloads.
  3. Valida la localidad de re-lectura. L2ARC es para “lecturas que vuelven”. Si no lo hacen, no las caches.
  4. Revisa el layout del pool y el dolor de metadata. Si la metadata es el cuello de botella, un vdev especial puede superar a L2ARC.

Plan B: Implementar NVMe L2ARC de forma segura

  1. Línea base antes de cambios. Captura arcstat, zpool iostat, iostat -x y latencia de la aplicación.
  2. Elige un NVMe sensato. Favorece latencia consistente y endurance sobre throughput pico.
  3. Comienza con un tamaño de caché moderado. Demuestra valor antes de escalar.
  4. Adjunta el dispositivo como cache. Verifica con zpool status.
  5. Evita la contaminación de caché. Pon secondarycache=none en datasets de streaming.
  6. Monitorea calentamiento y carga del dispositivo. Observa l2hit/l2miss y await del NVMe.
  7. Ajusta con cautela. Reduce la tasa de escritura de L2ARC si compite con I/O real.
  8. Documenta rollback. Sabe cómo zpool remove el dispositivo de cache y qué significa “éxito”.

Plan C: Guardarraíles operativos que te mantienen fuera de problemas

  • Alerta sobre desgaste y errores de media del NVMe. L2ARC puede ser duro con las unidades; trátalo como un componente consumible.
  • Rastrea ratios de acierto de caché a lo largo del tiempo. Una caché útil puede volverse inútil tras cambios en la aplicación.
  • Planificación de reinicios. Si L2ARC no es persistente, programa reinicios cuando el calentamiento no perjudique.
  • Mantén los cambios pequeños. Si cambias tamaño de caché, tunables y propiedades de datasets a la vez, nunca sabrás qué funcionó.

Preguntas frecuentes

1) ¿Es L2ARC lo mismo que SLOG?

No. L2ARC es una caché de lectura. SLOG es un dispositivo de log separado usado para acelerar escrituras síncronas acortando la ruta de commit del ZIL. Problema distinto, herramienta distinta.

2) ¿Debería espejar dispositivos L2ARC?

Usualmente no, porque L2ARC no contiene datos únicos. Si falla, pierdes caché y el rendimiento vuelve al del pool. Espeja solo si el coste operativo de perder la caché es alto y tienes ranuras y presupuesto.

3) ¿Puede L2ARC empeorar el rendimiento?

Sí. Los mecanismos habituales son encogimiento de ARC (overhead de metadatos), contención por llenado de caché y contaminación por workloads secuenciales. “Caché” no es automáticamente “más rápido”.

4) ¿Cuánto tarda L2ARC en calentarse?

Depende de tu working set, la tasa de expulsión de ARC y los límites de alimentación de L2ARC. Para sistemas ocupados puede ser horas; para sistemas más tranquilos, días. Si necesitas ganancias instantáneas, compra más RAM primero.

5) ¿Debería cachear prefetch en L2ARC?

La mayoría de las veces: no. Prefetch puede inundar L2ARC con datos secuenciales que no se volverán a leer. Si tu workload es principalmente secuencial y se vuelve a leer, pruébalo—no asumas.

6) ¿Cómo evito que los backups arruinen mi caché?

Pon secondarycache=none en datasets de backup. En algunos entornos, considera también primarycache=metadata para datasets de streaming para que ARC mantenga metadata pero no datos voluminosos.

7) ¿Vale la pena habilitar L2ARC persistente?

Si tus cargas son sensibles al calentamiento post-reboot y tu versión de ZFS lo soporta de forma fiable, puede ser una gran mejora de calidad de vida. Prueba reinicios en staging y observa el comportamiento de arranque y uso de memoria.

8) Tengo un pool todo NVMe. ¿Aún necesito L2ARC?

Rara vez. ARC en RAM sigue siendo más rápido que NVMe. Pero si el working set es enorme y muy re-lecturado, y tu pool está tan ocupado que descargar lecturas ayuda, L2ARC aún puede ser útil. Mide primero; si no, solo añades complejidad.

9) ¿Qué es mejor: más RAM o más L2ARC?

Más RAM, casi siempre. Los aciertos en ARC son más baratos que los aciertos en L2ARC, y la RAM no se desgasta por haber mirado el mismo archivo dos veces. Usa L2ARC cuando la RAM ya esté razonablemente dimensionada y aún faltes.

10) ¿Cómo sé si L2ARC se paga a sí mismo?

Observa la latencia p95/p99 y el throughput de la aplicación, no solo ratios de caché. Un aumento de l2hit es bonito, pero la métrica de negocio es “menos requests lentas”. Si no puedes mostrar mejora, elimínalo.

Próximos pasos prácticos

  1. Línea base hoy. Captura arcstat, zpool iostat -v y iostat -x durante un periodo conocido como “lento”.
  2. Decide si la carga vuelve a leer. Si es streaming, no construyas un santuario de caché.
  3. Arregla la presión de memoria primero. Si estás haciendo swap o ARC no puede alcanzar un tamaño estable, L2ARC es una distracción.
  4. Empieza con un NVMe L2ARC pequeño y protégelo. Excluye datasets de streaming, evita cachear prefetch y mantén tasas de alimentación razonables.
  5. Mide resultados, no sentimientos. Si la latencia p99 mejora y el desgaste de NVMe es aceptable, mantenlo. Si no, quítalo y pasa a cambios de layout o RAM.
← Anterior
La carrera armamentista de DirectX: por qué los controladores a veces superan al silicio
Siguiente →
Historias de «rm -rf /»: el comando que se convirtió en un género de terror informático

Deja un comentario