Netty源码学习(一)Netty线程模型

给你一台4路E7-4820V2(32核心64线程),512G内存的服务器,你该如何编程才能支持百万长连接?

 

最直接的想法是采用BIO的模式,为每个连接新建一个线程,在一一对应的线程中直接处理连接上的数据请求。

但在Java中,新建线程的开销非常昂贵(默认情况下每个线程会占据1M多的内存,百万连接就是1T内存,这显然是不可接受的)

 

优化点的想法是使用Java NIO,用一个线程来处理所有客户端的请求。

但是根据我之前的测试,单个线程最多同时处理5w/s的echo message,此时单个core已经跑满,如果再接着加大负载会导致请求堆积。

 

进一步的优化是将线程分离,使用一个线程作为acceptor,一堆线程作为worker

acceptor监听服务端口的accept事件,如果有accept事件被触发,说明有客户端连接进来,acceptor获取连接(Channel)并将其分派给某个worker,worker监听这个Channel的read事件,一旦Channel可读,worker就会做出相应的处理。

也就是说将连接均分到各个worker,减轻压力,也可以让多个core被利用起来,使单机处理百万长连接成为可能。

 

这就是所谓Reactor模型了,也是Netty所采用的线程模型。(还有更进一步的主从多线程模型,用于处理认证较为耗时的情况,这里不做介绍)

借用一下Doug Lea老爷子的示例图:

 

用这个思想分析一下Netty的示例代码:

    public void go(int port) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);//acceptor线程
        EventLoopGroup workerGroup = new NioEventLoopGroup();//worker线程组
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelRead(ChannelHandlerContext ctx,
                                        Object msg) { //ehco to client
                                    ctx.write(msg);
                                    ctx.flush();
                                }
                            });
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            
            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (Exception e) {
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

可以猜出所谓的bossGroup就是Reactor模型中的acceptor,负责处理客户端产生的TCP连接请求,workerGroup则是worker,真正负责IO读写操作。具体实现我们后续再做分析。

 

posted @ 2017-09-22 20:26  qeDVuHG  阅读(1970)  评论(0编辑  收藏  举报