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

23

Eu sei que posso eliminar 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 diga a um processo para não armazenar em cache nenhum arquivo que ele gravar?

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

Jay Hacker
fonte
1
Em relação à recompensa, estou especificamente interessado na questão do título: remover um arquivo específico do cache (em vez de impedir que ele chegue lá em primeiro lugar).
Gilles 'SO- stop be evil'

Respostas:

21

Método potencial # 1 - F_DROP_CACHES

Eu encontrei um método a partir de 2012 que discute um patch proposto para o kernel Linux neste segmento de e-mail intitulado: Re: [RFC Patch] fs: implemente caches de descarte por arquivo .

excerto

Cong> Este é um patch de rascunho da implementação de caches descartáveis ​​por arquivo.

Interessante. Então, posso fazer isso de fora de um processo? Como sou um SysAdmin, meu POV é 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 no desempenho disso quando executado em um sistema ocupado? E o que esse patch nos compra desde que eu acho que a VM já deveria estar deixando caches quando o sistema fica sob pressão de memória ...

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

O encadeamento inclui um testcase e o patch real em vários arquivos no kernel do Linux, o que adiciona uma função adicional ao fs/drop_caches.cchamado drop_pagecache_file(struct file *filp). Esta função é, 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 ao arquivo especificado. 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 já tenha chegado ao repositório principal de códigos do kernel do Linux; portanto, essa opção parece estar disponível apenas se você estiver disposto a recompilar o kernel do Linux.

Método potencial # 2 - Usando dd

Nesse mesmo segmento, outro usuário menciona uma metodologia completamente diferente que utiliza dd.

A seguir, trecho desse email

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

Aqui estão os exemplos desse patch:
  • Aconselhar a descartar o cache do arquivo inteiro

     $ dd if=ifile iflag=nocache count=0
    
  • Garanta que o cache seja descartado para o arquivo inteiro

     $ dd of=ofile oflag=nocache conv=notrunc,fdatasync count=0
    
  • Soltar cache para 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

Eu não estava 100% positivo em como testar isso, mas criei a seguinte abordagem.

  1. faça um arquivo de 100MB

    $ dd if=/dev/urandom of=sample.txt bs=100M count=1
    
  2. arquivo de rastreio acessa usando fatrace

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

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

    $ cat sample.txt > /dev/null
    
  5. solte 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 # 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 2:
$ top
...
KiB Mem:   7968336 total,  6900956 used,  1067380 free,   267080 buffers
...
No terminal # 3:
$ sudo fatrace | grep sample.txt
Agora abra o arquivo sample.txt,, e observe a quantidade de RAM. No terminal # 1.
$ cat sample.txt > /dev/null
No terminal 2:
KiB Mem:   7968336 total,  7011896 used,   956440 free,   267336 buffers
Observe a saída do fatraceterminal # 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 # 4:
$ sudo dd of=/home/saml/tst/162600/sample.txt \
    oflag=nocache conv=notrunc,fdatasync count=0
Observe a saída do fatraceterminal # 2:
dd(26229): O /home/saml/tst/162600/sample.txt
dd(26229): CW /home/saml/tst/162600/sample.txt
Observe a RAM no terminal # 3:
KiB Mem:   7968336 total,  6908364 used,  1059972 free,   267364 buffers

Portanto, parece que tudo o que foi consumido pelo arquivo na RAM é liberado.

Método potencial # 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 utiliza a 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

Notei uma queda idêntica na RAM sendo consumida como antes quando eu usei dd.

slm
fonte
ddfunciona para mim. Acabei com chris-lamb.co.uk/projects/python-fadvise-me, que é a mesma coisa em um comando mais óbvio.
Frostschutz 18/10/2014
@frostschutz - muito legal. Eu não tinha ouvido falar disso até Gilles perguntar se alguém sabia como fazer isso no chat. python-fadviseé muito mais fácil, adicionei um exemplo mostrando dd.
slm
O link para o script python deve ser movido para o corpo principal da pergunta. Os comentários podem desaparecer sem rastreio. Uma edição, na pior das hipóteses, ainda permanece na história. Dito isto, uma pesquisa no Google encontra com facilidade, portanto não é grande coisa.
Faheem Mitha
Parece até funcionar sem sudo, então qualquer pessoa que possa ver um arquivo (mesmo sem permissão de gravação) pode ter seu cache descartado, isso é ... interessante.
Frostschutz 18/10/2014
1
Agora existe os.posix_fadvise()na biblioteca padrão do Python.
Kawing-chiu 31/08/19
3

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_DIRECTpara todos os arquivos. No entanto, simplesmente adicionando mais lógica strncmp, __do_wrap_openvocê pode aplicar seletivamente O_DIRECT.

Disclaimer: Eu não testei isso.

Mark Wagner
fonte
2

Você pode abrir arquivos individuais com o O_DIRECTsinalizador (consulte man 2 open) - leia a seção NOTAS dessa página de manual com cuidado e considere se também deseja / precisa O_SYNC.

geekosaur
fonte
1
Bem, meu processo é cate eu prefiro não reescrevê-lo. :) Eu esperava uma ferramenta de linha de comando ou um /proc/sysbotão.
Jay Hacker
2
Pior que isso, suspeito que você realmente queira dizer que está usando o redirecionamento, portanto seu processo é o shell. Não conheço uma maneira por arquivo de controlar isso além da openbandeira; você realmente precisaria escrever um programa para fazê-lo. ( cat -uÚnica desativa stdioo buffer, não OS buffering.)
geekosaur
-2

Se você deseja forçar um arquivo a sempre usar O_SYNC, é possível marcá-lo 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 dos arquivos.

O_SYNC força os dados + metadados a serem gravados nos buffers de disco, mas ainda passa 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 que está sendo anexado, a diferença pode ser pequena. Mas se o arquivo grande foi reescrito em locais aleatórios, o O_DIRECT será um grande sucesso no desempenho, mesmo levando em conta que tê-lo em cache pode expulsar do cache alguns dos pequenos arquivos de leitura.

Se você tiver o carneiro para manter todos os arquivos pequenos, poderá abordar o problema de outra maneira. Certifique-se de que os arquivos pequenos estejam sempre em ram, então sugiro copiá-los para tmpfs :

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

Jorge Nerín
fonte
chattr +Snão é a mesma coisa que O_DIRECT, é a mesma coisa que O_SYNC. O_DIRECTfaz com que as leituras não sejam armazenadas em cache (que é essa a questão) e as gravações não devem ser armazenadas em buffer, sem garantia. O_SYNCfaz com que apenas as gravações não sejam armazenadas em buffer.
Gilles 'SO- stop be evil'
@ Gilles, você está certo, eu li a pergunta e pensei em liberar dados para o disco, como havia feito antes. E há outra diferença sutil, mas importante neste caso, entre O_DIRECT e O_SYNC, O_DIRECT ignora o cache da página, mas O_SYNC não, força os dados (e metadados) a serem liberados para o disco, mas passa pelo cache da página e é mantido lá para acelerar as leituras. Devo alterar O_DIRECT para O_SYNC na minha resposta para não deixar que ela fique com uma afirmação errada?
Jorge Nerín
Esta pergunta é sobre como manter um arquivo grande que foi gravado fora do cache. Acho que abri-lo com O_DIRECT seria prejudicial ao desempenho e, se o arquivo grande estiver sendo anexado, a diferença poderá ser pequena. Mas se o arquivo grande tiver sido reescrito em locais aleatórios, o O_DIRECT será um grande sucesso no desempenho, mesmo levando em consideração que ele pode expulsar do cache alguns dos pequenos arquivos de leitura.
Jorge Nerín
Mudar O_DIRECTpara O_SYNCtornaria sua resposta consistente internamente, mas ainda errada ao considerar a pergunta.
Gilles 'SO- stop be evil'