Netty是Reactor模式事件驱动网络框架,Netty不仅用法简单,而且性能和可靠性都很好,所以被很多的中间件作为网络层使用,像dubbo, RocketMQ底层都采用了Netty。
Netty采用的是Reactor模式,由一个boss线程池充当main reactor,worker线程池充当sub reactor,main reactor负责监听端口,接收socket连接;sub reactor负责socket数据的读写,main reactor将接收的socket连接分配给sub reactor,sub reactor负责管理socket,并调用Handlet处理socket的IO事件。
Netty为什么这么高效?因为Netty使用了Nio,Nio主要由三部分构成:Channel, Buffer和Selector,相比于Bio服务器,Nio实现了非阻塞io和多路复用,充分利用多CPU的性能,所以Netty具有很好的性能。
启动Netty服务器:
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
//Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EventHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// bind and start to accept incoming connections.
ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
channelFuture.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
主要类分析:
类图:
ServerBootstrap:
ServerBootstrap启动类,通过初始化boos和worker线程池,创建ServerSocketChannel绑定端口,并初始化ServerSocketChannel配置,启动Socket Server。
关键类和方法:
1. group(group)
group方法初始化boss和work工作线程都为group
2. group(parentGroup, childGroup)
group方法初始化boss和work工作线程,parentGroup为boss,childGroup为worker
3. bind( )
AbstractBootstrap通过bind方法用boss线程绑定端口并返回ChannelFuture
4. ServerBootstrapAcceptor
ServerBootstrapAcceptor继承ChannelInboundHandlerAdapter,作为ServerSocketChannel的ChannelHandler处理事件
5. ServerBootstrapAcceptor channelRead( )
ServerBootstrapAcceptor的channelRead方法,处理ServerSocketChannel的read事件,将新的连接NioSocketChannel注册到childGroup中,从而实现了boss分配连接到work。
NioEventLoopGroup:
NioEventLoopGroup线程池类,继承MultithreadEventLoopGroup和MultithreadEventExecutorGroup,MultithreadEventExecutorGroup其中包含一个EventExecutor数组,NioEventLoopGroup通过实现newChild( )方法实例一个NioEventLoop工作线程池。关键类和方法:
1. newChild( )
newChild方法实现了MultithreadEventExecutorGroup的抽象方法,返回一个NioEventLoop工作
2. MultithreadEventLoopGroup register(channel)
MultithreadEventLoopGroup的register一个channel到一个NioEventLoop上
3. MultithreadEventLoopGroup next( )
MultithreadEventLoopGroup的next方法返回一个NioEventLoop
NioEventLoop:
NioEventLoop线程类,继承SingleThreadEventLoop和SingleThreadEventExecutor,NioEventLoop包含一个Selector负责监听加入的socket事件,SingleThreadEventExecutor包含一个Thread和task队列,execute第一个任务时才会启动工作线程,线程负责依次处理监听事件和任务队列,所以boss只有一个线程,worker有CPU x 2个线程。
关键类和方法:
1. register(SelectableChannel ch)
register方法注册一个channel到NioEventLoop的Selector上
2. run( )
NioEventLoop线程方法,依次处理Selector上的非IO事件和IO事件
3. SingleThreadEventExecutor execute(task)
SingleThreadEventExecutor的execute方法第一次被调用时才会启动本线程
ServerBootstrap: 将AbstractBootstrap.ServerBootstrapAcceptor绑定到ServerChannel
void init(Channel channel) throws Exception {
Map options = this.options();
synchronized(options) {
channel.config().setOptions(options);
}
Map attrs = this.attrs();
synchronized(attrs) {
Iterator currentChildGroup = attrs.entrySet().iterator();
while(true) {
if(!currentChildGroup.hasNext()) {
break;
}
Entry currentChildHandler = (Entry)currentChildGroup.next();
AttributeKey currentChildOptions = (AttributeKey)currentChildHandler.getKey();
channel.attr(currentChildOptions).set(currentChildHandler.getValue());
}
}
ChannelPipeline p = channel.pipeline();
if(this.handler() != null) {
p.addLast(new ChannelHandler[]{this.handler()});
}
final EventLoopGroup currentChildGroup1 = this.childGroup;
final ChannelHandler currentChildHandler1 = this.childHandler;
Map var9 = this.childOptions;
final Entry[] currentChildOptions1;
synchronized(this.childOptions) {
currentChildOptions1 =(Entry[])this.childOptions.entrySet().toArray(newOptionArray(this.childOptions.size()));
}
var9 = this.childAttrs;
final Entry[] currentChildAttrs;
synchronized(this.childAttrs) {
currentChildAttrs = (Entry[])this.childAttrs.entrySet().toArray(newAttrArray(this.childAttrs.size()));
}
/**
* 将ServerBootstrapAcceptor作为ChannlelHandler绑定到ServerChannel,
* ServerChannel上的Selector事件将通过ServerBootstrapAcceptor处理。
*/
p.addLast(new ChannelHandler[]{new ChannelInitializer() {
public void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ChannelHandler[]{new ServerBootstrap.ServerBootstrapAcceptor(currentChildGroup1, currentChildHandler1, currentChildOptions1, currentChildAttrs)});
}
}});
}
private static void doBind0(final ChannelFuture regFuture, final Channel channel, final SocketAddress localAddress, final ChannelPromise promise) {
channel.eventLoop().execute(new Runnable() {
public void run() {
if(regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
AbstractBootstrap.ServerBootstrapAcceptor:绑定新channel到workGroup
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
child.pipeline().addLast(new ChannelHandler[]{this.childHandler});
Entry[] t = this.childOptions;
int len$ = t.length;
int i$;
Entry e;
for (i$ = 0; i$ < len$; ++i$) {
e = t[i$];
try {
if (!child.config().setOption((ChannelOption) e.getKey(), e.getValue())) {
ServerBootstrap.logger.warn("Unknown channel option: " + e);
}
} catch (Throwable var10) {
ServerBootstrap.logger.warn("Failed to set a channel option: " + child, var10);
}
}
t = this.childAttrs;
len$ = t.length;
for (i$ = 0; i$ < len$; ++i$) {
e = t[i$];
child.attr((AttributeKey) e.getKey()).set(e.getValue());
}
try {
/**
* Acceptor接受新的channel后,将channel注册到childGroup中去,
* childGroup则通过next方法返回一个eventLoop,将channel注册到eventLoop的selector上。
*/
this.childGroup.register(child).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()){
ServerBootstrap.ServerBootstrapAcceptor.forceClose(child, future.cause());
}
}
});
} catch (Throwable var9) {
forceClose(child, var9);
}
}
SingleThreadEventExecutors: 启动线程
public void execute(Runnable task) {
if(task == null) {
throw new NullPointerException("task");
} else {
/**
* 如果在本线程中,则添加新的任务到eventLoop任务队列;
* 如果不在本线程中,则检测线程是否启动并添加任务到eventLoop任务队列。
*/
boolean inEventLoop = this.inEventLoop();
if(inEventLoop) {
this.addTask(task);
} else {
this.startThread();
this.addTask(task);
if(this.isShutdown() && this.removeTask(task)) {
reject();
}
}
if(!this.addTaskWakesUp) {
this.wakeup(inEventLoop);
}
}
}
NioEventLoop:线程处理
protected void run() {
while(true) {
this.oldWakenUp = this.wakenUp.getAndSet(false);
try {
/**
* 如果task队列上有任务,则直接wakeup。
* 如果task队列上没有任务,则进入select状态,等待事件wakeup。
* task队列上的任务主要是注册新的Channel。
*/
if(this.hasTasks()) {
this.selectNow();
} else {
this.select();
if(this.wakenUp.get()) {
this.selector.wakeup();
}
}
/**
* ioRatio默认为50,nio线程用一半时间处理selector上的事件,一半处理task队列上的任务。
*/
this.cancelledKeys = 0;
long t = System.nanoTime();
this.needsToSelectAgain = false;
if(this.selectedKeys != null) {
this.processSelectedKeysOptimized(this.selectedKeys.flip());
} else {
this.processSelectedKeysPlain(this.selector.selectedKeys());
}
long ioTime = System.nanoTime() - t;
int ioRatio = this.ioRatio;
this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
if(this.isShuttingDown()) {
this.closeAll();
if(this.confirmShutdown()) {
return;
}
}
} catch (Throwable var7) {
logger.warn("Unexpected exception in the selector loop.", var7);
try {
Thread.sleep(1000L);
} catch (InterruptedException var6) {
}
}
}
}