所以在我的 Linux 桌面上,我正在将一些大文件写入本地磁盘或 NFS 挂载。
要写入的数据缓存在某种系统缓冲区中。(我认为在我的系统上有 0.5-2GB 范围内的东西?)
如果缓冲区已满,所有文件访问都会阻塞,从而有效地冻结系统,直到写入完成。(我很确定甚至读取访问都被阻止了。)
我需要配置什么才能确保永远不会发生?
我想要的是:
如果一个进程不能足够快地将数据写入磁盘(或网络挂载等),该进程可能会阻塞,直到磁盘赶上,但其他进程仍然可以以合理的速率和延迟读取/写入数据而不会出现任何中断。
理想情况下,我可以设置 dsik 的总读/写速率中有多少可用于某种类型的程序(cp、git、mplayer、firefox 等),例如“所有 mplayer 进程一起获得至少10MB/s,无论系统的其余部分在做什么”。但是“所有 mplayer 实例一起至少获得总速率的 50%,无论如何”也很好。(即,我不太关心是否可以设置绝对费率或总费率的比例)。
更重要的是(因为最重要的读/写很小),我想要一个类似的延迟设置。同样,我保证单个进程的读/写不能阻塞系统的其余部分超过 10 毫秒(或其他),无论如何。理想情况下,我有一个保证,例如“无论系统在做什么,mplayer 都不必等待超过 10 毫秒的时间来处理读/写”。
无论有问题的进程是如何开始的(包括它在哪个用户下运行等),这都必须起作用,所以“在 ionice 中包装一个大 cp ”或任何几乎没有用的东西。如果我记得对它们进行离子化,它只会阻止某些任务可预测地冻结所有内容,但是 cron 作业、来自某个正在运行的守护程序的 exec 调用等呢?
(我想我可以用一个总是对它们进行离子化的 shell 脚本来包装最严重的罪犯,但即便如此,通过查看 ionice 的手册页,它给我的确切保证似乎有些模糊,所以我更喜欢更系统的和可维护的替代方案。)
通常 Linux 使用缓存将数据异步写入磁盘。但是,可能会发生写入请求和实际写入之间的时间跨度或未写入(脏)数据量变得非常大的情况。在这种情况下,崩溃会导致大量数据丢失,因此如果脏缓存变大或变旧,Linux 会切换到同步写入。由于还必须遵守写入顺序,因此您不能在不保证小 IO 完全独立于所有早期排队写入的情况下绕过小 IO。因此,依赖写入可能会导致巨大的延迟。(这种依赖也可能是在文件系统级别引起的:参见https://ext4.wiki.kernel.org/index.php/Ext3_Data%3DOrdered_vs_Data%3DWriteback_mode)。
我的猜测是,您正在经历某种与依赖写入相结合的缓冲区膨胀。如果你写一个大文件并有一个大磁盘缓存,你最终会遇到在同步写入之前必须写入大量数据的情况。LWN上有一篇很好的文章,描述了问题:https : //lwn.net/Articles/682582/
调度程序的工作仍在进行中,新内核版本的情况可能会好转。但是,到目前为止:有几个开关可以影响 Linux 上的缓存行为(还有更多,请参阅:https : //www.kernel.org/doc/Documentation/sysctl/vm.txt):
在这种情况下,减少最大延迟的最简单解决方案是减少脏磁盘缓存的最大数量,并使后台作业提前写入。当然,这可能会导致性能下降,否则较大的缓存会完全阻止同步写入。例如,您可以在 /etc/sysctl.conf 中配置以下内容:
vm.dirty_background_ratio = 1
vm.dirty_ratio = 5
Run Code Online (Sandbox Code Playgroud)
请注意,适合您系统的值取决于可用 RAM 的数量和磁盘速度。在极端情况下,上述脏口粮可能仍然很大。例如,如果您有 100GiB 的可用 RAM 并且您以大约 100MiB 的速度写入磁盘,则上述设置将导致最大数量的 5GiB 脏缓存,这可能需要大约 50 秒的时间来写入。使用dirty_bytes
和dirty_background_bytes
您还可以以绝对方式设置缓存的值。
您可以尝试的另一件事是切换 io 调度程序。在当前的内核版本中,有 noop、deadline 和 cfq。如果您使用的是较旧的内核,则与 cfq 相比,使用截止时间调度程序可能会遇到更好的反应时间。但是,您必须对其进行测试。在你的情况下应该避免 Noop。还有一个非主线 BFQ 调度程序,它声称与 CFQ 相比可以减少延迟(http://algo.ing.unimo.it/people/paolo/disk_sched/)。但是,它并未包含在所有发行版中。您可以在运行时检查和切换调度程序:
cat /sys/block/sdX/queue/scheduler
echo <SCHEDULER_NAME> > /sys/block/sdX/queue/scheduler
Run Code Online (Sandbox Code Playgroud)
第一个命令还将为您提供可用调度程序及其确切名称的摘要。请注意:重启后设置将丢失。要永久选择调度,您可以添加内核参数:
elevator=<SCHEDULER_NAME>
Run Code Online (Sandbox Code Playgroud)
NFS 的情况类似,但包括其他问题。以下两个错误报告可能会提供有关 NFS 上处理 stat 的一些内幕,以及为什么大文件写入会导致 stat 非常慢:
https://bugzilla.redhat.com/show_bug.cgi?id=688232 https://bugzilla.redhat.com/show_bug.cgi?id=469848
更新:(2017年8月14日)
内核4.10新内核选项CONFIG_BLK_WBT
及其子选项BLK_WBT_SQ
,并CONFIG_BLK_WBT_MQ
相继出台。它们正在防止由硬件缓冲区引起的缓冲区膨胀,其大小和优先级不能由内核控制:
Enabling this option enables the block layer to throttle buffered
background writeback from the VM, making it more smooth and having
less impact on foreground operations. The throttling is done
dynamically on an algorithm loosely based on CoDel, factoring in
the realtime performance of the disk
Run Code Online (Sandbox Code Playgroud)
此外,BFQ-Scheduler 以内核 4.12 为主线。
归档时间: |
|
查看次数: |
7134 次 |
最近记录: |