零拷貝技術是指在計算機操作中,cpu不需要將數據從一個存儲區域復制到另一個存儲區域,從而減少上下文切換和cpu的拷貝時間。其主要作用是在數據傳輸過程中減少拷貝次數和系統調用,實現cpu的零參與,徹底消除cpu在這方面的負載。零拷貝技術主要依賴于dma數據傳輸技術和內存區域映射技術。
零拷貝技術可以減少數據在內核緩沖區和用戶緩沖區之間的反復I/O拷貝操作,以及用戶進程地址空間和內核地址空間之間因上下文切換帶來的CPU開銷。Linux中提供了輪詢、IO中斷和DMA傳輸三種磁盤與主存之間的數據傳輸機制。
傳統的IO讀寫方式包括兩次CPU拷貝和兩次DMA拷貝,經過了四次上下文切換。
在DMA出現之前,IO操作通過CPU中斷完成,每次讀取磁盤數據時都需要CPU中斷并等待數據讀取和拷貝完成,導致CPU的上下文切換。
DMA(直接內存訪問)是一種允許外設直接訪問系統主存的機制,數據傳輸可以繞開CPU調度,大多數硬件設備都支持DMA技術。
整個DMA數據傳輸操作在DMA控制器的控制下進行,CPU僅在傳輸開始和結束時做中斷處理,傳輸過程中CPU可以繼續其他工作,提高系統效率。
零拷貝在Linux中的實現主要有三種思路:
- 用戶態直接IO:應用程序直接訪問硬件存儲,數據直接從硬件傳輸到用戶空間,減少數據拷貝次數。
tmp_buf = mmap(file_fd, len); write(socket_fd, tmp_buf, len);
- sendfile:sendfile系統調用在Linux內核2.1中引入,簡化了網絡數據傳輸過程,減少了CPU拷貝和用戶與內核態轉換次數。
sendfile(socket_fd, file_fd, len);
sendfile在Linux2.4版本中引入DMA gather操作,進一步減少了CPU拷貝操作。
sendfile(socket_fd, file_fd, len);
splice(fd_in, off_in, fd_out, off_out, len, flags);
- 寫時拷貝:當多個進程共享數據時,只有在需要修改數據時才進行拷貝操作。
無論是傳統IO還是零拷貝方式,兩次DMA拷貝是必需的。以下是幾種IO拷貝方式的對比:
在應用案例中,rocketmq使用mmap + write方式,適用于小塊文件的數據持久化和傳輸;kafka使用sendfile方式,適用于大塊文件的高吞吐量數據傳輸,但其索引文件使用mmap + write方式。