LoginSignup
0
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-03-05

components.png
Netty components

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

6345f1.jpg

// 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

// 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

// 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
kernel buffer append socket buffer
省去了多餘的cpu copy動作
這就是Zero-Copy

Multi-Thread Server

1個client request對應1個server thread處理
Blocking_SingleBurst_Algorithm.png
(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處理
NonBlocking_MultiBurst_Algorithm.png
(from grizzly-sendfile: Wiki: Algorithms — Project Kenai)

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

Reactor Pattern

130828_uKWD_190591.jpeg
(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

20110208092958.png
(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時會有點感覺或是幫助

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0