我可以配置我的 Linux 系统以获得更积极的文件系统缓存吗?

Iva*_*van 146 linux performance filesystems fstab sysctl

我既不担心 RAM 使用情况(因为我已经足够了),也不担心在意外关闭的情况下丢失数据(因为我的电源有保障,系统是可靠的,数据并不重要)。但是我做了很多文件处理并且可以使用一些性能提升。

这就是为什么我想将系统设置为使用更多 RAM 进行文件系统读写缓存,积极预取文件(例如,预读应用程序访问的整个文件,以防文件大小合理或至少否则,请提前读取其中的一大块)并减少刷新写入缓冲区的频率。如何实现这一目标(可能)?

我在 XUbuntu 11.10 x86 上使用 ext3 和 ntfs(我经常使用 ntfs!)文件系统。

Mik*_*nen 132

一般来说,提高磁盘缓存性能不仅仅是增加文件系统缓存大小,除非您的整个系统适合 RAM,在这种情况下您应该使用 RAM 驱动器(tmpfs这很好,因为如果您在某些情况下需要 RAM,它允许回退到磁盘)用于运行时存储(可能还有一个 initrd 脚本,用于在启动时将系统从存储复制到 RAM 驱动器)。

您没有说明您的存储设备是 SSD 还是 HDD。这是我发现对我有用的东西(在我的情况下sda是安装在 的 HDD/homesdb安装在 的 SSD /)。

首先优化load-stuff-from-storage-to-cache部分:

这是我的 HDD 设置(如果有切换,请确保在 BIOS 中启用了 AHCI+NCQ):

echo cfq > /sys/block/sda/queue/scheduler
echo 10000 > /sys/block/sda/queue/iosched/fifo_expire_async
echo 250 > /sys/block/sda/queue/iosched/fifo_expire_sync
echo 80 > /sys/block/sda/queue/iosched/slice_async
echo 1 > /sys/block/sda/queue/iosched/low_latency
echo 6 > /sys/block/sda/queue/iosched/quantum
echo 5 > /sys/block/sda/queue/iosched/slice_async_rq
echo 3 > /sys/block/sda/queue/iosched/slice_idle
echo 100 > /sys/block/sda/queue/iosched/slice_sync
hdparm -q -M 254 /dev/sda
Run Code Online (Sandbox Code Playgroud)

值得注意的是,对于 HDD 来说,HDD 的情况是高fifo_expire_async(通常是写)和长,slice_sync以允许单个进程获得高吞吐量(slice_sync如果遇到多个进程并行等待来自磁盘的某些数据的情况,则设置为较低的数字)。这slice_idle始终是 HDD 的妥协,但根据磁盘使用情况和磁盘固件,将其设置在 3-20 范围内应该没问题。我更喜欢以低值为目标,但将其设置得太低会破坏您的吞吐量。该quantum设置似乎对吞吐量影响很大,但尽量将其保持在尽可能低的水平,以将延迟保持在合理的水平。设置quantum太低会破坏吞吐量。3-8 范围内的值似乎适用于 HDD。读取的最坏情况延迟是 ( quantum* slice_sync) + (slice_async_rq *slice_async) ms 如果我正确理解了内核行为。异步方式主要用于写入,因为你是愿意延迟写入磁盘,集两者slice_async_rqslice_async以非常低的数字。但是,设置slice_async_rq太低的值可能会导致读取延迟,因为读取后不能再延迟写入。我的配置将尝试将数据写入磁盘最多10秒后数据已经传递到内核之后,但因为你可以容忍的功率损耗数据也设置的损失fifo_expire_async3600000告诉大家,1个小时还好耽搁到磁盘。slice_async但是,请保持较低,否则您可能会获得较高的读取延迟。

hdparm需要该命令以防止 AAM 破坏 AHCI+NCQ 允许的大部分性能。如果您的磁盘噪音太大,请跳过此步骤。

这是我对 SSD(英特尔 320 系列)的设置:

echo cfq > /sys/block/sdb/queue/scheduler
echo 1 > /sys/block/sdb/queue/iosched/back_seek_penalty
echo 10000 > /sys/block/sdb/queue/iosched/fifo_expire_async
echo 20 > /sys/block/sdb/queue/iosched/fifo_expire_sync
echo 1 > /sys/block/sdb/queue/iosched/low_latency
echo 6 > /sys/block/sdb/queue/iosched/quantum
echo 2 > /sys/block/sdb/queue/iosched/slice_async
echo 10 > /sys/block/sdb/queue/iosched/slice_async_rq
echo 1 > /sys/block/sdb/queue/iosched/slice_idle
echo 20 > /sys/block/sdb/queue/iosched/slice_sync
Run Code Online (Sandbox Code Playgroud)

这里值得注意的是不同切片设置的低值。SSD 最重要的设置是slice_idle必须设置为 0-1。将其设置为零会将所有排序决策移至本机 NCQ,而将其设置为 1 允许内核对请求进行排序(但如果 NCQ 处于活动状态,硬件可能会部分覆盖内核排序)。测试这两个值以查看您是否可以看到差异。对于 Intel 320 系列,似乎设置slide_idle0可提供最佳吞吐量,但将其设置为可1提供最佳(最低)整体延迟。

有关这些可调参数的更多信息,请参阅https://www.kernel.org/doc/Documentation/block/cfq-iosched.txt

2020 年更新和内核版本 5.3(cfq 已死):

modprobe bfq
for d in /sys/block/sd?
do
        # HDD (tuned for Seagate SMR drive)
        echo bfq > "$d/queue/scheduler"
        echo 4 > "$d/queue/nr_requests"
        echo 32000 > "$d/queue/iosched/back_seek_max"
        echo 3 > "$d/queue/iosched/back_seek_penalty"
        echo 80 > "$d/queue/iosched/fifo_expire_sync"
        echo 1000 > "$d/queue/iosched/fifo_expire_async"
        echo 5300 > "$d/queue/iosched/slice_idle_us"
        echo 1 > "$d/queue/iosched/low_latency"
        echo 200 > "$d/queue/iosched/timeout_sync"
        echo 0 > "$d/queue/iosched/max_budget"
        echo 1 > "$d/queue/iosched/strict_guarantees"

        # additional tweaks for SSD (tuned for Samsung EVO 850):
        if test $(cat "$d/queue/rotational") = "0"
        then
                echo 36 > "$d/queue/nr_requests"
                echo 1 > "$d/queue/iosched/back_seek_penalty"
                # slice_idle_us should be ~ 0.7/IOPS in µs
                echo 16 > "$d/queue/iosched/slice_idle_us"
                echo 10 > "$d/queue/iosched/fifo_expire_sync"
                echo 250 > "$d/queue/iosched/fifo_expire_async"
                echo 10 > "$d/queue/iosched/timeout_sync"
                echo 0 > "$d/queue/iosched/strict_guarantees"
        fi
done
Run Code Online (Sandbox Code Playgroud)

设置非常相似,但我现在使用bfq而不是cfq因为后者不适用于现代内核。我尽量保持nr_requests尽可能低,以便bfq更准确地控制调度。至少三星 SSD 驱动器似乎需​​要相当深的队列才能以高 IOPS 运行。

我正在使用带有内核包的 Ubuntu 18.04,linux-lowlatency-hwe-18.04-edgebfq只有作为模块,所以我需要先加载它才能切换到它。

我现在也使用,zram但我只将 5% 的 RAM 用于 zram。这允许 Linux 内核在不接触磁盘的情况下使用交换相关逻辑。但是,如果您决定采用零磁盘交换,请确保您的应用程序不会泄漏 RAM 或浪费金钱。

现在我们已经配置内核以合理的性能从磁盘加载内容到缓存,是时候调整缓存行为了:

根据我所做的基准测试,我根本不会费心设置预读blockdev。内核默认设置很好。

将系统设置为更喜欢交换文件数据而不是应用程序代码(如果您有足够的 RAM 来保存整个文件系统所有应用程序代码以及应用程序在 RAM 中分配的所有虚拟内存,这并不重要)。这减少了在不同应用程序之间交换的延迟,而不是从单个应用程序访问大文件的延迟:

echo 15 > /proc/sys/vm/swappiness
Run Code Online (Sandbox Code Playgroud)

如果您希望将应用程序几乎始终保留在 RAM 中,您可以将其设置为 1。如果您将其设置为 0,内核将根本不会交换,除非绝对有必要避免 OOM。如果您的内存有限并且处理大文件(例如高清视频编辑),那么将其设置为接近 100 可能是有意义的。

如果您有足够的 RAM,我现在(2017 年)更喜欢根本没有交换。在长时间运行的台式机上,没有交换通常会丢失 200-1000 MB 的 RAM。我愿意牺牲那么多以避免最坏情况下的延迟(当 RAM 已满时交换应用程序代码)。实际上,这意味着我更喜欢 OOM Killer 而不是交换。如果您允许/需要交换,您可能还想增加/proc/sys/vm/watermark_scale_factor以避免一些延迟。我建议 100 到 500 之间的值。您可以将此设置视为交易 CPU 使用率以降低交换延迟。默认值为 10,最大可能值为 1000。较高的值(根据内核文档)应该会导致kswapd进程的CPU 使用率更高并降低整体交换延迟。

接下来,告诉内核更喜欢将目录层次结构保留在内存中而不是文件内容中,以防需要释放一些 RAM(同样,如果所有内容都适合 RAM,则此设置不执行任何操作):

echo 10 > /proc/sys/vm/vfs_cache_pressure
Run Code Online (Sandbox Code Playgroud)

环境 vfs_cache_pressure设置为低值是有道理的,因为在大多数情况下,内核需要知道目录结构才能使用缓存中的文件内容,而过早刷新目录缓存会使文件缓存几乎毫无价值。如果您有很多小文件(我的系统有大约 150K 10 兆像素的照片并且算作“很多小文件”系统),请考虑使用此设置一直降到 1。切勿将其设置为零或目录结构始终保留在内存中,即使系统内存不足。仅当您只有几个不断被重新读取的大文件时,才将此设置为大值是明智的(同样,没有足够 RAM 的高清视频编辑将是一个示例案例)。官方内核文档说“

2021 年更新:在使用内核版本 5.4 运行足够长的时间后,我得出的结论是,当内存压力足够高时,非常低的vfs_cache_pressure设置(我曾经运行1多年)现在可能会导致长时间停顿/不良延迟。但是,我从未注意到内核版本 5.3 或更低版本的这种行为。

例外:如果你真的有大量的文件和目录并且你很少接触/读取/列出所有文件设置vfs_cache_pressure高于 100 可能是明智的。这仅适用于您没有足够的 RAM 并且无法在 RAM 中保留整个目录结构并且仍然有足够的 RAM 用于正常文件缓存和进程(例如,具有大量存档内容的公司范围的文件服务器)的情况。如果您觉得需要增加到vfs_cache_pressure100 以上,那么您的运行内存不足。增加vfs_cache_pressure可能会有所帮助,但唯一真正的解决方法是获得更多 RAM。拥有vfs_cache_pressure一套以大量牺牲平均业绩整体有更稳定的性能(即,你能避免非常糟糕的最坏情况的行为,但不得不面对较差总体性能)。

最后告诉内核使用到RAM作为缓存写入,并指示内核放缓是的写作过程之前,使用最多的RAM 50%的99%(默认dirty_background_ratio10)。警告:我个人不会这样做,但您声称有足够的 RAM 并愿意丢失数据。

echo 99 > /proc/sys/vm/dirty_ratio
echo 50 > /proc/sys/vm/dirty_background_ratio
Run Code Online (Sandbox Code Playgroud)

并告诉 1 小时写入延迟甚至可以开始在磁盘上写入内容(同样,我不会这样做):

echo 360000 > /proc/sys/vm/dirty_expire_centisecs
echo 360000 > /proc/sys/vm/dirty_writeback_centisecs
Run Code Online (Sandbox Code Playgroud)

有关这些可调参数的更多信息,请参阅https://www.kernel.org/doc/Documentation/sysctl/vm.txt

如果您将所有这些都放入/etc/rc.local并在最后包含以下内容,则启动后所有内容都将尽快在缓存中(仅当您的文件系统确实适合 RAM 时才这样做):

(nice find / -type f -and -not -path '/sys/*' -and -not -path '/proc/*' -print0 2>/dev/null | nice ionice -c 3 wc -l --files0-from - > /dev/null)&
Run Code Online (Sandbox Code Playgroud)

或者一个更简单的替代方案,它可能会更好(仅缓存/home/usr,仅当您的/home/usr真正适合 RAM时才这样做):

(nice find /home /usr -type f -print0 | nice ionice -c 3 wc -l --files0-from - > /dev/null)&
Run Code Online (Sandbox Code Playgroud)

  • 一个消息灵通且总体上比接受的答案要好得多的答案!这个被低估了......我想大多数人只是想要简单的说明,而不会费心去理解他们*真正*做什么...... (5认同)
  • @Phpdevpad:此外,问题是“我既不关心 RAM 使用情况 [...]”——我认为任何 Maemo 设备都不符合条件。 (2认同)
  • 您还可以从 [vm 内核文档](https://www.kernel.org/doc/Documentation/sysctl/vm.txt) 中了解这些 vm 可调参数。 (2认同)

Fel*_*Yan 17

首先,我不建议您继续使用 NTFS,因为在 Linux 中实施 ntfs 随时都会出现性能和安全问题。

您可以执行以下几项操作:

  • 使用一些较新的 fs,例如ext4btrfs
  • 例如,尝试更改您的 io 调度程序 bfq
  • 关闭交换
  • 使用一些自动预加载器,如 preload
  • systemd在启动时使用类似预加载的东西
  • ......还有更多

也许你想试一试:-)

  • 除了性能之外,Linux 上的 NTFS 几乎可以接受。考虑到这个问题是专门针对提高文件系统性能的,NTFS 应该是第一件事。 (3认同)
  • 我已经完全从 NTFS 转移到 ext4 一次,将唯一的 NTFS 分区保留为 Windows 系统分区。但它给我带来了许多不便,我又回到了 NTFS 作为主要数据分区(我在其中存储所有文档、下载、项目、源代码等)文件系统。我不会放弃重新考虑我的分区结构和我的工作流程(使用更少的 Windows),但现在放弃 NTFS 似乎不是一个现实的选择。 (2认同)

Ole*_*nge 8

提前阅读:

在 32 位系统上:

blockdev --setra 8388607 /dev/sda
Run Code Online (Sandbox Code Playgroud)

在 64 位系统上:

blockdev --setra 4294967295 /dev/sda
Run Code Online (Sandbox Code Playgroud)

写在缓存后面:

echo 90 > /proc/sys/vm/dirty_ratio # too high rates can cause crash
Run Code Online (Sandbox Code Playgroud)

这将使用多达 90% 的可用内存作为写入缓存。

或者你可以全力以赴使用tmpfs。这仅在您有足够的 RAM 时才相关。把这个放在/etc/fstab. 用您选择的数量替换 50%。它始终是整个 RAM 的百分比。此外,8G 可用作 8GB,3M 可用作 3MB

tmpfs /mnt/tmpfs tmpfs size=50%,rw,nosuid,nodev 0 0 # you can do that with more things, as the /tmp folder. The 50% can be replaced with 4G, 5G... 50% is the half of the whole ram. Also higher values work because it will go into swap
Run Code Online (Sandbox Code Playgroud)

然后:

mkdir /mnt/tmpfs; mount -a
Run Code Online (Sandbox Code Playgroud)

然后使用 /mnt/tmpfs。

  • 3GB 还是 2TB 预读?真的吗?你甚至知道这些选项有什么作用吗? (11认同)
  • @syss 预读设置保存为内存“块”的数量,而不是字节或位。在某些情况下,一个块的大小是在内核编译时(因为预读块是内存块)或文件系统创建时确定的。通常,1 个块包含 512 或 4096 个字节。见 http://linux.die.net/man/8/blockdev (6认同)

psu*_*usi 6

您可以使用 设置预读大小blockdev --setra sectors /dev/sda1,其中扇区是您想要的 512 字节扇区的大小。