日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

io_uring设计理念及使用方式总结

發布時間:2024/2/28 编程问答 228 豆豆
生活随笔 收集整理的這篇文章主要介紹了 io_uring设计理念及使用方式总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

io_uring設計理念及使用方式總結

    • overview
      • 設計目標
    • io_uring系統調用
      • io_uring_setup
        • 特性
      • io_uring_enter
      • io_uring_register
    • liburing
      • op code
      • feature
    • IO interfaces 比較
      • spdk+io_uring
      • 參考鏈接


overview

io_uring通過使用先進的IO特性,以及內核支持下的各種免拷貝、免context switch特性,成為kernel下一代高性能異步IO接口,不同于libaio,io_uring支持direct和非direct IO。

Fundamentally, io_uring is just ring based communication channel. ---- Jens

IO請求通過submission queue SQ下發到內核中,內核完成IO之后通過completion queue CQ放回IO result。兩個隊列在用戶態和內核態之間通過共享內存的方式溝通,從而免拷貝,每個SQE(submission queue entry)的大小為64byte,正好容納近一個cache line。內核通過memory ordering、fense等技巧保證整個IO鏈路是不出錯且高效的。

設計目標

作者Jens在文章中明確列出了io_uring的設計目標:

  • 易用 Easy to use。從筆者的角度來看,與現有的IO接口相比,io_uring相關syscall接口其實并不算易用,甚至理解起來也不算容易。作者自己也說,這些設計目標之間是有沖突的,特性豐富、高效還可伸縮的接口必然是很難用的。為了解決這個問題,作者為io_uring開發了一個配套的庫liburing。既然支持全部需求的接口對于一般開發者來說使用難度過高,那就對其中最常用的部分再封裝一層,提供一個更簡單易用的接口。使用liburing無法使用io_uring全部的功能,特別是一些為高性能目標設計的功能,但能夠使用一套風格與io_uring類似,但簡單的多的接口來使用io_uring的基本功能,這對于大部分開發者來說也已經足夠了。對于需要高級特性的開發者來說,也可以在使用liburing的基礎上調用io_uring syscall接口來獲取自己需要的特性,因為這類開發者一般也不會同時需要所有高級特性,而只是使用其中很小的一部分。這個設計方式值得我們學習,如何解決功能強大和接口易用之間的矛盾,“加一個中間層”永遠是一個有效的思路。
  • 可擴展 Extendable。這里的可擴展指的是io_uring操作的IO設備類型是可擴展的,io_uring實現的異步接口不止能夠用于塊設備,也能夠支持socket網絡IO等非塊設備,后續還可能支持更多fd類型,從接口語義方面沒有限制。
  • 特性豐富 Feature rich。這一項是針對linux aio機制的局限性而來的。aio機制由于支持的特性不多,使用限制卻很多,因此使用場景非常有限。作者的目標是在所有需要異步IO的場景都能夠使用io_uring接口,并且不需要程序本身做架構級別的調整。
  • 高效 Efficiency。這里的高效主要體現在兩個方面:
  • 一是每次調用io_uring系統調用接口的開銷要小,這里主要是和aio相比減少了每次調度傳遞的參數大小;
  • 二是減少io_uring系統調用的次數,這是io_uring最重要的設計之一,通過一次系統調用提交多個IO請求的方式,io_uring可以大幅減少系統調用次數,這在spectre/meltdown修復導致系統調用開銷顯著上漲的背景下更加重要。
  • 可拓展性 Scalability。這里的Scalability不同于上文的Extendable,Scalability主要指隨著使用IO使用系統資源的增多(主要指cpu計算之資源),IO性能會得到線性增長。因此io_uring占用系統資源是可調的。
  • io_uring系統調用

    io_uring_setup

    創建并配置io_uring

    #include <linux/io_uring.h> int io_uring_setup(u32 entries, struct io_uring_params *p);

    通過io_uring_params設置申請uring的參數:

    struct io_uring_params {__u32 sq_entries; // 指定分配多少個sqe__u32 cq_entries; // 指定分配多少個cqe__u32 flags; // io_uring各種參數,包括IORING_SETUP_IOPOLL設置用戶態polling,IORING_SETUP_SQPOLL設置內核態polling,IORING_SETUP_SQ_AFF設置內核態polling的綁核等等__u32 sq_thread_cpu; // 內核態綁核__u32 sq_thread_idle; // 內核態polling 如果idle超過sq_thread_idle milliseconds會進入休眠,進入休眠后用戶態進程必須通過調用io_uring_enter設置IORING_SQ_NEED_WAKEUP 來喚醒內核polling線程__u32 features; // 由內核填寫,表明內核支持那些io_uring特性__u32 wq_fd; // 可以指定一個已經存在的io_uring,而不重新創建__u32 resv[3];struct io_sqring_offsets sq_off; // 指定sq的一些特性struct io_cqring_offsets cq_off; };

    ring創建好之后是以fd的形式呈現的,用戶可以通過mmap的方式訪問特定的ring

    #define IORING_OFF_SQ_RING 0ULL #define IORING_OFF_CQ_RING 0x8000000ULL #define IO_RING_OFF_SQES 0x10000000ULL // 通過以上三個flag來mmap對應的三片IOring的區域 // 下面舉例:sq->ring_ptr = mmap(0, sq->ring_sz, PROT_READ | PROT_WRITE,MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING); if (sq->ring_ptr == MAP_FAILED)return -errno;sq->khead = sq->ring_ptr + p->sq_off.head; // p就是之前設置的io_uring_params sq->ktail = sq->ring_ptr + p->sq_off.tail;// sq配置好之后,用戶態進程作為生產者在sq tail追加sqe,kernel作為消費者從head獲取待處理的sqe

    上述講解的是io_uring系統調用的方法,我們也可以使用上層封裝liburinginclude/liburing.h中的函數進行初始化和下發IO

    特性

    我們可以通過io_uring_params配置io_uring不同的特性

  • hipri模式,通過配置flag參數IORING_SETUP_IOPOLL,可以使用用戶態poll模式處理IO。這種場景下適配的硬件的completion事件不會中斷上來更改uring的cq。用戶需要自己收割查看硬件隊列。這樣可以帶來更低是時延和更好的性能,經典的場景有如下兩種:
  • 通過poll模式降低系統context switch、中斷開銷,降低單個IO的時延,提高IOPS。
  • 如果當前系統IO負載特別繁重(例如600K+ IOPS),傳統的中斷irq模式就會占用特別多的系統資源且變得低效,這時poll模式的優勢就體現出來了。
  • polled IO submission,通過配置flag參數IORING_SETUP_SQPOLL,啟動內核態poll,這意味著用戶提交IO不用進入內核態通知內核,內核會持續的poll sq
  • 該場景下我們也可以通過IORING_SETUP_SQ_AFF綁定內核態polling的核
  • 也可以配置參數sq_thread_idle控制內核的polling線程(某cpu core 的sys cpu會跑到100%)在空閑多少時間之后可以進入休眠。
  • 也可以配置submit/complete IO在不同的code上。
  • 如果不設置以上兩個參數,上層業務在調用io_uring_enter收割IO的時候會進入sleep(min>0),等待cq中有完成時entry,目前spdk uring_bdev 使用min=0的模式輪詢查看CQ隊列。 fio使用min>0阻塞等待cq返回。
  • io_uring_enter

    int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t sig);

    在程序向sq,即請求隊列中插入了IO請求后(可以通過io_uring_get_sqe插入),需要通知內核開始處理,這時就需要調用io_uring_enter。參數中的fd是io_uring的fd,to_submit是提交的IO請求數。

    min_complete可以用來阻塞等待內核完成特定數量的請求,前提是flags中設置IORING_ENTER_GETEVENTS。這個功能可以單獨調用來等待內核處理完成。需要注意的是由于采用共享內存隊列的方式來同步請求完成情況,因此程序也可以不使用這個接口而是直接判斷cqring的狀態來獲取IO完成情況并處理cqring中的完成事件(使用liburing中的io_uring_peek_cqe)。

    io_uring_register

    int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args);

    這個syscall用于支持一些高級的優化用法,主要有兩種模式,opcode分別為:

  • IORING_REGISTER_FILES。內核異步處理sqe請求時,需要保證fd不會在處理過程中被關閉,因此需要在開始處理前增加fd引用計數,結束后再減少。而調用這個接口后就可以避免這種反復的引用計數操作。在調用后指定的文件fd的引用計數會增加,后續提交請求時只要在sqe的flags中指定IOSQE_FIXED_FILE就不會再修改引用計數。如果不再需要操作這個fd,可以用IORING_UNREGISTER_FILES這個opcode解除注冊。
  • IORING_REGISTER_BUFFERS。在使用O_DIRECT模式時,內核在處理IO時需要先映射用戶態的頁面,處理完后再解除映射(When O_DIRECT is used, the kernel must map the application pages into the kernel before it can do IO to them, and subsequently unmap those same pages when IO is done)(這意味著directIO應該是免拷貝的),這也是一種重復開銷。使用這個opcode后,就可以把指定的buffer頁面固定映射到內核中,處理請求時就不需要反復映射、解除映射。用戶可以在下發IO的時候使用IORING_OP_READ_FIXED和IORING_OP_WRITE_FIXED指定當前IO使用fixed buffer中的空間。
  • IOURING_REGISTER_EVENTFD。和libaio類似,io_uring也可以注冊一個eventfd,用戶隨后可以poll這個eventfd獲取相關事件通知。
  • liburing

    op code

    IO entry中不同的opcode可指示kernel做不同的事情:

  • IORING_OP_NOP不做任何事,測試系統開銷。
  • IORING_OP_READV常規讀
  • IORING_OP_WRITEV常規寫
  • IORING_OP_READ_FIXED使用fixed buffer進行讀
  • IORING_OP_WRITE_FIXED使用fixed buffer進行寫
  • IORING_OP_FSYNC類似fsync()系統調用,只不過是以異步的形式。
  • IORING_OP_POLL_ADD和IORING_OP_POLL_REMOVE可以使用io_uring poll特定的fd,只不過每次poll完成之后需要重新添加。
  • IORING_OP_TIMEOUT和IORING_OP_TIMEOUT_REMOVE,使用該OP下發的entry會在特定的timeout時間之后才會返回。
  • 還有一些網絡相關OP
  • feature

    使用io_uring_get_sqe獲取一個新的sqe之后,可以通過sqe->flages設置特性,一些比較重要的特性列述如下:

  • IOSQE_IO_DRAIN,同步等待之前下發的io_uring command全部返回
  • IOSQE_IO_LINK,linked commands,設置在中,設置feature的command會在IO_uring中順序完成,liburingexamples/link-cp.c
  • IO interfaces 比較

    SW overheadsynchronous I/Olibaioio_uring
    system callsat least 1 per I/O2 per I/O batch1 per patch, zero when using SQ submission thread
    memory copyyesyes - SQE & CEQzero-copy for SQE&CQE
    context switchesyesyesminimal context switching polling
    interruptsInterupt drivenInterupt drivensupports both interrupts and polling I/O
    Blocking I/Osynchronousasynchronousasynchronous
    buffer I/Oyesnoyes

    spdk+io_uring

    目前spdk已經支持了io_uring,具體代碼可見pdk/module/bdev/uring/bdev_uring.c,由于目前有一些遠程掛載設備不支持IORING_SETUP_IOPOLL特性,spdk為了維護模塊的通用性,目前的spdk實現也沒有啟用IORING_SETUP_IOPOLL特性,當然定制添加的工作量并不大。

    使用如下命令可以在spdk中測試io_uring

    ./scripts/rpc.py -s /var/tmp/spdk.sock bdev_uring_create /dev/nvme0n1 nvme0n1 512 # 創建uring_bdev LD_PRELOAD=/root/spdk_bdev ./fio ./example_config.fio # 使用fio_plugin測試io_uring,需要更改對應的bdev參數配置。

    參考鏈接

  • liburing github
  • IO_URING_SETUP
  • Faster IO through io_uring Jens講io_uring以及liburing
  • Improved Storage Performance Using the New Linux Kernel I O Interface (SDC 2019)
  • io_uring技術的分析與思考
  • The rapid growth of io_uring
  • An Introduction to the io_uring Asynchronous I/O Framework
  • 總結

    以上是生活随笔為你收集整理的io_uring设计理念及使用方式总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。