Netty源码分析:图解Pipeline、Handler、Context

      为了和以前的Wangle源码分析系列造成呼应,如今将之前写的Netty的图解过程搬移过来。 如下所绘制图形均基于Netty4.0.28版本。nginx

1、connect(outbound类型事件)

   当用户调用channel的connect时,会发起一个outbound类型的事件,该事件将在pipeline中传递(pipeline.connect),首先由tail handler处理,该handler只是将事件透传给下一个outbound类型的用户Handler(若是有),事件依次传递下去,直到传递到head handler,该handler会调用unsafe.connect()向eventloop(nio的selector)注册一个读事件。 缓存

             

 

2、connect成功以后数据流图(inbound类型事件)

   当用户发起一个connect请求后,当链接可用时,eventloop(底层使用nio的selector)会引起一个ChannelActive事件,该事件最早有unsafe捕获,以后会调用pipeline.fireChannelActive()将该事件在pipeline中传播,紧接着会根据inbound类型事件的传递方式在各个handler和context之间进行链式传递。其中,有一个比较关注的地方是,在channelActive事件触发的时候,若是channel被设置成autoRead,那么此时还会调用channel.read()方法,该方法并非真正的从channel读取数据,而是向eventloop注册读事件(由于一个channel在向eventloop中注册时,默认不注册任何事件),关于channel.read的过程能够看下文的另外一张图。网络

              

3、channel.read事件流图(outbound类型事件)

     当用户调用channel.read()后,会发起一个outbound类型的事件,该事件最早会由pipeline中tail handler处理,该handler只是将该事件透传给前面一个outbound类型的用户handler(若是有的话),这样依次继续向前传递,直到传递到head handler,该handler会调用unsafe.read()向eventloop注册读事件(也就是向nio的selector上添加读事件)。oop

                

4、channel.write(outbound类型事件)

      与channel.read()类型相同,wirte也是一个outbound类型事件,该事件最早会由pipeline中的tail handler透传给前面的一个outbound类型的用户handler(若是有的话),这样依次传递,直到传递给head handler,该handler会调用unsafe.write()方法,这里的wirte并不会执行真正的发送,而是将要发送的数据缓存起来,直到调用flush时,这些数据才会执行真正的网络io。 这里须要注意,若是调用write的线程不是当前channel绑定的io线程(EventLoop),那么在write内部会判断,并将写操做封装成一个task强行加入io线程(EventLoop)的队列,所以后续的write操做就是在io线程中执行的。源码分析

                  

5、flush(outbound类型事件)

         如前文所示,flush也是一个outbound类型的事件,与wirte不一样,flush会执行真正的网络io操做。spa

                 

6、当channel有数据可读时(inbound类型事件)

      当eventloop层检测到网络层有数据可读时(nio的selector返回相应的seleciontKeys),该事件会首先传递给unsafe,紧接着会调用pipeline.fireChannelRead(),将事件开始在pipeline中传递,该事件最早会有head handler处理(head.fireChannelRead()),该handler直接将事件透传给下一个inbound类型的用户handler(若是有的话),该事件依次向下传递,直到传递到tail handler。这里须要注意,由于全部的handler默认都是在io线程中串行执行的,所以若是某个handler比较耗时,就可能致使io线程阻塞,从而致使绑定在这个io线程(EventLoop)上的全部channel上的事件得不处处理,引发各类超时,为此,能够为这样的handler单独设置一个线程池EventExecutorGroup,这样当执行到这个handler时,将从EventExecutorGroup取一个线程执行,可是此时要注意handler之间的共享访问问题。线程

                 

 

 

       最后,盗用一张网络的图,从总体上介绍一下Netty的线程模型,便于理解。3d

                

 

一、Boss Group:做为服务端 Acceptor 线程,用于 accept 客户端连接,并转发给 WorkerGroup 中的线程。Netty中虽然也能够将Boss Group设置为多个,可是在执行bind的时候只会绑定其中的一个,而不是同时绑定全部(相似nginx之前的惊群效应)。blog

二、Worker Group:做为 IO 线程,负责 IO 的读写,从 SocketChannel 中读取报文或向 SocketChannel 写入报文。队列

三、Task Queue/Delay Task Queue:做为定时任务线程,执行定时任务,例如链路空闲检测和发送心跳消息等。

四、ExecutorGroup:业务自定义线程池,处理一些耗时任务。

相关文章
相关标签/搜索