在Linux中排队写入文件系统的问题?

3

在一个具有许多CPU的非常大的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时间(在top中>80%),然后出现了一个刷新进程(10% CPU),所有其他进程的CPU都降到了很低(1%),然后又回到了更高的速率。这些暂停持续几秒钟。刷新意味着写入超过了文件缓存。此外,我认为操作系统和/或底层RAID控制器可能会使物理磁头不规则地反弹,从而降低了最终写入物理磁盘的速度。不过这只是一个猜测,因为很难说到底发生了什么,因为在写入和磁盘之间有文件缓存(在一个具有超过500Gb RAM的系统中)和RAID控制器。
是否有程序或方法可以控制这种IO,强制文件系统写入排队以最大化写入速度?
“缓冲”程序在这里帮助不大,因为虽然它会将输出流累积成一个大块,但不会有有序的写入排队,因此几个写入可能会同时进行。如果输出流中的数据速率不相关,这将是较小的问题,但在某些情况下,所有流的数据速率都完全相同,这意味着缓冲区将同时填满。这将使整个树停止,直到最后一个被写入,因为任何无法写出输出的进程都不会读取其下一个输入,这将使分离器停止,因为所有I/O都是同步的。最好在任何一个缓冲区完全填满之前就循环地清空缓冲区,尽管当数据输出速率超过文件系统写入速率时,这可能是不可避免的。
有数十个调整文件系统的参数,其中一些可能有所帮助。调度程序从cfq更改为deadline,因为前者会导致系统锁定数分钟。

2
如果您的工作是IO绑定的,请跨越更多核心并行化它只会使情况变得更糟。特别是在写入HDD时。您尝试过仅运行较少的作业吗? - that other guy
也许你想要的是将这些10字节的写入累积到内存页或磁盘块大小的块中(甚至更大),然后异步地将它们刷新到磁盘上,即在等待旧块提交到磁盘时继续累积新块。 - Chris Stratton
2个回答

0
如果问题纯粹是I/O带宽,那么缓冲不会解决任何问题。在这种情况下,您需要缩小数据或将其发送到更高带宽的接收器以改善和平衡性能。一种方法是减少并行作业的数量,就像@thatotherguy所说的那样。
然而,如果问题实际上是与不同I/O操作的数量有关,而不是与数据的总体积有关,则缓冲可能是可行的解决方案。我不熟悉您提到的“buffer”程序,但我想它做了它的名字所示的事情。然而,我不完全同意您的缓冲评论:
“buffer”程序在这里不会有太大的帮助,因为虽然它会将输出流累积成一个大块,但不会有有序的写入队列,因此几个写入可能同时进行。
您不一定需要大块。最好将其分块为文件系统的本机块大小或小整数倍。这可能是4096或8192字节块。
此外,我不明白为什么您认为现在有“有序的写入队列”,或者为什么您有信心需要这样的东西。
如果输出流中的数据速率不相关,那么这将不是一个问题,但在某些情况下,所有流的数据速率完全相同,这意味着缓冲区会同时填满。这将导致整个树结构停滞,直到最后一个写入完成,因为无法写入输出的任何过程都不会读取其下一个输入,这将使分离器停滞,因为所有I/O都是同步进行的。
你的分离器正在写入FIFO队列。尽管它可能是串行的,但从不需要等待数据在另一端被排空才能继续进行,至少在写入的数据不超过FIFO缓冲区大小的情况下不需要等待。 FIFO缓冲区容量因系统而异,在某些系统上动态适应,并且可以通过某些系统上的fcntl()进行配置。现代Linux的默认缓冲区大小为64kB。
这些缓冲区需要以循环方式被清空,最好在它们完全填满之前进行,尽管在数据输出速率超过文件系统写入速率时这可能是无法避免的。

我认为这是一个相当自解决的问题。如果其中一个缓冲区足够堵塞分离器,那么这就确保了竞争进程将在不久的将来给被阻塞的缓冲区写入的机会。但这也是为什么你不想要巨大的缓冲区--你想要相对细致地交错不同进程的磁盘I/O,以尝试保持一切运行。

与外部缓冲程序相比,另一种选择是修改您的进程以执行内部缓冲。这可能是一个优点,因为它从混合物中删除了整个管道集(到外部缓冲程序),并减轻了机器上的进程负载。不过,这意味着修改您的工作处理程序,因此也许最好从外部缓冲开始,看看它的表现如何。


0
如果您的40个流每个都有很高的数据速率,而且RAID控制器无法快速地写入物理磁盘,则需要重新设计您的磁盘系统。基本上,将其分为40个RAID-1镜像,每组镜像写入一个文件。这使得每个流的写入是顺序的,但需要80个磁盘。
如果数据速率不是问题,那么您需要添加更多缓冲区。您可能需要一对线程。其中一个线程将数据收集到内存缓冲区中,另一个线程将其写入数据文件并进行fsync()同步。为了使磁盘写入顺序,它应该依次fsync每个输出文件。这应该会导致按照您的缓冲区大小(可能为8 MB)写入大块顺序数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接