一般讀取數據 先是從磁盤複製---->內核態模式中的buffer--->cpu控制將內核態buffer的數據copy到用戶態模式 這是讀取的過程
如下圖:
下面是寫入網絡的過程:
先從用戶態中的buffer獲取到數據------>內核態的socket buffer----->網絡設備中傳送
從上面的過程可以看出,數據白白從kernel模式到user模式走了一圈,浪費了2次copy(第一次,從kernel模式拷貝到user模式;第二次從user模式再拷貝回kernel模式,即上面4次過程的第2和3步驟。)。而且上面的過程中kernel和user模式的上下文的切換也是4次。
下面就說說今天的主角 zero-copy
Zero-Copy技術省去了將操作系統的read buffer拷貝到程序的buffer,以及從程序buffer拷貝到socket buffer的步驟,直接將read buffer拷貝到socket buffer. Java NIO中的FileChannal.transferTo()方法就是這樣的實現,這個實現是依賴於操作系統底層的sendFile()實現的。
linux內核版本2.4下的實現
-
將文件拷貝到kernel buffer中;
-
向socket buffer中追加當前要發生的數據在kernel buffer中的位置和偏移量;
-
根據socket buffer中的位置和偏移量直接將kernel buffer的數據copy到網卡設備(protocol engine)
中經過上述過程,數據只經過了2次copy就從磁盤傳送出去了。這個纔是真正的Zero-Copy(這裏的零拷貝是針對kernel來講的,數據在kernel模式下是Zero-Copy)。正是Linux2.4的內核做了改進,Java中的TransferTo()實現了Zero-Copy,如下圖:
netty和kafaka 就是使用了這個原理