文件系统与异步操作异步IO那些破事

为什么想起写这篇文章前面这篇文章提到,旧的 Linux AIO 只支持直接(Direct)IO,还对读写区域大小有限制,但是 Windows 上的 IOCP 就有完整的 AIO 支持。之前真的觉得 Windows 真的很牛B,但是对为什么这样一直懵懵懂懂。 直到昨天我看到了这篇讨论帖:https://news.ycombinator.com/...,他说微软的异步IO是用线程模拟的。 WTF?这个内核原生支持这么高大上的东西居然是模拟的?但是人家还拿了微软官方的文章佐证 ... so if you issue an asynchronous cached read, and the pages are not in memory, the file system driver assumes that you do not want your thread blocked and the request will be handled by a limited pool of worker threads.微软官方的说明总不会错。但为什么会这样?缓冲(Buffered)IO实现异步为什么就这么难? 还得从硬件说起回顾一下大学学的计算机硬件知识:https://www.cnblogs.com/jswan... 每个硬盘有多个盘面,每个盘面都是由一圈圈的同心圆组成的,叫做磁道(track)。每个磁道又被等比划分为若干个弧段,叫做扇区(sector)。扇区有固定的大小和个数,而且从硬盘诞生就被分配在固定位置。一般一个扇区具体的大小视总磁盘大小而定,传统上512B为一个扇区(但是也有不同)。 扇区是实际上的磁盘最小读写单位,操作系统与磁盘文件系统通信必须以扇区的整数个进行。这里的整数个不仅代表大小,而且指个体,例如你不能只读第一个扇区的后半个+第二个扇区的前半个,虽然加起来大小也是一个扇区。 直接(Direct)IO,最原始的文件IO这种扇区操作磁盘的方式就直接派生了一种文件IO方式——直接(Direct)IO,也叫裸(Raw)IO,也叫非缓存(Unbuffered)IO。在 *nix 系中对应 O_DIRECT,在 Windows 中对应 FILE_FLAG_NO_BUFFERING。 ...

June 16, 2019 · 1 min · jiezi

用-iouring-替代-epoll-实现高速-polling

前面的文章说到 io_uring 是 Linux 中最新的原生异步 I/O 实现,实际上 io_uring 也支持 polling,是良好的 epoll 替代品。 API使用 io_uring 来 poll 一个 fd 很简单。首先初始化 io_uring 对象(io_uring_queue_init),拿到 sqe(io_uring_get_sqe)是所有 io_uring 操作都必要的,前文已经介绍这里不做过多说明。拿到 sqe 之后,使用 io_uring_prep_poll_add 初始化 sqe 指针。 static inline void io_uring_prep_poll_add(struct io_uring_sqe *sqe, int fd, short poll_mask);第一个参数就是前面获得的 sqe 指针;第二个参数是你要 poll 的文件描述符;第三个是标志位,这里 io_uring 没有引入新的标志(宏),而是沿用了 poll(2) 定义的标志,如 POLLIN、POLLOUT 等。 如其他 I/O 请求一样,每个 sqe 都可以设置一个用户自己的值在里面,使用 io_uring_sqe_set_data 可以看到一次只能添加一个 poll 请求。如果有多个 fd,那么重复调用 io_uring_get_sqe 获取多个 sqe 指针分别 io_uring_prep_poll_add 即可。io_uring_get_sqe 不是系统调用不会进入内核,io_uring_prep_poll_add 则是简单的结构体参数赋值,所以没有速度问题。 ...

June 2, 2019 · 1 min · jiezi

原生的-Linux-异步文件操作iouring-尝鲜体验

Linux异步IO的历史异步IO一直是 Linux 系统的痛。Linux 很早就有 POSIX AIO 这套异步IO实现,但它是在用户空间自己开用户线程模拟的,效率极其低下。后来在 Linux 2.6 引入了真正的内核级别支持的异步IO实现(Linux aio),但是它只支持 Direct IO,只支持磁盘文件读写,而且对文件大小还有限制,总之各种麻烦。到目前为止(2019年5月),libuv 还是在用pthread+preadv的形式实现异步IO。 随着 Linux 5.1 的发布,Linux 终于有了自己好用的异步IO实现,并且支持大多数文件类型(磁盘文件、socket,管道等),这个就是本文的主角:io_uring IOCP于IO多路复用模型 epoll 不同,io_uring 的思想更类似于 Windows 上的 IOCP。用快递来举例:同步模型就是你从在电商平台下单前,就在你家楼下一直等,直到快递公司把货送到楼下,你再把东西带上楼。epoll 类似于你下单,快递公司送到楼下,通知你可以去楼下取货了,这时你下楼把东西带上来。虽然还是需要用户下楼取货(有一段同步读写的时间),但是由于不需要等快递在路上的时间,效率已经有非常大的提升。但是,epoll不适用于磁盘IO,因为磁盘文件总是可读的。 而 IOCP 就是一步到位,直接送货上门,连下楼取的动作都不需要。整个过程完全是非阻塞的。 io_uring 的简单使用io_uring 是一套系统调用接口,虽然总共就3个系统调用,但实际使用却非常复杂。这里直接介绍封装过便于用户使用的 liburing。 在尝试前请首先确认自己的 Linux 内核版本在 5.1 以上(uname -r)。liburing 需要自己编译(之后可能会被各大Linux发行版以软件包的形式收录),git clone 后直接 ./configure && sudo make install 就好了。 io_uring 结构初始化liburing 提供了自己的核心结构 io_uring,它内部封装了 io_uring 自己的文件描述符(fd)以及其他与内核通信所需变量。 struct io_uring { struct io_uring_sq sq; struct io_uring_cq cq; int ring_fd;};使用之前需要先初始化,使用 io_uring_queue_init 初始化此结构。 ...

May 27, 2019 · 2 min · jiezi