零拷貝的原理


"狼哥,面試又跪了,碰到了知識盲區"
"哪個?"
"一面還可以,二面面試官問我零拷貝的原理,懵逼了...這塊內容沒去研究過"
"哦,這個知識點,我之前應該有講過,你沒注意到?"
"這東西工作中用不到,可能被我忽略了"
"嘖嘖嘖..."
"哎,有空和我大概講講?"

"先從簡單開始,實現下這個場景:從一個文件中讀出數據並將數據傳到另一台服務器上?"

"為啥寫這個?"

"你先寫"

"行..."

1分鍾后

"我寫了偽代碼"

File.read(file, buf, len); Socket.send(socket, buf, len); 

"這里涉及到了幾次數據拷貝?"

"2次?磁盤拷貝到內存,內存拷貝到Socket?"

"emmm,怪不得掛了,一點不冤。"

"這種方式一共涉及了4次數據拷貝,知道用戶態和內核態的區別嗎?"

"了解"

"行,文字有點干癟,你先看這個圖"

 
image.png

1、應用程序中調用read() 方法,這里會涉及到一次上下文切換(用戶態->內核態),底層采用DMA(direct memory access)讀取磁盤的文件,並把內容存儲到內核地址空間的讀取緩存區。

2、由於應用程序無法讀取內核地址空間的數據,如果應用程序要操作這些數據,必須把這些內容從讀取緩沖區拷貝到用戶緩沖區。這個時候,read() 調用返回,且引發一次上下文切換(內核態->用戶態),現在數據已經被拷貝到了用戶地址空間緩沖區,這時,如果有需要,應用程序可以操作修改這些內容。

3、我們最終目的是把這個文件內容通過Socket傳到另一個服務中,調用Socket的send()方法,這里又涉及到一次上下文切換(用戶態->內核態),同時,文件內容被進行第三次拷貝,被再次拷貝到內核地址空間緩沖區,但是這次的緩沖區與目標套接字相關聯,與讀取緩沖區沒有半點關系。

4、send()調用返回,引發第四次的上下文切換,同時進行第四次的數據拷貝,通過DMA把數據從目標套接字相關的緩存區傳到協議引擎進行發送。

"在整個過程中,過程1和4是由DMA負責,並不會消耗CPU,只有過程2和3的拷貝需要CPU參與,整明白了?"

"我消化一下..."

半小時后...

"狼哥,這個過程,感覺好幾次的數據拷貝都是多余的,很影響性能啊"

"對,所以才有了零拷貝技術"

"具體咋實現?"

"慢慢來,如果在應用程序中,不需要操作內容,過程2和3就是多余的,如果可以直接把內核態讀取緩存沖區數據直接拷貝到套接字相關的緩存區,是不是可以達到優化的目的?"

 
 

這種實現,可以有以下幾點改進:

  • 上下文切換的次數從四次減少到了兩次
  • 數據拷貝次數從四次減少到了三次(其中DMA copy 2次,CPU copy 1次)

"怎么實現?"

"在Java中,正好FileChannel的transferTo() 方法可以實現這個過程,該方法將數據從文件通道傳輸到給定的可寫字節通道, 上面的file.read()socket.send() 調用動作可以替換為 transferTo() 調用"

public void transferTo(long position, long count, WritableByteChannel target); 

在 UNIX 和各種 Linux 系統中,此調用被傳遞到 sendfile() 系統調用中,最終實現將數據從一個文件描述符傳輸到了另一個文件描述符。

"確實改善了很多,但還沒達到零拷貝的要求,還有其它黑技術嗎?"

"對的,如果底層網絡接口卡支持收集操作的話,就可以進一步的優化。"

"怎么優化?"

在 Linux 內核 2.4 及后期版本中,針對套接字緩沖區描述符做了相應調整,DMA自帶了收集功能,對於用戶方面,用法還是一樣的,但是內部操作已經發生了改變:

 
 
  • 第一步,transferTo() 方法引發 DMA 將文件內容拷貝到內核讀取緩沖區。
  • 第二步,把包含數據位置和長度信息的描述符追加到套接字緩沖區,避免了內容整體的拷貝,DMA 引擎直接把數據從內核緩沖區傳到協議引擎,從而消除了最后一次 CPU參與的拷貝動作。


作者:占小狼
鏈接:https://www.jianshu.com/p/2581342317ce
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
 
 

內核態和用戶態

從系統安全和保護的角度出發,在進行計算機體系結構設計時,處理機的執行模式一般設定為兩種:分別稱為內核模式(內核態)和用戶模式(用戶態)。當處理機處於內核模式執行時,意味着系統除了可以執行一般指令外,還可以執行特權指令,即可以執行訪問各種控制寄存器的指令、I/O指令以及程序狀態字。

當處理機處於用戶模式執行時,只能執行一般指令,而不允許執行特權指令。這樣做可以保護核心代碼不受用戶程序有意和無意的攻擊。 顯然,處理機在運行期間需要在內核模式和用戶模式之前進行切換。

零拷貝

Kafka使用零拷貝(Zero-Copy)技術來提供它的性能,所謂的零拷貝是指將數據直接從磁盤文件復制到網卡設備中,而不需要經由應用程序之手,減少了內核和用戶模式之間的上下文切換,零拷貝技術通過DMA技術實現。

直接存儲器存取方式(Direct Memory Access, DMA) DMA控制方式是以存儲器為中心,在主存和I/O設備之間建立一條直接通路,在DMA控制器的控制下進行設備和主存之間的數據交換。這種方式只在傳輸開始和傳輸結束時才需要CPU的干預。它非常適用於高速設備與主存之間的成批數據傳輸。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM