理解Netty中的Zero-copy

Zero-copy概念

    wiki上關於zero-copy的概念定義java

    "Zero-copy" describes computer operations in which the CPU does not perform the task of copying data from one memory area to another. This is frequently used to save CPU cycles and memory bandwidth when transmitting a file over a network. 數組

 

    從WIKI的定義中,咱們看到「零拷貝」是指計算機操做的過程當中,CPU不須要爲數據在內存之間的拷貝消耗資源。而它一般是指計算機在網絡上發送文件時,不須要將文件內容拷貝到用戶空間(User Space)而直接在內核空間(Kernel Space)中傳輸到網絡的方式。緩存

Non-Zero Copy方式: 
Non-Zero Copy網絡

Zero Copy方式: 
在此輸入圖片描述app

    從上圖中能夠清楚的看到,Zero Copy的模式中,避免了數據在用戶空間和內存空間之間的拷貝,從而提升了系統的總體性能。socket

程序訪問方式

  1. The Linux kernel supports zero-copy through various system calls, such as sys/socket.h's sendfile, sendfile64, and splice. Some of them are specified in POSIX and thus also present in the BSD kernels or IBM AIX, some are unique to the Linux kernel API.
  2. Microsoft Windows supports zero-copy through the TransmitFile API.
  3. Java input streams can support zero-copy through the java.nio.channels.FileChannel's transferTo() method if the underlying operating system also supports zero copy

Netty支持的zero-copy有2種:

1 包裝FileChannel.tranferTo方法實現zero-copy

      Netty中經過在FileRegion中包裝了NIO的FileChannel.transferTo()方法實現了零拷貝。模塊化

      FileRegion是一個接口,默認的實現類是:DefaultFileRegion性能

2 複合緩衝類型中內置的透明的零拷貝實現。  

 

Transparent Zero Copy 透明的零拷貝

 

    舉一個網絡應用到極致的表現,你須要減小內存拷貝操做次數。你可能有一組緩衝區能夠被組合以造成一個完整的消息。網絡提供了一種複合緩衝,容許你從現有的任意數的緩衝區建立一個新的緩衝區而無需內存拷貝。例如,一個信息能夠由兩部分組成;header 和 body。在一個模塊化的應用,當消息發送出去時,這兩部分能夠由不一樣的模塊生產和裝配。優化

+--------+----------+
 | header |   body   |
 +--------+----------+

    若是你使用的是 ByteBuffer ,你必需要建立一個新的大緩存區用來拷貝這兩部分到這個新緩存區中。或者,你能夠在 NiO作一個收集寫操做,但限制你將複合緩衝類型做爲 ByteBuffer 的數組而不是一個單一的緩衝區,打破了抽象,而且引入了複雜的狀態管理。此外,若是你不從 NIO channel 讀或寫,它是沒有用的。spa

// 複合類型與組件類型不兼容。
ByteBuffer[] message = new ByteBuffer[] { header, body };

    經過對比, ByteBuf 不會有警告,由於它是徹底可擴展並有一個內置的複合緩衝區。

// 複合類型與組件類型是兼容的。
ByteBuf message = Unpooled.wrappedBuffer(header, body);

// 所以,你甚至能夠經過混合複合類型與普通緩衝區來建立一個複合類型。
ByteBuf messageWithFooter = Unpooled.wrappedBuffer(message, footer);

// 因爲複合類型還是 ByteBuf,訪問其內容很容易,
//而且訪問方法的行爲就像是訪問一個單獨的緩衝區,
//即便你想訪問的區域是跨多個組件。
//這裏的無符號整數讀取位於 body 和 footer
messageWithFooter.getUnsignedInt(
     messageWithFooter.readableBytes() - footer.readableBytes() - 1);

Automatic Capacity Extension 自動容量擴展

    許多協議定義可變長度的消息,這意味着沒有辦法肯定消息的長度,直到你構建的消息。或者,在計算長度的精確值時,帶來了困難和不便。這就像當你創建一個字符串。你常常估計獲得的字符串的長度,讓 StringBuffer 擴大了其自己的需求。

// 一種新的動態緩衝區被建立。在內部,實際緩衝區是被「懶」建立,從而避免潛在的浪費內存空間。
ByteBuf b = Unpooled.buffer(4);

// 當第一個執行寫嘗試,內部指定初始容量 4 的緩衝區被建立
b.writeByte('1');

b.writeByte('2');
b.writeByte('3');
b.writeByte('4');

// 當寫入的字節數超過初始容量 4 時,
//內部緩衝區自動分配具備較大的容量
b.writeByte('5');

 

Better Performance 更好的性能

    最頻繁使用的緩衝區 ByteBuf 的實現是一個很是薄的字節數組包裝器(好比,一個字節)。與 ByteBuffer 不一樣,它沒有複雜的邊界和索引檢查補償,所以對於 JVM 優化緩衝區的訪問更加簡單。更多複雜的緩衝區實現是用於拆分或者組合緩存,而且比 ByteBuffer 擁有更好的性能。

    ByteBuf 具備豐富的操做集,能夠快速的實現協議的優化。例如,ByteBuf 提供各類操做用於訪問無符號值和字符串,以及在緩衝區搜索必定的字節序列。你也能夠擴展或包裝現有的緩衝類型用來提供方便的訪問。自定義緩衝仍然實現自 ByteBuf 接口,而不是引入一個不兼容的類型

    與ByteBuffer相比,再也不須要調用的flip()方法,而且正常狀況下效率更高、響應更好。

相關文章
相關標籤/搜索