ZFS no Linux - L2ARC não está sendo lido

ZFS no Linux - L2ARC não está sendo lido

Hoje fiz alguns testes no L2ARC usando o ZFS mais recente no Linux 0.7.10. Eu vi que o L2ARC fica cheio de dados, mas com as configurações padrão do módulo, os dados que residem no cache L2ARC nunca são tocados. Em vez disso, os dados são lidos dos vdevs do pool principal. Também vi esse comportamento em 0.7.9 e não tenho certeza se esse é o comportamento esperado.
Mesmo que esse seja o comportamento esperado, acho estranho estragar o L2ARC com dados que nunca são lidos.


A instalação de teste é uma VM:

  • CentOS 7.5 com patches mais recentes
  • ZFS no Linux 0.7.10
  • 2 GB de RAM

Fiz algumas configurações do ZFS:

  • l2arc_headroom=1024e l2arc_headroom=1024para acelerar a população L2ARC

Veja como o pool foi criado e o layout. Eu sei que é um tanto estranho para uma configuração do mundo real, mas isso foi planejado apenas para testes 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%

Agora grave alguns dados em um arquivo e observe o uso do 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%

Tudo bem, alguns dados já foram movidos para o L2ARC, mas não todos. Então, leia mais algumas vezes para torná-lo completamente em 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%

Ok, o L2ARC está preenchido e pronto para ser lido. Mas primeiro é preciso se livrar do L1ARC. Eu fiz o seguinte, que pareceu 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

Tudo bem, agora estamos prontos para ler o L2ARC (desculpe pelo longo prefácio, mas achei importante).
Então, executando o dd if=/tank/testfile of=/dev/null bs=512comando novamente, fiquei observando zpool iostat -v 5em um segundo terminal.

Para minha surpresa, o arquivo foi lido nos vdevs normais em vez do L2ARC, embora o arquivo esteja no L2ARC. Este é o único arquivo no sistema de arquivos e nenhuma outra atividade está ativa durante meus testes.

              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
----------  -----  -----  -----  -----  -----  -----

Em seguida , mexi em algumas configurações como zfetch_array_rd_sz, zfetch_max_distance, e , definindo-as para um número ímpar alto. Mas nada mudou. zfetch_max_streamsl2arc_write_boostl2arc_write_max

Depois de mudar

  • l2arc_noprefetch=0(o padrão é 1)
  • ou zfs_prefetch_disable=1(o padrão é 0)
  • alternar ambos de seus padrões

as leituras são servidas pelo L2ARC. Novamente executando dd if=/tank/testfile of=/dev/null bs=512e observando zpool iostat -v 5em um segundo terminal e livre-se do 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 

E o 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
----------  -----  -----  -----  -----  -----  -----

Agora os dados são lidos do L2ARC, mas somente após alternar os parâmetros do módulo mencionados acima.

Eu também li que o L2ARC pode ser muito grande. Mas os tópicos que encontrei sobre esse tópico referiam-se a problemas de desempenho ou ao mapa espacial do L2ARC estragando o L1ARC.
O desempenho não é meu problema aqui e, pelo que posso dizer, o mapa espacial do L2ARC também não é tão grande.

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

Como já mencionado, não tenho certeza se esse é o comportamento pretendido ou se estou faltando alguma coisa.

Responder1

Então, depois de ler sobre esse assunto, principalmenteesta postagem, parece que este é o comportamento padrão do ZFS.

O que acontece é que o arquivo chega ao L1ARC após ser lido e devido aos blocos acessados ​​ele é considerado colocado no L2ARC.
Agora, em uma segunda leitura do arquivo, o ZFS está fazendo uma pré-busca no arquivo, o que ignora o L2ARC, embora os blocos do arquivo estejam armazenados no L2ARC.

Ao desabilitar completamente a pré-busca zfs_prefetch_disable=1ou instruir o ZFS para fazer a pré-busca no L2ARC com l2arc_noprefetch=0, as leituras usarão os blocos do arquivo que residem no L2ARC.
Isso pode ser desejado se o seu L2ARC for grande o suficiente em comparação com os tamanhos dos arquivos que estão sendo lidos.
Mas pode-se querer colocar apenas metadatano L2ARC com zfs set secondarycache=metadata tank. Isso evita que arquivos grandes acabem em L2ARC e nunca sejam lidos. Já que isso seriaestragaro L2ARC e pode expulsar blocos de arquivos menores que não foram pré-buscados e metadados, que você deseja manter no L2ARC.

Não encontrei uma maneira de dizer ao ZFS para colocarapenas arquivos pequenosno L2ARC e não mesclar os candidatos de pré-busca no L2ARC. Então, por enquanto, dependendo do tamanho dos arquivos e do tamanho do L2ARC, é necessário fazer uma troca.
Uma abordagem diferente parece estar disponível na versão ZoL 0.8.0, onde é possível usar diferentesClasses de Alocaçãoe deve tornar possível, por exemplo, colocar seus metadados em SSDs rápidos, deixando blocos de dados ativados.lentodiscos giratórios. Isso ainda deixará a disputaarquivos pequenosvs.arquivos grandespara L2ARC, mas resolverá o problema de acesso rápido aos metadados.

Responder2

O que acontece neste caso é que o ZFS está tentando preservar a largura de banda L2ARC para leituras aleatórias/sem streaming, onde atingir os discos físicos causaria estragos no desempenho. As leituras de streaming são muito bem servidas em HDDs mecânicos, e qualquer pool com discos 6/8+ provavelmente superará qualquer dispositivo SATA L2ARC para leituras sequenciais. E qualquer zpool de tamanho médio (ou seja: 24/48+ discos) fornecerábastantede largura de banda real sequencial.

Como você descobriu, você pode alterar o L2ARC para permitir que ele se comporte de forma mais semelhante a um cache de vítima (ou seja: armazene qualquer coisa despejada do ARC; se um bloco for encontrado no L2ARC, nem tente acessar o pool principal). Em algumas configurações específicas, isso pode ser bom; no entanto, o ZFS foi (corretamente) arquitetado para preservar o desgaste/uso do L2ARC onde pode ser realmente vantajoso: armazenar em cache blocos realmente usados ​​para desempenho de leituras aleatórias mais rápido.

informação relacionada