草庐IT

linux - Linux 上真的没有异步 block I/O 吗?

coder 2023-06-16 原文

考虑一个受 CPU 限制但也具有高性能 I/O 要求的应用程序。

我正在将 Linux 文件 I/O 与 Windows 进行比较,我根本看不出 epoll 将如何帮助 Linux 程序。内核会告诉我文件描述符“准备好读取”,但我仍然需要调用阻塞 read() 来获取我的数据,如果我想读取兆字节,很明显这会阻塞。

在 Windows 上,我可以创建一个设置了 OVERLAPPED 的文件句柄,然后使用非阻塞 I/O,并在 I/O 完成时得到通知,并使用来自该完成函数的数据。我不需要花费应用程序级挂钟时间来等待数据,这意味着我可以根据我的内核数精确调整线程数,并获得 100% 的 CPU 利用率。

如果我必须在 Linux 上模拟异步 I/O,那么我必须分配一些线程来执行此操作,而这些线程将花费一点时间做 CPU 的事情,并且大量时间阻塞 I/O,此外,与这些线程之间的消息传递会产生开销。因此,我要么过度订阅,要么未充分利用我的 CPU 内核。

我将 mmap() + madvise() (WILLNEED) 视为“穷人的异步 I/O”,但它仍然没有完全到达那里,因为完成后我无法收到通知 - 我有“猜测”,如果我猜测“错误”,我最终会阻塞内存访问,等待数据来自磁盘。

Linux 似乎在 io_submit 中有异步 I/O 的开始,并且它似乎也有用户空间 POSIX aio 实现,但这种方式已经有一段时间了,我知道没有人会为这些系统的关键问题提供担保, 高性能应用程序。

Windows 模型的工作原理大致如下:

  • 发出异步操作。
  • 将异步操作绑定(bind)到特定的 I/O 完成端口。
  • 等待该端口上的操作完成
  • 当 I/O 完成时,在端口上等待的线程解除阻塞,并返回对挂起的 I/O 操作的引用。

  • 步骤 1/2 通常作为一件事情完成。步骤 3/4 通常使用工作线程池完成,而不是(必须)与发出 I/O 的线程相同。这个模型有点类似于 boost::asio 提供的模型,除了 boost::asio 实际上并没有给你基于块(磁盘)的异步 I/O。

    Linux 中 epoll 的不同之处在于,在第 4 步中,还没有发生 I/O——它将第 1 步提升到第 4 步之后,如果您已经确切地知道自己需要什么,那就是“向后”。

    在编写了大量嵌入式、桌面和服务器操作系统之后,我可以说这种异步 I/O 模型对于某些类型的程序来说非常自然。它也是非常高吞吐量和低开销的。我认为这是 Linux I/O 模型在 API 级别上剩余的真正缺点之一。

    最佳答案

    (2020) 如果您使用的是 5.1 or above Linux kernel,则可以使用 io_uring interface 进行类文件 I/O 并获得出色的异步操作。
    与现有的libaio/KAIO接口(interface)相比,io_uring具有以下优点:

  • 在执行缓冲 I/O 时(而不仅仅是在执行直接 I/O 时)保留异步行为
  • 更易于使用(尤其是在使用 liburing 辅助库时)
  • 可以选择以轮询方式工作(但您需要更高的权限才能启用此模式)
  • 减少每个 I/O 的簿记空间开销
  • 由于较少的用户空间/内核系统调用模式切换而降低 CPU 开销(由于 0x2518122213341142,这些天很重要)
  • 可以预先注册文件描述符和缓冲区以节省映射/取消映射时间
  • 更快(可以实现更高的聚合吞吐量,I/O 具有更低的延迟)
  • “链接模式”可以表达 I/O 之间的依赖关系(>=5.3 内核)
  • 可以与基于套接字的 I/O 一起工作(impact of spectre/meltdown mitigations/ recvmsg() 从 >=5.3 起支持,请参阅消息中提到 0x251812421333412421334123934124124124122133412412213341142 中的支持一词
  • 支持尝试取消排队的 I/O (>=5.5)
  • 可以请求 I/O 总是从异步上下文执行,而不是当内联提交路径触发阻塞(>=5.6 内核)时仅回退到将 I/O 踢到异步上下文的默认值
  • 生长 sendmsg() (例如read(> = 5.1),write(> = 5.6),fsync(> = 5.7)和更多)
  • 更高的发展势头
  • io_uring.c's git history

  • 相比glibc的POSIX AIO,fallocate有以下优点:
  • 更快、更高效(上述更低的开销优势在这里更适用)
  • 接口(interface)是内核支持的,不使用用户空间线程池
  • 执行缓冲 I/O 时生成的数据副本较少
  • support for performing asynchronous operations beyond splice / io_uring
  • Doesn't become blocking each time the stars aren't perfectly alignedio_uring 绝对可以!

  • wrestling with signals 文档更详细地介绍了 io_uring 的好处和用法。 Glibc's POSIX AIO can't have more than one I/O in flight on a single file descriptor 文档描述了自 io_uring 成立以来添加的新功能,而 Efficient IO with io_uring 描述了 5.1 - 5.5 内核中的每一个都提供了哪些功能,以及对将要进行的内容的前瞻。185.1253 1243还有一个 What's new with io_uring ( The rapid growth of io_uring LWN article ) 由 io_uring 作者 Jens Axboe 于 2019 年底发布。最后,LWN's list of io_uring介绍了io_uring的用法。io_uring 社区可以通过 "Faster IO through io_uring" videoed presentation 访问,slides 显示 2021 年初的每日流量。
    重新“支持的recv()感部分I/O VS read()”:一个Lord of the io_uring tutorial和进一步 promise 进了5.4内核调整的行为io_uring mailing list(它看起来像您可以通过io_uring或用REQ_F_NOWAIT打开文件要求REQ_F_NOWAIT )。因此,您也可以从 IOCB_NOWAIT 获得 O_NONBLOCK 样式-“短”I/O 行为。
    使用 recv() 的软件/项目
    虽然界面很年轻(它的第一个化身于 2019 年 5 月推出),但一些开源软件正在“野外”使用 io_uring:
  • io_uring mailing list archives(也由 Jens Axboe 编写)有一个 patch went into the 5.3 kernel that will automatically retry io_uring short reads 后端(实际上它是从 2019 年 2 月在 fio-3.13 中引入的!)。两位英特尔工程师的“only automatically take care of short reads when working with "regular" files on requests that haven't set the io_uring flag ” ( fio ) 表示,当比较 0x25181223134313141414141414141414 引擎时,他们能够在一个工作负载上获得两倍的 IOPS,而在另一个工作负载上队列深度为 1 时的平均延迟不到一半。傲腾设备。
  • io_uring ioengine (!) 在 v19.04 版本中用于块设备访问(但显然这不是您通常将 SPDK 用于基准测试以外的后端)。最近,他们似乎还在 v20.04 中添加了 Improved Storage Performance Using the New Linux Kernel I/O Interface SNIA presentation ...
  • 2019 年 12 月的
  • slides,这是其 15.1.0 版本的一部分。提交作者发布了一条 github 评论,显示了一些 SPDK project added support for using io_uring(在 IOPS、带宽和延迟方面),具体取决于工作负载。
  • support for using it with sockets 在 2019 年 12 月,是其 Ceph committed an io_uring backend 的一部分。 Jens 表示 io_uring backend has some wins and losses versus the libaio backend
  • RocksDB committed an io_uring backend for MultiRead 于 2019 年 12 月。虽然作者的一些原始观点已在较新的内核中得到解决,但在撰写本文时(2021 年年中)6.7.3 release 并正在采取进一步改进的方法,并在实现之前等待
  • libaio helped to dramatically cut latency 在 2020 年 1 月,是 libev released 4.31 with an initial io_uring backend 的一部分。在“libev's author has some choice words about io_uring 's maturity ” PDF 演示文稿中,Julia Suvorova 展示了 io_uring 后端优于 io_uringio_uring 后端的 threads 后端的一个工作负载块。
  • 2020 年 2 月的
  • QEMU committed an io_uring backendQEMU 5.0 release 的一部分。在 io_uring in QEMU: high-performance disk IO for Linux Samba 邮件列表线程中,Stefan Metzmacher(提交作者)说 aio 模块能够在综合测试中将吞吐量提高 19%(与某些未指定的后端相比)。您还可以阅读 Stefan 的 Samba merged an io_uring VFS backend PDF 演示文稿,了解更改背后的一些动机。
  • Samba 4.12 release 使用它(但您还需要一个 5.6+ 内核)
  • Rust 人一直在编写包装器,使 io_uring 更容易被纯 Rust 访问。 "Linux io_uring VFS backend." 是一个有点讨论的库,作者说它们是 "Async VFS Future" 。作者在 FOSDEM 2020 上给出了 Facebook's experimental C++ libunifex ,其中包括颂扬 io_uring 优点的部分。
  • rio 只使用 io_uring 。作者 (Glauber Costa) 发表了一份名为 achieved higher throughput compared to using sync calls wrapped in threads 的文档,表明在 Optane 设备上执行顺序 I/O 时,通过仔细调整 glommio 可以获得比常规(非 io_uring)系统调用高 2.5 倍的性能。
  • presentation about his database and library 于 2020 年 10 月,是 rust library glommio 的一部分。提交作者提到性能“并不比常规的 pwrite/pread 系统调用差”。

  • 使用 io_uring 进行调查的软件
  • PostgreSQL 开发人员 Andres Freund 一直是 io_uring 改进(例如 Modern storage is plenty fast. It is the APIs that are bad )背后的插入力之一。有一个演示文稿 Gluster merged an io_uring posix xlator(请注意视频在 5 分钟之前被破坏)(Gluster 9.0 release)激发了对 PostgreSQL 更改的需求并展示了一些实验结果。他表达了 workaround to reduce for filesystem inode contention 并且似乎敏锐地意识到甚至到内核级别的工作和不工作。 2020 年 12 月,“阻塞 I/O、异步 I/O 和 io_uring”pgsql-hackers 邮件列表线程中的 "Asynchronous IO for PostgreSQL" 和提及正在进行的工作可以在 PDF 中看到。
  • 需要 5.9 内核的 hope of getting his optional io_uring support into PostgreSQL 14
  • Andres further discusses his PostgreSQL io_uring work 但项目进展缓慢
  • 2020 年 4 月的
  • https://github.com/anarazel/postgres/tree/aio(但不是系统调用)和 Netty project has an incubator repo working on io_uring support 问题概述了进一步集成它的计划
  • Tokio Rust 项目已经开发了一个概念证明 libuv has a pull request against it adding io_uring support

  • Linux 发行版支持 io_uring
  • (2020 年末)Ubuntu 18.04 的最新 HWE 启用内核是 5.4,因此可以使用 io_uring 系统调用。此发行版未预先打包 io_uring 帮助程序库,但您可以自己构建它。
  • Ubuntu 20.04 的初始内核是 5.4,因此可以使用 io_uring 系统调用。如上所述,发行版没有预先打包 liburing
  • Fedora 32 的初始内核是 5.6 它有一个打包的 io_uring 所以是 132141 133241
  • SwiftNIO added liburing support for eventing 所以可以使用 liburing 系统调用。此发行版未预先打包 io_uring 帮助程序库,但您可以自己构建它。
  • (2021 年中)RHEL 8 的默认内核 不支持 支持 io_uring。这个答案的前一个版本说错了。根据 Linux: full io_uring I/O(内容位于订阅者付费墙后面),正在将 liburing 向后移植到默认的 RHEL 8 内核。

  • 希望 io_uring 会为 Linux 带来更好的类似异步文件的 I/O 故事。
    (为了给这个答案增加一点可信度,在过去的某个时候 Jens Axboe(Linux 内核块层维护者和 io_uring 的发明者)tokio-uring :-)

    关于linux - Linux 上真的没有异步 block I/O 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13407542/

    有关linux - Linux 上真的没有异步 block I/O 吗?的更多相关文章

    1. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

      我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

    2. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

      exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

    3. ruby-on-rails - rails 目前在重启后没有安装 - 2

      我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

    4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    5. 没有类的 Ruby 方法? - 2

      大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow

    6. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

      我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

    7. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

      我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

    8. ruby - 没有类方法获取 Ruby 类名 - 2

      如何在Ruby中获取BasicObject实例的类名?例如,假设我有这个:classMyObjectSystem我怎样才能使这段代码成功?编辑:我发现Object的实例方法class被定义为returnrb_class_real(CLASS_OF(obj));。有什么方法可以从Ruby中使用它? 最佳答案 我花了一些时间研究irb并想出了这个:classBasicObjectdefclassklass=class这将为任何从BasicObject继承的对象提供一个#class您可以调用的方法。编辑评论中要求的进一步解释:假设你有对象

    9. ruby - 没有轨道的 ActiveRecord 时区 - 2

      我在非Rails项目中使用ActiveRecord。在Rails中,我可以这样做:config.time_zone='EasternTime(US&Canada)'config.active_record.default_timezone='EasternTime(US&Canada)'但如果我不使用rails,我该如何设置时区? 最佳答案 ActiveRecord::Base.default_timezone='EasternTime(US&Canada)' 关于ruby-没有轨道的A

    10. ruby-on-rails - 没有这样的文件或目录 - 用 Mini Magick 识别 - 2

      在我让另一个人重做我的前端UI之前,我的Rails应用程序运行平稳。我已经尝试解决此错误3天了。这是错误:Nosuchfileordirectory-identifyExtractedsource(aroundline#59):575859606162@post=Post.find(params[:id])authorize@postif@post.update_attributes(post_params)flash[:notice]="Postwasupdated."redirect_to[@topic,@post]else{"utf8"=>"✓","_method"=>"patc

    随机推荐