1.Netty 中的 NioEventLoop 是什么?请谈一下你的认识。
Netty 中的 NioEventLoop 是一个 EventExecutor,其是在创建 NioEventLoopGroup 时创
建的,存放在一个 EventExecutor 数组中。但其本质上是一个 Executor,用于执行相应的任
务。同时,NioEventLoop 包含了一个 Executor,该 Executor 绑定了一个新创建线程,
NioEventLoop 真正的任务是由这个线程完成的。
2.Netty 中的 NioEventLoop 本身是一个 Executor,所以其实现了 execute()方法。同时,
NioEventLoop 中还包含了一个 Executor,该 Executor 也具有 execute()方法。这两个 execute()
方法完成的工作有什么不同?请谈一下你的认识。
NioEventLoop 本身的 execute()方法主要完成两样工作:
用于将任务添加到任务队列
调用请所包含的 executor 的 execute()方法
NioEventLoop 中包含的 Executor 的 execute()方法主要完成了两项工作:
调用NioEventLoopGroup中总的executor的execute()方法,创建并启动这个NioEventLoop
所包含的 executor 所相绑定的线程,去执行任务
将真正的任务执行任务再封装为一个任务
3.
Netty 中的 NioEventLoopGroup 是什么?请谈一下你的认识。
【RA】Netty 中的 NioEventLoopGroup 本质上是一个 Executor,主要完成了两项工作:
从 EventLoop 数组中按照策略选择一个 EventLoop
调用这个选出的 EventLoop 的 execute()方法
同时,NioEventLoopGroup 还包含了一个 Executor,该 Executor 为每个 NioEventLoop 创
建并启动了一个线程去完成每个 NioEventLoop 的任务。
4.
Netty Server 中需要创建 ServerBootstrap 实例,这个实例的作用是什么?它有很多
的属性方法,这些属性方法有什么规律?请谈一下你的认识。
Netty Server 中需要创建 ServerBootstrap 实例。这个实例中可以设置很多的属性,这
些属性都是通过方法设置到 bootstrap 中的,将来都会作用于创建的 channel。
ServerBootstrap 中的属性方法可以分为两类:
作用于处理连接请求 channel 的属性:channel()、option()、attr()、handler()等
作用于处理 IO 请求 channel 的属性:childOption()、childAttr()、childHandler()等
5.
Netty 的 EventLoopGroup 中用于存放 eventLoop 的数据结构是什么?大小是多少?
请谈一下你的认识。
Netty 的 EventLoopGroup 中用于存放 eventLoop 的数据结构是数组。数组元素的个数
可以在创建 eventLoopGroup 时指定,默认为当前主机逻辑内核数量的 2 倍。
Netty 系统会自动将这些 NioEventLoop 所绑定线程的执行平均分配到各个逻辑内核上。这样做是为了充分
利用内核,提高系统性能
Netty 的 EventLoopGroup 在构造器中可以指定要创建的 EventLoop 的数量,这个数
量如何设置会使 EventLoop 的选择效率更高?请谈一下你的认识。
Netty 的 EventLoopGroup 在构造器中可以指定要创建的 EventLoop 的数量,同时在创
建这个 Group 时也会创建一个选择器 chooser,用于从 EventLoop 数组中选择一个。根据这
个数量是否是 2 的次幂,会创建不同的 chooser。它们的选择策略都是轮询,但实现方式不
同。若数量为 2 的次幂,则采用位移方式实现轮询,效率较高。所以在指定 EventLoop 数量
时最好指定为 2 的次幂。
6.请简述 Channel 实例在创建过程中都完成了哪些重要任务。
在创建 Channel 过程中完成了以下几个重要任务:
生成了 Channel 的 id
创建了真正的数据传输对象 Unsafe
创建了与 Channel 相绑定的 ChannelPipeline
为 Channel 创建了其配置类 ChannelConfig
7.
在 Netty 源码中出现了很多的 ChannelPromise,请谈一下你对它的认识。
ChannelPromise 是一种特殊的 ChannelFuture,其是可写的。该接口中具有很多的 set
方法,即是可以修改的,也就是可写的。其作用是,根据异步操作的结果:成功或失败,来
修改这个 Promise 的相关属性,以使 Promise 的获得者可以获知异步执行结果。
8.异步对象 Future 的 isDone()方法返回值为 true,表示的是异步操作执行成功吗?请
谈一下你对它的认识。
异步对象 Future 的 isDone()方法返回值为 true,表示的是异步操作完成。可以是任务
正常终止、异常发生,或取消任务
9.Netty 的每一个 Channel 都有一个唯一的标识 id,该 id 由什么组成?请谈一下你对
它的认识。
Netty 的每一个 Channel 都有一个唯一的标识 id,该 id 由五部分构成:
MACHINE_ID:机器 id,
即 MAC PROCESS_ID:进程 id
SEQUENCE:当前的时钟序列
TIMESTAMP:时间戳
RANDOM:随机数
9.Netty 的 Channel 中封装这一个 Unsafe 对象,请谈一下你对它的认识。
Netty 的 Channel 中封装这一个 Unsafe 对象,该对象中的方法就是对 channel 的底层
操作,这些方法用户代码是不能直接调用的。unsafe 实例就是对 channel 的底层操作对象。
也就是说,在进行 Netty 源码解析是,代码跟踪到 unsafe 的方法就相当于跟踪到了底层实现
了。
10.
对于 parentChannel,其在初始化过程中主要完成了哪些工作?
该初始化 channel 过程,其实主要完成了两项工作:
获取 ServerBootStrap 中的非 child 开头的属性,并初始化到 channel 中
获取 ServerBootStrap 中的 child 开头的属性,并初始化到一个连接处理器中,然后
再将这个连接处理器添加到 channel 的 pipeline 中
11.连接处理器 ServerBootstrapAcceptor 是何时实例化的,作用是什么?请谈一下你的
认识。
连接处理器 ServerBootstrapAcceptor 主要是用于处理 Client 的连接请求。该处理器在
Server 启动时实例化到 parentChannel 的 pipeline 中。也就是说,一个 parentChannel 就会绑
定一个连接处理器实例。而该连接处理器用于处理“由这个 parentChannel 接收的 Client 的
连接请求”。
当这个 parentChannel 接收到连接请求后,在其 channelRead()方法中会将其接收到的消
息强转为一个 childChannel,然后使用在 ServerBootstrap 中配置的 child 开头的属性初始化这
个 childChannel,并将 ServerBootstrap 中通过 childHandler 配置的 ChannelInitializer 中指定的
处理器添加到 childChannel 的 pipeline 中。
12.服务端启动会将 parentChannel 注册到相应的 selector,但为什么在注册时指定的其
关注的事件 ops 为 0,不应该是 OPS_ACCEPT 吗?请谈一下你的看法。
首先请注意当前类为 AbstractNioChannel,所有 channel 的注册都是调用的该方法,
该方法具有一般性。我们知道,channel 注册到 selector 后,selector 会为其生成一个
SelectionKey。这个 key 会一直保持其有效性,即一直会被 selector 轮询,直到调用了它的
cancel()方法,或它的 channel 关闭,或它的 selector 关闭。而 SelectionKey 中维护着两个表
现为整型数的集合 interestSet 与 readySet。其中 interestSet 中存放着其关注的就绪操作,用
户是可以修改的。
第二,parentChannel 对 OPS_ACCEPT 事件的关注是在哪里指定的呢?在注册之前,创建
NioServerSocketChannel 时就已经指定了。
就当前的问题来说,这里注册的是原生的 NIO 的 channel,而在创建 Netty 的
NioServerSocketChannel 时指定了 parentChannel 对 OPS_ACCEPT 事件的关注,其会修改
SelectionKey 的 interestSet。所以对于这个一般性的注册,指定的关注事件 ops 为 0 而不是具
体的事件。
13.Netty Server 中的 parentChannel 与 childChannel 都注册到了 Selector,它们注册的
是同一个 Selector 吗?请谈一下你的看法。
Netty Server 中的 parentChannel 与 childChannel 都注册到了 Selector,但它们注册的
却不是同一个。因为这两个 channel 绑定的 NioEventLoop 来自于不同 NioEventLoopGroup,
是不同的 NioEventLoop。而 Selector 于 NioEventLoop 间的关系为 1:1,所以 NioEventLoop 不
同,Selector 就不同。
14.与 eventLoop 所绑定的线程是由谁创建的,是何时创建的?请谈一下你的认识。
与 eventLoop 所绑定的线程是由 eventLoopGroup 所封装的 executor 创建的,确切地
说,是由与这个 executor 所绑定的 ThreadFactory 创建的,是在完成 channel 注册到 eventLoop
的 selector 时创建的。