我读自这里我可以使用以下命令将文件加载到 RAM 中以便更快地访问。
cat filename > /dev/null
不过,我想测试一下上面的说法是否属实。所以,我做了以下测试。
创建一个 2.5 GB 的测试文件,如下所示。
dd if=/dev/zero of=demo.txt bs=100M count=10
现在,计算文件访问时间如下。
mytime="$(time ( cat demo.txt ) 2>&1 1>/dev/null )" echo $mytime real 0m19.191s user 0m0.007s sys 0m1.295s
根据命令的建议,现在我需要将文件添加到缓存内存中。所以我做了,
cat demo.txt > /dev/null
现在,我假设该文件已加载到缓存中。所以我计算了再次加载文件的时间。这就是我得到的价值。
mytime="$(time ( cat demo.txt ) 2>&1 1>/dev/null )" echo $mytime real 0m18.701s user 0m0.010s sys 0m1.275s
我重复步骤 4 5 次迭代来计算时间,这些是我得到的值。
real 0m18.574s user 0m0.007s sys 0m1.279s real 0m18.584s user 0m0.012s sys 0m1.267s real 0m19.017s user 0m0.009s sys 0m1.268s real 0m18.533s user 0m0.012s sys 0m1.263s real 0m18.757s user 0m0.005s sys 0m1.274s
所以我的问题是,为什么即使文件加载到缓存中时间也会变化?我预计,由于文件已加载到缓存中,因此每次迭代的时间都会减少,但情况似乎并非如此。
答案1
不不不!
事情不是这样的。 Linux(内核)可以选择将一些文件放入缓存中,并在需要时删除它们。您确实无法确定缓存中是否有任何内容。这个命令不会改变这一点(很多)。
您提供的链接中的建议在很多方面都是错误的!
- 缓存是操作系统的事情。您不需要
cat
该文件即可/dev/null
利用此功能。这实际上是一件非常愚蠢的事情,因为你强迫 Linux 额外读取一次文件。例如,如果您计划读取一个文件 4 次。如果你不关心它,第一次读取会很慢,随后的 3 个读取应该会更快(因为缓存)。如果你使用这个“技巧”,第一次阅读会很慢,所有的4后续的应该更快(但不为空)。让 Linux 来处理吧。 - 仅当您想确保 Linux 将其保留在 RAM 中时,此命令才有用。所以你必须在系统空闲时经常执行它。然而,正如我所说,这也是愚蠢的,因为你永远无法确定 Linux 是否真的将文件缓存在 RAM 中,即使它缓存了,你也会花时间在 RAM 或磁盘上读取它(如果它没有缓存或已经缓存)从缓存中删除)。
- 通过在一个大文件上重复执行此操作,您基本上会欺骗 Linux 认为该文件应该位于 RAM 中,而牺牲您所创建的其他文件。实际上更频繁地使用。
所以这里的结论是:不要做这种伎俩,这通常会适得其反。
然而,如果您知道某些小文件(与您的 RAM 大小相比)确实会从 RAM 访问中受益,您可以使用tmpfs
山并将您的文件存储在那里。在现代发行版中,/tmp
文件夹通常是tmpfs
一个。
我个人认为有价值的另一种选择是使用 BTRFS 在 FS 级别压缩文件,例如或手动压缩文件(但这要求访问文件的程序具有解压缩它的能力)。当然,您的文件应该受益于压缩,否则这是没有用的。这样,您可以更加确信 Linux 将压缩文件保存在 RAM 中(因为它更小),并且如果您的应用程序受 IO 限制,则从磁盘加载 100MB 而不是加载 10GB 应该快得多。
答案2
我重复了你的测试并执行了如下命令:
dd if=/dev/zero of=/mnt/disk8/Marc/2GB.bin bs=100M count=20
现在,看看文件生成的速度有多快,尽管目标是 HDD:
20+0 records in
20+0 records out
2097152000 bytes (2.1 GB, 2.0 GiB) copied, 0.6319 s, 3.3 GB/s
发生了什么:
- 该文件没有写入磁盘,而是写入 RAM。原因:
vm.dirty_ratio
默认值为 20,这意味着它使用 20% 的空闲 RAM 作为写入缓存 - 一段时间后,我能够通过服务器的仪表板看到 HDD 的写入传输速率。原因:
vm.dirty_expire_centisecs
设置为 1500(我的 Unraid 服务器的默认值,Linux 的默认值是 3000),这意味着对 HDD 的写入发生了时移。
现在让我们测量读取文件所需的时间:
mytime="$(time ( cat /mnt/disk8/Marc/2GB.bin ) 2>&1 1>/dev/null )"
echo $mytime
real 0m0.193s user 0m0.012s sys 0m0.181s
发生了什么:
- 该文件仍在 Linux 页面缓存中
现在我们清除缓存:
sync; echo 1 > /proc/sys/vm/drop_caches
下一个基准测试很慢:
real 0m8.330s user 0m0.017s sys 0m0.753s
我们再次清除缓存(当我们的基准测试填充它时),再次打开文件,同时将内容移动到垃圾箱中(您被描述为“技巧”):
cat /mnt/disk8/Marc/2GB.bin > /dev/null
下一个基准测试速度很快并且按预期工作:
real 0m0.233s user 0m0.008s sys 0m0.225s
原因,为什么它对你不起作用:
- 测试时,您(几乎)没有可用 RAM,因此无法缓存大部分文件
- 其他读取操作覆盖了您的缓存文件
结论:你需要足够的内存,而且这个“技巧”并不持久。手动缓存文件总体有用吗?这取决于。假设您正在使用 Plex、Emby 或 Jellyfin 等媒体服务器软件。他们都需要为客户提供电影封面。将它们放在 RAM 中会导致更快的加载时间,因此最好缓存它们。 Linux 自动执行此操作并将它们保存在活动列表如果它们经常被加载。但是,现在使用这个技巧可能是个好主意,如果您请求的文件等于甚至大于可用 RAM,则缓存将被完全覆盖。 Linux 不会跳过大文件。现在,您的缓存文件不再被缓存,直到客户端再次加载电影封面并且具有活动和非活动列表的游戏重新开始。这就是为什么这可能是个好主意的原因使用 O_DIRECT 请求大文件或者不使用这个技巧,而是使用虚拟触摸将它们锁定在缓存中。