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

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

我既不担心 RAM 使用情况(因为我有足够的内存),也不担心意外关闭时丢失数据(因为我的电源有后备,系统可靠且数据不重要)。但我进行了大量的文件处理,并且需要一些性能提升。

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

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

答案1

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

你没有告诉你的存储设备是SSD还是HDD。这是我发现对我有用的东西(在我的例子中,sdaHDD 安装在/homesdbSSD 安装在/)。

首先优化从存储加载内容到缓存部分:

这是我的 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

值得注意的是,HDD 的情况是高fifo_expire_async(通常是写入)和长slice_sync,以允许单个进程获得高吞吐量(slice_sync如果遇到多个进程并行等待磁盘中的某些数据的情况,则设置为较低的数字)。对于 HDD 来说,这slice_idle始终是一个折衷方案,但根据磁盘使用情况和磁盘固件,将其设置在 3-20 范围内应该没问题。我更喜欢以较低的值为目标,但将其设置得太低会破坏您的吞吐量。该quantum设置似乎对吞吐量影响很大,但请尝试将其保持在尽可能低的水平,以将延迟保持在合理的水平。设置quantum太低会破坏吞吐量。 3-8 范围内的值似乎适用于 HDD。如果我正确理解了内核行为,则最坏情况下的读取延迟是 ( quantum* slice_sync) + ( slice_async_rq* ) 毫秒。slice_async异步主要用于写入,并且由于您愿意延迟写入磁盘,因此将 和 都设置slice_async_rqslice_async非常低的数字。但是,设置slice_async_rq太低的值可能会阻止读取,因为读取之后写入无法再延迟。我的配置将在数据传递到内核后最多 10 秒后尝试将数据写入磁盘,但由于您可以容忍断电时数据丢失,因此也设置为fifo_expire_async告诉3600000磁盘延迟 1 小时是可以的。不过,请保持slice_async较低的值,否则可能会导致较高的读取延迟。

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

这是我的 SSD(Intel 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

这里值得注意的是不同切片设置的低值。 SSD 最重要的设置是slice_idle必须设置为 0-1。将其设置为零会将所有排序决策移至本机 NCQ,而将其设置为 1 允许内核对请求进行排序(但如果 NCQ 处于活动状态,硬件可能会部分覆盖内核排序)。测试这两个值,看看是否可以看到差异。对于 Intel 320 系列,似乎设置slide_idle0可提供最佳吞吐量,但将其设置为1可提供最佳(最低)总体延迟。如果您有足够新的内核,您可以使用slide_idle_us以微秒而不是毫秒为单位设置值,并且可以使用类似的东西echo 14 > slice_idle_us来代替。合适的值似乎接近 700000 除以您的存储设备可以支持的最大实际 IOPS,因此对于相当快的 SSD 设备来说 14 就可以了。

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

2020 年更新,内核版本 5.3(cfq 已失效):

#!/bin/bash
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

设置非常相似,但我现在使用bfq而不是cfq因为后者不适用于现代内核。我尽量保持nr_requests尽可能低的水平,以便bfq更准确地控制日程安排。至少三星 SSD 驱动器似乎需​​要相当深的队列才能以高 IOPS 运行。更新:nr_requests许多三星 SSD 都存在固件错误,如果太高并且操作系统快速提交大量请求,则可能会挂起整个设备。如果我使用高值(例如 32 或 36),我会看到大约每 2 个月随机冻结一次,但到目前为止nr_requests该值一直稳定。6官方的修复是设置为,1但是这样对性能影响很大!有关更多详细信息,请参阅https://bugzilla.kernel.org/show_bug.cgi?id=203475https://bugzilla.kernel.org/show_bug.cgi?id=201693– 基本上,如果您有三星 SSD 设备并failed command: WRITE FPDMA QUEUED在内核日志中看到,那么您已经被这个错误所困扰。

我正在使用带有内核包的 Ubuntu 18.04,linux-lowlatency-hwe-18.04-edge该包bfq仅作为模块,因此我需要先加载它,然后才能切换到它。

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

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

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

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

echo 15 > /proc/sys/vm/swappiness

如果您希望将应用程序几乎始终保留在 RAM 中,您可以将其设置为 1。如果将其设置为零,内核将根本不会交换,除非绝对必要以避免 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

设置vfs_cache_pressure为较低的值是有意义的,因为在大多数情况下,内核需要知道目录结构和其他文件系统元数据,然后才能使用缓存中的文件内容,并且过早刷新目录缓存将使文件缓存几乎毫无价值。但是,页面缓存还包含其他数据,但仅包含文件内容,因此应像元数据缓存与系统其他部分的整体重要性一样考虑此设置。如果您有大量小文件(我的系统有大约 150K 10 兆像素照片,算作“大量小文件”系统),请考虑将此设置一直降至 1。切勿将其设置为零,否则即使系统内存不足,目录结构也始终保留在内存中。仅当您只有几个需要不断重新读取的大文件时,才将其设置为较大的值(同样,没有足够 RAM 的高清视频编辑就是一个示例)。官方内核文档表示“将 vfs_cache_Pressure 大幅增加到超过 100 可能会对性能产生负面影响”。

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

2022 年更新:我已经运行内核 5.4.x 系列又一年了,我得出的结论vfs_cache_presure已经永久改变了。我使用 5.3 或更早版本的内核版本(值在 1..5 范围内)获得的内核内存管理器行为似乎与现实世界的行为(值在 100..120 范围内的 5.4)相匹配。较新的内核使此调整更加重要,因此我建议vfs_cache_presure=120现在使用该值以实现整体低延迟。我认为,内核版本 5.3 或更早版本应该使用非常低但非零的值。

例外:如果您有大量的文件和目录,并且您很少触摸/读取/列出所有文件,则设置vfs_cache_pressure高于 100 可能是明智的。仅当您没有足够的 RAM 并且无法将整个目录结构保留在 RAM 中并且仍然有足够的 RAM 用于正常文件缓存和进程(例如,具有大量存档内容的公司范围的文件服务器)时,这才适用。如果您觉得需要增加到vfs_cache_pressure100 以上,则说明您的 RAM 不足。增加内存vfs_cache_pressure可能会有所帮助,但唯一真正的解决办法是获得更多内存。设置vfs_cache_pressure为高数字会牺牲平均性能以获得更稳定的整体性能(也就是说,您可以避免非常糟糕的最坏情况行为,但必须处理更差的整体性能)。

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

echo 99 > /proc/sys/vm/dirty_ratio
echo 50 > /proc/sys/vm/dirty_background_ratio

并告知 1h 写入延迟是可以的开始在磁盘上写入内容(同样,我不会这样做):

echo 360000 > /proc/sys/vm/dirty_expire_centisecs
echo 360000 > /proc/sys/vm/dirty_writeback_centisecs

有关这些可调参数的更多信息,请参阅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)&

或者一个更简单的替代方案,可能效果更好(仅缓存/home/usr,只有当您的/home/usr真正适合 RAM 时才执行此操作):

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

答案2

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

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

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

也许你想尝试一下:-)

答案3

继续阅读:

在 32 位系统上:

blockdev --setra 8388607 /dev/sda

在 64 位系统上:

blockdev --setra 4294967295 /dev/sda

写在缓存后面:

echo 90 > /proc/sys/vm/dirty_ratio # too high rates can cause crash

这将使用高达 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

然后:

mkdir /mnt/tmpfs; mount -a

然后使用/mnt/tmpfs。

答案4

与写入缓存无关,但与写入相关:

  • 对于 ext4 系统,您可以完全禁用日记功能

    这将减少任何特定更新的磁盘写入次数,但可能会在意外关闭后使文件系统处于不一致状态,需要 fsck 或更糟的情况。

要阻止磁盘读取触发磁盘写入:

  • 安装与关系时间或者诺阿泰姆选项

    当您读取文件时,该文件的“上次访问时间”元数据通常会更新。该noatime选项将禁用该行为。这减少了不必要的磁盘写入,但您将不再拥有该元数据。某些发行版(例如 Manjaro)已将此作为所有分区的默认设置(可能是为了延长早期型号 SSD 的使用寿命)。

    relatime根据有助于支持使用 atime 的应用程序的启发法,更新访问时间的频率较低。这是 Red Hat Enterprise Linux 上的默认设置。

其他选项:

  • 在上面的评论中,Mikko 分享了安装的可能性无障碍选项。但伊瓦伊洛引用 RedHat谁警告不要这样做。您有多想要额外的 3%?

相关内容