我想提高将几个通常很小的文件写入网络附加卷的软件的吞吐量。
卷限制为 100 IOPS 和 80 MB/s 的带宽。
目前我已达到 100 IOPS 的饱和,但带宽与可达到的 80 MB/s 相去甚远,约为 4 MB/s,甚至更少。
我认为主要问题是我们提出了很多小请求,这些小请求使 IOPS 饱和,但带宽几乎没有得到利用。
该软件是用 C 语言编写的,我几乎可以控制一切,包括实际的write
系统调用。
目前架构是多线程的,多个线程作为“后台处理程序”工作并进行同步 write
调用,每个线程针对不同的文件。
假设我们有文件 a
、b
和 c
以及线程 t1
、t2
和 t3
。
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 block (5/10 千字节)。
我认为解决问题的唯一方法是提出更大的请求,但每个文件都很小,所以我不太确定什么是最好的前进方式。
一个可能的想法是发出单个write
请求而不是多个请求的循环,因此查找文件有多大,分配足够的内存,填充缓冲区并最终执行单个写
。
另一个想法可能是切换到 async io,但我不明白在这种情况下会有什么优势。
您还有什么建议吗?
最佳答案
您可以将所有文件放入内存中的 tar 存档中。然后您可以将 tar 存档作为一个大请求写入,然后将 tar 存档作为一个单独的进程解压缩,从而释放写入程序。
这里有一个更“有创意”的idea。首先根据文件的保存位置(可能按目录)将文件分组。然后找到组中最大的文件。填充每个其他文件的内容,使每个文件的大小相同。然后将这些文件相互附加,这样您就有了一个大文件。发送该写入请求。所以现在我们写了一个大文件,其中包含许多大小相同的小文件。所以使用 linux split 命令将文件拆分成多个原始文件(https://kb.iu.edu/d/afar)。这可能有效,但您必须接受在文件末尾进行填充。
编辑:重要的是要注意这些解决方案不可扩展。长期解决方案将是@AndrewHenle 在评论中提出的建议。
关于c - 提高在 C 中写入大量小文件的吞吐量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51898141/