Netty中BossGroup与WokerGroup协同工作—源码简要分析

1.BossGroup与WorkerGroup简单示意图如下:

Netty中BossGroup与WokerGroup协同工作—源码简要分析

2.首先搞清楚BossGroup和WorkerGroup中Channel分别如何产生与注册到Group中去的?

3.BossGroup中的Channel是何时以及如何创建的?

(1) 在ServerBootstrap.bind()绑定相应的地址时,会根据传入的channelClass类创建对应的ChannelFactory,在ServerBootstrap.initAndRegister()方法中

使用ChannelFactory反射实例化NioServerSocketChannel。

(2)初始化NioServerSocketChannel实例之后传入到ServerBootStrap.init(Channel)

设置Channel初始化值,如ChannelOptions,Attributes。

还有利用ChannelInitializer 将原始初始化ChannelHandler加入到Pipeline中

关键也加入了对于新channel接受动作。

这边是利用一个ServerBootstrapAcceptor来监听channelRead事件,将新产生的channel绑定到childGroup (workerGroup),最终是绑定到WorkerGroup中某个EventLoop 中去。

Netty中BossGroup与WokerGroup协同工作—源码简要分析

4.BossGroup中的Channel是如何注册到BossGroup中的?

在以上初始化好NioServerSocketChannel之后,进行注册。config().group()其实是返回的parent group,即在我们初始化时,传入的BossGroup。

Netty中BossGroup与WokerGroup协同工作—源码简要分析

注:这边再详细说一下绑定过程

group().register(),其实通过代码跟进,它会通过Group中一个next()方法选择NioEventLoopGroup中一个NioEventLoop来具体进行绑定一个Channel对象。因为一个channel只能对应一个Eventloop。

SingleThreadEventLoop中 绑定关键代码如下:

public ChannelFuture register(final ChannelPromise promise) 
{
    ObjectUtil.checkNotNull(promise, "promise");
    promise.channel().unsafe().register(this, promise);
    return promise;
}复制代码

可以看最终是调用Channel对象下的一个内部类UnSafe对象进行完成注册。

最终的注册动作是将真正的jdk channel绑定到的EventLoop中的Selector中去。每个channel绑定到Selector中之后,就会形成一个SelectionKey,会加入到EvenLoop中的keyset集合中去。方便在循环遍历时检查每个channel的状态。

Netty中BossGroup与WokerGroup协同工作—源码简要分析

5.WorkerGroup中的Channel是何时以及如何创建的?

在BossGroup启动之后,对应的NioEventLoopGroup线程池的NioEventLoop线程就会死循环检查已经绑定到对应的Selector上的Channel的I/O事件。

(1)当没有发生I/O事件时,NioEventLoop线程会一直堵塞在selector.select() 该方法上

Netty中BossGroup与WokerGroup协同工作—源码简要分析

(2)一旦有I/O过来之后,就会调用processSelectedKeys()去处理,循环检查SelectedKeys中的每个key,再进入processSelectedKey()。

(3)再调用对应发送符合事件的channel的unsafe.read() 方法。再该方法中会创建对应NioSocketChannel对象。

Netty中BossGroup与WokerGroup协同工作—源码简要分析

6.WorkerGroup中的Channel是如何注册到WorkerGroup中的?

从上面的小点中可以看出在NioServerSocketChannel发生了I/O事件中初始化了NioSocketChannel对象,下面就是需要将该对象中是如何注册到WorkerGroup中的解释了。

因为在创建NioServerSocketChannel实例是我们在其Pipeline中添加了ServerBootstrapAcceptor的InboundChannelHandler。并且如下图所示,在创建完Channel之后又将会会NioServerSocketChannel的Pipeline的channelread方法。这样在ServerBootstrapAcceptor中的channelread方法也会得到相应的触发。

Netty中BossGroup与WokerGroup协同工作—源码简要分析

这样在ServerBootStrap中的ServerBootstrapAcceptor中

的channelRead就会触发,将新生成的channel注册到ChildGroup中去。接下来就会由WorkGroup的EventLoop对channel进行管理

Netty中BossGroup与WokerGroup协同工作—源码简要分析

7.对SevrerBootstrapAcceptor类简单概述

SeverBootstrapAcceptor也是一个Inbound处理器,用于Server端accept新的客户端连接时,向新生成的socketChannel中添加用户定义的业务处理器。且将新生成的socketChannel注册到WorkerGroup中去。

8.对UnSafe类简单概述

Unsafe是Channel的内部类,一个Channel对应一个UnSafe。

UnSafe用于处理Channel对应网络IO的底层操作。ChannelHandler处理回调事件时产生的相关网络IO操作最终也会委托给UnSafe执行。

UnSafe接口中定义了socket相关操作,包括SocketAddress获取、Selector注册、网卡端口绑定、socket建联与断连、socket写数据

其实workgroup与bossgroup在监听I/O事件逻辑是一样(本身就是同一块代码实现),为什么会有不同read效果呢。从上面的分析,BossGroup会通过UnSafe.read()会有Channel实例产生,但是如果是wokergroup就不是这样的。

为什么呢?

那是因为NioServerSocketChannel 和 NioSocketChannel内部对unsafe的实现不一样。次啊会有此区别。每次与socket的交互还是会通过对应channel的unsafe类进行的。这样虽然BossGroup和Woke人Group共享NioEventLoop代码,但是由于其使用的Channel类型对应的UnSafe实现不一样才会导致对read方法调用有不一样的行为。

Netty中BossGroup与WokerGroup协同工作—源码简要分析

Bossgroup : 

NioMessageUnsafe —> AbstractNioMessageChannel、NioServerSocketChannel

Workergroup :

NioByteUnsafe —> AbstractNioByteChannel、NioSocketChannel

原文 

https://juejin.im/post/5eef8b7ae51d45741a7edfec

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Netty中BossGroup与WokerGroup协同工作—源码简要分析

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址