Linux 内核如何处理异步 I/O (AIO) 请求?

How does the Linux kernel handle Asynchronous I/O (AIO) requests?

我正在编写一个 C 程序,通过直接从原始块设备文件读取数据来从 SSD 驱动器读取数据。

我正在试用Linux一体机(我说的是Linux一体机API,即linuxaio.h提供的功能,比如io_submit(...) 等,而不是 POSIX AIO API)。我使用 O_DIRECT 标志打开块设备文件,并确保我写入的缓冲区与块大小对齐。

我注意到 Linux AIO 比使用带有 O_DIRECT 标志的同步 IO 要快得多。

最让我惊讶的是,通过使用 Linux AIO 发出许多每次几 KB 的小随机读取所实现的吞吐量甚至比进行大量(顺序)读取所实现的吞吐量高得多使用同步 I/O 和 O_DIRECT.

的几个 MB

所以,我想知道:为什么 Linux AIO 的性能比同步 I/O 更好?使用AIO时内核做了什么?内核是否执行请求重新排序?使用 Linux AIO 是否比使用同步 I/O 导致更高的 CPU 利用率?

非常感谢

简答: AIO 实现很可能是 "faster",因为它并行提交多个 IOs,而同步实现有零个或一个 I/O 正在运行。它与写入内存或内核 I/O 路径具有同步 I/Os.

的额外开销无关。

您可以使用 iostat -x -d 1 进行检查。查看 avgqu-sz(平均队列大小 = 飞行中的平均数量 I/Os)和 %util(利用率= 设备至少收到一个 I/O 的时间百分比。

长答案:

  • "faster" 的概念在谈论 I/O 时很棘手。 "faster" 是否意味着更高的带宽?还是延迟更低?或者给定请求大小的带宽?或者给定队列深度的延迟?还是延迟、带宽、请求大小、队列深度和许多其他参数或工作负载的组合?我在这里假设您正在考虑 throughput/bandwidth,但是,最好记住存储设备的性能不是单一维度指标。

  • SSD 是高度并行的设备。一个SSD是由很多flash chip组成的,每个chip有多个die可以read/write独立。 SSD 利用这一点并并行执行许多 I/Os,而响应时间没有明显增加。因此,就吞吐量而言,SSD 看到的并发 I/O 数量非常重要。

  • 让我们了解当线程提交同步 I/O 时会发生什么:a) 线程花费一些 CPU 周期准备 I/O 请求(生成数据,计算偏移量,将数据复制到缓冲区等),b)执行系统调用(例如 pread()),执行传递给内核 space,然后线程阻塞,c)I/O 请求由内核处理并遍历各种内核 I/O 层,d) I/O 请求被提交给设备并遍历互连(例如 PCIe),e) I/O 请求是由 SSD 固件处理,f) 实际读取命令发送到相应的闪存芯片,g) SSD 控制器等待数据,h) SSD 控制器从闪存芯片获取数据并通过互连发送。此时数据离开 SSD,阶段 e-a) 发生相反的情况。

  • 如您所见,同步I/O进程正在与SSD打请求乒乓球。在上述的许多阶段中,实际上并没有从闪存芯片中读取数据。最重要的是,虽然您的 SSD 可以并行处理数十到数百个请求,但它在任何给定时刻最多只能处理一个请求。因此,吞吐量非常非常低,因为您实际上并没有真正使用 SSD。

  • 异步I/O有两个方面的帮助:a)它允许进程并行提交多个I/O请求(SSD有足够的工作来保持忙碌),以及b) 它允许流水线化 I/Os 通过各种处理阶段(因此将阶段延迟与吞吐量解耦)。

  • 您看到异步 I/O 比同步 I/O 快的原因是因为您比较了苹果和橘子。同步吞吐量是在给定的请求大小、低队列深度且没有流水线的情况下。异步吞吐量处于不同的请求大小、更高的队列深度和流水线。你看到的数字没有可比性

  • 大多数 I/O 密集型应用程序(即大多数应用程序,如数据库、网络服务器等)都有许多线程执行同步 I/O。尽管每个线程在任何给定时刻最多可以提交一个 I/O,但内核和 SSD 设备会看到许多可以并行处理的 I/O 请求。多个同步 I/O 请求产生与多个异步 I/O 请求相同的好处。

    异步和同步 I/O 之间的主要区别归结为 I/O 如何处理调度和编程模型。如果操作正确,异步和同步 I/O 都可以从存储设备中提取相同的内容 IOPS/throughput。