linux aio linux支持aio吗

今天给各位分享linux aio的知识,其中也会对linux支持aio吗进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

linux下的异步io(aio)是否已成熟

io uring成为 Linux异步 IO的首选,当前版本已成熟稳定,但需注意在 5.12以前的内核中使用 io uring需调整 locked memory limit(RLIMIT_MEMLOCK)。libaio虽然作为古代 Linux的异步 IO解决方案,仅支持 direct IO操作。而 posix aio,作为 Glibc中的实现,自 1999年 Glibc-2.1版本以来就已支持,其内部使用线程池进行操作,导致性能有所牺牲,并且该实现中存在已知 bug。

MyTopling是一个基于 ToplingDB的 MySQL分叉,旨在复用 MyRocks的成果,而 ToplingDB又是基于 RocksDB的改进。在 ToplingDB的底层库 topling-zip中,通过 fiber+ io uring实现了高效的 MultiGet IO并发,为 MyTopling的 MRR(Multi Range Read)提供了强大的支撑。尽管 io uring已经存在数年,但在实际应用中仍有许多旧内核未更新至支持 io uring的版本,故 posix aio成为了这些环境下的替代选择。

posix aio最初定义于 POSIX.1-2001标准,支持多变体,其在 Glibc中的实现从 1999年 Glibc-2.1版本开始,一直沿用至今,其核心使用线程池结构。在 topling-zip的早期阶段,虽然支持 posix aio,但实际应用中并未采用。MyTopling中则将 posix aio整合,测试结果显示性能略逊于 io uring,但在其他方面一切正常。

在 CentOS 7.3系统上,直接使用 MyTopling进行测试时,遇到了问题,表现为系统崩溃且崩溃现场信息混乱。在排查过程中,发现 glibc的线程池最终调用的是 pread函数,而 pread函数本身并未出现问题。因此,问题最有可能出现在 glibc的 posix aio实现上,尽管该实现自 1999年以来就已存在,与标准发布时间相隔数年,但考虑到该实现的长时间稳定运行,该 bug应该已经被修复。

在深入分析和优化代码时,发现 posix aio的处理流程与 io uring和 Linux native aio存在差异,前者采用 submit→ wait→ reap模型,而后者则使用就地 submit→ poll。为了提升代码的对称性和美观性,决定将 posix aio的实现统一为 submit→ wait→ reap模型,这一改动不仅符合代码美学,还意外地解决了崩溃问题。在这一改动中,glibc在 aio_read后调用 aio_suspend,进而设置正确的 aio_error,使得系统能正确地处理并发 IO操作。

总结,经过深入分析和代码优化,发现 centos 7.3中的 glibc-2.17实现中,在 aio_read后并未立即设置 EINPROGRESS,而是在后续操作中设置。这种行为导致用户代码错误地认为 IO操作已完成,但实际上 IO未执行,随后使用了已释放的缓冲区,导致系统崩溃。在对代码进行优化后,通过在 aio_read后调用 aio_suspend设置正确的 aio_error,解决了这个问题,使得系统能正确地处理并发 IO操作。

进一步推测,在 glibc-2.17之后的某个版本中,该 bug被修复,使得在 aio_read后直接设置 EINPROGRESS,从而避免了调用 aio_suspend的必要性。这说明在后续版本中,glibc的 posix aio实现已经进行了优化,提高了系统的稳定性和可靠性。

Linux 文件 I/O 进化史(三):Direct I/O 和 Linux AIO

Direct I/O方式在Linux中提供了一种绕过 page cache读写文件的途径,适用于数据库等自我缓存应用。在打开文件时通过增加 O_DIRECT标志启用此功能。然而,使用Direct I/O时,需要确保内存地址、每次读写数据的大小以及文件的 offset都与底层设备的逻辑块大小对齐,通常是 512字节。若不满足对齐要求,系统会报“EINVAL”(无效参数)错误。Linux 2.6.0版本起,逻辑块大小可通过 ioctl(2) BLKSSZGET操作或 shell命令“blockdev--getss”来获取。直接 I/O与数据持久化之间,使用 buffered I/O写入的数据实际上只到达 page cache,等待内核线程周期性刷新至持久化存储,或通过 fsync手动刷新。理论上,直接 I/O的数据应直接达到持久化存储,但文件的重要元数据如大小仍需经过内核缓存。MySQL提供了 O_DIRECT_NO_FSYNC参数,允许在需要时才进行 fsync,仅对数据本身有效。Linux AIO接口是为了应对同步 I/O在高并发读写时性能不佳的问题而引入的,它支持异步文件 I/O,但仅适用于使用 O_DIRECT方式读写文件。Linux AIO的流程包括创建 aio_request结构体、发起 I/O操作以及通过 aio_error、aio_nbytes和 aio_current函数检查操作状态。Linux AIO一直在不断改进,但目前仍然存在不足,特别是在支持的直接 I/O方面。为了彻底解决这个问题,Linux 5.1引入了全新的异步 I/O接口 io_uring,旨在解决 Linux下的异步 I/O问题。

Linux异步IO:AIO教程(libaio)

深入探索Linux异步IO(AIO):libaio教程的精髓

Linux AIO(Asynchronous I/O)是一种提高文件I/O性能的关键技术,它通过异步操作减少磁盘I/O对CPU的占用,提升系统响应速度。AIO的核心流程包括创建IO上下文(io_context_t)、提交请求并获取事件。io_context_t结构包含共享完成队列,通过io_setup初始化,io_destroy负责销毁。AIO的核心数据结构,如io_callback_data(iocb),在io_submit中扮演重要角色,io_prep_pread/v和io_prep_write用于初始化操作,如异步写入(io_prep_write)处理并行写入。

io_prep_pwritev用于批量异步写入,通过io_submit提交,它允许一次性处理多个IO请求。注意,io_submit批量操作可能影响性能和CPU使用,出现EAGAIN错误时需要谨慎处理。

io_prep_pread则用于预读,同样依赖io_submit进行提交,为高性能读取提供了便利。但是,如果元数据不在内存,io_submit可能导致阻塞,不支持某些文件系统放大写入,这就需要考虑多线程策略来优化。

处理AIO操作的结果,通过io_event对象获取,其中包括data、obj和res字段,io_getevents函数根据ctx_id、min_nr、nr和timeout参数来确定行为。min_nr参数影响阻塞或轮询策略,而nr值则影响性能和内存消耗,过大的nr可能导致性能瓶颈。

AIO的局限性在于,它在某些场景下可能引起阻塞,而且不是所有文件系统都支持。例如,ext4文件系统仅部分支持AIO。为了提高并行性和降低锁竞争,可以使用多个io_context_t,通过哈希线程和文件地址进行管理。POSIX AIO提供了一种替代方式,利用线程池实现异步IO,但线程开销可能影响性能。

在代码实现层面,例如Daniel Ehrenberg的示例,我们看到如何创建AIORequest子类,如AIOReadRequest和AIOWriteRequest,这些类在io_context_t上下文中提交读写请求,并在完成后处理结果。AIOAdder类负责初始化,读写操作的提交,以及事件的处理和剩余请求的收尾。

在性能考量方面,io_submit影响文件系统操作,而io_getevents负责处理完成事件,确保I/O操作的高效完成。当满足预期条件,如计算的总和等于预期值(FLAGS_file_size*(FLAGS_file_size- 1))/ 2时,整个异步IO过程才宣告结束。最后,整个程序通过main函数启动,完成异步读写后返回计算结果。

总结,Linux AIO是提升文件系统性能的重要工具,但需要根据具体应用场景和系统特性进行优化,以达到最佳的并发性和资源利用效率。在实际操作中,结合适当的策略和配置,AIO可以显著提升系统性能,降低CPU占用。

阅读剩余
THE END