Zero-Copy
要談到Netty如何實現Non-Blocking I/O (New I/O or NIO)
就得先說明一下Zero-Copy1 2
首先聊聊OS level
資料I/O存取透過buffer機制完成R/W
以下4張圖
上半部為context switches
下半部為copy operations
Copying in Two Sample System Calls
// sample code:
read(file, tmp_buf, len);
write(socket, tmp_buf, len);
由上圖說明下半部cpu copy行為
資料讀出至kernel buffer然後cpu copy至user buffer
再由user buffer將資料cpu copy至socket buffer進行傳送
為了減少重覆的複製搬移
於是有了另一種實作方式mmap
Calling mmap
// sample code:
tmp_buf = mmap(file, len);
write(socket, tmp_buf, len);
kernel buffer和user buffer是shared共享
所以減少了1次的cpu copy行為
之後又有了另一種實作方式sendfile
Replacing Read and Write with Sendfile
// sample code:
sendfile(socket, file, len);
上圖下半部說明了
資料由kernel buffer直接cpu copy至socket buffer而沒有使用user buffer
也因為如此
圖的上半部顯示減少了context switch行為
如果硬體提供gather功能
Gather can assemble data from multiple memory locations, eliminating another copy

kernel buffer append socket buffer
省去了多餘的cpu copy動作
這就是Zero-Copy
Multi-Thread Server
1個client request對應1個server thread處理

(from grizzly-sendfile: Wiki: Algorithms — Project Kenai)
由上圖可知
Thread1, 2, 3分別處理Download1, 2, 3
而且每個thread中會因I/O而出現blocked
而Download4, 5, 6只能排隊等待
直到有thread釋放才會處理
Event-Driven Server
多個client request共享多個server thread處理

(from grizzly-sendfile: Wiki: Algorithms — Project Kenai)
由上圖可知
Download1, 2, 3... 6切割tasks給Thread1, 2, 3同時處理
最後tasks會經過合併回傳結果
Reactor Pattern

(from Netty源码解读(四)Netty与Reactor模式)
Netty NIO其實是Reactor Pattern的實作
**dispatcher(selector)傳送message
讓event handler(channelhandler)**處理
而Reactor Pattern和Observer Pattern有些許相似及不同之處
請參考
Observer Pattern vs Reactor Pattern
UpStream DownStream

(from Netty の基本)
另外談到寫作的naming
底層實作Netty的有Akka, Ratpack, Vert.x...3
這邊舉Ratpack的<O> Promise<O> transform(Function<? super Upstream<? extends T>,? extends Upstream<O>> upstreamTransformer)為例
public class Example {
public static void main(String... args) throws Exception {
ExecResult<String> result = ExecHarness.yieldSingle(c ->
Promise.value("foo")
.transform(up -> down ->
up.connect(down.<String>onSuccess(value -> {
try {
down.success(value.toUpperCase());
} catch (Throwable e) {
down.error(e);
}
}))
)
);
assertEquals("FOO", result.getValue());
}
}
可以看到up和down的字眼
其實簡單想就是
up: receive data
down: send data
up接收client訊息成功後轉給down將訊息UpperCase後傳回
以server角度
UpStream -> DownStream
以client角度
DownStream -> UpStream
這只是Netty的channel pipeline handler名詞定義
而Ratpack拿來命名用
以上提的這些
最重要還是得看kernel也就是OS level的支援
請參考
Is Netty's Zero Copy different from OS level Zero Copy?
OS若不支援是無法實現Zero-Copy
當然NIO也無法
另外
想要很簡單的區分async, blocking, non-blocking可以只看這篇的code部份說明
比較 Winsock 環境下 Blocking、Non-Blocking、以及 Asynchronous
Sockets 的不同
應該會有一點想法
最後要說明的是
上述都沒有談到java.nio或是io.netty.channel等class
只是稍微分享NIO相關議題
希望未來在使用Netty api時會有點感覺或是幫助



