【问题标题】:Queueing writes to file system on Linux?在 Linux 上排队写入文件系统?
【发布时间】:2015-07-27 17:55:28
【问题描述】:

在具有许多 CPUS 脚本的大型 SMP 机器上运行数十个同时作业(少于 CPU 数量),如下所示:

some_program -in FIFO1 >OUTPUT1 2>s_p1.log </dev/null &
some_program -in FIFO2 >OUTPUT2 2>s_p2.log </dev/null &
...
some_program -in FIFO40 >OUTPUT40 2>s_p40.log </dev/null &
splitter_program -in real_input.dat -out FIFO1,FIFO2...FIFO40

分离器读取输入数据并按顺序将其分配到 FIFO。 (记录 1,41,81... 到 FIFO1;2,42,82 到 FIFO2 等)拆分器的开销很低,并且几乎可以以文件系统提供的速度处理数据。

每个 some_program 处理其流并将其写入其输出文件。但是,没有任何东西可以控制文件系统看到这些写入的顺序。写入也非常小,大约 10 个字节。脚本“知道”这里有 40 个流,它们可以缓冲在 20M(或其他)块中,然后将每个块按顺序写入文件系统。也就是说,应该使用排队写入来最大化磁盘的写入速度。然而,操作系统只会在 40 个流中的每一个上以大致相同的速率看到一堆写入。

在实际运行过程中发生的情况是子进程获得大量 CPU 时间(在顶部,>80%),然后出现刷新进程(10% CPU),所有其他进程下降到低 CPU(1 %),然后它又回到更高的比率。这些停顿一次持续几秒钟。刷新意味着写入压倒了文件缓存。此外,我认为操作系统和/或底层 RAID 控制器可能会不规律地弹跳物理磁盘磁头,这会降低物理磁盘的最终写入速度。这只是一个猜测,因为很难说到底发生了什么,因为在写入和磁盘之间存在文件缓存(在具有超过 500Gb RAM 的系统中)和 RAID 控制器。

是否有控制这种 IO 的程序或方法,强制文件系统写入很好地排队以最大限度地提高写入速度?

“缓冲区”程序在这里没有多大帮助,因为虽然它会将输出流累积成一个大块,但不会有写入的有序排队,所以几个可能同时出去.如果输出流中的数据速率不相关,这将不是问题,但在某些情况下,所有流中的数据速率完全相同,这意味着缓冲区将同时填充。这将停止整个树,直到最后一个被写入,因为任何无法写入输出的进程都不会读取其下一个输入,这将停止拆分器,因为所有 I/O 都是同步的。缓冲区需要以循环方式清空,最好在其中任何一个完全填满之前清空,尽管当数据输出速率超过文件系统写入速率时,这可能无法避免。

有许多用于调整文件系统的参数,其中一些可能会有所帮助。调度程序已从 cfq 更改为截止日期,因为系统一次锁定了几分钟。

【问题讨论】:

  • 如果你的工作是受 IO 限制的,在更多的内核上并行只会让事情变得更糟。特别是在写入 HDD 时。您是否尝试过只运行更少的作业?
  • 也许你想要的是将那些 10 字节的写入累积到内存页面或磁盘块大小的块(甚至更大)中,然后异步将它们刷新到磁盘,即继续积累新的块,即使在等待旧块被提交到磁盘时也是如此。

标签: linux io


【解决方案1】:

如果问题是纯粹的 I/O 带宽,那么缓冲将无法解决任何问题。在这种情况下,您需要缩小数据或将其发送到更高带宽的接收器以提高和平衡您的性能。正如@thatotherguy 所说,一种方法是减少并行作业的数量。

但是,如果实际上问题在于不同 I/O 操作的数量而不是总体数据量,那么缓冲可能是一个可行的解决方案。我不熟悉您提到的buffer 程序,但我想它确实如其名。但是,我并不完全同意您的缓冲 cmets:

“缓冲区”程序在这里没有多大帮助,因为虽然它会将输出流累积成一个大块,但不会有写入的有序排队,所以几个可以同时出去.

您不一定需要 块。以文件系统的本机块大小或其小整数倍进行分块可能是理想的。例如,可能是 4096 或 8192 字节的块。

此外,我不明白您为什么认为您现在有“有序的写入队列”,或者您为什么确信需要这样的事情。

如果输出流中的数据速率不相关,这将不是问题,但在某些情况下,所有流中的数据速率完全相同,这意味着缓冲区将同时填充。这将使整个树停止,直到最后一个被写入,因为任何无法写入输出的进程都不会读取其下一个输入,这会停止拆分器,因为所有 I/O 都是同步的。

您的分离器正在写入 FIFO。虽然它可能是串行执行的,但这不是“同步”的,因为数据需要在分离器继续之前从另一端排出——至少,如果写入不超过 FIFO 的大小,则不会缓冲区。 FIFO 缓冲区容量因系统而异,在某些系统上动态适应,并且在某些系统上是可配置的(例如通过fcntl())。现代 Linux 上的默认缓冲区大小为 64kB。

需要以循环方式清空缓冲区,最好在它们中的任何一个完全填满之前清空,尽管当数据输出速率超过文件系统写入速率时这可能无法避免。

我认为这是一个几乎可以自行解决的问题。如果其中一个缓冲区备份到足以阻塞拆分器,那么这将确保竞争进程很快就会给被阻塞的缓冲区写入的机会。但这也是您不想要巨大缓冲区的原因——您希望相对精细地交错来自不同进程的磁盘 I/O,以保持一切正常。

外部缓冲程序的替代方案是修改您的进程以执行内部缓冲。这可能是一个优势,因为它从混合中删除了一整套管道(到外部缓冲程序),并且减轻了机器上的进程负载。不过,这确实意味着修改您的工作处理程序,所以最好从外部缓冲开始,看看效果如何。

【讨论】:

    【解决方案2】:

    如果问题是您的 40 个流每个都具有高数据速率,并且您的 RAID 控制器无法足够快地写入物理磁盘,那么您需要重新设计您的磁盘系统。基本上,将其划分为 40 个 RAID-1 镜像,并将一个文件写入每个镜像集。这使得每个流的写入都是连续的,但需要 80 个磁盘。

    如果数据速率不是问题,那么您需要添加更多缓冲。您可能需要一对线。一个线程将数据收集到内存缓冲区中,另一个线程将其写入数据文件并 fsync() 它。为了使磁盘写入顺序,它应该一次一个地同步每个输出文件。这应该导致写入大的顺序块,无论您的缓冲区大小是多少。 8 MB 可能吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-16
      • 2011-12-14
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      • 2012-01-11
      • 2013-05-31
      • 2015-08-07
      相关资源
      最近更新 更多