零拷貝技術是一種思想,指的是計算機操作時,CPU不需要先將數據從某處內存復制從某處內存復制到另一個特定區域。可見,零拷貝的特點是 CPU 不全程負責內存中的數據寫入其他組件,CPU 僅僅起到管理的作用。但注意,零拷貝不是不進行拷貝,而是 CPU 不再全程負責數據拷貝時的搬運工作。如果數據本身不在內存中,那么必須先通過某種方式拷貝到內存中(這個過程 CPU 可以不參與),因為數據只有在內存中,才能被轉移,才能被 CPU 直接讀取計算。
零拷貝技術的具體實現方式有很多,例如:
- mmap(內存映射) + write
- sendfile
不同的零拷貝技術應用于不同場景,下面依次進行sendfile、mmap的分析
mmap(內存映射) + write
在前面我們知道,read() 系統調用的過程中,CPU會把內核緩沖區的數據拷貝到用戶的緩沖區里,于是為了減少這一步開銷,我們可以用 mmap() 替換 read() 系統調用函數,mmap的系統調用作用是將內核空間地址映射為用戶空間地址映射,這樣CPU就不用將數據從內核態拷貝到用戶態了
mmap內存映射+write
圖中涉及3次數據拷貝(1次CPU拷貝、兩次DMA拷貝),具體拷貝過程如下:
1、應用進程調用mmap后,DMA會把磁盤數據拷貝到內核page cache中,然后操作系統的應用進程和內核空間的共享這個緩沖區
2、應用進程再調用 write,操作系統直接將用戶緩沖區的數據拷貝到 內核的socket 緩沖區中,這一切都發生在內核態,由 CPU 來搬運數據
3、最后,把內核的 socket 緩沖區里的數據,拷貝到網卡的緩沖區里,這個過程是由 DMA 搬運的。
由此可見mmap的優勢:
1、可以減少一次數據拷貝的過程。
2、但這還不是最理想的零拷貝,因為把用戶緩沖區的數據拷貝到內核socket 緩沖區里的工作仍然需要通過CPU完成。
3、相對于傳統數據傳輸,mmap減少了一次CPU拷貝,上下文切換依然需要四次
sendfile
sendfile主要使用到了兩個技術:
1、DMA技術
2、傳遞文件描述符代替數據拷貝
3、一次系統調用代替兩次系統調用
下面依次講解這三個技術的作用。
1.利用 DMA 技術
sendfile 依賴于 DMA 技術,將四次 CPU 全程負責的拷貝與四次上下文切換減少到兩次,如下圖所示:
sendfile利用DMA技術
DMA 負責磁盤到內核空間中的 Page cache(read buffer)的數據拷貝以及從內核空間中的 socket buffer 到網卡的數據拷貝。
2.傳遞文件描述符代替數據拷貝
傳遞文件描述可以代替數據拷貝,這是由于兩個原因:
- page cache 以及 socket buffer 都在內核空間中;
- 數據傳輸過程前后沒有任何寫操作;
sendfile利用傳遞描述符
利用傳遞文件描述符代替內核中的數據拷貝
sendfile + SG-DMA技術傳輸文件,需要進行2次用戶態和內核態的切換,2次數據拷貝(1次DMA拷貝,1次SG-DMA拷貝)
注意事項:只有網卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技術才可以通過傳遞文件描述符的方式避免內核空間內的一次 CPU 拷貝。這意味著此優化取決于 linux 系統的物理網卡是否支持,這也就意味著硬件也要受限制(Linux 在內核 2.4 版本里引入了 DMA 的 scatter/gather – 分散/收集功能,只要確保 Linux 版本高于 2.4 即可)。
3.一次系統調用代替兩次系統調用
由于 sendfile 僅僅對應一次系統調用,而傳統文件操作則需要使用 read 以及 write 兩個系統調用。
正因為如此,sendfile 能夠將用戶態與內核態之間的上下文切換從 4 次講到 2 次。
sendfile系統調用代替read/write
總結下sendfile的具體過程如下:
- 通過 DMA 將磁盤上的數據拷貝到內核緩沖區里;
- 緩沖區描述符和數據長度傳到 socket 緩沖區,這樣網卡的 SG-DMA 控制器就可以直接將內核緩存中的數據拷貝到網卡的緩沖區里,此過程不需要將數據從操作系統內核緩沖區拷貝到 socket 緩沖區中,這樣就減少了一次數據拷貝;
此種方式對比之前的,真正意義上去除了CPU拷貝,CPU 可以去執行其他的業務計算任務,同時和 DMA 的 I/O 任務并行,極大地提升系統性能。
但他的劣勢也很明顯,強依賴于硬件的支持