netty之事件驱动原理

Netty使用了异步的事件驱动模型,来触发网络I/O的各种操作,其在socket层上面封装一层异步事件驱动模型,使得业务代码不需要关心网络底层,就可以编写异步的无网络I/O阻塞的代码。


Netty的异步事件驱动模型主要涉及到下面几个核心的概念:

  • Channel:表示一个与socket关联的通道
  • ChannelPipeline: 管道,一个Channel拥有一个ChannelPipeline,ChannelPipeline维护着一个处理链(严格的说是两 个:upstream、downstream),处理链是由很多处理句柄ChannelHandler所构成,每个ChannelHandler处理完以 后会传递给链中的下一个处理句柄继续处理。
  • ChannelHandler:处理句柄,用户可以定义自己的处理句柄来处理每个请求,或发出请求前进行预处理,典型的有编码/解码器:decoder、encoder。
  • ChannelEvent:事件,是整个模型的处理对象,当产生或触发(fire)一个事件时,该事件会沿着ChannelPipeline处理链依次被处理。
  • ChannelFuture: 异步结果,这个是异步事件处理的关键,当一个事件被处理时,可以直接以ChannelFuture的形式直接返回,不用在当前操作中被阻塞。可以通过 ChannelFuture得到最终的执行结果,具体的做法是在ChannelFuture添加监听器listener,当操作最终被执行完 后,listener会被触发,我们可以在listener的回调函数中预定义我们的业务代码。

模型的结构图如下:


ChannelPipeline实际上维持了两个处理链:upstream、downstream。 Upstream一般处理来自Channel的读事件,而downstream一般处理向Channel的写事件。需要注意的是,这两个处理链是相互独立 的,在upstream链中传递到最后一个ChannelHandler处理后,不会再传递到downstream链中继续处理。

在downstream链的末端会有个ChannelSink处理,用户可以自定义这个ChannelSink的实现,系统也有个默认的实现,当downstream链中最后一个ChannelHandler处理完后会被传递给这个ChannelSink进行最后的处理。

Netty4 SEDA事件驱动原理分析

AioServerSocketChannel的事件处理线程(AioEventLoop)建立过程分析

(Bootstrap启动ServerSocketChannel处理线程的过程分析)

1:AbstractBootstrap.initAndRegister():向BossGroup(AioEventLoopGroup)

注册初始化后的AioServerSocketChannel,

netty之事件驱动原理_第1张图片

2,调用MultithreadEventExecutorGroup.next()方法,在BossGroup中取出一个可用的EventLoop

netty之事件驱动原理_第2张图片

3,返回到MultithreadEventLoopGroup.register(Channel channel, ChannelPromise promise)方法,
将AioServerSocketChannel注册到(2)从BossGroup中取出的那个EventLoop.

4,进入到AioEventLoop.register(Channel channel, ChannelPromise future)方法

AioEventLoop实现了JDK的ScheduledExecutorService,持有一条线程,具备任务执行能力,

将AioServerSocketChannel测试到AioEventLoop后,由AioEventLoop执行ServerSocketChannel的accept新的socket的操作

netty之事件驱动原理_第3张图片

5,进入到AbstractChannel.AbstractUnsafe.register(EventLoop eventLoop, ChannelPromise promise)方法,

netty之事件驱动原理_第4张图片

6)进入到SingleThreadEventExecutor.execute(Runnable task)方法,执行startThread()后,AioServerSocketChannel的事件处理线程(AioEventLoop)启动,将由它来接管AioServerSocketChanel的事件处理(如Accept新的Socket),然后ServerBootstrap线程就进入等待状态,等待ServerSocketChannel绑定端口,然后等待ServerSocketChannel关闭.

netty之事件驱动原理_第5张图片

7)先看下面

netty之事件驱动原理_第6张图片

netty之事件驱动原理_第7张图片

8)AioServerSocketChannel的事件处理线程AioEventLoop从一个BlockingDeque里取出新任务,取出的第一个任务是给AioServerSocketChannel注册JDK的AsynchronousServerSocketChannel(这才是真正和底层操作系统通信的ServerSocketChannel)

netty之事件驱动原理_第8张图片

注册了:

9)Channel成功注册后,调用其pipeline.fireChannelRegistered()方法Fire这个channel注册的事件

netty之事件驱动原理_第9张图片

10)ChannelPipeline的fireChannelRegistered方法先初始化其处理器链的第一个元素HeadHandler,然后再执行HeadHandler的fireChannelRegistered()方法

netty之事件驱动原理_第10张图片

DefaultChannelHandlerContext.fireChannelRegistered(),Netty4的DefaultChannelHandlerContext对ChannelInboundInvoker接口的的事件处理方法fireXxxx(),具有链式传递效应,顺序将同一方向上的所有事件

netty之事件驱动原理_第11张图片

netty之事件驱动原理_第12张图片

netty之事件驱动原理_第13张图片

11)然后,AioServerSocketChanel的pipeline的处理器链上的ChannelInitializer响应channelRegistered事件:pipeline安装上Acceptor,使得AioServerSocketChanel得以具备处理socket Accept事件的能力.

12) AioServerSocketChanel将accept委托给JDK的异步ServerSocketChannel来执行异步accept,并指定了事件处理器,当ACCEPT事件发生的时候, AcceptHandler就会被调用

netty之事件驱动原理_第14张图片

然后AioServerSocketChanel的AioEventLoop就进入等待状态,等待taskQueue有任务到来

13)现在在浏览器输入http://127.0.0.1:8080/,向服务器发出请求

当相应事件发生时,JDK的CompletionHandler.complted(..)方法会被一条后台Daemon的线程调用:

netty之事件驱动原理_第15张图片

netty之事件驱动原理_第16张图片

netty之事件驱动原理_第17张图片

将接收到的SocketChannel包装成AioSocketChannel作为一个Message写进AioServerSocketChannel的ChannelPipeline的inboundMessageBuffer,然后Fire相关事件inboundBufferUpdated事件

14)AioServerSocketChannel的ChannelPipeline Fire inboundBufferUpdated事件

netty之事件驱动原理_第18张图片

15)沿inbound方向找到了SererBootstrapAcceptor的ChannelHandlerContext

netty之事件驱动原理_第19张图片

16)inboundBufferUpdate事件传递到ServerBootstrapAcceptor

netty之事件驱动原理_第20张图片

17)DefaultChannelHandlerContext.invokeInboundBufferUpdated(),调用Acceptor的inboundBufferUpdated方法

netty之事件驱动原理_第21张图片

18)Acceptor取得AioSocketChannel,并向其添加ChannelInitializer

netty之事件驱动原理_第22张图片

19)向ChildGroup注册AioSocketChannel

netty之事件驱动原理_第23张图片

20)将AioSocketChannel注册到AioEventLoopGroup分配的AioEventLoop上

netty之事件驱动原理_第24张图片

21)BOSS线程(AioServerSocketChannel所属的线程)启动AioSocketChannel所属的AioEventLoop线程,BOSS线程的Accept工作也至此结束,然后就去回去处理其taskQueue中的任务,或进入wait状态,等待下一个Accept事件的发生.

netty之事件驱动原理_第25张图片

Worker线程线程的初始化

22)Worker线程(AioSocketChannel所属的AioEventLoop)独立运行后,取出其taskQueue中的第一个任务:通过AioSocketChannel的ChannelPipeline触发pipeline的ChannelHandlerContext处理器链的channelRegistered注册事件

netty之事件驱动原理_第26张图片

23)初始化ByteHeadHandler(ChannelOutboundHandler的子类),给它分配outByteBuf和outMsgBuf

netty之事件驱动原理_第27张图片

24)触发处理器链的下一节点的channelRegistered事件


netty之事件驱动原理_第28张图片

25)沿ChannelHandlerContext处理器链找到了自己定义的用户AioSocketChannel初始化的HttpSnoopServerInitializer

netty之事件驱动原理_第29张图片

26)ChannelInitializer是利用channelRegistered事件来初始化pipeline,向其安装相关channelHandler

netty之事件驱动原理_第30张图片

27)从pipeline的处理器链删除初始化器,并触发下一处理器的channelRegistered事件

netty之事件驱动原理_第31张图片

28) channelRegistered事件通过一个一个ChannelHandlerContext的fireChannelRegistered方法沿ByteHeadHandler传递到TailHandler,然后事件就停止传播

netty之事件驱动原理_第32张图片

29)ChannelPipeline完成channelRegistered的事件触发后,就触发channelActive事件,

然后channelActive事件就随着ChannelHandlerContext和链式调用而在处理器链中传递,原理上上面差不多,故不详细说.

netty之事件驱动原理_第33张图片

30)AioSocketChannel读取数据

netty之事件驱动原理_第34张图片

由pipeline来读取数据

netty之事件驱动原理_第35张图片

到TailHandler读取数据

netty之事件驱动原理_第36张图片

31)向outbound方向上寻找最近的ChannelOperationHandler,委托它进行数据读取

netty之事件驱动原理_第37张图片

首先委托给HttpResponseEncoder读取

netty之事件驱动原理_第38张图片

HttpRequestDecoder委托给下一个ChannelOperationHandler读取

netty之事件驱动原理_第39张图片

最终委托给ByteHeadHandler读取

netty之事件驱动原理_第40张图片

32)最终由AioSocketChannel通过JDK的AsynchronousSocketChannel从底层读取

netty之事件驱动原理_第41张图片

33)AioSocketChannel将读取数据操作委托给JDKAsynchronousSocketChannel来完成,AioSocketChannel的当前线程不会被阻塞,立马返回处理taskQueue中下一任务或没任务时进入wait等待BlockingQueue的状态.

AsynchronousSocketChannelread操作完成后,ReadHandler会被一条后台Daemon线程调用

netty之事件驱动原理_第42张图片

34)ReadHandler的执行从Daemon线程转移回AioSocketChannle所属的AioEventLoop线程来执行

netty之事件驱动原理_第43张图片

35)由AioEventLoop执行ReadHandler

netty之事件驱动原理_第44张图片

36)数据已准备好,pipeline触发inboundBufferUpdated方法,然后pipeline中处理器链的inbound方向上的ChannelStateHandler的inboundBufferUpdated方法会被顺度调用

netty之事件驱动原理_第45张图片

37)head触发处理器链上inbound方向上的stateHandler的inboudBufferUpdated方法的顺序调用

netty之事件驱动原理_第46张图片

38)处理器链上inbound方向上的stateHandler的inboudBufferUpdated方法的顺序调用

-----这里省略,参考:http://blog.csdn.net/irelandken/article/details/8760302

39)输入数据:DefaultChannelHandlerContext.flush(ChannelPromise promise)

netty之事件驱动原理_第47张图片

40)由HttpServerCodec中的HttpResponseEncoder将HttpMessage转换为ByteBuf

DefaultChannelHandlerContext.invokeFlush0(ChannelPromise promise)

netty之事件驱动原理_第48张图片

41)由Pipeline的ByteHeadHandler将ByteBuf flush出去

netty之事件驱动原理_第49张图片

42)AioSocketChannel将Flush操作委托给JDK AsyncounsSocketChannel异步进行,最终结果等写操作完成后由后台Deamon线程通知并执行WriteHandler.

而AioEventLoop线程是马上返回的,不会被write操作阻塞,然后继续执行taskQueue中的任务或进入wait状态等待BlockingQueue.

netty之事件驱动原理_第50张图片

43)Write操作完成后,WriteHandler被后台Daemon线程调用

netty之事件驱动原理_第51张图片

44)再次WriteHandler转交由关联的AioSocketChannel所属的AioEventLoop执行

netty之事件驱动原理_第52张图片

45) AioEventLoop执行完WriteHandler后,整个接收和响应过程就完成了.

你可能感兴趣的:(netty之事件驱动原理)