netty 图解_Netty源码分析:图解Pipeline、Handler、Context

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

一、connect(outbound类型事件)

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

二、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的过程可以看下文的另一张图。

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

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

四、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线程中执行的。

五、flush(outbound类型事件)

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

六、当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的线程模型,便于理解。

1、Boss Group:作为服务端 Acceptor 线程,用于 accept 客户端链接,并转发给 WorkerGroup 中的线程。Netty中虽然也可以将Boss Group设置为多个,但是在执行bind的时候只会绑定其中的一个,而不是同时绑定所有(类似nginx以前的惊群效应)。

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值