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

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

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

我有一个进程读取很多小文件并写入一个大文件。我想将小文件保留在缓存中以避免磁盘查找,并且我不关心缓存大文件。

答案1

潜在方法#1 - F_DROP_CACHES

我发现了 2012 年的一个方法,该方法在此邮件主题中讨论了 Linux 内核的拟议补丁:回复:[RFC 补丁] fs:实现每个文件删除缓存

摘抄

Cong> 这是实现每个文件删除缓存的补丁草案。

有趣的。那么我可以从流程外部执行此操作吗?我是一名系统管理员,所以我的视角是在系统面临压力时注意到、发现并修复性能问题。

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 脚本的工具,[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

我注意到,当我使用dd.

答案2

O_DIRECT扩展@geekosaur的答案,您可以通过使用 LD_PRELOAD 和此处的程序来强制使用:http://aighi.blogspot.com/2007/04/how-to-bypass-buffer-cache-in-linux.html

该代码适用O_DIRECT于所有文件。然而,只需添加一些更多的 strncmp 逻辑,__do_wrap_open您就可以有选择地应用 O_DIRECT。

免责声明:我没有对此进行测试。

答案3

您可以使用该标志打开单个文件O_DIRECT(请参阅man 2 open) — 阅读笔记仔细阅读该联机帮助页的部分,并考虑您是否也想要/需要O_SYNC.

答案4

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

男人聊天:

当修改设置为“S”属性的文件时,更改会同步写入磁盘;这相当于应用于文件子集的“同步”安装选项。

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

但请注意,使用 O_DIRECT 打开它会对性能产生不利影响,如果只是附加大文件,则差异可能很小。但是,如果大文件在随机位置被重写,O_DIRECT 将对性能造成很大影响,即使考虑到它在缓存中也可能会从缓存中逐出一些小读取文件。

如果你有内存来保存所有小文件,你可以用另一种方式解决这个问题。确保小文件始终在内存中,然后我建议将它们复制到临时文件系统:

tmpfs 将所有内容放入内核内部缓存并增长和收缩以容纳其包含的文件

相关内容