当前位置:  开发笔记 > 编程语言 > 正文

Ubuntu Linux中的异步IO io_submit延迟

如何解决《UbuntuLinux中的异步IOio_submit延迟》经验,为你挑选了2个好方法。

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



1> Anon..:

Linux AIO是一种黑色艺术,有经验的从业者知道陷阱,但由于某种原因,与某人谈论他们还不知道的陷阱是禁忌.从网络和经验,围绕刮伤我已经拿出了几个例子,其中的Linux的异步I/O 提交可能成为(默默)同步(由此将libaio进入一个阻塞调用):

    您正在提交缓冲(也称为非直接)I/O. 你受到Linux缓存的支配,当你请求的内容尚未在读缓存/写缓存中已满并且在写回完成之前无法接受新请求时,你的提交可以同步.

    您要求对文件系统中的文件进行直接I/O,但由于某种原因,文件系统决定忽略io_submit()"提示"(例如,您提交I/O的方式不符合O_DIRECT对齐约束,文件系统或特定文件系统的配置不支持O_DIRECT)并静默执行缓冲I/O,导致上面的情况.

    您正在对文件系统中的文件执行直接I/O,但文件系统必须执行同步操作(例如更新元数据)才能实现I/O. 与其他文件系统相比,某些文件系统(如XFS)更难以提供良好的AIO行为,但即使在那里,用户仍然必须非常小心,以避免会触发同步的操作.

    您提交了太多优秀的I/O. 您的磁盘/磁盘控制器将具有可以同时处理的最大I/O请求数.每个特定设备都有最大AIO请求队列大小(请参阅O_DIRECT文档和文档中记录的un(der))以及内核中/sys/block/[disk]/queue/nr_requests系统全局最大AIO请求数(请参阅/sys/block/[disk]/device/queue_depth文档).使I/O备份并超过内核队列的大小会导致阻塞.

    一个要点是:如果您提交"太大"(即大于/sys/block/[disk]/queue/max_sectors_kb)的I/O,它们将在内核中拆分并继续咀嚼多个请求...

    您和提交到磁盘之间的Linux块设备堆栈中的层必须阻止.例如,像Linux软件RAID(md)这样的东西可以使I/O请求通过它停止,同时更新单个磁盘上的RAID 1元数据.

    您的提交会导致内核等待,因为:

    它需要采用正在使用的特定锁.

    它需要分配一些额外的内存或页面内容.

上面的列表并非详尽无遗.

未来希望的微光,是拟议的功能,它允许程序通过设置要求更好的行为导致AIO提交失败,EAGAIN是否会继续阻止标志.在撰写本文时,AIO EAGAIN补丁是针对4.13内核提交的.即使这些补丁进入未来的内核,您仍然需要(或更高版本)内核使用该功能,并且b)必须知道它没有覆盖的情况(尽管我注意到有完全独立的补丁正在建议在堆叠的被阻止设备触发阻塞时尝试返回EAGAIN.

参考文献:

该AIOUserGuide具有"性能注意事项"一节有关的警告/proc/sys/fs/aio-max-nr阻断/缓慢的情况.

阅读器的"性能问题"部分给出了一个很好的Linux AIO缺陷列表,用于ggaoed AoE目标.

该XFS邮件列表线程"期间io_submit睡觉,等待"在与文件系统的一些AIO约束提示.

"[PATCH 1/1 linux-next] ext4:添加兼容性标志检查补丁"LKML邮件列表线程有一个来自Ext4领导开发者Ted Ts'o的回复谈论文件系统io_setup()io_submit()如何可以回退到缓冲I/O 而不是没有通话.

在LKML线程中,BTRFS主管开发人员Chris Mason表示,当RWF_NONBLOCK压缩文件请求时,BTRFS会对缓冲I/O进行调度.

Linux上的ZFS已从错误更改为RWF_NONBLOCK通过缓冲I/O"支持"它(参见第3点).从Linux到"Direct IO"GitHub问题的ZFS上的提交还有进一步的讨论.

ext4的wiki有一个警告,某些Linux实现(哪个?)做的时候回落到缓冲I/O EAGAIN分配写入.

2004年的Linux Scalability Effort标题为"内核异步I/O(AIO)支持",列出了一些有用的东西以及与Linux AIO不兼容的东西(有点陈旧但是快速参考).

有关:

Linux AIO:扩展性差

io_submit()会阻塞,直到完成上一个操作

在linux上缓冲异步文件I/O(但坚持明确谈论Linux内核AIO的位)

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



2> Niall Dougla..:

我在这里作为提议的Boost.AFIO的作者发言.

首先,Linux的KAIO(io_submit)几乎总是堵,除非O_DIRECT已打开,并且不需要任何程度的分配,如果O_DIRECT是你需要阅读和写作上的4K对齐边界4Kb的倍数,否则将强制设备进行读取-modify写.因此,除非您将应用程序重新架构为O_DIRECT且4Kb对齐i/o友好,否则您将无法获得Linux KAIO.

其次,永远不要在写入期间扩展输出文件,强制扩展分配并可能强制元数据刷新.而是将文件的最大范围分配给某个适当大的值,并保留文件末尾的内部原子计数器.这应该将问题简化为仅限于ext4批量和懒惰的分配 - 更重要的是,你不会强制元数据刷新.这应该意味着ext4上的KAIO大部分时间都是异步的,但不可预测的是会同步,因为它会延迟对期刊的延迟分配.

第三,我可能会接近你的问题的方法是使用原子的append(O_APPEND)没有O_DIRECT也不O_SYNC,所以你要做的就是追加更新内核的页面缓存日益增长文件,该文件是非常快和并发安全.然后,您不时地收集垃圾收集日志文件中的哪些数据是陈旧的,并且可以使用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解决方案的领域.作为一整天都在做这些事情的人,我强烈建议你尽可能避免使用它们,归档系统是古怪和奇怪行为的恶魔坑.将永无止境的调试留给其他人.

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有