大部分系统调用都处理I / O,因为大多数应用程序都是这样做的。 对于网络I / O,我们拥有 epoll一系列syscall,它们为我们提供了相当快的性能。 但是在文件系统I / O部门中,有点缺乏。 我们已经有 async_io一段时间了,但是除了少量的利基应用程序之外,它并不是非常有益。 主要原因是它仅在使用 打开文件时才起作用 O_DIRECT标志 。 这将使内核绕过所有操作系统缓存,并尝试直接在设备之间进行读写。 当我们试图使事情进展很快时,这不是执行I / O的好方法。 在缓冲模式下,它将同步运行。
All that is changing slowly because now we have a brand new interface to perform I/O with the kernel: io_uring。
周围有很多嗡嗡声。 没错,因为它为我们提供了一个与内核进行交互的全新模型。 让我们深入研究它,并尝试了解它是什么以及它如何解决问题。 然后,我们将使用Go来构建一个小型演示应用程序来使用它。
io_uring简介
要将请求推送到SQ,我们需要创建一个提交队列条目(SQE)。 假设我们要读取文件。 略过许多细节,SQE基本上将包含:
操作码 :描述要进行的系统调用的操作码。 由于我们对读取文件感兴趣,因此我们将使用 的 readv映射到操作码 系统调用 IORING_OP_READV。
标志 :这些是可以随任何请求传递的修饰符。 我们稍后会解决。
Fd :我们要读取的文件的文件描述符。
地址 :对于我们的 readv调用,它将创建一个缓冲区(或向量)数组以将数据读入其中。 因此,地址字段包含该数组的地址。
Length :向量数组的长度。
用户数据 :一个标识符,用于将我们的请求从完成队列中移出。 请记住,不能保证完成结果的顺序与SQE相同。 那会破坏使用异步API的全部目的。 因此,我们需要一些东西来识别我们提出的请求。 这达到了目的。 通常,这是指向一些保存有请求元数据的结构的指针。
在完成方面,我们从CQ获得完成队列事件(CQE)。 这是一个非常简单的结构,其中包含:
结果 : 的返回值 readvsyscall 。 如果成功,它将读取字节数。 否则,它将具有错误代码。
用户数据 :我们在SQE中传递的标识符。
这里只需要注意一个重要的细节:SQ和CQ在用户和内核之间共享。 但是,尽管CQ实际上包含CQE,但对于SQ而言却有所不同。 它本质上是一个间接层,其中SQ数组中的索引值实际上包含保存SQE项的实际数组的索引。 这对于某些在内部结构中具有提交请求的应用程序很有用,因此允许它们在一个操作中提交多个请求,从本质上简化了 的采用 io_uringAPI 。
https://studygolang.com/articles/31360
https://bbs.huaweicloud.com/blogs/204127
https://github.com/go-rod/rod
https://beta.pkg.go.dev/net/http
https://gocn.vip/topics/11159
https://johnstarich.medium.com/how-to-compile-code-in-the-browser-with-webassembly-b59ffd452c2b
https://www.cncf.io/blog/2020/10/29/kubernetes-1-19-the-future-of-traffic-ingress-and-routing/
https://minikube.sigs.k8s.io/docs/start/