关于Netty线程模型的文章特别多,其中也有讲的非常好的。Netty线程模型的核心在于其如何实现Reactor模型,以能够满足海量I/O请求。本文主要简单总结、回顾一下Reactor模型,然后重点介绍Netty是如何实现Reactor模型并提供给使用者的。
1.Reactor模型回顾(以服务端实现为例)
关于Java NIO构建Reactor模式,Doug Lea在“Scalable IO in Java”中给了很好的阐述。在这里仅仅简单介绍一下。
1.1单线程模型
这是最简单的单Reactor单线程模型。Reactor线程的处理过程为:Accept新连接,并分派请求到处理器链中。在该模型中,所有的操作都在Reactor的线程中执行,不能充分利用多核资源,一旦连接请求数目上升,性能瓶颈比较大。
1.2多线程模型
相比上一种模型,该模型Reactor主线程中只处理了acceptor以及read/sent 操作,将中间的computer、decode、encode放在多线程的Pool中去执行。这样就可以充分利用多线程的优势,提升系统可处理连接的并发数。但是感觉单个Reactor处理的事情还是太多,对于百万量级的连接数,性能上可能还是会有问题。或者对于一个连接可能会读取一个大文件时可能会堵塞到其他连接的请求。
1.3主从模型
第三种模型比起第二种模型,是将Reactor分成两部分:mainReactor和subReactor,mainReactor负责accept新连接,并将建立的socket分派给subReactor。subReactor负责处理read、send操作。
摘抄了其他人的一段话,不知道是不是正确的:“在绝大多数场景下,Reactor多线程模型都可以满足性能需求;但是,在极个别特殊场景中,一个NIO线程负责监听和处理所有的客户端连接可能会存在性能问题。例如并发百万客户端连接,或者服务端需要对客户端握手进行安全认证,但是认证本身非常损耗性能。在这类场景下,单独一个Acceptor线程可能会存在性能不足问题,为了解决性能问题,产生了第三种Reactor线程模型-主从Reactor多线程模型。”
2.Netty线程模型的实现(以服务端为例)
Netty Server端通过提供类ServerBootstrap
实现不同类型的Reactor模型。简单总结下边的例子,bossGroup
代表的是Reactor模型中的mainReactor,workerGroup
代表的是Reactor模型中的subReactor。
注意:bossGroup
设定的线程个数应该与所要监听的端口数目保持一致。如果仅仅是监听一个端口,bossGroup
设定的线程个数应该为1,因为在Netty模型中只会有一个acceptor线程。
2.1单线程模型
单线程模型比较简单:
public void bind(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024).handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new SimpleNettyServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
}
}
2.2多线程模型
不太标准的一个多线程模型,但模型上大致与Reactor多线程模型类似,区别的地方在于read、send操作由谁执行的问题。
public void bind(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new SimpleNettyServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
2.3主从线程模型
新增了一个EventExecutorGroup
用于执行业务逻辑。
static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
public void bind(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(group, new SimpleNettyServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
3.参考资料
http://www.infoq.com/cn/articles/netty-threading-model/
http://blog.csdn.net/heyutao007/article/details/45626235
http://www.importnew.com/15656.html
http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf
http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html
网友评论