Linux 零拷貝技術-mmap與sendFile

零拷貝是網絡編程的關鍵, 很多性能優化都離不開

數據角度分析 : 在零拷貝機制中 , 整個數據在內存中只有一份數據 , 非零拷貝機制中 , 內核緩衝區 , 用戶緩衝區 , Socket 緩衝區 , 各有一份數據 ;

零拷貝指的是沒有 CPU 拷貝 , 都是 DMA ( 直接內存訪問 ) 拷貝 ;

零拷貝性能優勢 : 沒有複製數據帶來的內存開銷 , 沒有 CPU 拷貝 , 直接節省了大量 CPU 計算資源 ;

普通IO方式

普通io讀取本地文件,網絡發送

File file = new File("index.html");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
byte[] arr = new byte[(int)file.length()];
raf.read(arr);
Socket socket = new ServerSocket(8080).accept();
socket.getOutputStream().write(arr);

在這裏插入圖片描述

讀寫文件100M文件,不是分配100M內存,而是分配64k內存循環讀寫,否則直接分配100M,其他應用就容易被掛起。
send是寫內存緩衝區成功,不是寫到網絡成功,網絡可能一直髮送不完。所以下次send的時候可能失敗,因爲buffer滿,沒發送出去.

下面說說他們的步驟:

  1. read 調用導致用戶態到內核態的一次變化,同時,第一次複製開始:DMA(Direct Memory Access,直接內存存取,即不使用 CPU 拷貝數據到內存,而是 DMA 引擎傳輸數據到內存,用於解放 CPU) 引擎從磁盤讀取index.html文件,並將數據放入到內核緩衝區。
  2. 發生第二次數據拷貝,即:將內核緩衝區的數據拷貝到用戶緩衝區,同時,發生了一次用內核態到用戶態的上下文切換。
  3. 發生第三次數據拷貝,我們調用 write 方法,系統將用戶緩衝區的數據拷貝到 Socket 緩衝區。此時,又發生了一次用戶態到內核態的上下文切換。
  4. 第四次拷貝,數據異步的從 Socket 緩衝區,使用 DMA 引擎拷貝到網絡協議引擎。這一段,不需要進行上下文切換。
  5. write 方法返回,再次從內核態切換到用戶態。

從本地磁盤讀取數據,通過網絡發送出去,用戶態和內核態之間需要發生4次切換;數據從磁盤取出來之後,一共要經過4次拷貝

mmap(內存映射)

把磁盤文件映射到內存中,然後把映射到內存的數據通過Socket發送出去。

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

在這裏插入圖片描述

mmap,內存映射,直接將磁盤文件數基於DMA引擎拷貝據映射到內核緩衝區,同時用戶緩衝區是跟內核緩衝區共享一塊映射數據,建立映射後,不需要從內核緩衝區拷貝到用戶緩衝區。可減少一次拷貝。總共是4次切換,3次拷貝。

sendFile

在這裏插入圖片描述

Linux提供sendfile技術。Kafka中,transferFrom和transferTo方法。

只要2次切換,2次拷貝。

  • 用戶態切換到內核態,DMA 引擎從文件拷貝到內核緩衝區,同時從內環緩衝區拷貝一些offset和length數據到socket緩衝區

  • 從內核態切換到用戶態,從內核緩衝區直接把數據拷貝到網絡協議引擎裏去,同時從Socket緩衝區拷貝一些offset和length信息到網絡協議引擎裏去

offset和length量幾乎可以忽略。

零拷貝不僅僅帶來更少的數據複製,還能帶來其他的性能優勢,例如更少的上下文切換,更少的 CPU 緩存僞共享以及無 CPU 校驗和計算。

各種框架使用零拷貝案例

kafka 在客戶端和 broker 進行數據傳輸時,會使用 transferTo 和 transferFrom 方法,即對應 Linux 的 sendFile。

tomcat 內部在進行文件拷貝的時候,也會使用 transferto 方法。

tomcat 在處理一下心跳保活時,也會調用該 sendFile 方法。

所以,如果你需要優化網絡傳輸的性能,或者文件讀寫的速度,請儘量使用零拷貝。它不僅能較少複製拷貝次數,還能較少上下文切換,緩存行污染。

小結

mmap與sendFile區別

  • mmap 用於文件共享,很少用於socket操作,sendfile用於發送文件.
  • mmap 適合小數據量讀寫,sendFile 適合大文件傳輸。
  • mmap 需要 4 次上下文切換,3 次數據拷貝;sendFile 需要 2 次上下文切換,最少 2 次數據拷貝。
  • sendFile 可以利用 DMA 方式,減少 CPU 拷貝,mmap 則不能(必須從內核拷貝到 Socket 緩衝區)。

mmap和共享內存的區別:

mmap是共享一個文件,共享內存是共享一段內存。mmap還可以寫回到file.

mmap缺點:

mmap 每次讀入都是1頁即4k,所以少於4k會造成大量內存碎片. 但是通過read,write也是這樣的。

mmap適用場景,是取代read,write 文件.

使用mmap+write方式

優點:即使頻繁調用,使用小文件塊傳輸,效率也很高
缺點:不能很好的利用DMA方式,會比sendfile多消耗CPU資源,內存安全性控制複雜,需要避免JVM Crash問題

使用sendfile方式

優點:可以利用DMA方式,消耗CPU資源少,大塊文件傳輸效率高,無內存安全新問題
缺點:小塊文件效率低於mmap方式,只能是BIO方式傳輸,不能使用NIO

rocketMQ 在消費消息時,使用了 mmap,因爲小塊數據傳輸比sendFile好。kafka 使用了 sendFile。

參考:

linux下的mmap和零拷貝技術

零拷貝原理詳解

零拷貝技術:mmap和sendfile

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章