当前位置: 首页 > news >正文

Netty—Reactor线程模型详解

文章目录

  • 前言
  • 线程模型基本介绍
    • 线程模型分类
    • Reactor线程模型介绍
    • Netty线程模型:
  • 传统阻塞IO的缺点
  • Reactor线程模型
    • 单Reactor单线程模式
    • 单Reactor多线程模式
    • 主从Reactor多线程
    • Reactor 模式小结
  • Netty 线程模型
    • 案例说明:
    • Netty核心组件简介
      • ChannelPipeline与Channel的关系
  • 参考文献

前言

前面我们说了Netty中的NIO:Netty—NIO万字详解 ;其中涉及到一个重要的底层模型—Reactor线程模型,而Netty线程模型就是基于Reactor线程模型的改进,它也是Netty中个人认为是最重要的一个知识点,在我看来只有掌握了Netty线程模型才算是真正意义上的理解了Netty!!

所以本文将详细说明Reactor线程模型,以及Netty线程模型,帮助大家更好的理解Netty

线程模型基本介绍

线程模型是指在操作系统中,线程是如何被创建、调度和管理的

线程模型分类

  1. 单线程模型:如Redis,它采用单线程来处理命令,所有命令都回进入到一个队列中,然后逐个执行。
  2. 多线程模型:也被称为并发多线程模型。

如果细分的话有以下几种:

  1. 单线程模型: 在单线程模型中,程序只有一个执行线程,所有的任务按照顺序执行。这种模型的优点是简单,易于理解和调试。然而,缺点是无法充分利用多核处理器的优势,因为在任何时刻只有一个任务在执行。
  2. 多线程模型: 多线程模型允许程序同时执行多个线程,每个线程独立执行不同的任务。这可以提高程序的并发性和性能,特别是在多核处理器上。但多线程编程也引入了一些复杂性,例如需要处理线程同步、死锁等问题。
  3. 分布式模型: 在分布式模型中,任务被分布到多个计算节点上执行。这可以通过网络进行通信,每个节点独立运行。分布式模型通常用于大规模系统,以提高可伸缩性和容错性。
  4. Reactor模型: Reactor模型是一种事件驱动的模型,其中一个主线程负责监听和分发事件,而多个工作者线程负责处理事件。这样可以有效地处理大量并发连接,例如在网络编程中。
  5. Proactor模型: Proactor模型也是一种事件驱动的模型,但与Reactor不同,Proactor模型中事件处理由操作系统负责,而应用程序只需提供回调函数。这样可以实现异步非阻塞的I/O操作。
  6. Actor模型: Actor模型是一种并发计算模型,其中每个"Actor"都是独立的实体,通过消息传递进行通信。每个Actor都有自己的状态和行为,可以并发地执行。

Reactor线程模型介绍

Reactor线程模型是一种事件驱动的编程模式,主要用于处理高并发网络I/O操作。它的核心思想是使用一个或多个反应器(Reactor)来监听和分发网络事件,然后将这些事件分配给相应的处理器(Handler)或者线程池进行处理。

主要组成部分和工作流程:

  1. Reactor:这是模型的核心组件,负责监听所有的网络连接和相应事件。它通过使用I/O多路复用技术(如Linux的epoll、Java的NIO Selector等)在一个单独的线程或者一组线程中监控多个socket的活动,这样可以避免传统阻塞I/O模型中为每个连接创建新线程带来的资源开销。
  2. Dispatcher:在某些实现中,dispatcher是一个逻辑角色,负责根据事件的类型将事件转发给合适的处理器。例如,新的连接请求可能被转发给Acceptor处理,而读写事件则被转发给对应的Handler
  3. Acceptor:在接收到新的连接请求时,Acceptor负责接受这个连接,并将其配置为非阻塞模式,然后将其添加到Reactor的监听列表中。
  4. Handler(也称为Worker):当Reactor检测到某个socket上有读写事件时,它会将事件转发给对应的Handler进行处理。Handler负责实际的业务逻辑,如读取数据、解析协议、执行操作并返回响应。

而根据Reactor和线程池的数量,Reactor线程模型可以有以下几种变体:

  • 单Reactor单线程模型:所有事件的监听、分发和处理都在一个线程中完成。
  • 单Reactor多线程模型:一个Reactor线程负责监听和分发事件,而事件的处理则由一个线程池完成。
  • 多Reactor多线程模型:多个Reactor线程并行监听和分发事件,每个Reactor都有自己的线程池来处理事件。

这种模型的优势在于其高并发性和低资源消耗。通过复用线程和高效地调度事件,Reactor线程模型能够在处理大量并发连接时保持良好的性能和可扩展性。然而,其复杂性也较高,需要精心设计以确保线程安全和高效的事件处理。在许多现代高性能网络框架和库中,如Java的Netty和Python的Twisted,都采用了Reactor线程模型或者其变体。

举例说明:

假设我们有一个餐厅,这个餐厅有很多的桌子,每个桌子上有一个人在等待食物。当食物准备好后,服务员会通知对应桌子的人来取食物。在这个过程中,餐厅就相当于Reactor,而桌子上的客人就是Handlers。当食物准备好后,餐厅会通知对应的桌子来取食物,也就是将事件分发给对应的处理程序来处理。

Netty线程模型:

虽然说Netty线程模型是由主从Reactor线程模型改进的,但Netty线程模型模型并不是一成不变的,它实际取决于启动参数配置。通过设置不同的启动参数来支持 Reactor 不同的线程模型。

  • Netty单线程模型—> Reactor单线程模型—> 传统阻塞IO+多路复用器
  • Netty多线程模型—> Reactor多线程模型—> Reactor单线程模型+线程池
  • 主从Netty多线程模型—> 主从Reactor多线程模型—>Reactor多线程模型+线程池

后面会详细说明!!

传统阻塞IO的缺点

传统阻塞IO很容易理解,这里不做过多的解释,直接说缺点,然后后面看Reactor线程模式是怎么解决这些缺点的,先看图:

20200421213026276

缺点主要包括以下3点:

  1. 性能低下:在等待I/O操作完成期间,线程会被阻塞,无法执行其他任务。这会导致CPU资源的浪费,尤其是在需要处理大量I/O操作的情况下。
  2. 无法处理大量并发连接:由于每个I/O操作都需要等待,因此无法高效地处理大量并发连接。这限制了系统的吞吐量和并发性。
  3. 无法充分利用多核资源:由于线程在等待I/O操作完成时会被阻塞,因此无法充分利用多核资源。这限制了系统的性能和并发性。

Reactor线程模型

针对传统阻塞IO服务模型的缺点,Reactor线程模型的解决办法是:

1、基于I/O复用模型:

Reactor线程模型采用I/O复用技术,允许多个连接共享同一个阻塞对象。这意味着应用程序只需要在一个阻塞对象上等待,无需为每个连接都创建一个独立的线程。当某个连接有新的数据可以处理时,操作系统会通知应用程序,线程从阻塞状态返回,开始进行业务处理。

crm客户资料表关系 (1)

对上图说明:

这里很像我们前面讲过的NIO,在案例七中,就是采用基于I/0复用模型,Selector就相当于一个IO复用器;但这种模式是有问题的?它还是无法充分利用多核CPU的性能,也会有性能瓶颈,因为虽然IO复用了,但还是一个线程去处理所有事物

2、基于线程池复用线程资源

Reactor线程模型通过线程池来复用线程资源。这意味着不必再为每个连接创建新的线程,而是将连接完成后的业务处理任务分配给线程池中的线程进行处理。一个线程可以处理多个连接的业务,提高了系统的并发性和效率。

crm客户资料表关系 (2)

对上图说明:

  1. Reactor模式,通过一个或多个输入同时传递给服务处理器的模式(基于事件驱动)
  2. 服务器端程序处理传入的多个请求,并将它们同步分派到相应的处理线程,因此Reactor模式也叫Dispatcher模式
  3. Reactor模式使用10复用监听事件,收到事件后,分发给某个线程(进程),这点就是网络服务器高并发处理关键

用前文说得NIO举例就是在传统的NIO处理读写事件时加入了线程池,如下:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ReactorMultiThread {public static void main(String[] args) throws IOException {// 创建一个ServerSocketChannelServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 设置为非阻塞模式serverSocketChannel.configureBlocking(false);// 绑定到端口8080serverSocketChannel.bind(new InetSocketAddress(8080));// 创建一个SelectorSelector selector = Selector.open();// 将ServerSocketChannel注册到Selector上,监听连接事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// 创建一个线程池ExecutorService executorService = Executors.newFixedThreadPool(10);while (true) {// 轮询Selector,等待事件发生int readyChannels = selector.select();if (readyChannels == 0) {continue;}// 处理发生的事件for (SelectionKey key : selector.selectedKeys()) {// 处理连接事件if (key.isAcceptable()) {// 接受连接ServerSocketChannel acceptChannel = (ServerSocketChannel) key.channel();SocketChannel socketChannel = acceptChannel.accept();// 将SocketChannel注册到Selector上,监听读写事件socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);}// 处理读写事件if (key.isReadable() || key.isWritable()) {// 提交给线程池处理executorService.submit(() -> {// 处理读写事件SocketChannel socketChannel = (SocketChannel) key.channel();// 读取数据byte[] buffer = new byte[1024];int readBytes = socketChannel.read(buffer);if (readBytes > 0) {// 处理读取到的数据}// 写数据socketChannel.write(buffer);});}}// 清空已处理的事件selector.selectedKeys().clear();}}
}

Reactor线程模型就是通过 单个线程 使用Java NIO包中的Selectorselect()方法,进行监听。当获取到事件(如accept、read等)后,就会分配(dispatch)事件进行相应的事件处理(handle)。

如果要给 Reactor线程模型 下一个更明确的定义,应该是:

Reactor线程模式 = Reactor(I/O多路复用)+ 线程池

单Reactor单线程模式

Reactor单线程

  1. Select是前面1/0复用模型介绍的标准网络编程API,可以实现应用程序通过一个阻塞对象监听多路连接请求
  2. Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发
  3. 如果是建立连接请求事件,则由Acceptor通过Accept处理连接请求,然后创建一个Handler对象处理连接完成后的后续业务处理
  4. 如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应
  5. Handler 会完成 Read→业务处理→Send 的完整业务流程
  1. 结合实例:服务器端用一个线程通过多路复用搞定所有的10操作(包括连接,读、写等),编码简单,清晰明了,但是如果客户端连接数量较多,将无法支撑,上篇文章中的的NIO案例就属于这种模型。

  2. 无论是事件监听、事件分发、还是事件处理,都始终只有 一个线程 执行所有的事情

优点

模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成

缺点

  1. 性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。Handler在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈
  2. 可靠性问题,线程意外终止,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障

使用场景

  1. 低负载的应用程序:当应用程序的负载较低,同时并发连接数也相对较少时,使用 Reactor 单线程模式可以满足需求,并且可以简化代码的编写和维护。
  2. 短时间处理的任务:如果应用程序的任务处理时间较短,不会导致单线程阻塞过长时间,那么使用 Reactor 单线程模式可以获得良好的性能。
  3. 资源有限的环境:在一些资源有限的环境中,如嵌入式设备或特定的服务器环境,使用 Reactor 单线程模式可以减少线程创建和上下文切换的开销,提高系统的效率。

比如Redis在业务处理的时间复杂度O(1)的情况


单Reactor多线程模式

为了提高性能,我们可以把复杂的事件处理handler交给线程池,那就可以演进为 「单Reactor多线程模型」

Reactor多线程模式 = Reactor单线程模式 + 线程池

Reactor多线程模型

  1. Reactor对象通过select监控客户端请求事件,收到事件后,通过dispatch进行分发
  2. 如果建立连接请求,则右Acceptor通过accept处理连接请求,然后创建一个Handler对象处理完成连接后的各种事件
  3. 如果不是连接请求,则由reactor分发调用连接对应的handler来处理
  4. handler只负责响应事件,不做具体的业务处理,通过read读取数据后,会分发给后面的worker线程池的某个线程处理业务
  5. worker线程池会分配独立线程完成真正的业务,并将结果返回给handler
  6. handler收到响应后,通过send将结果返回给client
  • 优点:可以充分的利用多核cpu的处理能力

  • 缺点:在极个别特殊场景中,一个Reactor线程负责监听和处理所有的客户端连接可能会存在性能问题。例如并发百万客户端连接(双十一、春运抢票)

适用于以下场景:

  1. 高并发的应用程序:当应用程序需要处理大量并发连接时,使用单Reactor多线程模式可以提高并发处理能力,每个连接都可以在独立的线程中进行处理,避免了线程之间的竞争。
  2. 长时间处理的任务:如果应用程序需要处理耗时较长的任务,使用单Reactor多线程模式可以避免阻塞主线程,提高系统的响应性能。主线程负责接收和分发事件,而具体的任务处理则由其他线程完成。
  3. 资源充足的环境:在资源充足的环境下,可以使用单Reactor多线程模式来充分利用多核处理器的性能优势,提高系统的吞吐量。 需要注意的是,单Reactor多线程模式需要合理配置线程池的大小,避免线程数过多导致资源浪费或线程数过少导致性能瓶颈。此外,多线程模式下需要注意线程安全性和资源共享的问题。

主从Reactor多线程

主从Reactor线程模型 (2)

  1. Reactor主线程MainReactor对象通过select监听连接事件,收到事件后,通过Acceptor处理连接事件
  2. Acceptor处理连接事件后,MainReactor将连接分配给SubReactor
  3. subreactor将连接加入到连接队列进行监听,并创建handler进行各种事件处理
  4. 当有新事件发生时,subreactor就会调用对应的handler处理
  5. handler通过read读取数据,分发给后面的worker线程处理
  6. worker线程池分配独立的worker线程进行业务处理,并返回结果
  7. handler收到响应的结果后,再通过send将结果返回给client
  8. Reactor主线程可以对应多个Reactor子线程,即MainRecator可以关联多个SubReactor

Reactor 模式小结

用生活中的例子说明:

  1. 单Reactor单线程模型,前台和服务员都是一个人,全称为客户服务
  2. 单Reactor多线程模型,一个前台接待员和多个服务员,前台只负责接待
  3. 主从Recator多线程模型,多个前台,多个服务员

Reactor线程模型的优点:

  1. 高效事件处理:通过I/O多路复用技术,Reactor能够同时监控多个连接,减少了系统的阻塞情况,提高了系统的并发性能。
  2. 非阻塞IO:Reactor模型基于异步非阻塞IO,使得线程在等待网络IO操作完成时,可以去处理其他任务,提高了资源利用率。
  3. 职责分离:Reactor模型将事件的分发和处理分离,父线程(或主Reactor)负责监听和分发事件,子线程(或工作线程、从Reactor)负责具体的业务处理,这种分工使得系统结构清晰,易于维护和扩展。
  4. 可伸缩性:根据系统的负载情况,可以通过增加或减少工作线程来调整系统的处理能力,具有良好的水平扩展性。
  5. 避免数据竞争:通过线程间的通信机制,如队列或者直接的数据传递,可以有效地避免多线程环境中的数据竞争问题。
  6. 降低上下文切换开销:由于父线程主要负责事件分发,子线程主要负责业务处理,这种分工可以减少不必要的上下文切换,提高系统效率。
  7. 支持高并发:尤其在高并发场景下,Reactor线程模型能够更好地处理大量的客户端请求,保持系统的响应能力和稳定性。
  8. 灵活的线程模型选择:Reactor模型有多种变体,如单线程、多线程和主从多线程模型,可以根据具体的应用需求和性能目标选择最适合的线程模型。
  9. 易于实现和使用:许多成熟的网络框架,如Netty,已经实现了Reactor线程模型,开发者可以直接使用这些框架,而无需从头开始实现复杂的网络编程逻辑。

其实这三种模型的演变就一句话:

没有什么是加一层解决不了的,如果有,那就再加一层!!!

Netty 线程模型

Netty的线程模型是基于主从Reactor多线程模型做了一定改进的,能理解Reactor线程模型,Netty线程模型基本也就理解了,只是要懂各个组件之间的功能和组合,先看图:

Netty工作流程图

不是说Netty线程模型只能是主从Reactor线程模型,而是可以根据传入的参数,来改变它的线程模式的!!!

  1. Nety抽象出两组线程池BossGroup (Boos NioEventLoopGroup)专门负责接收客户端的连接,WorkerGroup专门负责网络的读写

  2. BossGroup和WorkerGroup类型都是NioEventLoopGroup

  3. NioEventLoopGroup相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环是NioEventLoop

  4. NioEventLoop表示一个不断循环的执行处理任务的线程,每个NioEventLoop都有一个selector,用于监听绑定在其上的socket的网络通讯

  5. NioEventLoopGroup可以有多个线程,即可以含有多个NioEventLoop

  6. 每个Boss NioEventLoop循环执行的步骤有3步

    • 轮询accept事件

    • 处理accept事件,与client建立连接,生成NioScocketChannel,并将其注册到某个worker NIOEventLoop上的selector

    • 处理任务队列的任务,即unAllTasks T)

  7. 每个Worker NIOEventLoop循环执行的3个步骤

    • 轮询read,write事件
    • 处理IO事件,即read,write事件,在对应NioScocketChannel处理
    • 处理任务队列的任务,即runAllTasks
  8. 每个Worker NIOEventLoop处理业务时,会使用pipeline(管道),pipeline中包含了channel,即通过pipeline可以获取到对应通道,管道中维护了很多的处理器

案例说明:

服务端:

/*** com.atguigu.netty** @author co_wb_junjie_qiu* @version Id: NettyServer, v 0.1 2023/12/19 9:23 co_wb_junjie_qiu Exp $*/
public class NettyServer {public static void main(String[] args) throws InterruptedException {//创建 BossGroup 和 WorkerGroup//1.创建两个线程组 bossGroup 和 workerGroup//2.bossGroup 只是处理连接请求,真正的和客户端业务处理,会交给 workerGroup 完成//3.两个都是无限循环//4.bossGroup 和 workerGroup 含有的子线程(NioEventLoop)的个数//默认实际 cpu 核数*2NioEventLoopGroup boosGroup = new NioEventLoopGroup();NioEventLoopGroup workerGroup = new NioEventLoopGroup();try {// 服务端的辅助程序// 创建服务器端的启动对象,配置参数ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(boosGroup, workerGroup) // 设置两个线程组// 设置服务器用于接受新的连接的通道为NioServerSocketChannel类。这是一个非阻塞的NIO服务器套接字通道。.channel(NioServerSocketChannel.class)// 设置服务器的TCP参数,SO_BACKLOG表示在拒绝新的连接之前,服务器可以排队等待的连接数。.option(ChannelOption.SO_BACKLOG, 128)// 为接受的新连接设置TCP参数,开启keep-alive机制,以避免长时间的不活动导致的连接中断(保持长连接)。.childOption(ChannelOption.SO_KEEPALIVE, true)// 设置处理新连接的初始化程序。当有新连接到达时,这个初始化程序会被用来配置新连接的管道。.childHandler(new ChannelInitializer<SocketChannel>() {// 创建一个通道初始化对象@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {// 给Pipeline 设置处理器(自定义)socketChannel.pipeline().addLast(new NettyServerHandler());}});// 给workerGroup 的 EventLoop 对应的管道设置处理器// 启动服务器,并绑定端口ChannelFuture sync = bootstrap.bind(6668).sync();// 对关闭通道进行监听sync.channel().closeFuture().sync();} finally {boosGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}

服务端处理器:

/*** com.atguigu.netty** 说明* 1.我们自定义一个Handler需要继续netty规定好的某个HandlerAdapter(规范)* 2.这时我们自定义一个Handler,才能称为一个handler** @author co_wb_junjie_qiu* @version Id: NettyServerHandler, v 0.1 2023/12/25 15:10 co_wb_junjie_qiu Exp $*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {/*** 读取通道数据* @param ctx 上下文对象,含有 管道pipeline,通道 channel 、地址* @param msg 客户端发送过来的数据,默认Object*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println("服务器读取线程 "+ Thread.currentThread().getName());ChannelPipeline pipeline = ctx.pipeline();System.out.println("pipeline 本身是一个双向列表" + pipeline);ByteBuf buf = (ByteBuf)msg;System.out.println("客户端发送的消息是:"+buf.toString(CharsetUtil.UTF_8));System.out.println("客户端地址:"+ctx.channel().remoteAddress());}/*** 数据读取完成之后* 一般来说,我们会对这个发送的数据进行编码*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {// writeAndFlush 是 写入和刷新// 将数据写入缓存并刷新// 一般讲,我们队这个发送的数据进行编码ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端",CharsetUtil.UTF_8));}/*** 处理异常,一般需要关闭通道*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}

客户端:

/*** com.atguigu.netty** @author co_wb_junjie_qiu* @version Id: NettyClient, v 0.1 2023/12/25 15:20 co_wb_junjie_qiu Exp $*/
public class NettyClient {public static void main(String[] args) throws InterruptedException {NioEventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new NettyClientHandler());}});ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync();channelFuture.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}
}

客户端处理器:

/*** com.atguigu.netty** @author co_wb_junjie_qiu* @version Id: NettyClientHandler, v 0.1 2023/12/25 15:30 co_wb_junjie_qiu Exp $*/
public class NettyClientHandler extends ChannelInboundHandlerAdapter {/*** 当通道就绪就会触发该方法*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("client channelActive");ctx.writeAndFlush(Unpooled.copiedBuffer("hello server", CharsetUtil.UTF_8));}/*** 当通道有读取事件时会触发*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf) msg;System.out.println("服务器回复的消息:"+buf.toString(CharsetUtil.UTF_8));System.out.println("服务器的地址:"+ctx.channel().remoteAddress());}/*** 处理异常,一般需要关闭通道*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

Netty核心组件简介

  1. Channel
    • ChannelNetty 中的核心概念,代表了应用程序和网络之间的连接。
    • 它封装了网络套接字,并提供了读写数据、绑定端口、连接远程地址、关闭连接等基本的 I/O 操作。
    • Channel 提供了非阻塞的 I/O 操作,使得 Netty 能够在单个线程中处理多个连接。
  2. EventLoop
    • EventLoopNetty 中负责处理 Channel 事件的组件。
    • 每个 EventLoop 负责监听和处理其关联的 Channel 上的事件,包括读写操作、连接建立、连接关闭等。
    • 一个 EventLoop 在其生命周期内通常会与一个或多个 Channel 关联,确保 Channel 的所有操作都在同一个线程上下文中执行,从而避免了线程安全问题。
  3. ChannelHandler
    • ChannelHandler 是 Netty 中处理 Channel 事件的接口或者类。
    • 应用程序通过实现 ChannelHandler 接口或者扩展 ChannelInboundHandlerChannelOutboundHandler 类来定制自己的业务逻辑。
    • ChannelHandler 可以参与到 Channel 的生命周期中的多个阶段,如连接建立、数据读取、数据写入、连接关闭等。
  4. ChannelPipeline
    • ChannelPipeline 是一个处理链,包含了多个 ChannelHandler
    • 当 Channel 上发生事件时,这些事件会在 ChannelPipeline按照一定的顺序传递给各个 ChannelHandler 进行处理。
    • ChannelPipeline 允许开发者灵活地配置和组织 ChannelHandler,以实现复杂的业务逻辑和协议解析。
  5. EventLoopGroup
    • EventLoopGroup 是一组 EventLoop 的集合。
    • Netty 通常会为服务器和客户端分别创建一个 EventLoopGroup
    • EventLoopGroup 负责分配 EventLoop 给新的 Channel,以及管理它们的生命周期。
  6. ChannelFuture
    • ChannelFuture 表示一个异步操作的结果。
    • 当在 Channel 上执行诸如连接、写入数据等异步操作时,会返回一个 ChannelFuture。
    • 通过注册 ChannelFutureListener,应用程序可以监听操作的完成、失败或者取消等事件。
  7. Bootstrap、ServerBootstrap(引导器):
    • Bootstrap是启动Netty应用程序的入口,用于配置Channel和其他相关的参数。
    • 通过Bootstrap可以配置客户端和服务器,包括线程模型、Channel类型、ChannelHandler等。
  8. ByteBuf(字节缓冲区):
    • ByteBuf是Netty中用于处理字节数据的缓冲区,提供了灵活的API用于读取、写入和操作字节数据。
    • ByteBuf具有池化和零拷贝等优化特性,使得数据的处理更加高效。
  9. Codec(编解码器):
    • Netty提供了丰富的编解码器,用于处理字节数据的编码和解码,包括StringDecoderStringEncoderObjectDecoderObjectEncoder等。
    • 编解码器可以简化开发者的工作,实现对各种协议的支持

其中最核心的是前4个 ,可以说其他组件都是为了辅助它们的。

  1. Channel:通道是 Netty 中的基本组件,它表示一个网络连接。
  2. EventLoop:事件循环是 Netty 中负责处理 I/O 事件的组件。
  3. ChannelHandler:通道处理器是 Netty 中负责处理 I/O 事件的组件。
  4. ChannelPipeline:通道管道是 Netty 中负责将 I/O 事件从 Channel 传递到 ChannelHandler 的组件。

ChannelPipeline与Channel的关系

其中比较难理解是ChannelPipeline通道与Channel管道,这两个概念,下面将详细说明:

  • 每个 Channel 都有一个与之关联的 ChannelPipeline
  • ChannelPipelineChannel 的一部分,它负责处理所有与该 Channel 相关的事件和数据。
  • Channel 接收到数据或者发生其他事件时,这些事件会被自动地传递到其关联的 ChannelPipeline 中进行处理。
  • 开发者可以通过操作 ChannelPipeline 来添加、删除或者替换 ChannelHandler,从而改变事件处理的逻辑。
  • channelChannelPipeline是相互包含的,也就是说可以通过Channel拿到ChannelPipeline,也可以通过ChannelPipeline拿到Channel

生活中的例子说明:

  • 假设你正在经营一家快递公司,Channel 可以类比为公司的运输车辆,它负责实际的包裹运输。

  • ChannelPipeline 则可以看作是包裹从发出到接收过程中的一系列处理环节。例如,当一个包裹(相当于网络数据)进入你的公司时,它首先会经过收件区(相当于 ChannelPipeline 中的第一个 ChannelHandler),在那里进行登记和初步检查。然后,包裹被送到分拣区(第二个 ChannelHandler),根据目的地进行分类。接着,包裹被装载到相应的运输车辆(Channel)上,运往目标城市。到达目标城市后,包裹再次经过一系列的处理环节(更多的 ChannelHandler),如卸货、本地配送等,最终送达客户手中。

  • 在这个例子中,每辆运输车辆(Channel)都有自己的运输流程(ChannelPipeline),包括了各个环节的处理步骤(ChannelHandler)。通过调整运输流程中的处理环节,你可以优化整体的运输效率和服务质量。同样,在 Netty 中,通过配置和操作 ChannelPipeline,你可以定制网络通信的处理逻辑,提高系统的性能和灵活性。

参考文献

尚硅谷Netty教程

相关文章:

Netty—Reactor线程模型详解

文章目录 前言线程模型基本介绍线程模型分类Reactor线程模型介绍Netty线程模型&#xff1a; 传统阻塞IO的缺点Reactor线程模型单Reactor单线程模式单Reactor多线程模式主从Reactor多线程Reactor 模式小结 Netty 线程模型案例说明&#xff1a;Netty核心组件简介ChannelPipeline与…...

开源verilog模拟 iverilog verilator +gtkwave仿真及一点区别

开源的 iverilog verilator 和商业软件动不动几G几十G相比&#xff0c;体积小的几乎可以忽略不计。 两个都比较好用&#xff0c;各有优势。 iverilog兼容性好。 verilator速度快。 配上gtkwave 看波形&#xff0c;仿真工具基本就齐了。 说下基本用法 计数器 counter.v module…...

mysql中按字段1去重,按字段2降序排序

数据举例 sql语句 按字段field4降序排序&#xff0c;按字段field1去重 SELECT tt1.name2,tt1.field1,tt1.field2,tt1.field4 from ( select tt2.name2,tt2.field1,tt2.field2,tt2.field4 from t2 tt2 ORDER BY tt2.field4 DESC ) tt1 GROUP BY tt1.field1执行结果...

OCP NVME SSD规范解读-4.NVMe IO命令-2

NVMe-IO-3&#xff1a; 由于设备具有掉电保护功能&#xff08;如Power Loss Protection&#xff0c;PLP&#xff09;&#xff0c;因此在以下情况下&#xff0c;性能不应降低&#xff1a; FUA&#xff08;Force Unit Access&#xff09;&#xff1a;是计算机存储设备中的一种命…...

平凯数据库亮相 2023 信息技术应用创新论坛

11 月 25 日&#xff0c;2023 信息技术应用创新论坛在常州开幕。江苏省工业和信息化厅副厅长池宇、中国电子工业标准化技术协会理事长胡燕、常州市常务副市长李林等领导出席论坛并致辞。中国工程院院士郑纬民出席并作主题报告。来自产学研用金等各界的千余名代表参加本次论坛。…...

2024深入评测CleanMyMac X4.14.6破解版新的功能

随着时间的推移&#xff0c;我们的Mac电脑往往会变得越来越慢&#xff0c;存储空间变得越来越紧张&#xff0c;这时候一个优秀的清理工具就显得尤为重要。作为一款备受好评的Mac清理工具&#xff0c;它能够为你的Mac带来全方位的清理和优化。在本文中&#xff0c;我们将深入评测…...

WPF+Halcon 培训项目实战(8):WPF+Halcon初次开发

前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视频来源于下方的Up主的提供的教程。这里只做笔记分享&#xff0c;想要源码或者教学视频可以和他联系一下。 相关链接 微软系列技术教程 WPF 年度公益课程 Halcon开发 CSD…...

Vue - 实现文件导出文件保存下载

1 文件导出&#xff1a;使用XLSX插件 需求背景&#xff1a;纯前端导出&#xff0c;如 在前端页面勾选部分表格数据&#xff0c;点击"导出"按钮导出Excel文件。 实现思路&#xff1a; 1.通过XLSX插件的 XLSX.utils.book_new()方法&#xff0c;创建excel工作蒲对象wb…...

c基础学习(一)

学习网站&#xff1a; C语言的过去与未来 - C语言教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/c-intros/ C 语言简介 - C 语言教程 - 网道 (wangdoc.com)https://wangdoc.com/clang/intro 变量&#xff1a; #include<stdio.h> /*引入头文件-- 标准…...

c语言的文件操作

当涉及到C语言中的文件操作时&#xff0c;我们需要了解一些基本的概念和函数。首先&#xff0c;让我们来看看如何打开和关闭文件&#xff0c;以及如何读取和写入文件。 要打开文件&#xff0c;我们使用fopen函数。这个函数接受两个参数&#xff1a;文件名和打开模式。打开模式…...

C语言 volatile关键字

volatile关键字介绍 volatile 是一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是易变的&#xff0c;即可能在任何时候被意外地改变。在多线程编程中&#xff0c;当多个线程同时访问同一个变量时&#xff0c;由于线程之间的交互和优化&#xff0c;可能会导致变量的…...

IDEA快捷使用-快捷键模板

常用快捷模板 .方法的使用,例如输入 arr.null 回车 其他常规方法直接输入回车&#xff0c;不需要对象通过.来调用。 创建变量 psfi 创建公开int类型常量 public static final int prsf 创建 私有静态变量 private static final psf 创建公开静态变量 public static final创…...

在VMware安装CentOS 7:详细教程

安装准备工作 本地虚拟机&#xff1a;我这里使用的是VMware Workstation 17 Pro centos7系统ISO镜像&#xff1a;我这里使用的是CentOS-7-x86_64-DVD-2009.iso&#xff0c;具体的下载地址是在阿里云官方镜像站&#xff1a;centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿…...

[Angular] 笔记 10:服务与依赖注入

什么是 Services & Dependency Injection? chatgpt 回答&#xff1a; 在 Angular 中&#xff0c;Services 是用来提供特定功能或执行特定任务的可重用代码块。它们可以用于处理数据、执行 HTTP 请求、管理应用程序状态等。Dependency Injection&#xff08;依赖注入&#…...

【产品经理】axure中继器的使用——表格增删改查分页实现

笔记为个人总结笔记&#xff0c;若有错误欢迎指出哟~ axure中继器的使用——表格增删改查分页实现 中继器介绍总体视图视频预览功能1.表头设计2.中继器3.添加功能实现4.删除功能实现5.修改功能实现6.查询功能实现7.批量删除 中继器介绍 在 Axure RP9 中&#xff0c;中继器&…...

面向对象进阶-继承

继承中&#xff1a;成员变量的访问特点 就近原则&#xff1a;谁离我近我就访问谁,先在局部位置找&#xff0c;找不到然后在到本类成员位置到&#xff0c;如果本类成员位置找不到就到父类成员位置找&#xff0c;逐级往上找。 package oop.Extends.a03oopextendsdemo03; public…...

[NOIP2012 普及组] 摆花

[NOIP2012 普及组] 摆花 题目描述 小明的花店新开张&#xff0c;为了吸引顾客&#xff0c;他想在花店的门口摆上一排花&#xff0c;共 m m m 盆。通过调查顾客的喜好&#xff0c;小明列出了顾客最喜欢的 n n n 种花&#xff0c;从 1 1 1 到 n n n 标号。为了在门口展出更…...

系统学习Python——装饰器:函数装饰器-[装饰器状态保持方案:外层作用域和全局变量]

分类目录&#xff1a;《系统学习Python》总目录 闭包函数&#xff08;带有外围def作用域引用和嵌套的def&#xff09;常常可以实现相同的效果&#xff0c;特别是用于像被装饰的最初咱数这样的静态数据时。然而在下面这个例子中&#xff0c;我们也需要外层作用域中的一个计数器&…...

Tekton

一. 概念 Tekton 官网 Github Tekton 是一种用于构建 CI/CD 管道的云原生解决方案&#xff0c;它由提供构建块的 Tekton Pipelines&#xff0c;Tekton 作为 Kubernetes 集群上的扩展安装和运行&#xff0c;包含一组 Kubernetes 自定义资源&#xff0c;这些资源定义了您可以为…...

2023,TEVC,A Competitive and Cooperative Swarm Optimizer for Constrained MOP

Abstract 通过元启发式方法求解多目标优化问题( MOPs )得到了广泛的关注。在经典变异算子的基础上&#xff0c;发展了几种改进的变异算子&#xff0c;以及多目标优化进化算法。在这些算子中&#xff0c;竞争群优化算法(CSO)表现出良好的性能。然而&#xff0c;在处理目标空间较…...

java设计模式学习之【中介者模式】

文章目录 引言中介者模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用聊天室示例代码地址 引言 想象一下一座忙碌的机场&#xff0c;各种飞机需要起飞、降落&#xff0c;而不同的飞行活动之间必须互不干扰。如果没有一个统一的控制系统&#xff0c;这将是一…...

C++三剑客之std::variant(一)

1简介 C17的三剑客分别是std::optional, std::any, std::vairant。今天主要讲std::variant。std::variant的定义如下&#xff1a; template< class... Types > class variant; 类模板 std::variant 表示一个类型安全的联合体&#xff08;以下称“变化体”&#xff09;…...

新火种AI|AI正在让汽车成为“消费电子产品”

作者&#xff1a;一号 编辑&#xff1a;小迪 AI正在让汽车产品消费电子化 12月28日&#xff0c;铺垫许久的小米汽车首款产品——小米SU7正式在北京亮相。命里注定要造“电车”的雷军&#xff0c;在台上重磅发布了小米的五大自研核心技术。在车型设计、新能源技术以及智能科技…...

Docker六 | Docker Compose容器编排

目录 Docker Compose 基本概念 使用步骤 常用命令 Docker Compose Docker-Compose是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排。Compose可以管理多个Docker容器组成一个应用。 需要定义一个YAML格式的配置文件docker-compose.yml&#xff0c;…...

Oraclelinux部署Oracle服务

采用图形化界面 user用户 oracle用户 #清屏 clear #设置主机名 hostnamectl set-hostname ceshidb sed -i 1,2 s/^/#/ /etc/hosts echo "127.0.0.1 ceshidb" >> /etc/hosts echo "::1 ceshidb" >> /etc/hosts ping -c 5…...

Ubuntu安装K8S(1.28版本,基于containrd)

原文网址&#xff1a;Ubuntu安装K8S(1.28版本&#xff0c;基于containrd&#xff09;-CSDN博客 简介 本文介绍Ubuntu安装K8S的方法。 官网文档&#xff1a;这里 1.安装K8S 1.让apt支持SSL传输 sudo apt-get update sudo apt-get -y install apt-transport-https ca-certi…...

Linux 线程安全 (2)

文章目录 线程同步概念条件变量使用生产消费模型信号量的使用读写锁的使用 Linux 线程安全 &#xff08;1&#xff09; 线程同步概念 竞态条件&#xff1a;因为时序问题&#xff0c;而导致程序异常. 饥饿问题&#xff1a;只使用互相锁保证线程安全时&#xff0c;锁资源总被某…...

异或运算^简述

异或运算&#xff1a;^ 两个变量之间异或运算时&#xff0c;其二进制位相同取0&#xff0c;不同取1. 示例&#xff1a;a10 (0b 0000 1010) b3 (0b 0000 0011) a^b9(0b 0000 1001) 据此可以推算异或运算"^"有以下特性&#xff1a; a^a0 (0b 0000 0000)…...

Google Play上架:2023年度总结报告

今天是2023年的最后一个工作日&#xff0c;今天用来总结一下2023年关于谷歌商店上架的相关政策改动和对应的拒审解决方法。 目录 政策更新与改动2023 年 2 月 22 日2023 年 4 月5 日2023 年 7 月 12 日2023 年 10 月 25 日 开发者计划政策拒审邮件内容和解决办法 政策更新与改…...

JAVA进化史: JDK10特性及说明

DK 10&#xff08;Java Development Kit 10&#xff09;是Java平台的一个版本&#xff0c;于2018年3月发布。尽管相对于之前的版本&#xff0c;JDK 10的变化较为温和&#xff0c;但仍然引入了一些新特性和改进&#xff0c;以下是其中一些主要特性&#xff0c;并带有相应的示例说…...

开封旅游网站建设网页推广/seo关键字排名优化

上一节中我们已经基本完成了django项目部署到nginx&#xff0c;这一节我们将http改为https&#xff0c;提升访问的安全性。 我是T型人小付&#xff0c;一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我&#xff0c;如果有问题欢迎在底下的评论区交流&#xff0…...

seo网站优化论文/百度最新版本2022

1.我们14年坚持的理念才成就了今天的成功&#xff0c;别人才进来了一两年就想与天猫和淘宝竞争是不可能的。他们应该去补充天猫和淘宝没有的东西&#xff0c;而不是去跟淘宝天猫比。现在的电商企业应该利用BAT去发展自己。2.至于IPO,我们自己也不知道在哪里IPO,今天是双11&…...

php网站后台搭建/安卓优化大师官方下载

iPhone12 mini、iPhone12、iPhone12 Pro、iPhone12 Pro Max四款手机&#xff0c;屏幕尺寸分别为5.4英寸、6.1英寸、6.1英寸、6.7英寸。采用OLED屏幕&#xff0c;多年不变的刘海屏设计。综合各方面这次iPhone12将不会有高刷新率。 iphone手机爆降2500 这活动太给力了机会不容错过…...

网站开发公司怎么查询/新闻摘抄2022最新5篇

目录 1、数据报方式 1.1、数据报方式的原理 1.2、数据报方式的特点 2、虚电路方式 2.1、虚电路方式简介 2.2、虚电路方式的工作原理&#xff08;流程&#xff09; 2.3、虚电路方式的特点 3、数据报服务和虚电路服务的对比 分组交换根据其通信子网向端点系统提供的服务&…...

如何做网站引流/网络营销推广方案案例

本文经AI新媒体量子位(公众号ID:QbitAI)授权转载&#xff0c;转载请联系出处。“有些人对大型语言模型(类似于GPT-3)能做的事&#xff0c;有着不切实际的幻想……GPT-3对于这世界的运作方式一无所知。”近日&#xff0c;LeCun忽然在脸书上发表了对GPT-3的看法。LeCun表示&#…...

主流的网站开发语言/seo网站优化论文

隐藏页面顶部的应用名称&#xff0c;在config.json - module 中加入下列配置 "metaData": {"customizeData": [{"name": "hwc-theme","value": "androidhwext:style/Theme.Emui.Light.NoTitleBar"}]},...