阅读netty pipeline文档
This commit is contained in:
130
netty/netty-doc.md
Normal file
130
netty/netty-doc.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# netty document
|
||||
## ChannelPipeline
|
||||
I/O Request
|
||||
via Channel or
|
||||
ChannelHandlerContext
|
||||
|
|
||||
+---------------------------------------------------+---------------+
|
||||
| ChannelPipeline | |
|
||||
| \|/ |
|
||||
| +---------------------+ +-----------+----------+ |
|
||||
| | Inbound Handler N | | Outbound Handler 1 | |
|
||||
| +----------+----------+ +-----------+----------+ |
|
||||
| /|\ | |
|
||||
| | \|/ |
|
||||
| +----------+----------+ +-----------+----------+ |
|
||||
| | Inbound Handler N-1 | | Outbound Handler 2 | |
|
||||
| +----------+----------+ +-----------+----------+ |
|
||||
| /|\ . |
|
||||
| . . |
|
||||
| ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
|
||||
| [ method call] [method call] |
|
||||
| . . |
|
||||
| . \|/ |
|
||||
| +----------+----------+ +-----------+----------+ |
|
||||
| | Inbound Handler 2 | | Outbound Handler M-1 | |
|
||||
| +----------+----------+ +-----------+----------+ |
|
||||
| /|\ | |
|
||||
| | \|/ |
|
||||
| +----------+----------+ +-----------+----------+ |
|
||||
| | Inbound Handler 1 | | Outbound Handler M | |
|
||||
| +----------+----------+ +-----------+----------+ |
|
||||
| /|\ | |
|
||||
+---------------+-----------------------------------+---------------+
|
||||
| \|/
|
||||
+---------------+-----------------------------------+---------------+
|
||||
| | | |
|
||||
| [ Socket.read() ] [ Socket.write() ] |
|
||||
| |
|
||||
| Netty Internal I/O Threads (Transport Implementation) |
|
||||
+-------------------------------------------------------------------+
|
||||
|
||||
如上图所示,i/o event将会被`ChannelInboundHandler`或`ChannelOutboundHandler`处理,并且通过调用`ChannelHandlerContext`中的event propagation method(触发事件传播的方法)来进行转发。
|
||||
|
||||
常见的event propagation method如下,例如`ChannelHandlerContext.write(Object)`。
|
||||
|
||||
### inbound event
|
||||
inbound event会通过inbound handler自底向上的进行处理,例如上图的左边部分所示。inbound handler通常处理由io thread产生的inbound data,inbound则是通常从remote peer读取。
|
||||
|
||||
> 如果inbound event传播到高于top inbound handler,那么该event将会被丢弃。
|
||||
|
||||
### outbound event
|
||||
outbound event会按照自顶向下的顺序被outbound进行处理,outbound handler通常产生outbound traffic或对outbound traffic进行处理。
|
||||
|
||||
> 如果outbound event传播到低于bottom outbound handler, 其会直接被channel关联的io线程处理。
|
||||
|
||||
> 通常,io thread会执行实际的输出操作,例如`SocketChannel.write(ByteBuffer)`。
|
||||
|
||||
### pipeline处理顺序
|
||||
例如,按照如下顺序项pipeline中添加handler时,
|
||||
```java
|
||||
ChannelPipeline p = ...;
|
||||
p.addLast("1", new InboundHandlerA());
|
||||
p.addLast("2", new InboundHandlerB());
|
||||
p.addLast("3", new OutboundHandlerA());
|
||||
p.addLast("4", new OutboundHandlerB());
|
||||
p.addLast("5", new InboundOutboundHandlerX());
|
||||
```
|
||||
#### inbound
|
||||
对于inbound event,handler的执行顺序为`1,2,3,4,5`
|
||||
|
||||
但由于`3,4`没有实现ChannelInboundHandler,故而Inbound event会跳过`3,4` handler,实际Inbound event的handler顺序为`1,2,5`
|
||||
|
||||
#### outbound
|
||||
对于outbound event,handler的执行顺序为`5,4,3,2,1`
|
||||
|
||||
对于outbound evnet,由于`1,2`并没有实现ChannelOutboundHandler,故而outbound event的handler顺序为`5,4,3`。
|
||||
|
||||
> inbound顺序和pipeline handler的添加顺序相同,outbound顺序和pipeline handler添加顺序相反。
|
||||
|
||||
### 将event转发给下一个handler
|
||||
如上图所示,再handler中必须调用`ChannelHandlerContext`中的event propagation method来将event转发给下一个handler。`event propagation event`包括的方法如下:
|
||||
|
||||
#### Inbound event propagation method
|
||||
- ChannelHandlerContext.fireChannelRegistered()
|
||||
- ChannelHandlerContext.fireChannelActive()
|
||||
- ChannelHandlerContext.fireChannelRead(Object)
|
||||
- ChannelHandlerContext.fireChannelReadComplete()
|
||||
- ChannelHandlerContext.fireExceptionCaught(Throwable)
|
||||
- ChannelHandlerContext.fireUserEventTriggered(Object)
|
||||
- ChannelHandlerContext.fireChannelWritabilityChanged()
|
||||
- ChannelHandlerContext.fireChannelInactive()
|
||||
- ChannelHandlerContext.fireChannelUnregistered()
|
||||
|
||||
#### Outbound event propagation method
|
||||
- ChannelHandlerContext.bind(SocketAddress, ChannelPromise)
|
||||
- ChannelHandlerContext.connect(SocketAddress, SocketAddress, ChannelPromise)
|
||||
- ChannelHandlerContext.write(Object, ChannelPromise)
|
||||
- ChannelHandlerContext.flush()
|
||||
- ChannelHandlerContext.read()
|
||||
- ChannelHandlerContext.disconnect(ChannelPromise)
|
||||
- ChannelHandlerContext.close(ChannelPromise)
|
||||
- ChannelHandlerContext.deregister(ChannelPromise)
|
||||
|
||||
### build pipeline
|
||||
在一个pipeline中,应该包含一个或多个ChannelHandler用于接收IO事件(read)和请求IO操作(write and close)。例如,一个典型的server其channel的pipeline中应该包含如下handler:
|
||||
- protocol decoder:将二进制数据转化为java object
|
||||
- protocol encoder:将java object转化为二进制数据
|
||||
- business logic handler:执行实际业务操作
|
||||
|
||||
构建pipeline示例如下:
|
||||
```java
|
||||
static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
|
||||
...
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
|
||||
pipeline.addLast("decoder", new MyProtocolDecoder());
|
||||
pipeline.addLast("encoder", new MyProtocolEncoder());
|
||||
|
||||
// Tell the pipeline to run MyBusinessLogicHandler's event handler methods
|
||||
// in a different thread than an I/O thread so that the I/O thread is not blocked by
|
||||
// a time-consuming task.
|
||||
// If your business logic is fully asynchronous or finished very quickly, you don't
|
||||
// need to specify a group.
|
||||
pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
|
||||
```
|
||||
当为BusinessLogicHandler指定DefaultEventExecutorGroup时,虽然会将操作从EventLoop中卸载,但是其针对每个ChannelHandlerContext仍然是串行进行处理的。故而,串行处理可能仍然会导致性能瓶颈。如果在用例场景下顺序不太重要时,可以考虑使用`UnorderedThreadPoolEventExecutor`来最大化任务的并行执行。
|
||||
|
||||
### ThreadSafety
|
||||
channelhandler可以在任何时刻添加到pipeline或从pipeline中移除,ChannelPipeline是线程安全的。例如,可以在交换敏感信息前添加encryption handler并且在交换完信息后将encryption handler移除。
|
||||
|
||||
Reference in New Issue
Block a user