zoukankan      html  css  js  c++  java
  • 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读写操作。具体实现我们后续再做分析。

  • 相关阅读:
    pytest常用命令行
    pytest中一些常用插件
    case运行失败进行重试-pytest-rerunfailures插件
    adb 在自动化测试中的截图
    app的冷启动和热启动
    ATX
    UI自动化中常用的三种等待
    allure
    性能指标分析
    接口自动化之接口依赖解决
  • 原文地址:https://www.cnblogs.com/stevenczp/p/7577004.html
Copyright © 2011-2022 走看看