如何限制复制所使用的缓存,以便仍有内存可用于其他缓存?

26

基本情况:

我在openSUSE上复制一些NTFS磁盘。每个磁盘大小为2TB。当我这样做时,系统运行缓慢。

我的猜测:

我认为这很可能是由于缓存。Linux决定丢弃有用的缓存(例如KDE 4膨胀、虚拟机磁盘、LibreOffice二进制文件、Thunderbird二进制文件等),并填充所有可用内存(总共24GB)以来自复制磁盘的内容,这些内容只会被读取一次,然后被写入并且永远不会再次使用。因此,每当我使用这些应用程序(或KDE 4)时,需要重新读取磁盘,重新从磁盘中读取膨胀的内容会导致系统卡顿。

由于缓存已经消失,而这些膨胀的应用程序需要大量的缓存,所以这使得系统非常缓慢。

由于它是USB接口,因此磁盘和磁盘控制器不是瓶颈,因此使用ionice并不能使它更快。
我认为这是缓存问题,而不仅仅是主板速度过慢,因为如果我停止所有复制,它仍然会在一段时间内运行得很卡,直到重新缓存所有内容。
如果我重新开始复制,需要大约一分钟才会再次卡顿。但也可以将其限制在约40 MB/s左右,然后它会再次运行得更快(不是因为有正确的缓存内容,而是因为主板总线对系统磁盘具有很多额外的带宽)。我完全可以接受来自我的主板I/O能力完全被消耗的性能损失(即已使用100%,这意味着没有浪费的电力,这让我感到高兴),但我无法接受这种缓存机制在这种特定用例中表现如此糟糕。
# free
             total       used       free     shared    buffers     cached
Mem:      24731556   24531876     199680          0    8834056   12998916
-/+ buffers/cache:    2698904   22032652
Swap:      4194300      24764    4169536

我也在Ubuntu上尝试了同样的操作,结果导致整个系统挂起。 ;)
为了澄清,我不是在问如何为“系统”留出可用内存,而是为“缓存”留出。我知道缓存内存会在需要时自动归还给系统,但我的问题是它没有被保留用于特定内容的缓存。
有没有办法告诉这些复制操作限制内存使用,以便一些重要内容仍然可以被缓存,因此任何减速都是由于正常磁盘使用而不是重新读取相同经常使用的文件造成的?例如,是否有一个最大内存使用量的设置,每个进程/用户/文件系统允许用作高速缓存/缓冲区?

顺便提一下,我正在使用rsync,并且有许多硬盘(目前一次性使用8个)。其中一些在本地传输,一些使用USB 3.0传输。还有一些通过1Gbps网络传输。 - Peter

free

总量 已用 空闲 共享 缓存区 缓存 内存: 24731556 24474096 257460 0 16478072 6342668 -/+ 缓存区: 1653356 23078200 交换空间: 4194300 22564 4171736缓存区似乎存在内存泄漏问题。
- Peter
8个回答

28

Nocache 命令是解决这个问题的通用答案!它也在 Debian 和 Ubuntu 13.10 (Saucy Salamander) 中提供。

感谢 Peter 指出 rsync 的 --drop-cache" 选项。但是,该选项已被上游拒绝 (Bug 9560 – drop-cache option),取而代之的是针对此问题的更通用的解决方案:基于 rsync 工作和 fadvise 的新 "nocache" 命令。

您只需在任何要执行的命令前加上 "nocache" 即可。它还具有描述和修改文件缓存状态的好用工具。例如,以下是 nocache 与不使用 nocache 的效果:

$ ./cachestats ~/file.mp3
pages in cache: 154/1945 (7.9%)  [filesize=7776.2K, pagesize=4K]
$ ./nocache cp ~/file.mp3 /tmp
$ ./cachestats ~/file.mp3
pages in cache: 154/1945 (7.9%)  [filesize=7776.2K, pagesize=4K]\
$ cp ~/file.mp3 /tmp
$ ./cachestats ~/file.mp3
pages in cache: 1945/1945 (100.0%)  [filesize=7776.2K, pagesize=4K]

希望这对其他备份程序(如rsnapshot、duplicity、rdiff-backup、amanda、s3sync、s3ql、tar等)和其他不想破坏缓存的命令也有用。


@Peter 我认为nealmcb提供的使用'nocache'选项的答案更合适,因为并非所有的rsync都有drop-cache选项,而nocache被广泛使用。 - Krzysztof Krasoń
从我的角度来看,我测试过的每个Linux发行版(除了Manjaro,也不包括FreeBSD)都已经应用了rsync的补丁...当我使用openSUSE时,它没有nocache,而在arch/manjaro的主要仓库中也没有。我更喜欢nocache的想法(就像我喜欢nice、ionice、trickle等一样),但除非我在更多的主要仓库中看到它,否则哪种解决方案对于每个人来说最好还是有点主观性的。 - Peter
@Peter Debian没有它。 - Krzysztof Krasoń
@krzyk nocache不在哪个Debian版本中?看起来它在wheezy-backports、jessie、stretch和sid中都有:https://packages.debian.org/sid/utils/nocache - nealmcb
我正在回复@Peter关于rsync中的--drop-cache。 - Krzysztof Krasoń
nocache 命令存在一些(对我来说)意外的性能问题。请注意如何应用它以及应用于哪些命令。我犯了一个错误,将其应用于一个 shell 脚本中,结果事情并不顺利。尝试运行 time /bin/truetime nocache /bin/true -- 使用 nocache 会为我尝试的每个命令增加一秒钟的 CPU 开销。(Ubuntu 20.04.4 LTS 上的 Intel(R) Xeon(R) CPU E5-1620 v4 @ 3.50GHz) - Ian D. Allen

3

Kristof Provost非常接近答案,但在我的情况下,我不想使用dd或编写自己的软件,所以解决方案是使用rsync中的“--drop-cache”选项。

自从创建这个问题以来,我已经多次使用它,并且似乎完全解决了问题。唯一的例外是当我使用rsync从FreeBSD机器复制时,它不支持“--drop-cache”。因此,我编写了一个包装器来替换/usr/local/bin/rsync命令,并删除该选项,现在从那里复制也可以正常工作。

它仍然会使用大量内存缓冲区,并且似乎几乎没有缓存,但无论如何它都可以平稳地工作。

$ free
             total       used       free     shared    buffers     cached
Mem:      24731544   24531576     199968          0   15349680     850624
-/+ buffers/cache:    8331272   16400272
Swap:      4194300     602648    3591652

5
官方版rsync不支持drop-cache。 - Krzysztof Krasoń

3

你实际上有两个选择:

  1. Limit the maximum disk buffer size: the problem you're seeing is probably caused by default kernel configuration that allows using huge piece of RAM for disk buffering and, when you try to write lots of stuff to a really slow device, you'll end up lots of your precious RAM for disk caching to that slow the device.

    The kernel does this because it assumes that the processes can continue to do stuff when they are not slowed down by the slow device and that RAM can be automatically freed if needed by simply writing the pages on storage (the slow USB stick - but the kernel doesn't consider the actual performance of that process). The quick fix:

     # Wake up background writing process if there's more than 50 MB of dirty memory
     echo 50000000 > /proc/sys/vm/dirty_background_bytes
     # Limit background dirty bytes to 200 MB (source: http://serverfault.com/questions/126413/limit-linux-background-flush-dirty-pages)
     echo 200000000 > /proc/sys/vm/dirty_bytes
    

    Adjust the numbers to match the RAM you're willing to spend on disk write cache. A sensible value depends on your actual write performance, not the amount of RAM you have. You should target on having barely enough RAM for caching to allow full write performance for your devices. Note that this is a global setting, so you have to set this according to the slowest devices you're using.

  2. Reserve a minimum memory size for each task you want to keep going fast. In practice this means creating cgroups for stuff you care about and defining the minimum memory you want to have for any such group. That way, the kernel can use the remaining memory as it sees fit. For details, see this presentation: SREcon19 Asia/Pacific - Linux Memory Management at Scale: Under the Hood

更新于 2022 年:

您还可以尝试创建新文件 /etc/udev/rules.d/90-set-default-bdi-max_ratio-and-min_ratio.rules,并将以下内容添加进去:

# For every BDI device, set max cache usage to 30% and min reserved cache to 2% of the whole cache
# https://unix.stackexchange.com/a/481356/20336
ACTION=="add|change", SUBSYSTEM=="bdi", ATTR{max_ratio}="30", ATTR{min_ratio}="2"

这个想法是对每个设备设置缓存最大利用限制。通过以上的限制(30%),即使有两个完全停滞的设备,其余系统仍可使用40%的磁盘缓存。如果有4个或更多的设备同时停滞,即使有这个解决方法也无法独立解决。这就是为什么我还增加了每个设备的最小缓存空间2%,但我不知道如何检查是否有效。我运行了大约半年的这个配置,我认为它运行得很好。

详情请参见https://unix.stackexchange.com/a/481356/20336


2

内核无法知道您是否会再次使用缓存的数据。这是您的信息优势。

但是,您可以将swapiness设置为0:sudo sysctl vm.swappiness=0。这将导致Linux在库等写入交换空间之前放弃缓存。

这对我也很有效,特别是在拥有大量RAM(16-32 GB)的情况下表现非常出色。


1

如果您使用的是普通的cp,那么这是不可能的。但是,如果您愿意重新实现或自己打补丁,可以在输入和输出文件上设置posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE),这样做可能会有所帮助。

posix_fadvise()告诉内核您的访问模式。在这种情况下,您只使用数据一次,因此没有缓存它的必要。Linux内核遵循这些标志,因此不应再缓存数据。


顺便提一下:在Linux中,POSIX_FADV_NOREUSE仍未实现。 - catpnosis

1
尝试使用 dd 而不是 cp
或者使用 sync 标志挂载文件系统。
我不完全确定这些方法是否绕过了交换空间,但试试可能值得一试。

根据我的经验,使用rsync总是一个好主意(不要使用破坏一切的-u选项)。否则,在传输中断时,我会得到未检测到的部分文件。 - Peter
第一次尝试在远程副本上运行时失败了,因为服务器不支持该选项。(两者都有rsync版本3.0.9协议版本30;Linux支持它,但FreeBSD 8.2不支持)而且在本地传输中,它似乎会限制速度。 - Peter
@Peter 嗯,我通常会尽量避免使用dd,我忘记了rsync...有这么多实用工具:D - KurzedMetal
2
在第二个注释之前插入此注释...不知何故被删除了:感谢您的建议。这让我阅读了rsync手册,在其中我找到了“--drop-cache”选项,它似乎对本地传输非常有效。 - Peter
看看其他答案,你甚至可以加快同步速度。 - KurzedMetal

1
我正在复制一些NTFS磁盘,但系统运行缓慢。由于是USB接口,这是一个已知的内存管理问题。
使用更新的Linux内核。旧版本存在USB数据和“透明巨大页面”问题。请参阅LWN文章。最近这个问题得到了解决-请参阅LinuxChanges中的“内存管理”。

我正在使用带有3.1.0-1.2-desktop内核的openSuSE。我不知道这是否适用;这个特定问题的症状是什么? - Peter
1
有趣 - 但我对此的状态感到困惑。在我的看法中,Mel Gorman在LWN上讨论的补丁似乎不在当前内核(3.13-rc5)中,并且我无法确定您引用的LinuxChanges页面上是否已解决该问题。解决方案是什么,它出现在哪个内核中?谢谢。 - nealmcb
1
@nealmcb 这个问题在Linux 3.3中已经得到解决。LinuxChanges中的一行是“压缩与透明大页面结合使用可能会导致USB存储设备或浏览器出现显著的停顿。建议参考LWN文章”。[与此答案中链接的同一篇LWN文章]。 - sourcejedi
1
@nealmcb 或者你可以在这里找到它的最初来源:https://lore.kernel.org/lkml/1323877293-15401-1-git-send-email-mgorman@suse.de/。与补丁1-10标题相同的提交已合并至v3.3-rc1。你可以在GitHub界面上一起查看它们,链接在这里:https://github.com/torvalds/linux/commits/0cee34fd72c582b4f8ad8ce00645b75fb4168199。信封中提到补丁11是“一个原型”,讨论中似乎表明它没有成功。我没有试图深入了解那部分的细节。但总的来说,这似乎是相当有力的证据。 - sourcejedi
参见:https://unix.stackexchange.com/q/714267/20336 - Mikko Rantalainen

0

好的信息,但我没有遇到任何内存不足的问题。我有22032652字节可用。这可能是因为我的大多数文件都很大。当rsync启动时,它会显示“18658个文件要考虑”。我还在处理数亿个文件时使用过它,它也可以正常工作。但由于您的dd建议以及找到了--drop-cache选项,它似乎已经完全解决了(只要我不在服务器不支持--drop-cache时进行太多远程传输)。 - Peter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接