Netty I/O模型和线程模型

news2025/1/11 16:50:13

目录

1.概述

1.1 为什么使用Netty

1.2 Netty的优势

1.3 Netty的常见使用场景

2.Netty高性能的原因

2.1 I/O模型

2.1.1 阻塞IO

2.1.2 IO复用模型

2.2 线程模型

2.2.1 线程模型1:传统阻塞 I/O 服务模型

2.2.2 线程模型2:Reactor 模式

2.2.2.1 单 Reactor 单线程

2.2.2.2 单 Reactor 多线程

2.2.2.3 主从 Reactor 多线程


1.概述

Netty的官网:Netty: 首页

Netty是一个异步 事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端

  • Netty是由JBoss提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
  • 也就是说,Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。
  • Netty 是一个吸收了多种协议(包括FTP、SMTP、HTTP等各种二进制文本协议)的实现经验,并经过精心设计的项目。最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。

1.1 为什么使用Netty

  1. 直接使用 NIO 的时候,它的复杂的类库和API让人头大,例如需要我们熟练掌握NIO的几大核心内容:Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等。
  2. 要编写出高质量的NIO程序需要熟练掌握多线程和网络编程技术,而这些工作量和难度都不小,例如客户端面临断连重连、网络闪断、半包卖写、失败缓存、网络拥塞和异常流的处理等等。
  3. NIO中有一些Bug:例如Epoll Bug,它会导致Selector 空轮询,最终导致CPU 100%。

1.2 Netty的优势

  • 设计:更优雅的设计简化了原生NIO中的复杂编程
  • 易用性:文档丰富的Javadoc、用户指南和示例
  • 性能:更好的吞吐量,更低的延迟;减少资源消耗;最小化不必要的内存拷贝(零拷贝--操作系统层面)
  • 安全:完整的SSL/TLS和StartTLS支持
  • 社区:社区活跃、不断更新

1.3 Netty的常见使用场景

  1. 互联网行业:在分布式系统中,各个节点之间需要远程服务调用,高性能的 RPC 框架必不可少,Netty 作为异步高性能的通信框架,往往作为基础通信组件被这些 RPC 框架使用。典型的应用有:阿里分布式服务框架 Dubbo 使用 Dubbo 协议进行节点间通信,Dubbo 协议默认使用 Netty 作为基础通信组件,用于实现各进程节点之间的内部通信。
  2. 游戏行业:无论是手游服务端还是大型的网络游戏,Java 语言得到了越来越广泛的应用。Netty 作为高性能的基础通信组件,它本身提供了 TCP/UDP 和 HTTP 协议栈。非常方便定制和开发私有协议栈,账号登录服务器,地图服务器之间可以方便的通过 Netty 进行高性能的通信。
  3. 大数据领域:经典的 Hadoop 的高性能通信和序列化组件 Avro 的 RPC 框架,默认采用 Netty 进行跨节点通信,它的 Netty Service 基于 Netty 框架的二次封装实现。

2.Netty高性能的原因

Netty 作为异步事件驱动的网络框架,高性能之处主要来自于其 I/O 模型和线程处理模型I/O 模型决定如何收发数据,线程模型决定如何处理数据。

2.1 I/O模型

用什么样的通道将数据发送给对方,BIO、NIO 或者 AIO,I/O 模型在很大程度上决定了框架的性能

2.1.1 阻塞IO

传统阻塞型I/O(BIO)

  1. 每个请求都需要独立的线程完成数据的读写和业务处理
  2. 当客户端请求并发数较大时,需要创建大量线程来处理连接,系统资源占用较大
  3. 建立连接后,如果当前线程暂时没有数据可读,则线程就会阻塞在读取数据的操作上,造成线程资源浪费

2.1.2 IO复用模型

在 I/O 复用模型中,会用到 Select,这个函数也会使进程阻塞,但是和阻塞 I/O 所不同的是这个函数可以同时阻塞多个I/O操作,而且可以同时对多个读操作、多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。

Netty的非阻塞I/O的实现关键是基于I/O复用模型,这里用Selector 对象表示:

  1. 当线程从一个客户端SocketChannel进行读写数据时,若没有数据可用时,该线程可以执行其他任务。
  2. 线程通常将非阳塞I/O的空闲时间用于在其他通道上执行I/O操作,所以单独的线程可以管理多个输入和输出通道。
  3. 由于读写操作都是非阻塞的,这就可以充分提升I/O线程的运行效率,避免由于频繁I/O阻塞导致的线程挂起。
  4. 一个I/O线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞I/O一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

传统的IO是面向字节流或字符流的,以流式的方式顺序地从一个stream中读取一个或多个字节,因此也就不能随意改变读取指针的位置。

在NIO中,抛弃了传统的IO流,而是引入Channel和Buffer的概念。在NIO中,只能从Channel中读取数据到Buffer中或将数据从Buffer中写入到channel。

基于Buffer操作不像传统IO的顺序操作,NIO中可以随意地读取任意位置的数据

2.2 线程模型

上面介绍了服务器如何基于I/O模型管理连接并获取输入数据,接着介绍一下决定服务器如何处理数据的线程模型。

2.2.1 线程模型1:传统阻塞 I/O 服务模型

特点:

  • 采用阻塞式I/O模型获取输入数据
  • 每个连接都需要独立的线程完成数据输入,业务处理,数据返回的完整操作

存在问题:

  • 当并发数较大时,需要创建大量线程来处理连接,系统资源占用较大
  • 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在读取数据(read)操作上,造成线程资源浪费

2.2.2 线程模型2:Reactor 模式

针对传统阻塞I/O服务模型的 2 个缺点,比较常见的有如下解决方案:

  • 基于I/O复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。
  • 基于线程池复用线程资源:不必再为每个连接创建线程,将连接完成后的业务处理任务分配给线程进行处理,一个线程可以处理多个连接的业务。

而Reactor模式基本设计思想就是I/O复用结合线程池:

Reactor 模式,是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。

服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor 模式也叫 Dispatcher 模式。即I/O多路复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术之一。

Reactor模式中有2个关键组成

  • Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对I/O事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人
  • Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际负责人。Reactor 通过调度适当的处理程序来响应I/O事件,处理程序执行非阻塞操作

根据Reactor的数量和Handler的数量不同,有3种典型的实现

  1. 单 Reactor 单线程
  2. 单 Reactor 多线程
  3. 主从 Reactor 多线程

可以这样理解,Reactor 就是一个执行 while(true){selector.select();...} 循环的线程,会源源不断的产生新的事件,称作反应堆很贴切。

2.2.2.1 单 Reactor 单线程

其中Select 是前面I/O复用模型介绍的标准网络编程API,可以实现应用程序通过一个阻塞对象监听多路连接请求。

说明:

  1. Reactor 对象通过Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发
  2. 如果是建立连接请求事件,则由Acceptor 通过 Accept 处理连接请求,然后创建一个Handler 对象处理连接完成后的后续业务处理
  3. 如果不是建立连接事件,则Reactor 会分发调用连接对应的 Handler 来响应
  4. Handler 会完成Read一业务处理一Send的完整业务流程
  • 优点:模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成。
  • 缺点:性能问题,只有一个线程,无法完全发挥多核CPU 的性能。Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈。当其中某个handler阻塞时,会导致其他所有的 client的 handler 都得不到执行,并目更严重的是,handler 的阻塞也会导致整个服务不能接收新的 client 请求(因为acceptor 也被阻塞了)。因为有这么多的缺陷,因此单线程Reactor 模型用的比较少。
  • 使用场景:客户端的数量有限,业务处理非常快速,比如Redis。
2.2.2.2 单 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 承担所有事件的监听和响应,在单线程中运行,高并发场景下容易成为性能瓶颈。
2.2.2.3 主从 Reactor 多线程

针对单 Reactor 多线程模型中,Reactor 在单线程中运行,高并发场景下容易成为性能瓶颈,可以让Reator在多线程中运行。

方案说明:

  1. Reactor 主线程 MainReactor 对象通过 Select 监控建立连接事件,收到事件后通过 Acceptor 接收,处理建立连接事件
  2. Acceptor 处理建立连接事件后,MainReactor 将连接分配给 SubReactor (Reactor 子线程) 进行处理
  3. SubReactor将连接加入连接队列进行监听,并创建一个Handler 用于处理各种连接事件
  4. 当有新的事件发生时,SubReactor 会调用连接对应的 Handler 进行响应
  5. Handler通过Read读取数据后,会分发给后面的 Worker 线程池进行业务处理
  6. Worker 线程池会分配独立的线程完成真正的业务处理,如何将响应结果发给 Handler 进行处理
  7. Handler 收到响应结果后通过 Send 将响应结果返回给 Client

优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。

这种模型在许多项目中广泛使用,包括 Nginx主从Reactor 多进程模型,Memcached 主从多线程,Netty 主从多线程模型的支持。

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

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

相关文章

rdf-file:API

一:组件架构 intefaces模块:主要包含用户使用接口APItools模块:包含组件内核实现的文件操作工具codec模块:对文件结构,行数据,字段数据进行编码解码meta模块: 元数据配置以及加载loader/extensi…

中低压MOSFET 2N7002KW 60V 300mA 双N通道 SOT-323封装

2N7002KW小电流双N通道MOSFET,电压60V电流300mA,采用SOT-323封装形式。超高密度电池设计,适用于极低的ros (on),具有导通电阻和最大直流电流能力,ESD保护。可应用于笔记本中的电源管理,电池供电系统等产品应…

CANdelaStudio 使用教程6 编辑DTC

文章目录 DTC的导入导出定义 19 服务的DTC编辑快照数据 DTC的导入导出 DTC导出的文件是 Excel 文件,可以先将这个池子的DTC导出去修改,再导入进来,完成DTC的修改 定义 19 服务的DTC 编辑快照数据

Java Thread 介绍

线程是操作系统调度的最小单元, 也叫轻量级进程。它被包含在进程之中, 是进程中的实际运作单位。 同一进程可以创建多个线程, 每个线程都有自己独立的一块内存空间, 并且能够访问共享的内存变量。 1 线程的分类 在 Java 中, 线程可以分为 2 种 守护线程: 守护线程是为用户线程…

使用Terraform创建Docker镜像和容器

为了实现自动化操作,Terraform需要明确指定所使用的提供者。因此,在主要的main.tf文件中,需要提供提供者的名称、源和版本信息。对于Docker,可以在main.tf中使用以下代码块。 1 Terraform配置模块 使用块和资源创建Terraform脚本…

nodejs+vue+elementui+express青少年编程课程在线考试系统

针对传统线下考试存在的老师阅卷工作量较大,统计成绩数据时间长等问题,实现一套高效、灵活、功能强大的管理系统是非常必要的。该系统可以迅速完成随机组卷,及时阅卷、统计考试成绩排名的效果。该考试系统要求:该系统将采用B/S结构…

C++类与对象(6)—初始化列表、explicit关键字、static成员

目录 一、初始化列表 1、定义 2、注意事项 3、尽量使用初始化列表初始化 4、初始化顺序 二、 explicit关键字 1、定义 2、特点 三、static成员 1、定义 2、特性 3、例题 一、初始化列表 下面这段代码可以正常编译: class A { private:int _a1;//成员…

innovus如何在floorplan view显示所有module

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 如题,innovus的图形界面在floorplan view下默认只能显示instance数量超过100个的module,如果要显示更小的module,需要在VIEW-Set Perference…

LeetCode Hot100 394.字符串解码

题目: 给定一个经过编码的字符串,返回它解码后的字符串。 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。 你可以认为输入字符串总是有效的;输入字符串中没有额外的…

东胜物流软件 SQL注入漏洞复现

0x01 产品简介 东胜物流软件是一款致力于为客户提供IT支撑的 SOP, 帮助客户大幅提高工作效率,降低各个环节潜在风险的物流软件。 0x02 漏洞概述 东胜物流软件 TCodeVoynoAdapter.aspx、/TruckMng/MsWlDriver/GetDataList、/MvcShipping/MsBaseInfo/Sav…

C语言——I /深入理解指针(二)

一、数组名的理解 int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0];这⾥我们使⽤ &arr[0] 的⽅式拿到了数组第⼀个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;⽽且 是数组⾸元素的地址&#xff0c;我们来做个测试。 #include <stdio.…

C++ :静态成员

静态成员 静态成员就是在成员变量和成员函数前加上关键字 static &#xff0c;称为静态成员 静态成员分为&#xff1a; 静态成员变量 1.所有对象共享同一份数据 2.在编译阶段分配内存 3.类内声明&#xff0c;类外初始化 静态成员函数 1.所有对象共享同一个函数 2.静态成…

计算机毕业设计springboot+vue高校田径运动会报名管理系统61s38

高校田径运动会管理采用java技术&#xff0c;基于springboot框架&#xff0c;mysql数据库进行开发&#xff0c;实现了首页、个人中心、运动员管理、裁判员管理、场地信息管理、项目类型管理、比赛项目管理、比赛报名管理、比赛成绩管理、通知公告管理、留言板管理、交流论坛、系…

1.ORB-SLAM3中如何保存多地图、关键帧、地图点到二进制文件中

1 保存多地图 1.1 为什么保存(视觉)地图 因为我们要去做导航&#xff0c;导航需要先验地图。因此需要保存地图供导航使用&#xff0c;下面来为大家讲解如何保存多地图。 1.2 保存多地图的主函数SaveAtlas /*** brief 保存地图* param type 保存类型*/ void System::SaveAtlas(…

Kubernetes基础入门:Kubernetes的有关概述

Kubernetes基础入门&#xff1a;Kubernetes的有关概述 一、摘要二、为什么需要 Kubernetes&#xff1f;三、Kubernetes 的功能架构 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 一、摘要 随着云计算和容器技术的快速发展&#xff0c;现代…

十分钟搭建VScode C/C++运行环境

一、下载配置vscode 1.下载安装VScode 地址&#xff1a;https://code.visualstudio.com/download 下载后&#xff0c;运行安装程序 (VSCodeUserSetup-{version}.exe)。这只需要一分钟。安装程序会将 Visual Studio Code 添加到环境变量中%&#xff0c;可以使用CMD键入“code”…

SQL FULL OUTER JOIN 关键字:左右表中所有记录的全连接解析

SQL RIGHT JOIN关键字 SQL RIGHT JOIN关键字返回右表&#xff08;table2&#xff09;中的所有记录以及左表&#xff08;table1&#xff09;中的匹配记录。如果没有匹配&#xff0c;则左侧的结果为0条记录。 RIGHT JOIN语法 SELECT column_name(s) FROM table1 RIGHT JOIN ta…

Javaweb之Vue组件库Element之Dialog对话框的详细解析

4.3.3 Dialog对话框 4.3.3.1 组件演示 Dialog: 在保留当前页面状态的情况下&#xff0c;告知用户并承载相关操作。其企业开发应用场景示例如下图所示 首先我们需要在ElementUI官方找到Dialog组件&#xff0c;如下图所示&#xff1a; 然后复制如下代码到我们的组件文件的templ…

【Qt】之QSet使用

描述 QSet类是一个模板类&#xff0c;它提供基于散列表的集合。 QSet是Qt的通用容器类之一。它以未指定的顺序存储值&#xff0c;并提供非常快速的值查找。在内部,QSet是作为QHash实现的。 下面是一个带有QString值的QSet示例: QSet<QString> set;插入方式1&#xff…

第1章 爬虫基础

目录 1. HTTP 基本原理1.1 URI 和 URL1.2 HTTP 和 HTTPS1.3 请求1.3.1 请求方法1.3.2 请求的网址1.3.3 请求头1.3.4 请求体 1.4 响应1.4.1 响应状态码1.4.2 响应头1.4.3 响应体 2. Web 网页基础2.1 网页的组成2.1.1 HTML2.1.2 CSS2.1.3 JavaScript 2.2 网页的结构2.3 节点树及节…