【问题标题】:Improve throughput writing a lot of small files in C提高在 C 中写入大量小文件的吞吐量
【发布时间】:2019-01-24 15:48:47
【问题描述】:

我想提高将几个通常很小的文件写入网络附加卷的软件的吞吐量。

卷限制为 100 IOPS 和 80 MB/s 的带宽。

目前我已达到 100 IOPS,但带宽与可达到的 80 MB/s 相差甚远,约为 4 MB/s,但甚至更低。

我认为主要问题是我们发出了很多小请求,这些小请求使 IOPS 饱和,但带宽几乎没有被利用。

该软件是用 C 语言编写的,我几乎可以控制一切,直到实际的 write 系统调用。

目前架构是多线程的,有几个线程作为“假脱机程序”工作并进行同步write 调用,每个线程用于不同的文件。

假设我们有文件abc 和线程t1t2t3

t1 将打开a 并在循环中调用write(fd_a, buff_a, 1024) 之类的东西,t2 (write(fd_b, buff_b, 1024)) 和t3 (write(fd_c, buff_c, 1024)) 也是如此。

每个文件都是一个新文件,所以它是在第一次写入时创建的。

我认为问题在于操作系统发出的请求(在 Linux IO 调度程序合并之后)非常小,每个大约 10/20 个块(5/10 KB)。

我认为解决问题的唯一方法是提出更大的请求,但每个文件都很小,所以我不太确定最好的方法是什么。

一个可能的想法是发出单个write 请求而不是多个请求的循环,因此查找文件有多大,分配足够的内存,填充缓冲区并最终执行单个write

另一个想法可能是切换如此异步 io,但我不明白在这种情况下会有什么优势。

你还有什么建议吗?

【问题讨论】:

  • 如果这是一个硬盘驱动器(看起来像一个非常低规格的慢速硬盘驱动器),你就处于硬件的极限。小请求在操作之间有一个寻道时间。这将限制您的带宽。对于这种类型的工作负载,4MB/s 实际上是一个不错的结果。
  • 这些小文件是否相互关联?将它们的内容组合成更少的大文件文件是否有意义,可能是类似 tar 的格式?
  • 这似乎是多余的,但我想在循环中没有做任何其他事情?
  • @drescherjm,是的,我们在非常商品化的硬件上运行,4MB/s 是实际架构达到的上限,通常它更慢。
  • @Siscia 你不能做什么?改代码?或者获得更快的存储系统?如果您需要更好的吞吐量,您必须至少完成其中一项。因为你现在的设计需要太多的 IO 操作来写入少量的数据。您当前的设计可能需要 4-5 次 IO 操作来写入少量千字节。设计良好的快速存储系统每次 IO 操作可以移动 1 兆字节或更多。您在问,“我怎样才能将我的Yugo 变成赛车并赢得 F1 比赛?”答案是你不能。

标签: c linux io filesystems


【解决方案1】:

您可以将所有文件放入内存中的 tar 存档中。然后,您可以将 tar 归档作为一个大请求编写,然后将 tar 归档作为一个单独的进程解压缩,从而释放编写程序。

这是一个更“有创意”的想法。首先根据文件的保存位置(可能按目录)将文件分组。然后找到组中最大的文件。填充其他文件的内容,使每个文件的大小相同。然后将文件相互附加,这样现在你就有了一个大文件。发送那个写请求。所以现在我们编写了一个大文件,其中包含许多大小相同的小文件。所以使用linux split 命令将文件拆分成多个原始文件(https://kb.iu.edu/d/afar)。这可能有效,但您必须同意在文件末尾添加填充。

编辑:重要的是要注意这些解决方案不可扩展。长期解决方案将是 @AndrewHenle 在 cmets 中提出的建议。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-03
    • 2019-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    相关资源
    最近更新 更多