Descartar um arquivo específico do cache do sistema de arquivos Linux?

Descartar um arquivo específico do cache do sistema de arquivos Linux?

Eu sei que possoelimine tudo do cache do sistema de arquivos Linux, mas existe uma maneira de eliminar apenas um arquivo específico? Ou impedir que um arquivo seja armazenado em cache? Ou dizer a um processo para não armazenar em cache nenhum arquivo que ele grava?

Eu tenho um processo que lê muitos arquivos pequenos e grava um arquivo grande. Quero manter os arquivos pequenos em cache para evitar buscas no disco e não me importo em armazenar em cache o arquivo grande.

Responder1

Método potencial nº 1 - F_DROP_CACHES

Encontrei um método de 2012 que discute um patch proposto para o kernel Linux neste tópico de e-mail intitulado:Re: [RFC Patch] fs: implementar caches de descarte por arquivo.

excerto

Cong> Este é um rascunho de patch para implementação de caches de descarte por arquivo.

Interessante. Então, posso fazer isso fora de um processo? Sou SysAdmin, então meu ponto de vista é perceber, encontrar e corrigir problemas de desempenho quando o sistema está sob pressão.

Cong> It introduces a new fcntl command  F_DROP_CACHES to drop  
Cong> file caches of a specific file. The reason is that currently  
Cong> we only have a system-wide drop caches interface, it could  
Cong> cause system-wide performance down if we drop all page caches  
Cong> when we actually want to drop the caches of some huge file.

Como posso saber quanto cache é usado por um arquivo? E qual é o impacto disso no desempenho quando executado em um sistema ocupado? E o que esse patch nos traz, já que acho que a VM já deveria estar descartando caches quando o sistema estiver sob pressão de memória...

Cong> Abaixo está um pequeno caso de teste para este patch:

O thread inclui um caso de teste e o patch real para vários arquivos no kernel do Linux, que adiciona uma função adicional ao fs/drop_caches.cchamado drop_pagecache_file(struct file *filp). Esta função fica então acessível através da ferramenta frontend, fnctl.catravés do comando F_DROP_CACHES. Este caso chama esta função:

file_drop_caches(filp, arg);

Que lida com a eliminação de todos os caches associados a um determinado arquivo. Do arquivo include/linux/mm.h:

void file_drop_caches(struct file *filp, unsigned long which);
Então isso pode ser usado?

Não encontrei nenhuma evidência de que esse patch tenha chegado ao repositório principal de código do kernel Linux, então esta opção parece estar disponível apenas se você estiver disposto a recompilar o kernel Linux sozinho.

Método potencial nº 2 - Usando dd

Nesse mesmo tópico, outro usuário menciona uma metodologia completamente diferente que faz uso do dd.

O seguinte é um trechodaquele e-mail

Esta é uma funcionalidade útil. Embora já não esteja fornecido POSIX_FADV_DONTNEED? Esta funcionalidade foi adicionada aoGNU dd (8.11) há um ano.

Aqui estão os exemplos desse patch:
  • Aconselho a descartar o cache de todo o arquivo

     $ dd if=ifile iflag=nocache count=0
    
  • Certifique-se de descartar o cache para todo o arquivo

     $ dd of=ofile oflag=nocache conv=notrunc,fdatasync count=0
    
  • Eliminar cache de parte do arquivo

     $ dd if=ifile iflag=nocache skip=10 count=10 of=/dev/null
    
  • Transmita dados usando apenas o cache de leitura antecipada

     $ dd if=ifile of=ofile iflag=nocache oflag=nocache
    
Testando

Não tive 100% certeza de como testar isso, mas descobri a seguinte abordagem.

  1. crie um arquivo de 100MB

    $ dd if=/dev/urandom of=sample.txt bs=100M count=1
    
  2. rastrear acessos a arquivos usandofatrace

    $ sudo fatrace | grep sample.txt
    
  3. execute toppara que possamos monitorar o uso da memória, observe a quantidade livre.

    $ top
    
  4. abra o arquivo, observe a quantidade de memória livre agora. Observe o fatracedo arquivo sample.txt.

    $ cat sample.txt > /dev/null
    
  5. elimine o arquivo da memória, observe a quantidade de memória livre agora. Observe a saída de fatrace.

    $ sudo dd of=/home/saml/tst/162600/sample.txt \
        oflag=nocache conv=notrunc,fdatasync count=0
    

Exemplo

No terminal nº 1:
$ dd if=/dev/urandom of=sample.txt bs=100M count=1
1+0 records in
1+0 records out
104857600 bytes (105 MB) copied, 7.37996 s, 14.2 MB/s

$ ls -l sample.txt 
-rw-rw-r--. 1 saml saml 104857600 Oct 17 22:54 sample.txt
No terminal nº 2:
$ top
...
KiB Mem:   7968336 total,  6900956 used,  1067380 free,   267080 buffers
...
No terminal nº 3:
$ sudo fatrace | grep sample.txt
Agora abra o arquivo sample.txte observe a quantidade de RAM. No terminal nº 1.
$ cat sample.txt > /dev/null
No terminal nº 2:
KiB Mem:   7968336 total,  7011896 used,   956440 free,   267336 buffers
Observe a saída fatraceno terminal #3:
cat(25940): R /home/saml/tst/162600/sample.txt
cat(25940): R /home/saml/tst/162600/sample.txt
cat(25940): RC /home/saml/tst/162600/sample.txt
Agora remova o arquivo da RAM, no terminal nº 4:
$ sudo dd of=/home/saml/tst/162600/sample.txt \
    oflag=nocache conv=notrunc,fdatasync count=0
Observe a saída fatraceno terminal #2:
dd(26229): O /home/saml/tst/162600/sample.txt
dd(26229): CW /home/saml/tst/162600/sample.txt
Observe a RAM no terminal nº 3:
KiB Mem:   7968336 total,  6908364 used,  1059972 free,   267364 buffers

Então parece que tudo o que foi consumido pelo arquivo na RAM é liberado.

Método potencial nº 3 - python-fadvise

Graças a um comentário de @frostchutz, existe outra ferramenta, um script Python, nomeado [pyadvise][4]que fornece uma interface muito mais simples do que os ddmétodos acima. Este script faz uso da mesma posix_fadvise(2)interface.

Exemplo
$ sudo pyadvise --help
Usage: 
    pyadvise [options] [FILE]..

Options:
  -h, --help        show this help message and exit
  -w, --willneed    The specified files will be accessed in the near future
  -s, --sequential  The application expects to access the specified files
                    sequentially (with lower offsets read before higher ones)
  -d, --dontneed    The specified files will not be accessed in the near
                    future
  -r, --random      The specified files will be accessed in random order
  -o, --noreuse     The specified files will be accessed only once. Under
                    Linux, this operation is a no-op; see contrib/copyfileobj-
                    fadvise.py in the python-fadvise source tree for an
                    example on how to achieve approximately the same effect
  -n, --normal      Indicates that the application has no advice to give about
                    its access pattern for the specified files. If no advice
                    is given for an open file, this is the default assumption
  -v, --verbose     Explain what is being done

E se repetirmos o teste acima e usarmos pyadviseno lugar de dd:

$ pyadvise -d /home/saml/tst/162600/sample.txt

Percebi uma queda idêntica na RAM sendo consumida como antes, quando usei o dd.

Responder2

Expandindo a resposta do @geekosaur você pode forçar o uso O_DIRECTusando LD_PRELOAD e o programa aqui:http://arighi.blogspot.com/2007/04/how-to-bypass-buffer-cache-in-linux.html

Esse código força O_DIRECTtodos os arquivos. No entanto, simplesmente adicionando um pouco mais de lógica strncmp __do_wrap_openvocê pode aplicar seletivamente O_DIRECT.

Isenção de responsabilidade: eu não testei isso.

Responder3

Você pode abrir arquivos individuais com a O_DIRECTbandeira (veja man 2 open) — leia oNOTASseção dessa página de manual com cuidado e considere se você também deseja/precisa O_SYNC.

Responder4

Se você quiser forçar um arquivo a sempre usar O_SYNC você pode marcá-lo como tal nos atributos estendidos com chattr +S $file:

homem chattr:

Quando um arquivo com o conjunto de atributos 'S' é modificado, as alterações são gravadas de forma síncrona no disco; isso é equivalente à opção de montagem 'sync' aplicada a um subconjunto de arquivos.

O_SYNC força os dados + metadados a serem gravados nos buffers do disco, mas ainda passam pelo cache da página. O_DIRECT ignora o cache da página.

Mas esteja ciente de que abri-lo com O_DIRECT seria prejudicial ao desempenho, se o arquivo grande estiver apenas sendo anexado, a diferença poderá ser pequena. Mas se o arquivo grande tiver sido reescrito em locais aleatórios, O_DIRECT será um grande impacto no desempenho, mesmo levando em consideração que tê-lo no cache poderia expulsar do cache alguns dos pequenos arquivos lidos.

Se você tiver memória RAM para manter todos os arquivos pequenos, poderá abordar o problema de outra maneira. Certifique-se de que os arquivos pequenos estejam sempre na memória RAM, então sugiro copiá-los paratmpfs:

tmpfs coloca tudo nos caches internos do kernel e aumenta e diminui para acomodar os arquivos que contém

informação relacionada