Ubuntu Linux

时间:2016-01-03 01:42:54

标签: linux performance latency aio

我正在寻找有关如何为在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。这太长了,我们甚至没有接近我们的性能要求。任何帮助我以最小延迟启动写请求的指南都将非常感激。

2 个答案:

答案 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)

Linux AIO(有时也称为KAIO)是一种黑色艺术,有经验的从业者知道这些问题,但由于某种原因,与某人谈论他们还不知道的陷阱是禁忌。从网上浏览和体验我已经提出了一些例子,其中Linux的异步I / O 提交可能(静默)同步(从而将io_submit()转变为阻塞调用) :

  1. 您正在提交缓冲(即非直接)I / O.你受Linux的缓存的影响,你的提交可以同步
    • 您要求的内容尚未包含在“阅读缓存”中
    • “写入缓存”已满,并且在完成某些现有回写之前无法接受新请求
  2. 您要求对文件系统中的文件进行直接I / O,但由于某种原因,文件系统决定忽略O_DIRECT“提示”(例如,您提交I / O的方式不符合{ {1}}对齐约束,文件系统或特定文件系统的配置不​​支持O_DIRECT)和silently performs buffered I/O instead,导致上述情况。
  3. 您正在对文件系统中的文件执行直接I / O,但文件系统必须执行同步操作(例如读取/更新元数据)才能实现I / O.有些filesystems such as XFS try harder to provide good AIO behaviour与其他人相比,但即使在那里,用户仍然必须非常小心,以避免会触发同步的操作。
  4. 您提交了太多优秀的I / O.您的磁盘/磁盘控制器将具有可以同时处理的最大I / O请求数,并且每个特定设备都有最大的AIO请求队列大小(请参阅/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,它们将在内核中拆分并继续咀嚼多个请求...
    • 系统全局最大并发AIO请求数(请参阅/proc/sys/fs/aio-max-nr documentation)也会产生影响,但结果将显示在/sys/block/[disk]/queue/max_sectors_kb而不是io_setup()
  5. 您与磁盘提交之间的Linux块设备堆栈中的层必须阻止。例如,像Linux软件RAID(md)这样的东西可以使I / O请求通过它停止,同时更新单个磁盘上的RAID 1元数据。
  6. 您的提交会导致内核等待,因为:
    • 需要使用正在使用的特定锁。
    • 需要分配一些额外的内存或页面内容。
  7. 上面的列表详尽无遗。

    未来的一线希望是一项建议的功能,它允许程序通过设置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}})。

    参考文献:

    相关:

    希望这篇文章可以帮助某些人(如果有帮助你可以帮助你吗?谢谢!)。