滴滴面试:谈谈你对Netty线程模型的理解?

简介: Netty 线程模型是指 Netty 框架为了提供高性能、高并发的网络通信,而设计的管理和利用线程的策略和机制。**Netty 线程模型被称为 Reactor(响应式)模型/模式,它是基于 NIO 多路复用模型的一种升级,它的核心思想是将 IO 事件和业务处理进行分离,使用一个或多个线程来执行任务的一种机制。**## 1.**Reactor三大组件**Reactor 包含以下三大组件:![image.png](https://cdn.nlark.com/yuque/0/2024/png/92791/1717079218890-89000a00-48bc-4a1a-b87e-e1b6

Netty 线程模型是指 Netty 框架为了提供高性能、高并发的网络通信,而设计的管理和利用线程的策略和机制。

Netty 线程模型被称为 Reactor(响应式)模型/模式,它是基于 NIO 多路复用模型的一种升级,它的核心思想是将 IO 事件和业务处理进行分离,使用一个或多个线程来执行任务的一种机制。

1.Reactor三大组件

Reactor 包含以下三大组件:
image.png
其中:

  1. Reactor(反应器):Reactor 负责监听和分发事件,它是整个 Reactor 模型的调度中心。Reactor 监视一个或多个输入通道,如监听套接字上的连接请求或读写事件。当检测到事件发生时,Reactor 会将其分发给预先注册的处理器(Handler)进行处理。在 Netty 中,这个角色经常是由 EventLoop 或其相关的 EventLoopGroup 来扮演,它们负责事件的循环处理、任务调度和 I/O 操作。
  2. Acceptor(接收器):用于处理 IO 连接请求。当 Reactor 检测到有新的客户端连接请求时,会通知 Acceptor,后者通过 accept() 方法接受连接请求,并创建一个新的 SocketChannel(在 Netty 中是 Channel)来表示这个连接。随后,Acceptor 通常会将这个新连接的 Channel 注册到 Worker Reactor 或 EventLoop 中,以便进一步处理该连接上的读写事件。
  3. Handlers(处理器):Handlers 负责具体的事件处理逻辑,即执行与事件相关的业务操作。在 Netty 中,Handler 是一个或多个 ChannelHandler 的实例,它们形成一个责任链(ChannelPipeline),每个 Handler 负责处理一种或一类特定的事件(如解码、编码、业务逻辑处理等)。数据或事件在 ChannelPipeline 中从一个 Handler 传递到下一个,直至处理完毕或被消费。Handler 可以分为入站(inbound)和出站(outbound)两种,分别处理流入的数据或流出的数据。

    2.Reactor三大模型

    Reactor 模式支持以下三大模型:

  4. 单线程模型

  5. 多线程模型
  6. 主从多线程模型

具体内容如下。

2.1 单线程模型

在单线程模型中,所有的事件处理操作都由单个 Reactor 实例在单个线程下完成。Reactor 负责监控事件、分发事件和执行事件处理程序(Handlers),如下图所示:
image.png
单线程模型的实现 Demo 如下:

// 假设有一个单线程的Reactor,负责监听、接收连接、读写操作
class SingleThreadReactor {
   
   
    EventLoop eventLoop; // 单个事件循环线程

    SingleThreadReactor() {
   
   
        eventLoop = new EventLoop(); // 初始化单个事件循环
    }

    void start(int port) {
   
   
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(port)); // 绑定端口

        eventLoop.execute(() -> {
   
    // 在事件循环中执行
            while (true) {
   
   
                SocketChannel clientSocket = serverSocket.accept(); // 接受连接
                if (clientSocket != null) {
   
   
                    handleConnection(clientSocket); // 处理连接
                }
            }
        });
        eventLoop.run(); // 启动事件循环
    }

    void handleConnection(SocketChannel clientSocket) {
   
   
        // 读写操作,这里简化处理
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while (clientSocket.read(buffer) > 0) {
   
   
            // 处理读取的数据
            buffer.flip();
            // 假设处理数据逻辑...
            buffer.clear();
        }
        // 写操作逻辑类似
    }
}

优缺点分析

  • 优点:简单、线程安全性好、适合编写简单的网络应用。
  • 缺点:处理能力受限于单个线程的处理能力,无法充分利用多核 CPU,可能会影响性能。

    2.2 多线程模型

    在多线程模型中,连接 Acceptor 和业务处理(Handlers)是由不同线程分开执行的,其中 Handlers 是由线程池(多个线程)来执行的,如下图所示:
    image.png
    多线程模型的实现 Demo 如下:

    // 假设有两个线程,一个用于监听连接,一个用于处理连接后的操作
    class MultiThreadReactor {
         
         
      EventLoop acceptLoop;
      EventLoop workerLoop;
    
      MultiThreadReactor() {
         
         
          acceptLoop = new EventLoop(); // 接收连接的线程
          workerLoop = new EventLoop(); // 处理连接的线程
      }
    
      void start(int port) {
         
         
          ServerSocketChannel serverSocket = ServerSocketChannel.open();
          serverSocket.socket().bind(new InetSocketAddress(port));
    
          acceptLoop.execute(() -> {
         
          // 在接受线程中监听
              while (true) {
         
         
                  SocketChannel clientSocket = serverSocket.accept();
                  if (clientSocket != null) {
         
         
                      workerLoop.execute(() -> handleConnection(clientSocket)); // 将新连接交给工作线程处理
                  }
              }
          });
    
          acceptLoop.run(); // 启动接受线程
          workerLoop.run(); // 启动工作线程
      }
    
      // handleConnection 方法与单线程模型中的相同
    }
    

    优缺点分析

  • 优点:此模式可以提高并发性能,充分利用多核 CPU,并且保持简单的编程模型。

  • 缺点:多线程数据共享和数据同步比较复杂,并且 Reactor 需要处理所有事件监听和响应,在高并发场景依然会出现性能瓶颈。

    2.3 主从多线程模型

    主从多线程模型是一个主 Reactor 线程加多个子 Reactor 子线程,以及多个工作线程池来处理业务的,如下图所示:

    主从多线程模型的实现 Demo 如下:
    ```java
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;

public class MainReactorModel {
public static void main(String[] args) {
// 主Reactor,用于接受连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 从Reactor,用于处理连接后的读写操作
EventLoopGroup workerGroup = new NioEventLoopGroup();

    try {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                 .channel(NioServerSocketChannel.class)
                 .childHandler(new ChannelInitializer<SocketChannel>() {
                     @Override
                     protected void initChannel(SocketChannel ch) {
                         // 在这里添加业务处理器,如解码器、编码器、业务逻辑处理器
                         ch.pipeline().addLast(new MyBusinessHandler());
                     }
                 });

        ChannelFuture future = bootstrap.bind(8080).sync();
        System.out.println("Server started at port 8080");
        future.channel().closeFuture().sync(); // 等待服务器关闭
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

}
```

优缺点分析

  • 优点:可以充分利用多核 CPU 的资源,提高系统的整体性能和并发处理能力。
  • 缺点:模型相对复杂,实现和维护成本较高。

    课后思考

    NioEventLoop 是如何实现的?它能够保证 Channel 操作的线程安全吗?为什么?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

相关文章
|
22天前
|
消息中间件 存储 网络协议
拼多多面试:Netty如何解决粘包问题?
粘包和拆包问题也叫做粘包和半包问题,**它是指在数据传输时,接收方未能正常读取到一条完整数据的情况(只读取了部分数据,或多读取到了另一条数据的情况)就叫做粘包或拆包问题。** 从严格意义上来说,粘包问题和拆包问题属于两个不同的问题,接下来我们分别来看。 ## 1.粘包问题 粘包问题是指在网络通信中,发送方连续发送的多个小数据包被接收方一次性接收的现象。这可能是因为底层传输层协议(如 TCP)会将多个小数据包合并成一个大的数据块进行传输,导致接收方在接收数据时一次性接收了多个数据包,造成粘连。 例如以下案例,正常情况下客户端发送了两条消息,分别为“ABC”和“DEF”,那么接收端也应该收到两
13 0
拼多多面试:Netty如何解决粘包问题?
|
3天前
|
Dart Serverless Android开发
Flutter 单线程模型保证UI运行流畅
Flutter 单线程模型保证UI运行流畅
9 0
|
4天前
|
安全 Java 容器
线程池,定时器以及阻塞队列(生产者/消费者模型)
线程池,定时器以及阻塞队列(生产者/消费者模型)
4 0
|
18天前
|
消息中间件 存储 Java
美团面试:说说Netty的零拷贝技术?
零拷贝技术(Zero-Copy)是一个大家耳熟能详的技术名词了,它主要用于提升 IO(Input & Output)的传输性能。 那么问题来了,为什么零拷贝技术能提升 IO 性能? ## 1.零拷贝技术和性能 在传统的 IO 操作中,当我们需要读取并传输数据时,我们需要在用户态(用户空间)和内核态(内核空间)中进行数据拷贝,它的执行流程如下: ![](https://cdn.nlark.com/yuque/0/2024/png/92791/1706491312473-52f5904a-2742-4e99-9b78-995e9a8b9696.png?x-oss-process=image%2F
17 0
|
26天前
|
安全 调度
鸿蒙HarmonyOS实战-Stage模型(线程模型)
本文介绍了线程作为操作系统调度的最小单位,是进程中的执行流,具有轻量级、并发执行、共享资源、通信简单和上下文切换等特点。线程分为用户线程和内核线程,其中内核线程由操作系统管理,而用户线程由应用程序控制。线程用于提高程序性能和响应速度,尤其适合多任务并发处理。在HarmonyOS中,每个应用有主线程负责UI和 ArkTS 引擎管理,以及Worker线程执行耗时任务。线程间通信可通过Emitter实现事件同步和Worker进行异步操作。
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13277 1
|
4天前
|
机器学习/深度学习 缓存 算法
netty源码解解析(4.0)-25 ByteBuf内存池:PoolArena-PoolChunk
netty源码解解析(4.0)-25 ByteBuf内存池:PoolArena-PoolChunk
|
1月前
|
消息中间件 Oracle Dubbo
Netty 源码共读(一)如何阅读JDK下sun包的源码
Netty 源码共读(一)如何阅读JDK下sun包的源码
54 1
|
1月前
|
编解码 前端开发 网络协议
Netty Review - ObjectEncoder对象和ObjectDecoder对象解码器的使用与源码解读
Netty Review - ObjectEncoder对象和ObjectDecoder对象解码器的使用与源码解读
61 0
|
1月前
|
编解码 安全 前端开发
Netty Review - StringEncoder字符串编码器和StringDecoder 解码器的使用与源码解读
Netty Review - StringEncoder字符串编码器和StringDecoder 解码器的使用与源码解读
68 0