linux异步IO:io_uring

为了改善posix aio目前存在的问题,新的异步IO驱动:io_uring如何解决了posix aio的问题。围绕这个问题,本文首先介绍了异步IO的概念,然后介绍了posix aio存在的问题,最后根据io_uring的源码分析io_uring为什么比posix aio优异。

同步IO和异步IO

posix定义如下:

同步IO:导致请求进程阻塞,知道IO操作完成。
异步IO:不导致请求进程阻塞。

下图详细描绘了五种不同的I/O模型。I/O操作被看成两个部分:等待数据和拷贝数据到用户空间。

  • 阻塞式I/O:第一阶段和第二阶段均阻塞;
  • 非阻塞式I/O:第一阶段不阻塞,但是第二阶段拷贝数据阻塞;
  • I/O复用:可以同时等待多个IO事件;
  • 信号驱动式I/O:事件到来时通知用户程序,用户程序通过recv类似的系统调用读取数据;
  • 异步I/O:两个阶段均不阻塞用户进程;
    linux异步IO:io_uring_第1张图片

摘自:unix网络编程-卷1

native aio存在的问题

1.最大的问题就是只对O_DIRECT方式的IO支持异步,用户程序得自己实现I/O缓存;

  • O_DIRECT表示内核不会为I/O数据创建buffer,硬盘数据直接通过DMA传送到用户程序指定的地址。所以用户得自己管理内存和内存对齐。也就少了文件系统带的page cache。

2.Even if you satisfy all the constraints for IO to be async, it’s sometimes not. There are a number of ways that the IO submission can end up blocking - if meta data is required to perform IO, the submission will block waiting for that. For storage devices, there are a fixed number of request slots available. If those slots are currently all in use, submission will block waiting for one to become available. These uncertainties mean that applications that rely on submission always being async are still forced to offload that part.

3.每次I/O至少需要两次系统调用:submission和wait-for-completion。

  • aio的三个系统调用:io_setup、io_submit和io_getevents

io_uring源码分析

1.增加对buffered io的支持,linux aio会在用户程序submit之后被阻塞,io_uring则创建多个内核线程(2*cpu个数)去处理IO,从而防止了阻塞。

以读取为例,下面是io_read函数,具体看注释:

static ssize_t io_read(struct io_kiocb *req, const struct io_uring_sqe *sqe,
		       bool force_nonblock)
{
	...
	ret = io_prep_rw(req, sqe, force_nonblock);
	ret = io_import_iovec(req->ctx, READ, sqe, &iovec, &iter);
	ret = rw_verify_area(READ, file, &kiocb->ki_pos, iov_iter_count(&iter));
	if (!ret) {
		ssize_t ret2;
		/* Catch -EAGAIN return for forced non-blocking submission */
		ret2 = call_read_iter(file, kiocb, &iter);
		if (!force_nonblock || ret2 != -EAGAIN)
			io_rw_done(kiocb, ret2);			// linux aio会在这里等带执行完毕
		else
			ret = -EAGAIN;						// io_uring则直接返回
	}
	return ret;
}

3.减少系统调用次数,io_uring中内核和用户程序共享三块内存,分别是:SQ ring、CQ ring 和 sqe array。采用producer和consumer模型,大大的降低了系统调用的次数。

你可能感兴趣的:(linux)