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

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

1.Reactor三大组件

Reactor 包含以下三大组件:



其中:

  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 模式支持以下三大模型:

  1. 单线程模型
  2. 多线程模型
  3. 主从多线程模型

具体内容如下。

2.1 单线程模型

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



单线程模型的实现 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 是由线程池(多个线程)来执行的,如下图所示:



多线程模型的实现 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 如下:

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、设计模式、消息队列等模块。

滴滴面试:谈谈你对Netty线程模型的理解?的更多相关文章

  1. Netty系列之Netty线程模型

    Reference: http://www.infoq.com/cn/articles/netty-threading-model 1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 ...

  2. 彻底搞懂 netty 线程模型

    编者注:Netty是Java领域有名的开源网络库,特点是高性能和高扩展性,因此很多流行的框架都是基于它来构建的,比如我们熟知的Dubbo.Rocketmq.Hadoop等.本文就netty线程模型展开 ...

  3. eventloop & actor模式 & Java线程模型演进 & Netty线程模型 总结

    eventloop的基本概念可以参考:http://www.ruanyifeng.com/blog/2013/10/event_loop.html Eventloop指的是独立于主线程的一条线程,专门 ...

  4. Netty线程模型

    一.Reactor模型 1.单线程模型 Reactor单线程模型,指的是所有的IO操作都在同一个NIO线程上面完成,NIO线程的职责如下: 1)作为NIO服务端,接收客户端的TCP连接: 2)作为NI ...

  5. Netty 线程模型

    一.线程模型概述 线程模型表明了代码的执行方式.从最开始的使用单线程,后来出现了多线程,之后是线程池.当有要执行的任务时,任务会被传到线程池,从线程池中获得空闲的线程来执行任务,执行完了后会将线程返回 ...

  6. Netty源码死磕一(netty线程模型及EventLoop机制)

    引言 好久没有写博客了,近期准备把Netty源码啃一遍.在这之前本想直接看源码,但是看到后面发现其实效率不高, 有些概念还是有必要回头再细啃的,特别是其线程模型以及EventLoop的概念. 当然在开 ...

  7. Java后端进阶-网络编程(Netty线程模型)

    前言 我们在使用Netty进行服务端开发的时候,一般来说会定义两个NioEventLoopGroup线程池,一个"bossGroup"线程池去负责处理客户端连接,一个"w ...

  8. Netty 线程模型(Reactor 线程模型)

    更多内容,前往个人博客 当说到 Netty 线程模型的时候,一般首先会想到经典的 Reactor 线程模型,尽管不同的 NIO 框架对于 Reactor 模式的实现存在差异,但本质上还是遵循了 Rea ...

  9. Reactor三种线程模型与Netty线程模型

    文中所讲基本都是以非阻塞IO.异步IO为基础.对于阻塞式IO,下面的编程模型几乎都不适用 Reactor三种线程模型 单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件,包括连接.读.写.异常 ...

  10. Netty核心概念(8)之Netty线程模型

    1.前言 第7节初步学习了一下Java原本的线程池是如何工作的,以及Future的为什么能够达到其效果,这些知识对于理解本章有很大的帮助,不了解的可以先看上一节. Netty为什么会高效?回答就是良好 ...

随机推荐

  1. docker 应用篇————docker 网络[十七]

    前言 简单介绍一下docker 网络. 正文 使用ip addr. 可以看到网络. 有一个虚拟网卡: 那么基本上容器就处于这样的模式了. 那么也就是所有容器都在同一网关下面了. 那么问题来了,理论上容 ...

  2. 我用这10招,能减少了80%的BUG

    前言 对于大部分程序员来说,主要的工作时间是在开发和修复BUG. 有可能修改了一个BUG,会导致几个新BUG的产生,不断循环. 那么,有没有办法能够减少BUG,保证代码质量,提升工作效率? 答案是肯定 ...

  3. k8s集群部署1.28.2版本(无坑)

    Kubernetes-1.28.2 集群介绍及搭建 一.Kubernetes 概述 1.什么是Kubernetes? K8S 的全称为 Kubernetes.用于自动部署.扩展和管理"容器化 ...

  4. HarmonyOS NEXT应用开发案例——行程地址交换动画

    介绍 本示例介绍使用显式动画 animateTo 实现左右地址交换动画.该场景多用于机票.火车票购买等出行类订票软件中. 效果预览图 使用说明 加载完成后显示地址交换动画页面,点击中间的图标,左右两边 ...

  5. 全方位事件监控管理,阿里云日志服务Kubernetes事件中心正式上线

    2020年2月21日,阿里云日志服务Kubernetes事件中心正式上线,为Kubernetes事件提供集中化采集.存储.分析.可视化.告警等能力,帮助Kubernetes使用者快速构建准实时.高可靠 ...

  6. 新型DDoS来袭 | 基于STUN协议的DDoS反射攻击分析

    简介: 作为新型反射类型,目前仍存绕过防御可能性. 阿里云安全近期发现利用STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)服务发起的DDoS反 ...

  7. dotnet 已知问题 使用 Directory.EnumerateXXX 方法枚举 C 盘根路径可能错误的问题

    在 dotnet 里面,可以使用 Directory.EnumerateXXX 系列方法进行枚举文件或文件夹.在准备枚举驱动器根路径的文件或文件夹时,可能获取到错误的路径.错误的步骤在于传入的是如 C ...

  8. netcore3.1 程序在cento8下运行selenium

    我需要在linux下运行selenium抓取数据,本人不熟悉Python,所以只能用netcore.在带linux界面上运行爬取程序,驱动chromedriver比较简单.界面化安装好chrome,下 ...

  9. css的animate做一个信号动画

    html <div class="jump flex-fs fadeAndScaleIn"> <span></span> <span> ...

  10. golang 常用操作

    golang 获取切片 slice 第一个 最后一个 元素 复合数据类型切片通常用作Go中索引数据的口语结构. 该类型[]intSlice是具有类型为integer的元素的切片. len函数用于获取切 ...