Reactor线程模型的对比

在高性能网络通信框架中,I/O 模型和线程模型是两个核心的关注点。对于 I/O 多路复用模型,需要将 selector 上的事件分发给对应的事件处理者。在 Reactor 线程模型中,Reactor 作为事件分发器,负责分发各种 I/O 事件。

一个 server 启动后,需要监听网络端口上的远程连接。

当有 client 请求建立连接时,selector 上会产生 accept 事件,Reactor 将 accept 事件交给 acceptor 处理,从而建立连接。

连接建立好后,server 和 client 之间就可以发送和接收数据了,数据的接收需要经过 decode 操作解析成所需的格式,然后 compute 进行业务逻辑处理,发送前需要 encode 成网络传输所需的格式。

整体流程为:accept -> 建立连接 -> read -> decode -> compute -> encode -> send

Reactor线程模型对比

单线程模型

所有的操作全部运行在一个 Reactor 线程中,一次只能接收和处理一个连接。

当一个请求未处理完时,selector 无法接收新的请求,也就无法建立新的连接,会造成请求超时。

即使每个请求的响应都很快,同时能够处理的请求数量也很有限。

多线程模型

多线程的改进在于将 decode、compute、encode 这些非 I/O 操作放到了线程池中进行处理,这样一来,业务逻辑的耗时长短不会对 Reactor 线程造成影响,Reactor 线程只需要负责处理 accept、read、send 等 I/O 操作即可。

主从多线程模型

在多线程模型中,Reactor 需要处理多种 I/O 操作,其中 read 和 send 操作可能因为数据量大导致耗时较长,这会影响其他事件的处理,从而影响并发度。

主从多线程模型中,Reactor 根据职责划分为 mainReactor 和 subReactor,其中 mainReactor 只负责分发 accept 事件给 acceptor 处理,acceptor 与 mainReactor 运行在同一个线程中,建立连接后交给 subReacotr 处理。subReactor 与多线程模型中的 Reactor 类似,它负责 read 和 send 操作,将 decode、compute和encode 操作放到业务线程池中处理。为了提高并发度,可以创建多个 subReactor,这样就可以充分利用多处理的能力。

netty中的实现

netty 中的 bossGroup 对应 Reactor 线程模型中的 mainReactor,workerGroup 对应 Reactor 线程模型中的 subReactor,可通过配置 bossGroup 和 workerGroup 参数指定线程模型。

单线程模型

1
2
3
4
5
6
7
8
// 配置eventLoopGroup为单线程
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);

// bossGroup和workerGroup共用一个EventLoopGroup
ServerBootstrap b = new ServerBootstrap();
b.group(eventLoopGroup)
.channel(NioServerSocketChannel.class)
...

多线程模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 配置eventLoopGroup为单线程
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);

// bossGroup和workerGroup共用一个EventLoopGroup
ServerBootstrap b = new ServerBootstrap();
b.group(eventLoopGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
p.addLast(new MyHandler);
}
});

// MyHandler中将decode、compute、encode事件放到业务线程池中处理

主从多线程模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 配置bossGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// 配置workerGroup,默认线程数为NettyRuntime.availableProcessors() * 2
EventLoopGroup workerGroup = new NioEventLoopGroup();

// bossGroup和workerGroup为单独的EventLoopGroup
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
p.addLast(new MyHandler);
}
});

// MyHandler中将decode、compute、encode事件放到业务线程池中处理