【一知半解】零值拷貝

2022-07-28 12:01:38

傳統IO

  1. 應用呼叫read方法向作業系統發起讀資料的請求,此時由使用者態切換為核心態
  2. 當系統收到讀資料請求時,利用DMA控制器把資料從磁碟讀取到系統快取區中(圖中2.1)
  3. 再然後CPU會把系統快取區的資料寫應用快取區(圖2.2),此時由核心態切換為使用者態
  4. 應用再呼叫write方法通知系統進行資料的寫操作,此時由使用者態切換為核心態
  5. CPU把應用快取中的資料寫到系統快取區(圖2.3)
  6. 再然後就是DMA控制器再把資料從系統快取區寫到網路卡快取區上(圖2.4),write方法返回,此時由核心態切換為使用者態

在普通的IO拷貝時要有4次的上下文切換過程和4次的拷貝過程,在高並行的場景下對效能會產生比較大的影響。

DMA

資料在讀寫的過程中都需要CPU發出對應的命令來完成,因為CPU的速度比IO操作要快的多,在資料拷貝的過程中CPU不可能一直處於等待的過程,但是如果不等,CPU又不知道IO什麼時候處理完,為了協調高速的CPU與低速的IO的矛盾,因此引入了DMA,DMA(Direct Memory Access)直接記憶體存取技術,通過它來進行記憶體和IO裝置的資料傳輸。大至就是CPU給DMA發一個指令,然後DMA開始幹活,然後CPU幹別的活,DMA幹完後告訴CPU,從而減少了CPU的等待時間。

零值拷貝

觀察圖可以2.1 和2.2 感覺資料在此過程做了個無用功,從核心態搬到使用者態,再由使用者態搬到核心態,因此提出了零值拷貝,零值拷貝不是沒有拷貝,而是不再有使用者態和核心態間資料拷貝過程,他的實現有mmapsendfile兩種方式。

mmap

mmap (member map)記憶體對映,資料讀取到系統快取區後,使用者態資料在系統快取區的對映就可以完成資料的傳輸過程。

  1. 首先向作業系統傳送一個mmap命令(上圖1.1),此時由使用者態切換為核心態
  2. 系統收到mmap命令後,會用DMA把資料從磁碟讀到到記憶體的快取區中(上圖1.2)。
  3. 返回資料快取區的一個對映mmap(上圖1.3),由核心態切換到使用者態
  4. 使用者在發起一個write的操作(上圖1.4),由使用者態切換到核心態
  5. cpu再把記憶體快取區中的資料拷貝到另一個快取區上(上圖1.5)
  6. DMA把資料拷貝到網路卡上後返回(上圖1.6),並由核心態切換到使用者態

mmap的操作共有4個上下文的切換和3次的資料拷貝過程,比普通的拷貝少了一次cpu的拷貝。

sendfile

mmap的拷貝方法要先獲取資料區的對映,然後有使用者發起寫資料的命令後,在往網路卡上寫,如果不需要對資料做任何處理,只是原封不動的把資料傳送出去,mmap命令和write命令可以合併為一個命令,直接告訴作業系統往外傳送哪個資料即可,合併後的命令就sendfile。

  1. 使用者往作業系統發直sendfile的命令,此時有使用者態切換到核心態
  2. 系統收到命令後,由DMA把資料從磁碟上讀取到系統快取區上
  3. 然後由cpu把讀到的到資料拷貝到另一個快取區上
  4. 再由DMA把資料寫到網上上
  5. 然後返回,由核心態切換到使用者態

sendfile的過程由2次上下文的切換和3次的資料拷貝過程,整個過程讀到的資料對使用者空間不可見,適應用靜態檔案伺服器。

sendfile升級

在sendfile的cpu把資料從快取區從一個地方拷貝到另一個地方,也會浪費額外的空間,能不能在往網路卡上寫資料時只用第一次DMA拷貝出來的資料,直接拷貝到網路卡上呢?因此對sendfile再次升級,引入了DMA Scatter/Gather 分散/收集功能。

  1. 使用者發起sendfile命令(上圖1.1),系統收到後,由使用者態 切換到核心態
  2. 呼叫DMA利用scatter從磁碟讀取資料到快取區離散儲存(上圖1.2)
  3. cpu把快取區資料的檔案描述符和資料長度傳送給另一個快取區(上圖1.3)
  4. DMA在從另一個快取區讀取資料時根據檔案描述符和資料長度,使用scatter/gather從快取區中讀取到網路卡上(上圖1.4)
  5. 返回,並有核心態切換到使用者態

此過程對使用者空間仍然是不可見的,而且需要硬體的支援。有2次上下文切換和2次的拷貝過程,效能在大幅的提高。

場景

kafka和rocketmq都用到了mmap技術,兩個中介軟體都有訊息的持久化過程,和訊息的讀取過程。

mq對訊息持久化和讀取的過程都用到了mmap+write,而kafka則是持久化的過程用到了mmap+write,讀取訊息用的sendfile。

總結

為什麼需要DMA?

DMA是為了解決高速CPU和低速IO操作的矛盾,cpu發起一個讀取指令後,由dma接管資料的讀取複製工作,cpu處理別的事件。

傳統IO與零值拷貝有比較

名稱 過程 上下文切換次數 拷貝次數
傳統IO 讀取命令、從磁碟讀、寫到快取、寫到使用者快取區、寫到快取區,寫到網路卡 4 4
mmap+write mmap命令,從磁碟讀,寫到快取、返回mmap、發起write命令,從快取讀,寫到另一快取,寫到網路卡 4 3
sendfile sendfile命令,從磁碟讀,寫快取區,寫到另一快取區,寫網路卡 2 3
sendfile升級版 sendfile命令,從磁碟讀,寫快取區,根據檔案描述符從快取區讀,寫網路卡 2 2