提交成功
返回列表

面向未来的Linux异步IO引擎:io-uring

2019 / 11 / 22
1

在SSD测试中,往往选择异步IO引擎进行测试,也就是在fio命令或者脚本中加上ioengine= libaio,这是因为异步IO模式的效率要远高于同步模式,尤其是测试NVMe SSD时,这样的测试结果是非常明显的。2019年,Linux Kernel走进了5.x时代,众多新特性中与存储密切相关的就是IO引擎——io_uring。其主要作者是Linux块设备层维护者Jens Axboe(他也是前文提到的fio的作者)。

 

Jens Axboe发布了一篇名为《Efficient IO with io_uring》文档,对io_uring进行了介绍。首先,他简述了Linux的IO发展历程,总结了当前Linux的原生异步IO接口(AIO)的局限,描述了io_uring易用、效率高等优势,并对io_uring的实现进行了概述。

 

 

io_uring的显著优势 

 

a. io_uring 通过 单一producer& 单一consumer的ring buffer数据结构,实现了用户态和内核态无锁共享;

b. 同时,io_uring的CQ与SQ通过 mmap() 共享数据;减少了不必要的数据拷贝overhead;

c. IO submission 数据结构设计的十分有前瞻性,为 E2E data protection等企业级需求预留了字段;非常的user-friendly;

d. io_uring 代码由 Jens Axboe 和 nvme 驱动维护者 Christoph Helwig 合作完成, 可以说是从立案阶段就有意识的与nvme驱动层紧密联动;与nvme高度匹配。

 

我们在Centos7.6上装了一个5.3.8版本的Kernel,并对一块U.2接口,7.68TB的 PBlaze5 910 NVMe SSD进行测试。测试工具是fio3.16,测试过程中主要对比io_uring和libaio两种IO 引擎的性能及QoS等指标。文章最后部分将借助perf工具等工具对io_uring的调度机制进行分析。

 

4k随机写(延时)——libaio、io_uring及polling模式下的io_uring

 

 

在同样的硬件平台上;仅仅更换IO引擎, 就可以带来0.83微秒,8% 的latency改善,应该说对于延时敏感的应用,是十分宝贵而难得的。下图是polling模式下的io_uring的最终log,从这张图我们可以看到不仅是平均写延时降低,更值得注意的是99.9%和99.99%的QoS有了更好的表现。

 

 

QoS的改善在随机读场景下表现更加明显。下图对比了io_uring和libaio的4k随机读测试结果(numjobs=1 iodepth=1)。

 

 

从这次测试的结果对比可以计算得出,io_uring延时百分点中99.9%、99.99%、99.999%(5个9的实验结果有一定的随机性,在此仅作参考)三个值分别比libaio降低了17%、77%和74%,io_uring带来的性能和服务质量的优势显而易见。

 

此外,测试数据显示4k随机读/写的IOPS也均有提升,值得一提的是,使用io_uring,可以以更少的资源消耗,达到同样的性能,这为今后更高速的SSD发挥性能潜力留足了空间。

 

这里我们对io_uring在性能上的优势进行了简单的验证,回到上文中提到的《Efficient IO with io_uring》文档,除了性能相关的效率(Efficiency)和性能可扩展性(Scalability),易用性是io_uring的一大亮点,接下来我们就分两步对io_uring的内部实现和调用做一个说明。

 

第一步我们借助 perf工具对fio (io_uring 引擎, 随机写)采集10秒,从生成的火焰图来看,fio调用主要有两类,一类是下图左侧部分,以io_poll 一类函数为代表;主要表现了其在内核态对IO请求进行poll的调用(下图左侧部分)。

 

 

而另一方面, 从右侧 io_submit_sqe部分的调用来看;其充分利用了blk-mq; blk_flush等优化;相比传统的block layer实现了对nvme更高效的调用。将上图右侧部分放大如下图。

 

 

火焰图让我们直观的看到了io_uring调用的分布,io_uring的主干代码超过3000行,对于非内核开发的读者看起来可能略微复杂,所以我们进一步使用能够追踪内核调用信息的ftrace功能进行实验,采用kernel tracing的方式,追踪一次完整的io_uring 的IO 堆栈。希望一窥其中奥妙。而使用ftrace可以追踪到具体的内核调用信息。下面就通过一段ftrace抓取的信息看io_uring的完整调用关系。

 

下面是节选的部分追踪轨迹:

 

 

 

可以看出io_uring的调用关系:

 

结合这段trace 读起io_uring的相关代码 事半功倍!

 

一定程度上,io_uring代表了Linux kernel block层的未来,至少从中我们可以看出一些block层进化的方向,而且我们看到io_uring也在快速发展,相信未来io_uring会更加的高效、易用,并拥有更加丰富的功能和更强的扩展能力。这让我们充满期待,NVMe的存储时代需要一个属于自己的高速IO引擎。

 

 

相关阅读

 

1.https://kernel-recipes.org/en/2019/talks/faster-io-through-io_uring

2.https://kernel.dk/io_uring.pdf

3.https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/fs/io_uring.c?h=v5.3.8