Netty线程模型

来源:互联网 发布:c语言那本书比较好 编辑:程序博客网 时间:2024/05/24 05:56

  • Reactor模型
    • 单线程Reactor
    • 多线程Reactor
    • 主从Reactor
  • Netty线程模型

Reactor模型

一般编写的网络框架以IO操作为主,将IO操作分割为相对独立的事件模块。大多数都是基于Reactor模式进行设计和开发,Reactor模式基于事件驱动,特别适合处理海量的I/O事件。

1 单线程Reactor

Reactor单线程模型:所有的IO操作都在同一个NIO线程上面完成,NIO线程的职责如下:

  1. 作为NIO服务端,接收客户端的TCP连接;
  2. 作为NIO客户端,向服务端发起TCP连接;
  3. 读取通信对端的请求或者应答消息;
  4. 向通信对端发送消息请求或者应答消息。

Reactor模式使用的是异步非阻塞IO,所有的IO操作都不会导致阻塞,理论上一个线程可以独立处理所有IO相关的操作(JDK类库Selector即为该线程模型)。然后在并发场景下,某些IO事件cpu耗时较长,在单线程环境下线程阻塞导致其他任务等待,导致系统性能较差。

2 多线程Reactor

Reactor多线程模型:Acceptor线程(NIO)用于监听服务端,接收客户端的TCP连接请求;网络IO操作-读、写等由一个NIO线程池负责;单个NIO线程可以同时处理N条链路,但是1个链路只对应1个NIO线程,防止发生并发操作问题。

线程池采用多线程处理IO事件,基本解决单个IO时间阻塞导致系统性能下降的问题。然而,并发百万客户端连接,或者服务端对客户端握手进行安全认证,但是认证本身非常损耗性能在,同时单个线程accept处理客户端请求将导致系统延迟,或客户端无法接入等问题。

3 主从Reactor

主从Reactor线程模型:服务端采用独立NIO线程池接收客户端连接。Acceptor接收到客户端TCP连接请求处理完成后,将新创建的SocketChannel注册到IO线程池的某个IO线程上,由它负责SocketChannel的读写和编解码工作。Acceptor线程池仅仅只用于客户端的登陆、握手和安全认证,链路建立成功,就将链路注册到后端IO线程池的IO线程上,由IO线程负责后续的IO操作。

通常而言,建议将Accept线程池线程数设置为1,在监听多端口、多种协议等情绪下,才将线程数配置;IO TheadPool 线程次建议线程数一般为(cpu核数+1~2*cpu核数)。

Netty线程模型

作为高并发网络编程框架,Netty线程为主从Reactor模型,其中Accpet Thread负责接收客户端连接,IO ThreadPool负责处理读、写等IO事件。Netty以串行化设计理念,避免任务在多线程并发过程中额外同步操作,将任务绑定与单个线程处理。一个IO事件由单个Netty NIO线程去处理,不过单个NIO线程可以串行化处理一系类事件。

给出一段Netty开发中服务端代码示例:

        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workGroup = new NioEventLoopGroup();        ServerBootstrap b = new ServerBootstrap();        b.group(bossGroup, workGroup).channel(NioServerSocketChannel.class)                .localAddress(new InetSocketAddress(port))                .childHandler(new ChannelInitializer<Channel>() {                    @Override                    protected void initChannel(Channel ch) throws Exception {                        ChannelPipeline channelPipeline = ch.pipeline();                        ch.pipeline().addLast(                                new ChannelInboundHandlerAdapter() {                                    @Override                                    public void channelActive(                                            ChannelHandlerContext ctx)                                            throws Exception {                                        ctx.writeAndFlush(buf.duplicate())                                                .addListener(                                                        ChannelFutureListener.CLOSE);                                    }                                });                    }                });        ChannelFuture f = b.bind().sync();        f.channel().closeFuture().sync();

通常,bossGroup线程组负责处理客户端连接,请求,认证;workGroup负责处理bossGroup认证通过的客户端IO事件。NioEventLoopGroup作为线程池,默认初始化线程数为Cpu核数*2;


DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(                "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

NioEventLoopGroup线程次中又由一系列(2*cpu核数)NioEventLoop线程组成,每次任务到来时,设计基于轮询的负载均衡策略将任务分配NioEventLoop,代码如下:


private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {        private final AtomicInteger idx = new AtomicInteger();        private final EventExecutor[] executors;        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {            this.executors = executors;        }        @Override//当executors.length =2的n次幂        public EventExecutor next() {            return executors[idx.getAndIncrement() & executors.length - 1];        }        @Override//当executors.length !=2的n次幂        public EventExecutor next() {            return executors[Math.abs(idx.getAndIncrement() % executors.length)];        }    }

如下图为NioEventLoopGroup分配链示意图

而Netty中的线程组(bossGroup、workGroup)处理的事件是是基于Netty Channel(NIO是面向Channel, 而 Java IO面向Stream)。Netty中的Channel与ChannelPipeline绑定,将事件处理业务交由一系列handler链组成,这些ChannelHandler由ChannelHandlerContext组织。在事件经过Channel时,由ChannelHandlerContext组织的ChannelHandler将对数据进行相应处理。此外,Channel将事件分为入站事件(读,从前往后流经Handler链)和出站事件(写,从后往前流经Hanlder),在事件流过ChannelPipeline时,出站事件将跳过处理入站事件ChannelHandler,入站事件将跳过出站事件的ChanneHanlder。下图给出一个Channel,ChannelPipeline,ChannelHandlerContext,ChannelHandler关系图:

此外,Netty除了使用reactor来提升性能,零拷贝,IO性能优化,通信上的粘包拆包,同步的设计。

原创粉丝点击