从Linux文件系统缓存中删除特定文件?


23

我知道我可以从Linux文件系统缓存中删除所有内容,但是有没有办法仅删除一个特定文件?还是阻止文件被缓存?还是告诉进程不要缓存它写入的任何文件?

我有一个读取很多小文件并写入一个大文件的过程。我想将小的文件保留在缓存中以避免磁盘寻道,而且我也不在乎缓存大文件。


1
关于赏金,我对标题问题特别感兴趣:从缓存中删除特定文件(而不是首先阻止它到达那里)。
吉尔(Gilles)'“ SO-不要邪恶”

Answers:


21

潜在方法1-F_DROP_CACHES

我从2012年开始发现了一种方法,该方法在此邮件线程中讨论了对Linux内核的提议补丁,标题为:Re:[RFC Patch] fs:实现每个文件丢弃缓存

摘抄

Cong>这是实现按文件删除缓存的草稿补丁。

有趣。那么我可以从流程外部执行此操作吗?我是SysAdmin,所以我的观点是从在系统处于压力下时注意到,发现和修复性能问题开始的。

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.

如何判断一个文件使用了多少缓存?在繁忙的系统上运行时,这会对性能产生什么影响?这个补丁对我们有什么好处,因为我认为一旦系统受到内存压力,虚拟机就应该已经丢弃了缓存...

Cong>以下是此补丁的小型测试用例:

螺纹包括测试用例和实际的补丁几个文件在Linux内核中,其增加了额外的功能,fs/drop_caches.c叫做drop_pagecache_file(struct file *filp)。然后可以通过前端工具,fnctl.c通过命令访问此功能F_DROP_CACHES。这种情况调用此函数:

file_drop_caches(filp, arg);

它处理与给定文件关联的所有缓存的删除。从文件include/linux/mm.h

void file_drop_caches(struct file *filp, unsigned long which);
那么可以使用吗?

我没有发现任何证据表明该修补程序已经进入了主要的Linux内核代码存储库,因此仅当您愿意自己重新编译Linux内核时,此选项才可用。

潜在方法2-使用dd

在同一线程中,另一个用户提到了一个完全不同的方法,该方法使用dd

以下是该电子邮件的摘录

这是有用的功能。虽然还没有提供 POSIX_FADV_DONTNEED一年前,此功能已添加到GNU dd(8.11)中

以下是该补丁中的示例:
  • 建议删除整个文件的缓存

     $ dd if=ifile iflag=nocache count=0
    
  • 确保整个文件的删除缓存

     $ dd of=ofile oflag=nocache conv=notrunc,fdatasync count=0
    
  • 删除部分文件的缓存

     $ dd if=ifile iflag=nocache skip=10 count=10 of=/dev/null
    
  • 仅使用预读缓存流数据

     $ dd if=ifile of=ofile iflag=nocache oflag=nocache
    
测试出来

我不是100%肯定如何进行测试的,但是我想出了以下方法。

  1. 制作一个100MB的文件

    $ dd if=/dev/urandom of=sample.txt bs=100M count=1
    
  2. 使用跟踪文件访问 fatrace

    $ sudo fatrace | grep sample.txt
    
  3. 运行,top以便我们可以监视内存使用情况,注意可用数量。

    $ top
    
  4. 打开文件,现在记下可用内存量。注意fatrace文件的sample.txt

    $ cat sample.txt > /dev/null
    
  5. 从内存中删除文件,现在记下可用内存量。注意的输出fatrace

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

在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
在2号航站楼:
$ top
...
KiB Mem:   7968336 total,  6900956 used,  1067380 free,   267080 buffers
...
在3号航站楼:
$ sudo fatrace | grep sample.txt
现在打开文件,sample.txt并记下RAM的数量。在1号航站楼。
$ cat sample.txt > /dev/null
在2号航站楼:
KiB Mem:   7968336 total,  7011896 used,   956440 free,   267336 buffers
注意fatrace端子#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
现在从终端4中的RAM中删除文件:
$ sudo dd of=/home/saml/tst/162600/sample.txt \
    oflag=nocache conv=notrunc,fdatasync count=0
注意fatrace端子2 的输出:
dd(26229): O /home/saml/tst/162600/sample.txt
dd(26229): CW /home/saml/tst/162600/sample.txt
请注意端子3中的RAM:
KiB Mem:   7968336 total,  6908364 used,  1059972 free,   267364 buffers

因此,似乎RAM中文件消耗的所有内存都已释放。

潜在方法#3-python-fadvise

感谢@frostchutz的评论,还有另一个工具,Python脚本,名为Python脚本,[pyadvise][4]它提供了比上述dd方法简单得多的界面。该脚本使用相同的posix_fadvise(2)界面。

$ 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

如果我们重复上述测试并pyadvise代替dd

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

我注意到使用时与以前一样消耗了相同的RAM dd


dd为我工作。我最终以chris-lamb.co.uk/projects/python-fadvise自己结束了,这在更明显的命令中也是一样。
弗罗斯特斯2014年

@frostschutz-非常酷。直到Gilles问是否有人在聊天中知道如何做到这一点,我才听说过。python-fadvise容易得多,我添加了一个显示示例dd
slm

python脚本的链接应移至问题的主体中。评论可以消失得无影无踪。最糟糕的是,编辑仍将保留在历史记录中。话虽如此,谷歌搜索很容易找到它,所以没什么大不了的。
Faheem Mitha 2014年

它甚至似乎在没有sudo的情况下也可以工作,因此任何可以查看文件(即使没有写许可)的人都可以删除其缓存,这很有趣。
弗罗斯特斯2014年

1
现在os.posix_fadvise()在Python的标准库中有。
kawing-chiu


2

您可以使用O_DIRECT标志打开单个文件(请参阅参考资料man 2 open)- 仔细阅读该联机帮助页的“ 注意”部分,并考虑是否也需要/需要O_SYNC


1
好吧,我的过程是cat,我不想重写它。:)我希望使用命令行工具或/proc/sys旋钮。
杰·哈克

2
更糟糕的是,我怀疑您确实是在使用重定向,所以您的过程就是外壳程序。除了open标志之外,我不知道一种按文件方式控制它的方法。您确实需要编写程序来执行此操作。(cat -u仅禁用stdio缓冲,
不禁用

-2

如果要强制文件始终使用O_SYNC,则可以在扩展属性中将其标记为chattr +S $file

男人聊天:

修改具有“ S”属性集的文件时,所做的更改将被同步写入磁盘。这等效于应用于文件子集的“ sync”安装选项。

O_SYNC强制将数据+元数据写入磁盘缓冲区,但仍会通过页面缓存。O_DIRECT绕过页面缓存。

但是请注意,使用O_DIRECT打开它会损害性能,如果只是附加大文件,差异可能会很小。但是,如果将大文件在任意位置重写,O_DIRECT会对性能产生重大影响,即使考虑到将其存储在高速缓存中也可能会从高速缓存中读取一些小的读取文件。

如果您拥有将所有小文件保存在其中的内存,则可以采用其他方法解决该问题。确保小文件始终位于ram中,然后建议将它们复制到tmpfs

tmpfs将所有内容放入内核内部高速缓存中,并进行扩展和收缩以容纳其中包含的文件


chattr +S与是不同的东西O_DIRECT,与是相同的东西O_SYNCO_DIRECT导致读取不被缓存(这是关于这个问题的意思),并且写入不被缓存(不保证)。O_SYNC仅导致不缓冲写操作
吉尔(Gilles)'所以

@Gilles,您是对的,我读了这个问题,并想到了像以前一样将数据刷新到磁盘的想法。在这种情况下,还有另一个微妙但重要的一点,即O_DIRECT和O_SYNC之间的区别,O_DIRECT绕过页面缓存,但是O_SYNC则不,它强制将数据(和元数据)刷新到磁盘,但它通过页面缓存和保留在那里以加快读取速度。我是否应该在答案中将O_DIRECT更改为O_SYNC,以免错误地保留它?
JorgeNerín2014年

该问题询问有关保留已从高速缓存中写入大文件的问题。我认为使用O_DIRECT打开它会损害性能,如果只是添加大文件,差异可能会很小。但是,如果考虑到将大文件在任意位置重写的话,O_DIRECT会对性能产生重大影响,即使考虑到它可能会从高速缓存中读取一些小的读取文件也是如此。
JorgeNerín2014年

更改O_DIRECTO_SYNC会使您的答案内部一致,但考虑到该问题仍然是错误的。
吉尔(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.