优化 O_DIRECT 写操作

4

我正在编写一个需要非常快速地写入磁盘的应用程序。我已经达到了写入磁盘的性能目标,这很好。

然而,我注意到快速写入磁盘会使用大量的CPU时间:一个核心被占满,另一个核心达到80%,另外两个核心则是10-20%。因此,我听说O_DIRECT可以通过避免所有那些进入内核空间的拷贝以及拷贝到磁盘来减少CPU消耗。

我运行了一个小测试程序,证实了这一点 - CPU使用率降低到了一个核心的50% - 更好了。

但是,当我进行正常写操作时,我从未获得过完全相同的吞吐量,为了使其快速,我必须使用一个真的非常大的记录大小(大约130MB!)

所以,问题是:

  • 除了O_DIRECT之外,是否有更好的方法可以降低写入时的CPU使用率?
  • 或者
  • 如何获得与内核获得的类似吞吐量?

我的环境是Linux,我正在使用RAID 50,并且我能够缓冲写入,直到达到一些最佳记录大小。每次只有一个写入者。

3个回答

3
引用这个页面

使用O_DIRECT,内核将直接从/向由作为read/write系统调用参数传递的用户空间缓冲区指向的物理内存进行DMA。因此,在用户空间内存和内核缓存之间进行复制时,不会花费CPU和内存带宽,并且在缓存管理方面不会花费内核中的CPU时间(例如缓存查找、每页锁定等)。

基本上,当使用O_DIRECT时,您正在交换吞吐量以获得CPU性能。内核停止为您优化吞吐量,作为回报,您获得可预测的结果和完全控制。
简而言之:使用O_DIRECT,您将不得不自己进行缓存和其他优化,从而提高吞吐量。现在巨大的记录大小似乎不那么奇怪了。
我不知道是否有其他方法,但我不是linux大师。可以随意询问 :)

谢谢nightcracker。我想我问的是,内核做了哪些优化?因为我可以复制它来获得类似于内核实现的吞吐量 - 或者采取更好的方法。从磁盘I/O统计数据来看,似乎内核在写入之前并没有缓冲超过100MB。 - Frederik
我不是Linux大师,而且我只有16岁 :) 我猜测可能涉及缓存和缓冲(也许使用动态缓冲区,在每次写入后将其大小加倍)。我建议你查看Linux内核源代码,但我不知道应该从哪里开始查找。抱歉,在这种情况下我帮不上太多忙 :) - orlp

1
您需要想办法同时保持更多的I/O并以最佳大小提交它们。当内核将您的写入I/O缓冲在一起时,可能会发生以下几种好处:
- 可能将连续的I/O合并为更大的I/O。如果是这样,就有机会节省开销,因为内核现在可以提交一个64K字节的I/O,而不是8个小的4K字节I/O。 - 它打开了并行提交的可能性。如果内核能够批量处理256k,则现在可以将其作为8个同时的I/O发送,从而实现更高的iodepth。
所以,

除了O_DIRECT写入之外,还有什么更好的方法来减少CPU使用率?

是的,请发送更大的I/O,直到达到磁盘所需的最佳大小。

如何获得与内核获取的类似吞吐量?

请发送更大的I/O,直到达到磁盘所需的最佳大小。
理想情况下,执行上述操作(发送最佳大小的I/O),并确保磁盘喜欢的最大I/O同时在飞行中(例如通过异步提交或通过多个线程/进程进行提交,如果您将使用阻塞例程)并按照磁盘LBA顺序提交I/O。一个稍微不那么优化的技巧是发送大量的I/O并强制内核分裂它们以创建并行性,但这种方法不太理想。

0
你尝试过使用 mmapmsync 吗?我不知道它是否更快或更少占用 CPU,但由于它代表了一种完全不同的 I/O 方法(基本上是内核为您执行 I/O),因此这可能是一个有趣的选择。

1
我刚刚尝试了mmap和msync - 我似乎得到了与O_DIRECT类似的结果 - 在我增加非常大的记录大小时效率更高,但除此之外,性能较差。感谢您的建议。 - Frederik

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