共计 2403 个字符,预计需要花费 7 分钟才能阅读完成。
Netty 解决的事情
Netty 主要解决两个相应关注领域。(1)异步和事件驱动的实现。(2)一组设计模式,将应用逻辑与网络层解耦。
EventLoop 接口
用于处理连接的生命周期中所发生的事件。
- 一个 EventLoopGroup 包含一个或者多个 EventLoop
- 一个 EventLoop 在它的生命周期内只和一个 Thread 绑定
- 所有由 EventLoop 处理的 I / O 事件都将在它专有的 Thread 上被处理
- 一个 Channel 在它的生命周期内只注册于一个 EventLoop
- 一个 EventLoop 可能会被分配给一个或者多个 Channel
Netty NIO 客户端
// 创建一个 EventLoopGroup 对象
EventLoopGroup group = new NioEventLoopGroup();
// 创建 Bootstrap 对象
Bootstrap b = new Bootstrap();
// 设置使用的 EventLoopGroup
b.group(group);
- Netty 只创建一个 EventLoop
- 一个 EventLoop 可以对应一个 Reactor
- 一个 Bootstrap 的启动,只能发起对一个远程的地址。所以只会使用一个 NIO Selector,也就是说仅使用一个 Reactor。即使,我们在声明使用一个 EventLoopGroup,该 EventLoopGroup 也只会分配一个 EventLoop 对 IO 事件进行处理。
Netty NIO 服务端
// 创建两个 EventLoopGroup 对象
EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 创建 boss 线程组 用于服务端接受客户端的连接
EventLoopGroup workerGroup = new NioEventLoopGroup(); // 创建 worker 线程组 用于进行 SocketChannel 的数据读写
// 创建 ServerBootstrap 对象
ServerBootstrap b = new ServerBootstrap();
// 设置使用的 EventLoopGroup
b.group(bossGroup, workerGroup);
- bossGroup 对应 Reactor 模式的 mainReactor,用于服务端接受客户端的连接。比较特殊的是,传入了方法参数 nThreads = 1,表示只使用一个 EventLoop,即只使用一个 Reactor。这个也符合我们上面提到的,“通常,mainReactor 只需要一个,因为它一个线程就可以处理”。
- workerGroup 对应 Reactor 模式的 subReactor,用于进行 SocketChannel 的数据读写。对于 EventLoopGroup,如果未传递方法参数 nThreads,表示使用 CPU 个数 Reactor。这个也符合我们上面提到的,“通常,subReactor 的个数和 CPU 个数相等,每个 subReactor 独占一个线程来处理”。
Netty 中的 Reactor 模型
- 处理链中的处理方法是串行化执行的
- 一个客户端连接只注册到一个 NioEventLoop 上,避免了多个 IO 线程并发操作
流程:
① 注册一个 Acceptor 事件处理器到 mainReactor 中,Acceptor 事件处理器所关注的事件是 ACCEPT 事件,这样 mainReactor 会监听客户端向服务器端发起的连接请求事件 (ACCEPT 事件)。启动 mainReactor 的事件循环。
② 客户端向服务器端发起一个连接请求,mainReactor 监听到了该 ACCEPT 事件并将该 ACCEPT 事件派发给 Acceptor 处理器来进行处理。Acceptor 处理器通过 accept() 方法得到与这个客户端对应的连接 (SocketChannel),然后将这个 SocketChannel 传递给 subReactor 线程池。
③ subReactor 线程池分配一个 subReactor 线程给这个 SocketChannel,即,将 SocketChannel 关注的 READ 事件以及对应的 READ 事件处理器注册到 subReactor 线程中。当然你也注册 WRITE 事件以及 WRITE 事件处理器到 subReactor 线程中以完成 I / O 写操作。Reactor 线程池中的每一 Reactor 线程都会有自己的 Selector、线程和分发的循环逻辑。
④ 当有 I / O 事件就绪时,相关的 subReactor 就将事件派发给响应的处理器处理。注意,这里 subReactor 线程只负责完成 I / O 的 read() 操作,在读取到数据后将业务逻辑的处理放入到线程池中完成,若完成业务逻辑后需要返回数据给客户端,则相关的 I / O 的 write 操作还是会被提交回 subReactor 线程来完成。
Netty 与 Reactor 模式
Netty 的线程模式就是一个实现了 Reactor 模式的经典模式。
结构对应:
NioEventLoop ———— Initiation Dispatcher
Synchronous EventDemultiplexer ———— Selector
Evnet Handler ———— ChannelHandler
ConcreteEventHandler ———— 具体的 ChannelHandler 的实现
模式对应:
Netty 服务端使用了“多 Reactor 线程模式”
mainReactor ———— bossGroup(NioEventLoopGroup) 中的某个 NioEventLoop
subReactor ———— workerGroup(NioEventLoopGroup) 中的某个 NioEventLoop
acceptor ———— ServerBootstrapAcceptor
ThreadPool ———— 用户自定义线程池
参考:
https://www.cnblogs.com/winne…
http://svip.iocoder.cn/Netty/…