我正在寻找有关如何为在Ubuntu Linux 14.04上运行的应用程序提供高效和高性能异步IO的建议。
我的应用处理事务并在磁盘/闪存上创建文件。当应用程序正在进行事务处理时,会创建必须附加到磁盘/闪存上的文件的附加块。应用程序还需要在处理新事务时频繁读取此文件的块。除了还要创建必须附加到此文件的新块之外,每个事务可能还需要从该文件中读取不同的块。有一个传入的事务队列,应用程序可以继续处理队列中的事务,以创建足够深的IO操作管道,以隐藏读取访问的延迟或磁盘或闪存上的写入完成。对于尚未写入磁盘/闪存的块读取(由先前的事务放入写入队列),应用程序将停止,直到相应的写入完成。
我有一个重要的性能目标 - 应用程序应该尽可能地延迟发出IO操作。我的应用程序大约需要10微秒来处理每个事务,并准备对磁盘/闪存上的文件发出写入或读取。发出异步读取或写入的额外延迟应尽可能小,以便应用程序可以在每次事务处理时尽可能接近10个usecs,只需要进行文件写入时完成每个事务的处理。
我们正在尝试使用io_submit发出写入和读取请求的实现。我将不胜感激任何有关我们要求的最佳方法的建议或反馈。 io_submit会给我们最好的表现以达到我们的目标吗?我应该期望每个写入io_submit的延迟和每个读取io_submit的延迟?
使用我们的实验代码(在2.3 GHz Haswell Macbook Pro,Ubuntu Linux 14.04上运行),我们在扩展输出文件时测量写入io_submit大约50个usecs。这太长了,我们甚至没有接近我们的性能要求。任何帮助我以最小延迟启动写请求的指南都将非常感激。
答案 0 :(得分:7)
我在这里作为proposed Boost.AFIO的作者发言。
首先,Linux KAIO(io_submit)几乎总是阻塞,除非O_DIRECT打开且不需要扩展分配,如果O_DIRECT打开,则需要在4Kb对齐的边界上读取和写入4Kb倍数,否则强制设备执行做一个读 - 修改 - 写。因此,除非您将应用程序重新架构为O_DIRECT且4Kb对齐i / o友好,否则您将无法使用Linux KAIO获得任何好处。
其次,永远不要在写入期间扩展输出文件,强制扩展分配和可能的元数据刷新。而是将文件的最大范围分配给某个适当大的值,并保留文件末尾的内部原子计数器。这应该将问题简化为仅限于ext4批量和懒惰的分配 - 更重要的是,你不会强迫元数据刷新。这应该意味着ext4上的KAIO大部分时间都是异步的,但不可预测的是会同步,因为它会延迟对期刊的延迟分配。
第三,我可能解决你的问题的方法是使用没有O_DIRECT或O_SYNC的原子追加(O_APPEND),所以你要做的是将更新附加到内核页面缓存中不断增长的文件这是非常快速和并发安全的。然后,您不时地收集垃圾收集日志文件中的哪些数据是陈旧的,并且可以使用fallocate(FALLOC_FL_PUNCH_HOLE)释放其范围,以便物理存储不会永远增长。这推动了将存储的写入合并到内核上的问题,其中花了很多精力来实现这一点,并且由于它始终是一个前进的进度写入,您将看到写入按照与序列非常接近的顺序命中物理存储它们的编写使得断电恢复变得简单明了。后一种选择是数据库如何做到这一点,并且实际上日志文件系统就是这样做的,尽管你可能需要对你的软件进行大量的重新设计,但这种算法已经被证明是在通用问题中延迟与持久性的最佳平衡情况下。
如果以上所有内容看起来都很多,那么操作系统已经将所有这三种技术集合在一起,形成一个高度优化的实现,更好地称为内存映射:4Kb对齐i / o,O_DIRECT,从不扩展文件,所有异步i / o。在64位系统上,只需将文件重定位到非常大的数量并将其映射到内存中。根据需要进行读写。如果您的i / o模式混淆了可能发生的内核页面算法,那么您可能需要在这里和那里使用madvise()来鼓励更好的行为。 madvise()更少,更信任我。
很多人尝试使用各种O_DIRECT算法复制mmaps而没有意识到mmaps已经可以完成你需要的一切。我建议首先探索这些,如果Linux不会尝试FreeBSD,它具有更可预测的文件i / o模型,并且只有深入研究滚动自己的i / o解决方案的领域。作为一整天都在做这些事情的人,我强烈建议你尽可能地避免使用它们,归档系统是古怪和怪异行为的恶魔。将永无止境的调试留给其他人。
答案 1 :(得分:7)
io_submit()
转变为阻塞调用) :
O_DIRECT
“提示”(例如,您提交I / O的方式不符合{ {1}}对齐约束,文件系统或特定文件系统的配置不支持O_DIRECT
)和silently performs buffered I/O instead,导致上述情况。/sys/block/[disk]/queue/nr_requests
documentation和un(der)记录内核中的O_DIRECT
)。制作I/O requests back-up and exceed the size of the kernel queues leads to blocking。
/sys/block/[disk]/device/queue_depth
)的I / O,它们将在内核中拆分并继续咀嚼多个请求... /proc/sys/fs/aio-max-nr
documentation)也会产生影响,但结果将显示在/sys/block/[disk]/queue/max_sectors_kb
而不是io_setup()
上面的列表不详尽无遗。
未来的一线希望是一项建议的功能,它允许程序通过设置flag which causes AIO submission to fail with EAGAIN if it would go on to block来请求更好的行为。在撰写本文时AIO EAGAIN patches were submitted against the 4.13 kernel。即使这些补丁进入未来的内核,你仍然会a)需要所述(或更晚的)内核来使用该功能,并且b)必须知道它没有覆盖的情况(尽管我注意到它们是完全独立的{{ 3}})。
参考文献:
io_submit()
阻止/缓慢情况的patches being proposed to try and return EAGAIN when stacked blocked devices would triggered blocking警告。O_DIRECT
rather than failing the open()
call。O_DIRECT
is requested on compressed files。在ZFS on Linux was changed from erroring on O_DIRECT
to "supporting" it via buffered I/O (see point 3)。O_DIRECT
allocating writes(有点旧但快速参考)。相关:
希望这篇文章可以帮助某些人(如果有帮助你可以帮助你吗?谢谢!)。