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性能优化,通信上的粘包拆包,同步的设计。

### Netty 线程模型概述 Netty 是一种基于 NIO 的高性能网络框架,它的线程模型设计非常精巧,能够高效处理大量并发连接。Netty 使用了 Reactor 模式来实现事件驱动机制,其中核心组件之一就是 `EventLoop` 和其对应的线程池。 #### 1. **Reactor 模型** Netty 基于经典的 Reactor 设计模式运行[^1]。在这种模式下,I/O 操作由专门的线程负责监听并分发到业务逻辑处理器中执行。具体来说,Netty 将 I/O 多路复用器(Selector)封装到了 EventLoop 中,使得开发者可以专注于编写业务逻辑而无需关心底层复杂的 I/O 实现细节。 #### 2. **EventLoop 组件** 在 Netty 中,`EventLoop` 负责管理一组 Channel 并轮询这些 Channel 上发生的事件。每一个 `Channel` 都绑定到唯一的 `EventLoop` 实例上,在整个生命周期内不会改变这种绑定关系[^2]。这意味着对于同一个客户端请求而言,所有的读写操作都会被分配给相同的线程去完成,从而避免了跨线程共享状态所带来的同步开销。 #### 3. **线程分工** 通常情况下,Netty线程分为两类:Boss Group 和 Worker Group。 - **Boss Group**: 主要职责在于接受新的连接请求并将新建立好的 Socket 分配至下一个阶段——Worker Group 进行进一步处理; - **Worker Group**: 则承担起实际的数据收发任务以及调用用户定义的各种回调方法来响应不同的网络行为(比如接收到消息后的解码编码过程)[^3]。 当一个新的 TCP 客户端尝试接入服务器时,流程如下所示: ```plaintext Client -> BossGroup (accepts connection) -> WorkerGroup (handles IO operations) ``` 每组都维护着自己的 NioEventLoop 或 EpollEventLoop 对象集合,并通过它们内部所包含的选择键集不断查询是否有就绪的任务待处理;一旦发现某个信道上有可利用资源,则立即触发相应的方法链路直至最终达成目标功能为止。 #### 4. **性能优化策略** 为了提高系统的吞吐量和降低延迟时间,可以通过调整以下几个方面来进行针对性改进: - **增加线程数**:适当增大 boss/worker groups size 参数可以让更多 CPU 参与进来共同协作完成繁重的工作负载; - **亲缘调度**:如果硬件支持 NUMA 架构的话,考虑让特定范围内的 channel 总是由固定几个临近物理位置上的 core 来服务可能会带来额外好处因为减少了内存访问跨越节点带来的成本; - **零拷贝技术应用**:充分利用操作系统层面提供的 sendfile() 函数或者 mmap 映射文件等方式减少不必要的数据搬移动作次数进而提升效率. 以下是创建自定义配置的一个简单例子展示如何设置多线程环境下的 netty server 启动参数: ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; public class NettyServer { public static void main(String[] args) throws Exception { int port = 8080; // 创建两个线程组分别用于接收新连接(boss group)和服务已存在的连接(worker group). EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class); // 设置其他选项... ChannelFuture f = b.bind(port).sync(); System.out.println("Server started and listen on " + f.channel().localAddress()); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值