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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 两种zero-copy零拷贝技术mmap和sendfile的介绍

發布時間:2023/12/8 java 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 两种zero-copy零拷贝技术mmap和sendfile的介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

詳細介紹了兩種zero-copy零拷貝技術mmap和sendfile的概念和基本原理。

文章目錄

  • 1 標準IO
  • 2 零拷貝
    • 2.1 sendfile調用
    • 2.1 mmap調用
    • 2.2 MQ中的應用

1 標準IO

很多軟件是基于server-client模式的,最常見的下載功能需要從Server端的磁盤中將文件通過網絡發送到客戶端中去。如果采用傳統標準IO的方式(基于數據拷貝),那么需要如下步驟:

傳統標準IO通過網絡傳輸數據,需要進行如下調用:

buffer = File.read Socket.send(buffer)

總共需要四步:

  • read():涉及到兩次上下文切換以及兩次數據拷貝;
  • 讀取磁盤文件,將數據DMA Copy到操作系統內核緩沖區Page Cache;
  • 將內核緩沖區Page Cache的數據,CPU Copy到應用程序緩存;
  • send():涉及到兩次上下文切換以及兩次數據拷貝;
  • 將應用程序緩存中的數據,CPU Copy到socket網絡發送緩沖區,即Socket Cache;
  • 將Socket Cache的數據,DMA Copy到網卡,由網卡進行網絡傳輸。
  • 可以發現,完成一次讀寫,需要4此上下文切換、2次DMA數據拷貝、兩次CPU數據拷貝,實際上,如果僅僅是數據傳輸,那么數據根本不需要經過這么多次的拷貝。

    DMA:Direct Memory Access ,它可以獨立地直接讀寫系統內存,不需要 CPU 介入,像顯卡、網卡之類都會用DMA。

    2 零拷貝

    零拷貝(Zero-copy)技術是指計算機執行操作時,CPU不需要先將數據從某處內存復制到另一個特定區域。這種技術通常用于通過網絡傳輸數據時節省CPU周期和內存帶寬。零拷貝技術可以減少數據拷貝和共享總線操作的次數,消除傳輸數據在存儲器之間不必要的中間拷貝次數,從而有效地提高數據傳輸效率。而且,零拷貝技術減少了用戶進程地址空間和內核地址空間之間因為上下文切換而帶來的開銷。

    常見的零拷貝技術分類:

  • 直接 I/O:數據直接跨過內核緩沖區,在用戶地址空間與 I/O 設備之間傳遞,內核只是進行必要的虛擬存儲配置等輔助工作;
  • 數據傳輸不經過用戶空間:當應用程序在數據傳輸過程中不需要對數據進行訪問時,則可以避免將數據從內核空間到用戶空間之間的拷貝,傳輸的數據在頁緩存中就可以得到處理;Linux 中提供類似的系統調用主要有 mmap(),sendfile() 以及 splice()。
  • 寫時復制:數據不需要提前拷貝,而是當需要修改的時候再進行部分拷貝。COW是對數據在 Linux 的頁緩存和用戶進程的緩沖區之間的傳輸過程進行優化手段。
  • 下面介紹數據傳輸不經過用戶空間的零拷貝技術:mmap和sendfile,這也是Netty、Kafka、RocketMQ等框架所使用的底層技術。

    2.1 sendfile調用

    Linux 在版本 2.1 中引入了 sendfile() 這個系統調用,sendfile()是一種零拷貝的實現。Java對sendfile的支持就是NIO中的FileChannel.transferTo()或者transferFrom()。

    使用sendfile進行網絡數據傳輸流程為:

  • 發起sendfile() 系統調用,上下文切換一次。將文件中的數據DMA Copy到Page Cache中。
  • 繼續將Page Cache中的數據CPU Copy到與 Scocket Cache中去。
  • 繼續將Scocket Cache的數據DMA Copy到網卡,由網卡進行網絡傳輸。sendfile() 系統調用返回,上下文切換一次。
  • 可以看到整個流程,減少了一次CPU Copy,減少了兩次的上下文切換,相比于傳統IO確實提升了性能。

    但是,數據仍舊需要一次從Page Cache到Socket Cache的CPU Copy,這個Copy能不能也去掉呢?

    當然可以,Linux 2.4+ 版本之后,文件描述符結果被改變,借助DMA Gather(帶有收集功能的DMA),sendfile()再次減少了一次 Copy 操作,變成了真正的零拷貝(沒有CPU Copy)。

    此時整個步驟變為:

  • 發起sendfile() 系統調用,上下文切換一次。將文件中的數據DMA Copy到Page Cache中。
  • 繼續將Page Cache中的帶有文件位置和長度信息的緩沖區描述符CPU Copy到Socket Cache中去,這部分拷貝很少的數據,可忽略。
  • 繼續借助DMA Gather ,直接將Scocket Cache的真正數據DMA Copy到網卡,由網卡進行網絡傳輸。這樣就避免了最后一次CPU Copy。sendfile() 系統調用返回,上下文切換一次。
  • sendfile + DMA Gather流程如下:

    sendfile + DMA Gather,使得整個傳輸只需要兩次上下文切換,數據只需要兩次DMA Copy,降低了上下文切換和數據拷貝帶來的開銷,極大的提升了數據傳輸的效率,沒有CUP拷貝,是真正的零拷貝。

    但是,sendfile調用有一個缺點,那就是無法在sendfile調用過程中修改數據,因此sendfile()只是適用于應用程序地址空間不需要對所訪問數據進行處理的和修改情況,常見的就是文件傳輸,或者MQ消費消息的獲取,如果想要在傳輸過程中修改數據,可以使用mmap系統調用。

    mmap調用是一個比sendfile調用昂貴但優于傳統I/O的零拷貝實現方式,而mmap調用則可以在中途直接修改Page Cache中的數據,這也是mmap零拷貝的優點。

    2.1 mmap調用

    mmap(Memory Mapped Files)是一種零拷貝技術,學名內存映射文件,Java中的實現就是MappedByteBuffer,通過channel#map方法得到。

    mmap將一個文件(或者文件的一部分)映射到進程的地址空間,實現文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。注意這時候沒有分配和映射到具體的物理內存空間,而是到第一次加載這個文件的時候,通過MMU把之前虛擬地址換算成物理地址,把文件加載進物理內存——內核空間的Page Cache中。

    實現這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用 read,write 等系統調用函數。相反,內核空間對這段區域的修改也直接反映用戶空間,從而可以實現不同進程間的文件共享。

    簡單的說,使用mmap之后,數據無需拷貝到用戶空間中,應用程序可以直接操作Page Cache中的數據。

    mmap()代替read()調用之后的數據發送流程為:

    buf = mmap(file, len); write(sockfd, buf, len);

    使用mmap技術之后,數據流轉圖如下:

    此時整個步驟變為:

  • mmap():涉及到兩次上下文切換以及一次數據拷貝;
  • 發出mmap系統調用,發生一次上下文切換。通過DMA引擎將磁盤文件中的內容拷貝到內核空間的一個緩沖區(Page Cache)中。
  • mmap系統調用返回,發生一次上下文切換。此后用戶空間和內核空間共享這個緩沖區,用戶空間就可以像在操作自己緩沖區中數據一般操作這個由內核空間共享的緩沖區數據,而不需要將數據在內核空間和用戶空間之間來回拷貝。
  • write():涉及到兩次上下文切換以及兩次數據拷貝;
  • 發起write調用,發生一次上下文切換。將緩沖區(Page Cache)的內容CPU Copy到Socket Cache。
  • 將Socket Cache的數據,DMA Copy到網卡,由網卡進行網絡傳輸。write調用返回,發生一次上下文切換。
  • 這種mmap+write的方式相比于傳統IO少了一次CPU Copy,從而極大地提高了效率。雖然性能弱于sendfile零拷貝,但其好處是可以在中途修改內存中的數據之后再傳輸。

    另外,當應用程序往 mmap 輸出數據時,此時就直接輸出到了內核態的緩沖區數據,如果此時輸出設備是磁盤的話,不會立即寫磁盤,linux系統下通常會間隔是30秒由操作系統自動落盤,也可手動調用fsync()函數讓其立即落盤,實現真正的持久化。

    2.2 MQ中的應用

    對于Kafka來說:

  • 數據從Producer到Broker,需要將來自網卡的消息持久化的磁盤中,Kafka中采用mmap的方式寫,并且不會立即持久化到磁盤中,而是存入page cache內核緩沖區中就直接返回成功。后續有消費者來拉取消息的時候,也是先沖緩沖區中查找消息,如果有就直接發送給消費者,不會再查找磁盤,又提升了拉消息的性能。實際上它的日志文件并沒有用到 mmap,而索引文件用了 mmap。
  • 數據從Broker到Consumer,需要將磁盤中的消息通過網卡發送出去,Kafka中采用sendfile的方式,將磁盤文件讀到OS內核緩沖區后,直接轉到socket buffer進行網絡發送。
  • 對于rocketMQ來說,如論是消息存儲還是消費,都是采用mmap的方式,并且通過預熱來減少大文件 mmap 因為缺頁中斷產生的性能問題。

    參考資料:

  • Kafka零拷貝
  • 零拷貝(Zero-copy)及其應用詳解
  • Kafka和RocketMQ底層存儲之那些你不知道的事
  • 如有需要交流,或者文章有誤,請直接留言。另外希望點贊、收藏、關注,我將不間斷更新各種Java學習博客!

    總結

    以上是生活随笔為你收集整理的Java 两种zero-copy零拷贝技术mmap和sendfile的介绍的全部內容,希望文章能夠幫你解決所遇到的問題。

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