系統設計 - Zero-Copy總結和性能測試

zero-copy應用場景

應用場景:將本地一個文件經過網絡傳輸給另外一個程序 關鍵字:數據複製過程當中,內容不進行修改java

zero-copy技術的使用場景有不少,好比Kafka, 又或者是Netty等,能夠大大提高程序的性能 下面咱們經過對比傳統方式和zero-copy的方式傳輸數據,來理解zero-copy。linux

傳統方式傳輸數據

代碼以下:bash

// 將文件讀取到buf中 
File.read(fileDesc, buf, len);
// 將buf中的數據寫入到socket中
Socket.send(socket, buf, len);
複製代碼

結合下圖理解理解操做以下:網絡

在這裏插入圖片描述
在這裏插入圖片描述
詳細步驟以下: 1. 調用File.read()方法會發生上下文切換(context switch),從user mode切換到kernel mode。在read()內部會調用sys_read()來從文件中讀取數據。第一次copy由DMA (direct memory access)完成,將文件內容從磁盤讀出,並存儲在kernel空間的buffer中,爲方便說明,這個buffer稱爲reader buffer。 2. 而後請求的數據被從kernel空間的buffer copy到user buffer中,這是第二次copy。調用的返回又觸發了第二次上下文切換,從kernel mode返回到user mode。至此,數據存儲在user buffer中。 3. Socket.send()會觸發了第三次上下文切換,從user mode到kernel mode,並執行第三次copy,將數據從user buffer從新複製到kernel的buffer中。固然,此次的kernel buffer和第一步的kernel buffer不是同一個buffer,此次buffer和目標socket關聯,命名爲socket buffer。 4. 完成copy後,Socket.send()返回時,同時也形成了第四次上下文切換。同時第四次copy發生,DMA egine將數據從kernel buffer複製到網卡設備(protocol engine)中。第四次copy是獨立並且異步的。

結論: 以上操做要經歷4次user mode和kernel mode之間的上下文切換,數據都被拷貝了4次。經過上面的分析,咱們發現第2步和第3步數據copy是多餘,系統徹底能夠將文件讀取到kernel buffer中後,直接將kernel buffer中的數據寫入socket。爲了實現這個優化,linux引入了zero copy。異步

zero-copy

要支持zero-copy要知足以下條件: a. 操做系統的要求:linux 2.4及以上版本的內核中,而且網卡支持 gather operation。socket

java中使用 FileChannel的transferTo()和transferFrom()方法使用zero-copy,若是底層系統支持zero-copy性能

代碼:測試

public void transferTo(long position, long count, WritableByteChannel target); 
// transferTo()方法底層會調用系統方法sendfile()
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
複製代碼

在這裏插入圖片描述
在這裏插入圖片描述

結合下圖理解理解操做以下: a. 執行transferTo()方法後,會發生上下文切換,從user mode到kernel mode,而後將文件內容copy到kernel buffer(稱爲Read buffer),這一操做由DMA engine完成。。 b. 和傳統方式不一樣,zero-copy沒有將數據copy到socket buffer,只有數據的描述信息(如數據的位置和長度)存儲到socket buffer中。而後DMA engine直接把數據從kernel buffer傳輸到網卡設備(protocol engine)。 完成複製後,又會發生上下文切換,從kernel mode到user mode優化

結論: 1. Zero-copy上下文切換的次數從4次下降到2次,數據複製次數從4次下降到2次 2. Zero-copy 中數據的copy都由DMA執行,CPU不參與複製,從而節省CPU的消耗 3. Zero-copy中的zero不是指不須要copy,而是指user mode到kernel mode copy數據的次數爲零ui

支持zero-copy的操做系統 除了Linux系統,其餘系統也支持zero-copy • Microsoft Windows經過TransmitFile API支持zero-copy • macOS supports zero-copy through the FreeBSD portion of the kernel

性能測試

下面咱們使用代碼來比較傳統方式和zero-copy的傳輸效率 測試代碼:客服端從本地讀取文件,經過網絡傳輸到服務端

  • TraditionalClient.java和 TraditionalClient.java分別實現測試的客服端和服務
  • TransferToServer.java and TransferToClient.java實現的功能和上面的相同,不一樣點時,TransferToClient使用transferTo()實現zero-copy功能。

測試代碼來源developer.ibm.com/articles/j-… 不過在測試過程當中,此源碼在測試有問題,咱們對測試代碼進行修改: TransferToClient.java

// 原來的版本,這裏會有問題,由於transferTo()一次最多發送8388608個字節,須要循環發送。
long position = 0;
while(curnset != 0) {
        curnset = fc.transferTo(position, fsize, sc);
        position += curnset;
        System.out.println("total bytes transferred--" + position + " and time taken in MS--" + (System.currentTimeMillis() - start));
}
複製代碼

TraditionalServer.java

// nread判斷條件修改成 nread <=0,而不是nread==0
byte[] byteArray = new byte[4096];
    while(true) {
    	int nread = input.read(byteArray , 0, 4096);
    	if (nread <= 0)
    		break;
    }
}
複製代碼

文件傳輸花費時間對比

在這裏插入圖片描述
結論:zero-copy的傳輸效率比傳統的方式快一倍
相關文章
相關標籤/搜索