Netty中Reactor模型的实现

在Netty中,能够同时支持单线程,多线程和主从Reactor三种模式:

下图为Netty的线程模型:

 

以常用的Netty代码举例分析:

// 配置服务端的NIO线程组
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .option(ChannelOption.SO_BACKLOG, 100)
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) {
                // ch.pipeline().addLast(
                // new ProtobufVarint32FrameDecoder());
                ch.pipeline().addLast(
                    new ProtobufDecoder(
                        SubscribeReqProto.SubscribeReq
                            .getDefaultInstance()));
                ch.pipeline().addLast(
                    new ProtobufVarint32LengthFieldPrepender());
                ch.pipeline().addLast(new ProtobufEncoder());
                ch.pipeline().addLast(new SubReqServerHandler());
            }
            });

        // 绑定端口,同步等待成功
        ChannelFuture f = b.bind(port).sync();

        // 等待服务端监听端口关闭
        f.channel().closeFuture().sync();
    } finally {
        // 优雅退出,释放线程池资源
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }

以上服务端启动,创建了两个EventLoopGroup,实际上就是两个Selector线程组。其中boss线程组负责接收客户端连接,work线程组负责处理IO操作和系统Task和定时任务的调度。每个EventLoopGroup里面都维护了一个selector。

为了减少锁竞争,Netty的work线程组处理IO操作时,都是单线程的,如图下图所示:

 

如图,work线程组接收到读事件时,将读事件往pipeline从头到尾传递,处理完数据后,将写事件往pipeline从尾到头传递,整个过程都是同一条线程,避免了多线程操作,也避免了锁竞争带来的性能消耗。

EventLoopGroup的简析:
  EventLoopGroup是一个不仅具备IO操作线程,还具体系统Task和定时任务的调度的功能的线程组。


EventLoopGroup内部维护了一个selector,因此会出现空轮询的bug,netty通过周期性的对select()为0的情况进行计数,当出现次数达到一定值,
则认为出现空轮询的bug,此时会重新打开一个新的selector,将旧的替换掉。


 

posted @ 2019-11-26 16:14  欧E  阅读(889)  评论(0编辑  收藏  举报