ZFS en Linux: L2ARC no se lee

ZFS en Linux: L2ARC no se lee

Hoy hice algunas pruebas en L2ARC usando el último ZFS en Linux 0.7.10. He visto que L2ARC se llena de datos, pero con la configuración predeterminada del módulo, los datos que residen en la caché L2ARC nunca se tocan. En cambio, los datos se leen de los vdevs del grupo principal. También he visto este comportamiento en 0.7.9 y no estoy seguro de si ese es el comportamiento esperado.
Incluso si ese fuera el comportamiento esperado, creo que es extraño estropear el L2ARC con datos que nunca se leen.


La instalación de prueba es una VM:

  • CentOS 7.5 con los últimos parches
  • ZFS en Linux 0.7.10
  • 2 GB de RAM

Hice algunas configuraciones de ZFS:

  • l2arc_headroom=1024y l2arc_headroom=1024acelerar la población L2ARC

Así es como se creó la piscina y su distribución. Sé que es bastante extraño para una configuración del mundo real, pero esto fue pensado únicamente para pruebas L2ARC.

[root@host ~]# zpool create tank raidz2 /dev/sda /dev/sdb /dev/sdc cache sdd -f
[root@host ~]# zpool list -v
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank  2.95G   333K  2.95G         -     0%     0%  1.00x  ONLINE  -
  raidz2  2.95G   333K  2.95G         -     0%     0%
    sda      -      -      -         -      -      -
    sdb      -      -      -         -      -      -
    sdc      -      -      -         -      -      -
cache      -      -      -         -      -      -
  sdd  1010M    512  1009M         -     0%     0%

Ahora escriba algunos datos en un archivo y observe el uso del dispositivo.

[root@host ~]# dd if=/dev/urandom of=/tank/testfile bs=1M count=512
512+0 records in
512+0 records out
536870912 bytes (537 MB) copied, 9.03607 s, 59.4 MB/s

[root@host ~]# zpool list -v
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank  2.95G  1.50G  1.45G         -    10%    50%  1.00x  ONLINE  -
  raidz2  2.95G  1.50G  1.45G         -    10%    50%
    sda      -      -      -         -      -      -
    sdb      -      -      -         -      -      -
    sdc      -      -      -         -      -      -
cache      -      -      -         -      -      -
  sdd  1010M   208M   801M         -     0%    20%

Muy bien, algunos de los datos ya se trasladaron al L2ARC, pero no todos. Entonces, léelo más veces para que esté completamente en L2ARC.

[root@host ~]# dd if=/tank/testfile of=/dev/null bs=512 # until L2ARC is populated with the 512MB testfile

[root@host ~]# zpool list -v
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank  2.95G  1.50G  1.45G         -    11%    50%  1.00x  ONLINE  -
  raidz2  2.95G  1.50G  1.45G         -    11%    50%
    sda      -      -      -         -      -      -
    sdb      -      -      -         -      -      -
    sdc      -      -      -         -      -      -
cache      -      -      -         -      -      -
  sdd  1010M   512M   498M         -     0%    50%

Bien, L2ARC está completo y listo para ser leído. Pero primero es necesario deshacerse de L1ARC. Hice lo siguiente, que pareció funcionar.

[root@host ~]# echo $((64*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; echo $((1024*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; arc_summary.py -p1

------------------------------------------------------------------------
ZFS Subsystem Report                        Sun Sep 09 17:03:55 2018
ARC Summary: (HEALTHY)
    Memory Throttle Count:                  0

ARC Misc:
    Deleted:                                20
    Mutex Misses:                           0
    Evict Skips:                            1

ARC Size:                           0.17%   1.75    MiB
    Target Size: (Adaptive)         100.00% 1.00    GiB
    Min Size (Hard Limit):          6.10%   62.48   MiB
    Max Size (High Water):          16:1    1.00    GiB

ARC Size Breakdown:
    Recently Used Cache Size:       96.06%  1.32    MiB
    Frequently Used Cache Size:     3.94%   55.50   KiB

ARC Hash Breakdown:
    Elements Max:                           48
    Elements Current:               100.00% 48
    Collisions:                             0
    Chain Max:                              0
    Chains:                                 0

Muy bien, ahora estamos listos para leer desde L2ARC (perdón por el prefacio tan largo, pero pensé que era importante).
Entonces, al ejecutar el dd if=/tank/testfile of=/dev/null bs=512comando nuevamente, estaba mirando zpool iostat -v 5en una segunda terminal.

Para mi sorpresa, el archivo se leyó desde los vdev normales en lugar del L2ARC, aunque el archivo se encuentra en L2ARC. Este es el único archivo en el sistema de archivos y no hay ninguna otra actividad activa durante mis pruebas.

              capacity     operations     bandwidth 
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        1.50G  1.45G    736     55  91.9M  96.0K
  raidz2    1.50G  1.45G    736     55  91.9M  96.0K
    sda         -      -    247     18  30.9M  32.0K
    sdb         -      -    238     18  29.8M  32.0K
    sdc         -      -    250     18  31.2M  32.0K
cache           -      -      -      -      -      -
  sdd        512M   498M      0      1  85.2K  1.10K
----------  -----  -----  -----  -----  -----  -----

Luego jugueteé con algunas configuraciones como , , zfetch_array_rd_szy zfetch_max_distance, configurándolas en un número impar alto. Pero nada cambió. zfetch_max_streamsl2arc_write_boostl2arc_write_max

Después de cambiar

  • l2arc_noprefetch=0(el valor predeterminado es 1)
  • o zfs_prefetch_disable=1(el valor predeterminado es 0)
  • alternar ambos desde sus valores predeterminados

las lecturas se sirven desde L2ARC. De nuevo corriendo dd if=/tank/testfile of=/dev/null bs=512y mirando zpool iostat -v 5en una segunda terminal y deshaciéndote de L1ARC.

[root@host ~]# echo 0 > /sys/module/zfs/parameters/l2arc_noprefetch 
[root@host ~]# echo $((64*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; echo $((1024*1024*1024)) > /sys/module/zfs/parameters/zfs_arc_max; sleep 5s; arc_summary.py -p1
...
[root@host ~]# dd if=/tank/testfile of=/dev/null bs=512 

Y el resultado:

              capacity     operations     bandwidth 
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        1.50G  1.45G      0     57    921   102K
  raidz2    1.50G  1.45G      0     57    921   102K
    sda         -      -      0     18      0  34.1K
    sdb         -      -      0     18      0  34.1K
    sdc         -      -      0     19    921  34.1K
cache           -      -      -      -      -      -
  sdd        512M   497M    736      0  91.9M   1023
----------  -----  -----  -----  -----  -----  -----

Ahora los datos se leen desde L2ARC, pero solo después de alternar los parámetros del módulo mencionados anteriormente.

También he leído que L2ARC puede tener un tamaño demasiado grande. Pero los hilos que encontré sobre ese tema se referían a problemas de rendimiento o al mapa espacial del L2ARC que estropeaba el L1ARC.
El rendimiento no es mi problema aquí y, hasta donde puedo decir, el mapa espacial del L2ARC tampoco es tan grande.

[root@host ~]# grep hdr /proc/spl/kstat/zfs/arcstats 
hdr_size                        4    279712
l2_hdr_size                     4    319488

Como ya se mencionó, no estoy seguro de si ese es el comportamiento previsto o si me falta algo.

Respuesta1

Entonces, después de leer sobre este tema, principalmenteesta publicación, parece que este es el comportamiento predeterminado de ZFS.

Lo que sucede es que el archivo llega a L1ARC después de ser leído y, debido a los bloques a los que se accede, se considera que está colocado en L2ARC.
Ahora, en una segunda lectura del archivo, ZFS está realizando una captación previa del archivo, lo que omite el L2ARC aunque los bloques del archivo están almacenados en L2ARC.

Al deshabilitar completamente la captación previa zfs_prefetch_disable=1o decirle a ZFS que realice la captación previa en L2ARC con l2arc_noprefetch=0, las lecturas harán uso de los bloques del archivo que residen en L2ARC.
Esto podría ser deseable si su L2ARC es lo suficientemente grande en comparación con los tamaños de archivos que se están leyendo.
Pero es posible que uno quiera poner solo metadataen L2ARC con zfs set secondarycache=metadata tank. Esto evita que archivos grandes terminen en L2ARC y nunca se lean. Ya que esto seríaarruinarL2ARC y podría desalojar bloques de archivos más pequeños que no se están recuperando previamente y metadatos que desea conservar en L2ARC.

No he encontrado una manera de decirle a ZFS que pongasolo archivos pequeñosen L2ARC y no fusionar los candidatos de captación previa en L2ARC. Entonces, por ahora, dependiendo del tamaño de los archivos y del tamaño de L2ARC, uno tiene que hacer una compensación.
Un enfoque diferente parece estar disponible en la versión ZoL 0.8.0, donde es posible utilizar diferentesClases de asignacióny debería permitir, por ejemplo, colocar sus metadatos en SSD rápidos, dejando bloques de datos enlentodiscos giratorios. Esto todavía dejará la contienda.archivos pequeñosvs.archivos grandespara L2ARC, pero resolverá el problema del acceso rápido a los metadatos.

Respuesta2

Lo que sucede en este caso es que ZFS está tratando de preservar el ancho de banda L2ARC para lecturas aleatorias/sin transmisión, donde golpear los discos físicos causaría estragos en el rendimiento. Las lecturas de transmisión se realizan bastante bien desde discos duros mecánicos, y cualquier grupo con más de 6/8 discos probablemente superará a cualquier dispositivo SATA L2ARC para lecturas secuenciales. Y cualquier zpool de tamaño mediano (es decir, 24/48+ discos) daráinfinidadde ancho de banda real secuencial.

Como descubrió, puede modificar L2ARC para permitir que se comporte de manera más similar a un caché de víctima (es decir, almacenar cualquier cosa expulsada de ARC; si se encuentra un bloque en L2ARC, ni siquiera intente acceder al grupo principal). En algunas configuraciones específicas esto puede ser algo bueno; sin embargo, ZFS fue diseñado (correctamente) para preservar el desgaste/uso de L2ARC donde puede ser realmente ventajoso: almacenar en caché los bloques realmente usados ​​para un rendimiento de lecturas aleatorias más rápido.

información relacionada