下一代異步 IO 技術解密

2020-08-29 凌雲時刻

導讀:Alibaba Cloud Linux 2 是阿里雲作業系統團隊基於開源 Linux 4.19 LTS 版本打造的一款針對雲應用場景的下一代 Linux OS 發行版。在首次推出一年後,阿里雲作業系統團隊對外正式發布了Alibaba Cloud Linux 2 LTS 版本。

作者 | 窅默


本文接上一篇《


概述

Alibaba Cloud Linux 2 是阿里雲作業系統團隊基於開源 Linux 4.19 LTS 版本打造的一款針對雲應用場景的下一代 Linux OS 發行版。在首次推出一年後,阿里雲作業系統團隊對外正式發布了Alibaba Cloud Linux 2 LTS 版本。LTS 版本的發布是一個重要的裡程碑,標誌著阿里雲作業系統團隊將為 Alibaba Cloud Linux 2 提供長期技術支持、穩定的更新和更好的服務,為 Alibaba Cloud Linux 2 的客戶提供更多保障。

上一篇我們在 Alibaba Cloud Linux 2 上對比測試了 io_uring 與 libaio 以及 SPDK,可以看到 io_uring 帶來的性能提升非常明顯。這篇文章我們詳細分析下 io_uring 的原理,以及我們在 io_uring 社區所做的工作。


io_uring原理介紹

為了從根本上解決當前 Linux aio 存在的問題和約束,io_uring 從零開始全新設計的了異步 IO 框架。其設計的主要目標如下:

  • 簡單易用,方便應用集成。
  • 可擴展,不僅僅為 block IO 使用,同樣可以用於網絡 IO。
  • 特性豐富,滿足所有應用,如 buffer io。
  • 高效,尤其是針對大部分場景的 512 字節或 4K IO。
  • 可伸縮,滿足峰值場景的性能需要。

io_uring 為了避免在提交和完成事件中的內存拷貝,設計了一對共享的 ring buffer 用於應用和內核之間的通信。其中,針對提交隊列(SQ),應用是 IO 提交的生產者(producer),內核是消費者(consumer);反過來,針對完成隊列(CQ),內核是完成事件的生產者,應用是消費者。

共享環的設計主要帶來以下 3 個好處:

  • 提交、完成請求時節省應用和內核之間的內存拷貝;
  • 使用 SQPOLL 高級特性時,應用程式無需調用系統調用;
  • 無鎖操作,用 memory ordering 實現同步。


io_uring 系統調用

io_uring 一共提供了 3 個系統調用:io_uring_setup(),io_uring_enter(),以及io_uring_register(),位於 fs/io_uring.c。

/** * io_uring_setup - setup a context for performing asynchronous I/O */int io_uring_setup(u32 entries, struct io_uring_params *p);/** * io_uring_enter - initiate and/or complete asynchronous I/O */int io_uring_enter(int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t *sig)/** * io_uring_register - register files or user buffers for asynchronous I/O */int io_uring_register(int fd, unsigned int opcode, void *arg, unsigned int nr_args)

Alibaba Cloud Linux 2 LTS 版本支持的異步操作如下,更多的特性支持持續完善中。

  • IORING_OP_NOP
    僅產生一個完成事件,除此之外沒有任何操作。
  • IORING_OP_READV / IORING_OP_WRITEV
    提交 readv() / writev() 操作,大多數場景最核心的操作。
  • IORING_OP_READ_FIXED / IORING_OP_WRITE_FIXED
    使用已註冊的 buffer 來提交 IO 操作,由於這些 buffer 已經完成映射,可以降低系統調用的開銷。
  • IORING_OP_FSYNC
    下發 fsync() 調用。
  • IORING_OP_POLL_ADD / IORING_OP_POLL_REMOVE
    使用 IORING_OP_POLL_ADD 可對一組文件描述符 (file descriptors) 執行 poll() 操作;可以使用 IORING_OP_POLL_REMOVE 顯式地取消 poll()。這種方式可以用來異步地監控一組文件描述符
  • IORING_OP_SYNC_FILE_RANGE
    執行 sync_file_range() 調用,是對 fsync() 的一個增強
  • IORING_OP_SENDMSG / IORING_OP_RECVMSG
    在 sendmsg() 和 recvmsg() 基礎上,提供異步收發網絡包功能
  • IORING_OP_TIMEOUT
    用戶態程序等待 IO 完成事件時,可以通過 IORING_OP_TIMEOUT 設置一個超時時間,類似 io_getevents(2) 的 timeout 機制


io_uring 用戶態庫 liburing

為了簡化使用,原作者 Jens 開發了一套 liburing 庫,用戶無需了解諸多 io_uring 細節便可以使用起來,如無需關心 memory barrier,以及 ring buffer 的管理等。相關接口在頭文件 /usr/include/liburing.h 中定義。

Alibaba Cloud Linux 2 LTS 提供了 liburing 和 liburing-devel 包供用戶安裝。

sodo yum install liburing liburing-devel

基於 liburing 的一個 HelloWorld 示例如下:

include <fcntl.h>include <stdio.h>define ENTRIES 4int main(int argc, char *argv[]){ struct io_uring ring; struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; struct iovec iov = { .iov_base = &34;, .iov_len = strlen(&34;), }; int fd, ret; if (argc != 2) { printf(&34;, argv[0]); return 1; } /* setup io_uring and do mmap */ ret = io_uring_queue_init(ENTRIES, &ring, 0); if (ret < 0) { printf(&34;, strerror(-ret)); return 1; } fd = open(&34;, O_WRONLY | O_CREAT); if (fd < 0) { printf(&34;); ret = 1; goto exit; } /* get an sqe and fill in a WRITEV operation */ sqe = io_uring_get_sqe(&ring); if (!sqe) { printf(&34;); ret = 1; goto out; } io_uring_prep_writev(sqe, fd, &iov, 1, 0); /* tell the kernel we have an sqe ready for consumption */ ret = io_uring_submit(&ring); if (ret < 0) { printf(&34;, strerror(-ret)); goto out; } /* wait for the sqe to complete */ ret = io_uring_wait_cqe(&ring, &cqe); if (ret < 0) { printf(&34;, strerror(-ret)); goto out; } /* read and process cqe event */ io_uring_cqe_seen(&ring, cqe);out: close(fd);exit: /* tear down */ io_uring_queue_exit(&ring); return ret;}


io_uring 高級特性

→ Polled IO

IORING_SETUP_IOPOLL,與非 polling 模式等待硬體中斷喚醒不同,內核將採用 polling 模式不斷輪詢硬體以確認IO請求是否已經完成,這在追求低延時和高 IOPS 的應用場景非常有用。


→ Kernel Side Polling

IORING_SETUP_SQPOLL,當前應用更新 SQ ring 並填充一個新的 sqe,內核線程 sqthread 會自動完成提交,這樣應用無需每次調用 io_uring_enter() 系統調用來提交 IO。應用可通過 IORING_SETUP_SQ_AFF 和 sq_thread_cpu 綁定特定的 CPU。

同時,為了節省無 IO 場景的 CPU 開銷,該內核線程會在一段時間空閒後自動睡眠。應用在下發新的 IO 時,通過 IORING_ENTER_SQ_WAKEUP 喚醒該內核線程,該操作在 liburing 中都已封裝完成。


Fixed Files

IORING_REGISTER_FILES/IORING_REGISTER_FILES_UPDATE/ IORING_UNREGISTER_FILES,通過 io_uring_register() 系統調用提前註冊一組 file,緩解每次 IO 操作因 fget() / fput() 帶來的開銷。


Fixed Buffers

IORING_REGISTER_BUFFERS/IORING_UNREGISTER_BUFFERS,通過 io_uring_register() 系統調用註冊一組固定的 IO buffers,當應用重用這些 IO buffers 時,只需要 map / unmap 一次即可,而不是每次 IO 都要去做,減少get_user_pages() / put_page() 帶來的開銷。


Linked SQE

IOSQE_IO_LINK,建立 sqe 序列之間的關聯,這在諸如 copy 之類的操作中非常有用。使用 linked sqe 後,copy 操作的寫請求連結在讀請求之後,應用程式無需等待讀請求數據返回後再下發寫請求,而是共享了同一個 buffer,避免了上下文切換的開銷。


社區工作

阿里雲作業系統團隊在 backport io_uring 特性到 Alibaba Cloud Linux 2 的過程中,進一步優化性能,並加固 io_uring 的穩定性,相關工作以補丁的形式回饋到社區。


性能優化

  • engines/io_uring: delete fio_option_is_set() calls when submitting sqes
    fio io_uring 提交 IO 性能提升 30%。
  • __io_uring_get_cqe: eliminate unnecessary io_uring_enter() syscalls
    在某些場景下,減少 50% 的 io_uring_enter() 系統調用開銷。
  • ext4: start to support iopoll method
  • io_uring: io_uring_enter(2) don&39;t submit sqes when ctx->refs is dying
  • io_uring: fix io_kiocb.flags modification race in IOPOLL mode
  • io_uring: don&39;s result and iopoll_completed
  • io_uring: fix possible race condition against REQ_F_NEED_CLEANUP

相關焦點

  • io_uring 新異步 IO 機制,性能提升超 150%,堪比 SPDK
    導讀:Alibaba Cloud Linux 2 是阿里雲作業系統團隊基於開源 Linux 4.19 LTS 版本打造的一款針對雲應用場景的下一代 Linux OS 發行版。前言LTS 版本的發布是一個重要的裡程碑,標誌著阿里雲作業系統團隊將為 Alibaba Cloud Linux 2 提供長期技術支持
  • linux異步IO編程實例分析
    異步阻塞IO模型的流程圖在Direct IO模式下,異步是非常有必要的(因為繞過了pagecache,直接和磁碟交互但異步IO的思想是:應用程式不能阻塞在昂貴的系統調用上讓CPU睡大覺,而是將IO操作抽象成一個個的任務單元提交給內核,內核完成IO任務後將結果放在應用程式可以取到的地方。這樣在底層做I/O的這段時間內,CPU可以去幹其他的計算任務。但異步的IO任務批量的提交和完成,必須有自身可描述的結構,最重要的兩個就是iocb和io_event。
  • 漫談Swoole協程與異步IO
    一部分PHP開發者並不清楚Swoole是什麼,只是覺得很牛掰就想用了,這種行為無異於寫作文的時候總想堆砌一些華麗的辭藻或是引經據典來提升文章逼格,卻背離了文章的主題,本末倒置,每一種技術的誕生都有它的原因,異步或是協程不是萬能的銀彈,你需要它的時候再去用它,而不是想用它而用它,畢竟編程世界的慣性是巨大的,這天下還是同步阻塞的天下。
  • 數聚論技術專場【北京站】丨China Alluxio User Meet
    大數據高效處理是當下一線網際網路公司都在持續探索和實踐的重要課題,業界各種新的技術和解決方案層出不窮,Alluxio(前稱Tachyon)是其中很優秀並受大量開發者關注及公司生產級實踐的一種。與李浩源面對面,交流Alluxio的發展歷程;與多位業績大咖一起,討論優秀案例,共話技術未來。
  • io_uring只適用於存儲IO?大錯特錯
    新異步編程框架,在高並發網絡編程方面我們多了一個利器。新異步編程框架,在高並發網絡編程方面我們多了一個利器。io_uring在進行初始設計時就充分考慮其框架自身的高性能和通用性,不僅僅面向傳統基於塊設備的fs/io領域,對網絡異步編程也提供支持,其最終目的是實現linux下一切基於文件概念的異步編程。
  • Java 高性能的異步網絡IO傳輸
    異步與同步模型最大的區別:同步模型會阻塞線程等待資源異步模型不會阻塞線程,它是等資源準備好後,再通知業務代碼來完成後續的資源處理邏輯。可很好解決IO等待的問題業務系統大都是IO密集型。相對的是計算密集型系統。
  • 聊聊工作中經常遇到的「異步」
    在我們編程的時候,經常會遇到一個概念——異步,諸如異步通信,異步線程,異步代碼,異步調用,異步編程等等,那麼什麼是異步呢?為什麼要異步?異步的典型場景是什麼?在《Unix網絡編程》第二卷中,提到了5種IO模型: 前四種io
  • io_submit:Linux內核新加入的epoll替代方案
    Linux的AIO是最初是設計用於磁碟異步IO的接口。文件與網絡套接字是大相逕庭的東西,可以用Linux AIO 接口,將其統一起來呢?在本文中,我們介紹如何使用Linux AIO API的優勢來編寫更好,更快的網絡伺服器。
  • VPP 的異步Crypto框架
    轉載自DPDK與SPDK開源社區公眾號VPP的crypto框架是VPP原生的一套數據加解密框架,其目的是為VPP框架中所有Graph node提供數據加密服務。收發間卸載相比NIC卸載要相對複雜一些:CPU需要管理失敗的加解密命令的結果,因為QAT的操作對象僅為內存而非網絡幀,CPU需要自行管理QAT交互使用的內存;CPU也需要針對加解密操作的結果進行相應的處理;如非法的加密網絡幀需要丟棄等。我們還需要一個獨立於收網絡幀之外的輪詢(polling)操作,以便將QAT處理完成的數據及時取回。
  • TData拷貝機之異步拷貝---詳解SOTA異步複製技術
    TData長期對客戶的反饋統計及市場調研發現,客戶反饋購買機器實際操作後發現目前一些同行產品中標榜的異步拷貝技術而真正使用起來並沒有其宣傳的那麼好,大部分品牌拷貝機在實際異步拷貝的過程中僅僅只能拷貝100MB大小以下的文件,性能較好的超過256MB的文件則不能再實現異步拷貝。甚至某些產品使用了低廉的複製晶片,導致在大量的拷貝文件時出現拖速的情況,拷貝的效率十分的緩慢。
  • 概況了解加解密技術
    將源自網絡層來的數據可靠地傳輸到相鄰節點的目標機網絡層數據鏈路層的主要協議有:(1)PPP點對點協議(Point-to-Point Protocol);(2)乙太網(Ethernet);(3)高級數據鏈路協議(High-Level Data Link Protocol);(4) 幀中繼(Frame Relay);(5) 異步傳輸模式
  • Java IO 以及 NIO 詳解
    例如,在往一個分布式資料庫中寫一條記錄,通常會有一份是同步阻塞的記錄,而還有兩至三份是備份記錄會寫到其他機器上,這些備份記錄通常都是採用異步阻塞的方式寫 I/O;異步阻塞對網絡 I/O 能夠提升效率,尤其像上面這種同時寫多份相同數據的情況異步非阻塞這種組合方式用起來比較複雜,只有在一些非常複雜的分布式情況下使用,像集群之間的消息同步機制一般用這種 I/O 組合方式。
  • 初識異步IO框架:asyncio 上篇
    asyncio是Python 3.4版本引入的標準庫,直接內置了對異步IO的支持。有些同學,可能很疑惑,既然有了以生成器為基礎的協程,我們直接使用yield 和 yield from 不就可以手動實現對IO的調度了嗎? 為何Python吃飽了沒事幹,老重複造輪子。
  • 在瀏覽器中異步下載文件監聽下載進度
    在瀏覽器中異步下載文件,其實就是把伺服器響應的文件先保存在內存中。然後再一次下載到磁碟。第二次下載過程,就是把內存的數據IO到磁碟,沒有網絡開銷。速度極快。之所以要先保存在內存,主要是可以在下載開始之前和下載結束後可以做一些業務邏輯(例如:校驗,判斷),還可以監聽下載的進度。
  • 一文帶你徹底了解Java異步編程
    那到底什麼是異步編程?異步化真正的好處又是什麼?如何選擇適合自己團隊的異步技術?在實施異步框架落地的過程中有哪些需要注意的地方?異步實現原理異步技術選型參考異步化真正的好處是什麼因為上文講到的異步技術都是基於線程的操作和封裝,Java中的線程概念對應的就是作業系統的線程。1.
  • linux環境高級編程-高級IO和進程間通信詳解
    高級io先介紹記錄鎖的概念和記錄鎖的數據結構。然後介紹阻塞io,非阻塞IO,異步io,IO多路轉接等概念,後者都是針對前者更優的技術。IO多路轉接技術包括:select,peslect,poll。最後介紹存儲映射IO。
  • 【翻譯】withoutboats的io-uring 筆記
    我不知道將來是否會繼續這項工作,但是有些人已經開始開發目標類似的庫了,因此我想就我在 io-uring 和 Rust 的 future 模型上的學習情況做一些筆記。這篇文章假定你對 io-uring API 有一定了解。這個文檔(https://kernel.dk/io_uring.pdf)提供了關於 io-uring 的高級概述。
  • Tokio 1.0 發布,Rust 異步編程框架
    Tokio 1.0 穩定版本已發布,Tokio 是 Rust 的異步 runtime,可用於編寫快速、可靠的網絡應用。
  • 網易嚴選案例:Alluxio+Impala深度融合架構BI系統性能優化實踐
    通過引入Alluxio,我們有效地提升了原來Apache Impala系統的查詢性能和穩定性。下面,首先簡要介紹一下網易有數、Apache Impala和Alluxio。1.1 Apache ImpalaApache Impala(見參考連結1)是網易內部廣泛使用的開源高性能MPP分析引擎之一,該系統在網易內部由網易數據科學中心負責持續的技術跟蹤和改進(見參考連結2)。
  • 實戰異步IO框架:asyncio 下篇
    輸出結果Thu May 31 22:11:16 2018第一個 協程運行完..Thu May 31 22:11:22 2018第二個 協程運行完..Thu May 31 22:11:25 2018主線程是異步的,這是重點,一定要掌握。。