關于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