一文讀懂零拷貝技術

零拷貝技術 是編寫高性能服務器的一個關鍵技術,在介紹 零拷貝技術 前先說明一下 用戶空間內核空間

用戶空間

通俗的說,用戶空間 就是運行着用戶編寫的應用程序的虛擬內存空間。在 32 位的操作系統中,每個進程都有 4GB 獨立的虛擬內存空間,而 0 ~ 3GB 的虛擬內存空間就是用戶空間 。

內核空間

內核空間 就是運行着操作系統代碼的虛擬內存空間,而 3GB ~ 4GB 的虛擬內存空間就是內核空間。

圖 1 展示了 用戶空間內核空間 在進程虛擬內存空間所在的位置:

發送文件

爲什麼要介紹 用戶空間內核空間 呢?

我們先來回憶一下,服務端發送一個文件給客戶端一般需要進行什麼操作。一般來說,服務端發送一個文件給客戶端的步驟如下:

while ((n = read(file, buf, 4069)) > 0) {
    write(sock, buf , n);
}

在上面的過程中,調用了 readwrite 兩個系統調用。read 系統調用是從文件中讀取數據到用戶空間的緩衝區中,所以調用 read 時需要從內核空間複製數據到用戶空間,如圖 2 所示:

圖 2 就是數據的複製過程,首先會從文件中讀取數據到內核的 頁緩存(page cache),然後再從頁緩存中複製到用戶空間的緩衝區中。

而當調用 write 系統調用把用戶空間緩衝區中的數據發送到客戶端 Socket 時,首先會把緩衝區的數據複製到內核的 Socket 緩衝區中,網卡驅動會把 Socket 緩衝區的數據發送出去,如圖 3 所示:

從上圖可以看出,服務端發送文件給客戶端的過程中需要進行兩次數據複製,第一次是從內核空間的頁緩存複製到用戶空間的緩衝區,第二次是從用戶空間的緩衝區複製到內核空間的 Socket 緩衝區。

仔細觀察我們可以發現,上圖中的頁緩存其實可以直接複製到 Socket 緩衝區,而不需要複製到用戶空間緩衝區的。如圖 4 所示:

如上圖所示,不需要用戶空間作爲數據中轉的技術叫 零拷貝技術。那麼,我們可以通過哪個系統調用來實現上圖中的技術呢?答案就是 sendfile,我們來看看 sendfile 系統調用的原型:

#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

下面介紹一下 sendfile 各個參數的作用:

sendfile 發送數據的過程如圖 5 所示:

對比圖 5 與 圖 3,我們發現使用 sendfile 可以減少一次系統調用,並且減少一次數據拷貝過程。

總結

本文主要通過 sendfile 系統調用來介紹 零拷貝技術,但 零拷貝技術 不單隻有 sendfile,如 mmapsplice直接I/O 等都是 零拷貝技術 的實現,有興趣的可以參考 Linux 官方文檔或相關資料。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/MKb80nS8JvrDO2287JBnQg