最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

一文圖解原理|Linux I/O 神器之 io_uring

2022-11-14 15:46 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

io_uring 是 Linux 于 2019 年加入到內(nèi)核的一種新型異步 I/O 模型,io_uring 主要為了解決 原生AIO(Native AIO) 存在的一些不足之處。下面介紹一下原生 AIO 的不足之處:

  • 系統(tǒng)調(diào)用開(kāi)銷(xiāo)大 :提交 I/O 操作和獲取 I/O 操作的結(jié)果都需要通過(guò)系統(tǒng)調(diào)用完成,而觸發(fā)系統(tǒng)調(diào)用時(shí),需求進(jìn)行上下文切換。在高 IOPS(Input/Output Per Second)的情況下,進(jìn)行上下文切換也會(huì)消耗大量的CPU時(shí)間。

  • 僅支持 Direct I/O(直接I/O) :在使用原生 AIO 的時(shí)候,只能指定 O_DIRECT 標(biāo)識(shí)位(直接 I/O),不能借助文件系統(tǒng)的頁(yè)緩存(page cache)來(lái)緩存當(dāng)前的 I/O 請(qǐng)求。

  • 對(duì)數(shù)據(jù)有大小對(duì)齊限制 :所有寫(xiě)操作的數(shù)據(jù)大小必須是文件系統(tǒng)塊大小(一般為4KB)的倍數(shù),而且要與內(nèi)存頁(yè)大小對(duì)齊。

  • 數(shù)據(jù)拷貝開(kāi)銷(xiāo)大 :每個(gè) I/O 提交需要拷貝 64+8 字節(jié),每個(gè) I/O 完成結(jié)果需要拷貝 32 字節(jié),總共 104 字節(jié)的拷貝。這個(gè)拷貝開(kāi)銷(xiāo)是否可以承受,和單次 I/O 大小有關(guān):如果需要發(fā)送的 I/O 本身就很大,相較之下,這點(diǎn)消耗可以忽略。而在大量小 I/O 的場(chǎng)景下,這樣的拷貝影響比較大。

鑒于原生 AIO 存在這么多不足之處,于是乎 Jens Axboe(io_uring 作者)就開(kāi)發(fā)出一套全新的異步 I/O 接口來(lái)解決這些問(wèn)題。

既然 io_uring 這么優(yōu)秀,我們就來(lái)學(xué)習(xí)一下其先進(jìn)思想吧!下面將會(huì)介紹 io_uring 的原理。io_uring 的出現(xiàn)就是為了解決上面的問(wèn)題,我們來(lái)看看 io_uring 是怎么處理的。

1. 減少系統(tǒng)調(diào)用

由于調(diào)用系統(tǒng)調(diào)用時(shí),會(huì)從用戶(hù)態(tài)切換到內(nèi)核態(tài),從而進(jìn)行上下文切換,而上下文切換會(huì)消耗一定的 CPU 時(shí)間。

使用 read() 和 write() 等系統(tǒng)調(diào)用進(jìn)行 I/O 操作時(shí),會(huì)從用戶(hù)態(tài)嵌入到內(nèi)核態(tài),如下圖所示:


io_uring 為了減少或者摒棄系統(tǒng)調(diào)用,采用了用戶(hù)態(tài)與內(nèi)核態(tài) 共享內(nèi)存 的方式來(lái)通信。如下圖所示:


用戶(hù)進(jìn)程可以向 共享內(nèi)存 提交要發(fā)起的 I/O 操作,而內(nèi)核線(xiàn)程可以從 共享內(nèi)存 中讀取 I/O 操作,并且進(jìn)行相關(guān)的 I/O 操作。

用戶(hù)態(tài)對(duì)共享內(nèi)存進(jìn)行讀寫(xiě)操作是不需要使用系統(tǒng)調(diào)用的,所以不會(huì)發(fā)生上下文切換的情況。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺(jué)得比較好的學(xué)習(xí)書(shū)籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書(shū)、實(shí)戰(zhàn)項(xiàng)目及代碼)??


2. 提交隊(duì)列與完成隊(duì)列

前面介紹過(guò),io_uring 通過(guò)用戶(hù)態(tài)與內(nèi)核態(tài)共享內(nèi)存的方式,來(lái)免去了使用系統(tǒng)調(diào)用發(fā)起 I/O 操作的過(guò)程。

io_uring 主要?jiǎng)?chuàng)建了 3 塊共享內(nèi)存:

  • 提交隊(duì)列(Submission Queue, SQ) :一整塊連續(xù)的內(nèi)存空間存儲(chǔ)的環(huán)形隊(duì)列,用于存放將執(zhí)行 I/O 操作的數(shù)據(jù)(指向提交隊(duì)列項(xiàng)數(shù)組的索引)。

  • 完成隊(duì)列(Completion Queue, CQ) :一整塊連續(xù)的內(nèi)存空間存儲(chǔ)的環(huán)形隊(duì)列,用于存放 I/O 操作完成后返回的結(jié)果。

  • 提交隊(duì)列項(xiàng)數(shù)組(Submission Queue Entry,SQE) :提交隊(duì)列中的一項(xiàng)。

它們之間的關(guān)系如下圖所示:


提交隊(duì)列

在內(nèi)核中,使用 io_sq_ring 結(jié)構(gòu)來(lái)表示 提交隊(duì)列,其定義如下:

io_sq_ring 結(jié)構(gòu)各個(gè)字段的含義如下:

  • head :環(huán)形隊(duì)列的頭指針。

  • tail :環(huán)形隊(duì)列的尾指針。

  • ring_entries :隊(duì)列中已存在的 I/O 操作項(xiàng)總數(shù)。

  • array :環(huán)形隊(duì)列數(shù)組,指向提交隊(duì)列項(xiàng)數(shù)組的索引。

io_sq_ring 的結(jié)構(gòu)圖如下所示:


內(nèi)核會(huì)將 io_sq_ring 結(jié)構(gòu)映射到應(yīng)用程序的內(nèi)存空間,這樣應(yīng)用程序與內(nèi)核都能操作 io_sq_ring 結(jié)構(gòu)。應(yīng)用程序可以直接向 io_sq_ring 結(jié)構(gòu)的環(huán)形隊(duì)列中提交 I/O 操作,而不用通過(guò)系統(tǒng)調(diào)用來(lái)提交,從而避免了上下文切換的發(fā)生。

而內(nèi)核線(xiàn)程可以通過(guò)從 io_sq_ring 結(jié)構(gòu)的環(huán)形隊(duì)列中獲取到要進(jìn)行的 I/O 操作,并且發(fā)起 I/O 請(qǐng)求。

提交隊(duì)列項(xiàng)

從上面的分析可知,io_sq_ring 結(jié)構(gòu) array 字段只是一個(gè)整形類(lèi)型的數(shù)組,用于存儲(chǔ)指向 提交隊(duì)列項(xiàng)數(shù)組 的的索引。在內(nèi)核中,提交隊(duì)列項(xiàng) 使用 io_uring_sqe 結(jié)構(gòu)表示,其定義如下:

下面介紹一下 io_uring_sqe 結(jié)構(gòu)各個(gè)字段的作用:

  • opcode :I/O 操作碼,主要用于表示當(dāng)前的 I/O 操作是什么類(lèi)型,如讀、寫(xiě)或者同步等。

  • ioprio :I/O 操作的優(yōu)先級(jí),可以通過(guò)此字段來(lái)把一些重要的 I/O 操作提前執(zhí)行。

  • fd :I/O 操作對(duì)應(yīng)的文件句柄。

  • off :當(dāng)前 I/O 操作的偏移量。

  • addr :用于指向當(dāng)前 I/O 操作所關(guān)聯(lián)的內(nèi)存地址。如寫(xiě)操作,指向的是要寫(xiě)入到文件的內(nèi)容的內(nèi)存地址。

  • len :表示當(dāng)前 I/O 操作的數(shù)據(jù)長(zhǎng)度。

當(dāng)用戶(hù)調(diào)用 io_uring_setup() 系統(tǒng)調(diào)用創(chuàng)建一個(gè) io_ring 對(duì)象時(shí),內(nèi)核將會(huì)創(chuàng)建一個(gè)類(lèi)型為 io_uring_sqe 結(jié)構(gòu)的數(shù)組。內(nèi)核也會(huì)將此數(shù)組映射到應(yīng)用程序的內(nèi)存空間,這樣應(yīng)用程序就可以直接操作這個(gè)數(shù)組。

應(yīng)用程序提交 I/O 操作時(shí),先要從 提交隊(duì)列項(xiàng)數(shù)組 中獲取一個(gè)空閑的項(xiàng),然后向此項(xiàng)填充數(shù)據(jù)(如 I/O 操作碼、要進(jìn)行 I/O 操作的文件句柄等),然后將此項(xiàng)在 提交隊(duì)列項(xiàng)數(shù)組 的索引寫(xiě)入 提交隊(duì)列 中。

liburing 代碼庫(kù)已經(jīng)把這些繁瑣的操作封裝成友好的 API,用戶(hù)只需要直接調(diào)用這些 API 來(lái)進(jìn)行操作即可。 關(guān)于 liburing 代碼庫(kù)的使用,可以參考其使用手冊(cè),本文不作詳細(xì)介紹。

完成隊(duì)列

當(dāng)內(nèi)核完成 I/O 操作后,會(huì)將 I/O 操作的結(jié)果保存到 完成隊(duì)列 中。內(nèi)核使用 io_cq_ring 結(jié)構(gòu)來(lái)表示,其定義如下:

完成隊(duì)列 與 提交隊(duì)列 類(lèi)似,也是一個(gè)環(huán)形隊(duì)列。下面介紹一下 io_cq_ring 結(jié)構(gòu)各個(gè)字段的作用:

  • head :環(huán)形隊(duì)列的頭指針。

  • tail :環(huán)形隊(duì)列的尾指針。

  • ring_entries :已完成的 I/O 操作總數(shù)。

  • cqes :用于保存 I/O 操作結(jié)果的環(huán)形隊(duì)列數(shù)組,其元素類(lèi)型為 io_uring_cqe 結(jié)構(gòu)。

io_cq_ring 的結(jié)構(gòu)圖如下所示:


內(nèi)核也會(huì)將 完成隊(duì)列 映射到應(yīng)用程序的內(nèi)存空間,這樣應(yīng)用程序就可以通過(guò)讀取完成隊(duì)列來(lái)獲取 I/O 操作的結(jié)果。而不用通過(guò)使用系統(tǒng)調(diào)用來(lái)獲取,從而避免了不必要的上下文切換。

3. SQ 線(xiàn)程

前面介紹了 io_uring 怎么通過(guò)共享 提交隊(duì)列 和 完成隊(duì)列 來(lái)避免不必要的系統(tǒng)調(diào)用,但應(yīng)用程序?qū)?I/O 操作提交到 提交隊(duì)列 后,內(nèi)核什么時(shí)候從 提交隊(duì)列 中獲取要進(jìn)行的 I/O 操作,并且發(fā)起 I/O 請(qǐng)求呢?

當(dāng)用戶(hù)使用 SQPOLL 模式(指定了 IORING_SETUP_SQPOLL 標(biāo)志)創(chuàng)建 io_uring 時(shí),內(nèi)核將會(huì)創(chuàng)建一個(gè)名為 io_uring-sq 的內(nèi)核線(xiàn)程(稱(chēng)為 SQ 線(xiàn)程),此內(nèi)核線(xiàn)程會(huì)不斷從 提交隊(duì)列 中讀取 I/O 操作,并且發(fā)起 I/O 請(qǐng)求。

當(dāng) I/O 請(qǐng)求完成以后,SQ 線(xiàn)程將會(huì)把 I/O 操作的結(jié)果寫(xiě)入到 完成隊(duì)列 中,應(yīng)用程序就可以從 完成隊(duì)列 中讀取 I/O 操作的結(jié)果。

如下圖所示:



我們簡(jiǎn)單總結(jié)下 io_uring 的操作步驟:

  • 第一步 :應(yīng)用程序通過(guò)向 io_uring 的 提交隊(duì)列 提交 I/O 操作。

  • 第二步 :SQ內(nèi)核線(xiàn)程從 提交隊(duì)列 中讀取 I/O 操作。

  • 第三步 :SQ內(nèi)核線(xiàn)程發(fā)起 I/O 請(qǐng)求。

  • 第四步 :I/O 請(qǐng)求完成后,SQ內(nèi)核線(xiàn)程會(huì)將 I/O 請(qǐng)求的結(jié)果寫(xiě)入到 io_uring 的 完成隊(duì)列 中。

  • 第五步 :應(yīng)用程序可以通過(guò)從 完成隊(duì)列 中讀取到 I/O 操作的結(jié)果。

4. 總結(jié)

io_uring 主要通過(guò)用戶(hù)態(tài)與內(nèi)核態(tài)共享內(nèi)存的途徑,來(lái)摒棄使用系統(tǒng)調(diào)用來(lái)提交 I/O 操作和獲取 I/O 操作的結(jié)果,從而避免了上下文切換的情況。另外,由于用戶(hù)態(tài)進(jìn)程與內(nèi)核態(tài)線(xiàn)程通過(guò)共享內(nèi)存的方式通信,從而避免了內(nèi)存拷貝的過(guò)程,提升了 I/O 操作的性能。

所以,io_uring 主要通過(guò)兩個(gè)優(yōu)化點(diǎn)來(lái)提升 I/O 操作的性能:

  • 摒棄使用系統(tǒng)調(diào)用來(lái)提交 I/O 操作和獲取 I/O 操作結(jié)果。

  • 減少用戶(hù)態(tài)與內(nèi)核態(tài)之間的內(nèi)存拷貝。


原文作者:Linux內(nèi)核那些事



一文圖解原理|Linux I/O 神器之 io_uring的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
阿荣旗| 晴隆县| 金昌市| 大宁县| 饶阳县| 龙里县| 汝州市| 丰原市| 育儿| 吉林市| 威信县| 咸阳市| 金昌市| 珠海市| 永登县| 九龙城区| 满城县| 和平区| 巴彦县| 墨玉县| 阿勒泰市| 西藏| 洱源县| 西和县| 广德县| 云南省| 海淀区| 陇西县| 安阳市| 洛浦县| 黑龙江省| 桑日县| 曲麻莱县| 石渠县| 虞城县| 吴江市| 全椒县| 兴和县| 乐山市| 罗甸县| 兴文县|