[Netty] brief talk about Non-Blocking I/O

![components.png](https://qiita-image-store.s3.amazonaws.com/0/84946/70753618-c57e-ae63-e0ea-bbac26f4343a.png)
**Netty components**

##Zero-Copy
要談到Netty如何實現Non-Blocking I/O (New I/O or NIO)
就得先說明一下Zero-Copy[^1] [^2]

首先聊聊OS level
資料I/O存取透過buffer機制完成R/W

以下4張圖
上半部為context switches
下半部為copy operations
###Copying in Two Sample System Calls
![6345f1.jpg](https://qiita-image-store.s3.amazonaws.com/0/84946/67338a0a-8295-a443-7f3c-24020990ed36.jpeg)

```java
// 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
![6345f2.jpg](https://qiita-image-store.s3.amazonaws.com/0/84946/f00a6986-cf7f-0b0b-5766-d891f07bf051.jpeg)

```java
// 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
![6345f3.jpg](https://qiita-image-store.s3.amazonaws.com/0/84946/44fc1b3a-42f8-44df-ef1c-504b8aa41264.jpeg)

```java
// 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
![6345f4.jpg](https://qiita-image-store.s3.amazonaws.com/0/84946/75fd8f0b-3a20-d9f8-a45f-559a4dcd90cb.jpeg)
kernel buffer append socket buffer
省去了多餘的cpu copy動作
這就是Zero-Copy

##Multi-Thread Server
1個client request對應1個server thread處理
![Blocking_SingleBurst_Algorithm.png](https://qiita-image-store.s3.amazonaws.com/0/84946/7208bee3-75d9-740e-0276-b59578408674.png)
(from [grizzly-sendfile: Wiki: Algorithms — Project Kenai](https://kenai.com/projects/grizzly-sendfile/pages/Algorithms))

由上圖可知
Thread1, 2, 3分別處理Download1, 2, 3
而且每個thread中會因I/O而出現blocked
而Download4, 5, 6只能排隊等待
直到有thread釋放才會處理

##Event-Driven Server
多個client request共享多個server thread處理
![NonBlocking_MultiBurst_Algorithm.png](https://qiita-image-store.s3.amazonaws.com/0/84946/1cb47895-3ca7-a090-7d76-58b42db8d87b.png)
(from [grizzly-sendfile: Wiki: Algorithms — Project Kenai](https://kenai.com/projects/grizzly-sendfile/pages/Algorithms))

由上圖可知
Download1, 2, 3... 6切割tasks給Thread1, 2, 3同時處理
最後tasks會經過合併回傳結果

##Reactor Pattern
![130828_uKWD_190591.jpeg](https://qiita-image-store.s3.amazonaws.com/0/84946/73491291-bc97-d89c-eb72-a71ffa5457ea.jpeg)
(from [Netty源码解读（四）Netty与Reactor模式](http://ifeve.com/netty-reactor-4/))

Netty NIO其實是Reactor Pattern的實作
**dispatcher(selector)**傳送message
讓**event handler(channelhandler)**處理

而Reactor Pattern和Observer Pattern有些許相似及不同之處
請參考
[Observer Pattern vs Reactor Pattern](http://stackoverflow.com/a/26470697)

##UpStream DownStream
![20110208092958.png](https://qiita-image-store.s3.amazonaws.com/0/84946/19174aed-31a7-c4bf-9932-7a0bb6841857.png)
(from [Netty の基本](http://d.hatena.ne.jp/fatrow/20110208/netty))

另外談到寫作的naming
底層實作Netty的有`Akka`, `Ratpack`, `Vert.x`...[^3]
這邊舉Ratpack的`<O> Promise<O> transform(Function<? super Upstream<? extends T>,? extends Upstream<O>> upstreamTransformer)`為例

```java
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?](http://stackoverflow.com/questions/20727615/is-nettys-zero-copy-different-from-os-level-zero-copy)
OS若不支援是無法實現Zero-Copy
當然NIO也無法

另外
想要很簡單的區分async, blocking, non-blocking可以只看這篇的code部份說明
[比較 Winsock 環境下 Blocking、Non-Blocking、以及 Asynchronous
Sockets 的不同](http://bbs.nsysu.edu.tw/txtVersion/treasure/winsock/M.855653325.A/M.826210979.A.html)
應該會有一點想法

最後要說明的是
上述都沒有談到`java.nio`或是`io.netty.channel`等class
只是稍微分享NIO相關議題
希望未來在使用Netty api時會有點感覺或是幫助

[^1]: [Zero Copy I: User-Mode Perspective](http://www.linuxjournal.com/article/6345)
[^2]: [什麼是Zero-Copy?](http://stenlyho.blogspot.tw/2008/08/zero-copy.html)
[^3]: [Netty.docs: Related projects](http://netty.io/wiki/related-projects.html)