Netty(三)——组件协作

2017-07-17 11:00:03来源:oschina作者:MarvelCode人点击


前言:

Netty的大部分设置都是通过Bootstrap来配置的,这节主要对Bootstrap的配置及启动作简单的分析。

Bootstrap:

3.x:ServerBootstrap 和 ClientBootstrap


4.x:ServerBootstrap 和 Bootstrap


//3.x
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
//4.x
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);
b.channel(NioServerSocketChannel.class);

指定了boss线程池和worker线程池:


boss线程用来监听端口,并accept客户端的socket请求,产生channel交由worker线程处理后,返回继续监听端口。和端口是一对一的关系。


worker线程用来处理请求。如果是阻塞式IO(NIO),worker会为一个socket工作直到此socket关闭为止,这样会造成线程数随连接数线性增长,最终造成线程堆栈溢出。如果是非阻塞式IO(OIO),worker会为不同的socket工作,这样很少一部分的worker线程就可以处理很多连接。


public B channel(Class<? extends C> channelClass) {
if(channelClass == null) {
throw new NullPointerException("channelClass");
} else {
return this.channelFactory(new AbstractBootstrap.BootstrapChannelFactory(channelClass));
}
}

通过指定Channel的类型,来选择NIO or OIO。


ServerBootstrap的初始化源码:


//ServerBootstrap
void init(Channel channel) throws Exception {
//...
ChannelPipeline p = channel.pipeline();
// 在AbstractBootstrap中实现
if (handler() != null) {
p.addLast(handler());
}
//...
final EventLoopGroup currentChildGroup = childGroup;// 通过childHandler(ChannelHandler childHandler)方法传入
final ChannelHandler currentChildHandler = childHandler;
//...
p.addLast(new ChannelInitializer() {
@Override
public void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ServerBootstrap.ServerBootstrapAcceptor(
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
final ChannelHandler handler() {
return handler; // 通过handler(ChannelHandler handler)方法传入
}

可以看到,初始化的过程中将你设置的Handler加入到了ChannelPipeline。Netty中常见的Handler比如StringEncoder/Decoder,ObjectEncoder/Decoder等。


worker线程会将数据读入后,触发相应的事件传递给ChannelPipeline,经过一系列的Handler数据、业务处理;通常业务处理放在Handler链的末端,如果其中包含复杂的逻辑判断、数据库交互等等耗时操作,worker线程会一直工作直至业务Handler方法执行结束。


为了有效的减少worker线程的周期循环时间,能够想到的办法就是在messageReceived方法中开启一个线程来处理业务,这样worker线程就可以快速返回。其实Netty已经为我们考虑到了这种情况,ExecutionHandler(3.x)就是用来解决这种场景:


private final Executor executor;
private final boolean handleDownstream;
private final boolean handleUpstream;
public ExecutionHandler(Executor executor) {
this(executor, false, true);
}

在业务处理Handler前添加:


pipeline.addLast("execution", new ExecutionHandler(
new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576)));
pipeline.addLast("business", new HelloHandler());

这样每当处理业务Handler前,就会从线程池中取出一个线程单独执行。

总结:

下一节会对Netty的线程模型进行分析。

微信扫一扫

第七城市微信公众平台