6.netty线程模型-Reactor

【README】

1..本文部分内容翻译自:

[Netty] Netty's thread model and simple usage

2.netty模型是以 Reactor模式为基础的,具体的,netty使用的是 主从Reactor多线程模型

3.先介绍了 Reactor线程模型;后介绍了 Netty 组成部分;

4.文末还po出了 netty服务器与客户端代码实现(总结自 B站《尚硅谷-netty》);

【注意】

  • 本文所有图片均转自:  

[Netty] Netty's thread model and simple usage


【1】netty线程模型-Reactor

1)Reactor模式

  • reactor模式,也叫分发器模式。当1个或多个请求同时发送到服务器时,服务器同步地把它们分发到独立的处理线程;

2)Reactor模式的三种角色:

  • Acceptor: (接收器)处理客户端新连接,并分配客户端分发到处理线程链;
  • Reacor:(反应器)负责监听,分配事件及IO事件给对应处理器Handler;
  • Handler:(处理器)处理事件,如编码,业务逻辑处理,解码等;

3)Reactor的3种线程模型

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

netty 使用的是 主从 Reactor多线程模型

4)除建立连接外,服务器处理客户端请求涉及的操作大致有5种:

  • IO读;
  • 编码;
  • 计算;
  • 解码;
  • IO写;

【2】Reactor3种线程模型

【2.1】单Reactor单线程模型

1)单Reactor单线程模型概述:

  • 在该线程模型下,所有请求连接的建立,IO读写,及业务逻辑处理都全部在同一个线程;
  • 若耗时操作发生在业务逻辑处理,则所有的请求都会延迟 与阻塞,因为这个线程上的所有操作都是同步的;这一点应该比较好理解;

2)模型图

【图解】

  • 服务器 仅 有一个  Reactor 线程;
  •  IO读,解码,计算,编码,发送(IO写)这5个步骤都由单个Reactor 线程来完成,一旦有一个步骤耗时过长,则整体阻塞

【优缺点】

  • 缺点:因为只有一个Reactor线程, 请求1耗时长会导致其他请求阻塞直到请求1处理完成服务器并发性非常低

【2.2】单Reactor多线程模型

1)单Reactor多线程模型概述:

  • 为了防止阻塞,请求连接的建立(包括认证与授权)及IO读写都在 Reactor线程里;
  • 此外,业务逻辑处理完全由异步线程池负责处理,并在处理后把结果写回;

2)模型图

【图解】

  • 服务器 仅 有一个  Reactor 线程;
  •  IO读与发送(IO写)由 Reactor线程负责执行;
  • 解码,计算,编码等业务逻辑处理由 工作线程池(WorkThreads)负责分配线程执行;

【优缺点】

  • 优点:解码,计算,编码等耗时操作若有阻塞,不会导致服务器的其他请求阻塞;
  • 缺点:仅有一个 Reactor线程来处理客户端连接,若客户端IO读写数据量大,容易在IO读写时发生阻塞

 【2.3】主从Reactor多线程模型

1)主从Reactor多线程模型概述:由于单Reactor线程会降低多核cpu能力(或未能发挥),所以需要建立多Reactor线程,即主从Reactor线程模型

  • 主Reactor线程(单个):用于建立请求的连接(包括认证与授权);
  • 从Reactor线程(多个):用于处理IO读写;
  • 补充:其他业务逻辑如解码,计算,编码等工作还是交由异步线程池(Worker线程池)处理;

 【图解】主从Reactor多线程模型下,服务器线程有3类:

  • 第1类:主Reactor线程负责客户端连接的建立(同步);
  • 第2类:子Reactor线程有多个,封装在线程池,异步处理客户端的IO读写(read 与 send);
  • 第3类:工作线程池:异步处理业务逻辑,包括 编码,计算,解码等操作;

【优缺点】

  • 优点1:显然,IO读写若有阻塞,不会导致其他客户端请求阻塞;
  • 优点2:显然,业务逻辑若有阻塞(耗时操作),也不会导致其他客户端请求阻塞;
  • 小结:在主从Reactor多线程模型条,服务器的并发性非常高(也充分利用了多核cpu的算力);

【3】netty线程模型

 【3.1】成员关系

1)netty线程模型包含 ServerBootStrap,NioEventLoopGroup 及其组成部分 NioEventLoop,NioChannel, ChannelPipeline, ChannelHandler 等;

  • ServerBootStrap:服务器启动引导对象;
  • NioEventLoopGroup:Nio 事件循环组;
  • NioEventLoop:Nio事件循环;
  • NioChannel:Nio通道;
  • ChannelPipeline:通道管道(封装了多个处理器);
  • ChannelHandler:处理器;

2)netty使用主从Reactor多线程模型来实现。

  • 主Reactor:对应 BossGroup;
  • 从(子)Reactor:对应 WorkerGroup;
  • BossGroup 用于接收连接并通过通道注册 与 WorkerGroup已建立的连接;
  • 当IO事件被触发,该事件交由管道处理;管道处理实际上是由对应的处理器Handler来处理;

【3.2】EventLoop 事件循环

1)即 事件循环器;顾名思义,他实际上是一个循环的处理过程;

2)EventLoop 等同于 while(true)  死循环里的代码段;

3)EventLoop 主要包含了一个选择器多路复用器和一个任务队列

  • 选择器多路复用器:处理IO事件的;
  • 任务队列:存储已提交任务;

4)EventLoop并不是从程序启动时就开始运行,而是当有任务提交时,它才会开始处理任务并一直运行;


【3.3】通道 channel

  • 1)netty封装了 java的本地Channel,并引入了 管道与通道处理器的概念。
  • 2)通道具体的IO事件处理是通过管道和通道处理器(管道中)来完成的;


【4】netty服务器与客户端-代码实现

1)初始化:

  • 服务器通过 ServerBootStrap,可以直接设置线程组;
  • 服务器的bossGroup(boss线程组)用于处理 NioServerSocketChannel 通道的 Accept 事件,即处理请求连接与认证;
  • 服务器的 workerGroup(工作线程组)用于处理 IO 读写事件及已提交的异步任务;

2)ServerBootStrap初始化 代码实现:

ServerBootstrap bootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup(1); // 设置boss线程组中的线程个数为1 (默认是cpu核数*2)
EventLoopGroup work = new NioEventLoopGroup(8); // 设置worker线程组中的线程个数为8 (默认是cpu核数*2)
bootstrap.group(boss, work).channel(NioServerSocketChannel.class); // 把参数设置到bootstrap 

【4.1】服务器

1)netty服务器

/*** @Description 简单netty服务器* @author xiao tang* @version 1.0.0* @createTime 2022年08月27日*/
public class SimpleNettyServer44 {public static void main(String[] args) throws InterruptedException {// 创建 BossGroup 和 WorkerGroup// 1. 创建2个线程组 bossGroup, workerGroup// 2 bossGroup 仅处理连接请求; 真正的业务逻辑,交给workerGroup完成;// 3 两个线程组都是无限循环// 4 bossGroup 和 workerGroup 含有的子线程(NIOEventLoop)个数// 默认是 cpu核数 * 2EventLoopGroup boosGroup = new NioEventLoopGroup();EventLoopGroup workerGruop = new NioEventLoopGroup();try {// 创建服务器端的启动对象, 配置参数ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(boosGroup, workerGruop) // 设置2个线程组.channel(NioServerSocketChannel.class) // 使用NIOSocketChannel 作为服务器的通道实现.option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列等待连接的个数.childOption(ChannelOption.SO_KEEPALIVE, true) // 设置保持活动连接状态.childHandler(new ChannelInitializer<SocketChannel>() { // 创建一个通道初始化对象// 给 pipeline 设置处理器@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {socketChannel.pipeline().addLast(new SimpleNettyServerHandler45());}});  // 给我们的workerGroup 的 EventLoop 对应的管道设置处理器System.out.println("... server is ready.");// 启动服务器, 绑定端口并同步处理 ,生成一个 ChannelFuture对象ChannelFuture channelFuture = bootstrap.bind(6668).sync();channelFuture.addListener((future1) -> System.out.println("Finish binding"));// 对关闭通道进行监听channelFuture.channel().closeFuture().sync();} finally {// 优雅关闭boosGroup.shutdownGracefully();workerGruop.shutdownGracefully();}}
}

2)netty服务器中的处理器(封装到管道)

/*** @Description netty服务器处理器* @author xiao tang* @version 1.0.0* @createTime 2022年08月27日*/
public class SimpleNettyServerHandler45 extends ChannelInboundHandlerAdapter {// 读写数据事件(读取客户端发送的消息)// 1. ChannelHandlerContext ctx: 上下文信息,包括管道pipeline,通道channel,地址// 2. Object msg: 客户端发送的数据,默认是 Object@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println("server ctx = " + ctx);System.out.println("查看 channel 和 pipeline的关系 ");Channel channel = ctx.channel();ChannelPipeline channelPipeline = ctx.pipeline(); // 管道是双向链表,出栈入栈// 将 msg 转为 ByteBuf 字节缓冲// 这个 ByteBuf 是 netty提供的, 不是 nio的ByteBufferByteBuf buf = (ByteBuf) msg;System.out.println("客户端发送消息:" + buf.toString(StandardCharsets.UTF_8));System.out.println("客户端地址:" + ctx.channel().remoteAddress());}// 数据读取完毕,回复客户端@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {// writeAndFlush 是 write + flush ;把数据写入到缓冲,并刷新ChannelFuture channelFuture = ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端", StandardCharsets.UTF_8));channelFuture.addListener(future -> System.out.println("回复成功"));}// 处理异常,关闭通道@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.channel().close();}
}

【4.2】客户端

1)netty客户端

/*** @Description netty客户端* @author xiao tang* @version 1.0.0* @createTime 2022年08月27日*/
public class SimpleNettyClient46 {public static void main(String[] args) throws InterruptedException {// 客户端需要一个事件循环组EventLoopGroup eventLoopGroup = new NioEventLoopGroup();try {// 创建客户端启动对象, 注意是 BootStrapBootstrap bootstrap = new Bootstrap();// 设置相关参数bootstrap.group(eventLoopGroup) // 设置线程组.channel(NioSocketChannel.class) // 设置客户端通道实现类(反射).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {socketChannel.pipeline().addLast(new SimpleNettyClientHaandler()); // 加入自己的处理器}});System.out.println("client is ok");// 启动客户端去连接服务器// ChannelFuture, 设计到netty的异步模型ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync();// 给关闭通道进行监听channelFuture.channel().closeFuture().sync();} finally {eventLoopGroup.shutdownGracefully();}}
}

2)netty客户端中的处理器

/*** @Description netty客户端处理器* @author xiao tang* @version 1.0.0* @createTime 2022年08月27日*/
public class SimpleNettyClientHaandler extends ChannelInboundHandlerAdapter {// 当通道就绪就会触发该方法@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("client " + ctx);ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 服务器", StandardCharsets.UTF_8));}// 当通道有读取事件时,会触发@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf byteBuf = (ByteBuf) msg;System.out.println("服务器回复消息:" + byteBuf.toString(StandardCharsets.UTF_8));System.out.println("服务器地址:" + ctx.channel().remoteAddress());}// 捕获异常@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

 【4.3】演示效果

server端:

... server is ready.
server ctx = ChannelHandlerContext(SimpleNettyServerHandler45#0, [id: 0x2995c48c, L:/127.0.0.1:6668 - R:/127.0.0.1:49427])
查看 channel 和 pipeline的关系
客户端发送消息:hello, 服务器
客户端地址:/127.0.0.1:49427

client端:

client is ok
client ChannelHandlerContext(SimpleNettyClientHaandler#0, [id: 0xe92524d8, L:/127.0.0.1:49427 - R:/127.0.0.1:6668])
服务器回复消息:hello, 客户端
服务器地址:/127.0.0.1:6668


【5】 netty小结

  • netty使用了 主从Reactor多线程模型;
  • EventLoop是netty处理请求,io事件及其他操作的检测与分配(这句翻译的不好,最好查看原文);
  • netty引入了 通道Channel,管道 Pipeline,通道处理器 ChannelHandler 以异步处理任务;
  • netty提供了 ServerBootStrap 简化了管道初始化;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329381.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python mac读取 文件属性_从Python获取和设置mac文件和文件夹查找器标签

macfile模块是^{}模块的一部分&#xff0c;在"2006-11-20 0.2.0"中被重命名为mactypes使用此模块&#xff0c;以下两个函数可用于获取和设置appscript 1.0版的查找器标签&#xff1a;from appscript import appfrom mactypes import File as MacFile# Note these lab…

Oracle入门(十四.1)之PL / SQL简介

一、PL / SQL描述程序语言扩展到SQL&#xff1a; •允许将基本程序逻辑和控制流与SQL语句组合在一起。 •是Oracle专有编程语言。- 它只能用于Oracle数据库或工具。二、程序语言扩展到SQL•是一种程序语言。 - 当遵循一系列指令时会产生结果。 •是3GL&#xff08;第三代编程语…

构建高性能.NET应用之配置高可用IIS服务器-第三篇 IIS中三个核心组件的讲解(上)

今天的文章的比较的容易&#xff0c;主要讲述IIS中三个比较重要的组件&#xff1a;协议监听者(Protocol Listeners)&#xff0c;WWW服务(World Wide Web Publishing Service)和WAS(Windows Process Activation Service)&#xff0c;理解这三个组件的功能&#xff0c;是理解IIS…

7.netty服务器中提交任务到NioEventLoop(Nio事件循环执行线程)

【README】 1.本文总结自 B站 《尚硅谷-netty》; 2.NioEventLoop实际上是一个提交到线程池的Runnable任务&#xff0c;在while无限循环中运行 taskQueue中的任务&#xff08;串行&#xff09;&#xff1b; 【1】提交任务到NioEventLoop 1&#xff09;NioEventLoop&#xff1…

Oracle入门(十四.2)之PL / SQL的好处

一、PL / SQL的好处在Oracle数据库中使用PL / SQL编程语言有很多好处。 1.将过程构造与SQL集成 2.模块化程序开发 3.改进的性能 4.与Oracle工具集成 5.便携性6.异常处理二、优点 优点1&#xff1a;使用SQL集成程序化结构PL / SQL的首要优势是程序结构与SQL的集成。 SQL是一种非…

炒菜机器人的弊端_机器人炒菜真不是你想的那样!

7月8日下午&#xff0c;爱餐全产业链模式发布会在张家口进行&#xff0c;会上&#xff0c;张家口文旅投集团与上海爱餐机器人有限公司签订了3000台智能机器人设备合作协议&#xff0c;这些机器人可是身手不凡&#xff0c;清一色的都是会厨艺的炒菜机器人&#xff0c;未来他们还…

构建高性能.NET应用之配置高可用IIS服务器-第四篇 IIS常见问题之:工作进程回收机制(上)

通过三篇文章的普及&#xff0c;相信大家对IIS应该有了一个基本的了解。那么从本篇文章开始&#xff0c;我们就开始进入IIS一些比较实际的话题&#xff1a;如何配置IIS&#xff0c;使得其性能尽可能的高。 我们在本篇中主要讲述的就是“工作进程回收机制”&#xff0c;下面我们…

8.基于netty实现群聊,心跳检测

【README】 1.本文总结自B站《netty-尚硅谷》&#xff0c;很不错&#xff1b; 2.本文po出了 Unpooled创建缓冲区的 代码示例&#xff1b; 3.本文示例代码基于netty实现以下功能&#xff1a; 群聊客户端及服务器&#xff1b;心跳检测&#xff1b;【1】Unpooled创建缓冲区 U…

Oracle入门(十四.3)之创建PL / SQL块

一、PL / SQL块结构 一个PL / SQL块由三部分组成。PL / SQL块结构部分二、PL / SQL编译器用高级编程语言&#xff08;C&#xff0c;Java&#xff0c;PL / SQL等&#xff09;编写的每个程序都必须经过检查并转换为二进制代码&#xff08;1和0&#xff09;&#xff0c;然后才能执…

[.NET Core].NET Core R2安装及示例教程

前言 前几天.NET Core发布了.NET Core 1.0.1 R2 预览版&#xff0c;之前想着有时间尝试下.NET Core。由于各种原因&#xff0c;就没有初试。刚好&#xff0c;前几天看到.NET Core发布新版本了&#xff0c;决定要去一探究竟。于是乎&#xff0c;就立马去官网查找相关的信息&…

Oracle入门(十四.4)之在PL / SQL中使用变量

一、变量的使用 &#xff08;1&#xff09;使用变量的原因•临时存储数据 •储存值的操作 •可重用性&#xff08;2&#xff09;处理PL / SQL中的变量变量是&#xff1a; •在声明部分声明并初始化 •在可执行部分中使用并分配新值 变量可以是&#xff1a; •作为参数传递给PL …

dismiss的词组_法律英语常用词必记:Dismiss

Dismiss英[dɪsmɪs] 美[dɪsmɪs]【英文释义】v.to refuse to give further hearing to a case in court. If a judge dismisses a court case, they officially decide that the case should not continue【中文释义】v. (1)解雇&#xff1b;免职&#xff1b;开除(2)驳回(起诉…

构建高性能.NET应用之配高可用IIS服务器-第五篇 IIS常见问题之:工作进程回收机制(中)

我们在本篇中接着讲述“工作进程回收机制”。 本篇文章的议题如下&#xff1a; 工作进程回收机制讲解 基于时间的回收机制 基于请求数的回收机制 基于内存使用的回收机制 基于活动状态的回收机制 基于请求数的回收机制 这种基于请求数量回收的机制非常的好理解&#xff1a;当我…

10.netty客户端与服务器使用protobuf传输报文

【README】 本文总结自B站《尚硅谷-netty》&#xff0c;很不错&#xff1b; 内容如下&#xff1a; netty的编码器与解码器&#xff1b;netty客户端与服务器通过 protobuf 传输报文的开发方式&#xff1b;文末po出了所有代码&#xff1b;【1】netty的编码器与解码器 codec 1&…

Oracle入门(十四.5)之识别数据类型

一、PL / SQL数据类型 数据类型指定存储格式&#xff0c;约束和有效的值范围。 PL / SQL支持五类数据类型&#xff1a;二、标量数据类型&#xff08;Scalar&#xff09; &#xff08;1&#xff09;标量数据类型•保持一个值 •没有内部组件 •可以分为四类&#xff1a; - 性格…

TFS2015的CI集成

这篇应该是这个系列的最后一篇了 配置生成代理 配置dotnet cli环境 这步&#xff0c;需要在生成代理的机器上配置cli环境&#xff0c;与本地配置方法一致&#xff0c;可以自行Google 下载及参考地址&#xff1a; https://www.microsoft.com/net/core#windows 配置环境变量 在生…

pivot sqlserver 条件_行转列之SQLSERVERPIVOT与用法详解

在数据库操作中&#xff0c;有些时候我们遇到需要实现“行转列”的需求&#xff0c;例如一下的表为某店铺的一周收入情况表&#xff1a;WEEK_INCOME(WEEK VARCHAR(10),INCOME DECIMAL)我们先插入一些模拟数据&#xff1a;INSERT INTO WEEK_INCOMESELECT 星期一,1000UNION ALLSE…

Oracle入门(十四.6)之使用标量数据类型

一、声明字符变量 字符数据类型包括CHAR&#xff0c;VARCHAR2和LONG。 DECLAREv_emp_job VARCHAR2(9);v_order_no VARCHAR2(6);v_product_id VARCHAR2(10);v_rpt_body_part LONG; …二、声明数字变量 数字数据类型包括NUMBER&#xff0c;PLS_INTEGER&#xff0c;BINARY_INTEGER…

11.netty入站与出站(处理器链调用机制)

【README】 1.本文源代码总结自 B站《netty-尚硅谷》&#xff1b;2.本文部分内容总结自 https://www.baeldung.com/netty3.本文主要介绍了通道管道中多个入栈处理器与多个出站处理器如何执行&#xff1f;并用代码演示执行顺序&#xff1b; 补充&#xff1a;文末附带了 log4j整…

1688推广工具_全面了解1688数字营销

全面了解1688数字营销什么是数字营销&#xff1f;在数字营销中&#xff0c;有一款很重要的工具-一键推广。在我们的日常经营和大促中&#xff0c;通过一键站外推广可以在各大站外平台实现全店、各产品的推广&#xff0c;尤其在大促中&#xff0c;结合活动当天的站内流量&#x…