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

Netty中的Reactor模型实现

Netty版本:4.1.17

Reactor模型是Doug Lea在《Scalable IO in Java》提出的,主要是针对NIO的。

其中的主从Reactor模式在Netty中的配置如下:

EventLoopGroup bossGroup = new NioEventLoopGroup(1); 
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap(); 
serverBootstrap.group(bossGroup, workerGroup);

基于此,我们来看下Netty是如何实现主从Reactor模式的。

EventLoop

EventLoop就是Netty中的Reactor,可以说它就是Netty的引擎,负责Channel上IO就绪事件的监听IO就绪事件的处理异步任务的执行驱动着整个Netty的运转。

Netty支持不同IO模型下,EventLoop有着不同的实现,我们只需要切换不同的实现类就可以完成对NettyIO模型的切换。

BIONIOAIO
ThreadPerChannelEventLoopNioEventLoopAioEventLoop

EventLoopGroup

Netty中的Reactor是以Group的形式出现的,EventLoopGroup正是Reactor组的接口定义,负责管理Reactor,Netty中的Channel就是通过EventLoopGroup注册到具体的Reactor上的。

Netty的IO线程模型是主从Reactor多线程模型主从Reactor线程组在Netty源码中对应的其实就是两个EventLoopGroup实例。

不同的IO模型也有对应的实现:

BIONIOAIO
ThreadPerChannelEventLoopGroupNioEventLoopGroupAioEventLoopGroup

多种NIO的实现

CommonLinuxMac
NioEventLoopGroupEpollEventLoopGroupKQueueEventLoopGroup
NioEventLoopEpollEventLoopKQueueEventLoop
NioServerSocketChannelEpollServerSocketChannelKQueueServerSocketChannel
NioSocketChannelEpollSocketChannelKQueueSocketChannel

我们通常在使用NIO模型的时候会使用Common列下的这些IO模型核心类,Common类也会根据操作系统的不同自动选择JDK在对应平台下的IO多路复用技术的实现。

而Netty自身也根据操作系统的不同提供了自己对IO多路复用技术的实现,比JDK的实现性能更优。比如:

  • JDK的 NIO 默认实现是水平触发,Netty 是边缘触发(默认)和水平触发可切换。

  • Netty 实现的垃圾回收更少、性能更好。

我们编写Netty服务端程序的时候也可以根据操作系统的不同,采用Netty自身的实现来进一步优化程序。做法也很简单,直接将上图中红框里的实现类替换成Netty的自身实现类即可完成切换。

由此,可以看到,我们使用Common下的NIO实现时,在Linux环境下,会自动使用水平触发的epoll。

PS: 在NIO模型下Netty会自动根据操作系统以及版本的不同选择对应的IO多路复用技术实现。比如Linux 2.6版本以上用的是Epoll,2.6版本以下用的是Poll,Mac下采用的是Kqueue

水平触发和边缘触发看附录二。

附录一:Netty如何根据操作系统选择JDK对应Selector的实现

Netty中,是通过SelectorProvider来根据操作系统的不同选择JDK在不同操作系统版本下的对应Selector的实现。Linux下会选择Epoll,Mac下会选择Kqueue

SelectorProvider是在前面介绍的NioEventLoopGroup类构造函数中通过调用SelectorProvider.provider()被加载,并通过NioEventLoopGroup#newChild方法中的可变长参数Object... args传递到NioEventLoop中的private final SelectorProvider provider字段中。

SelectorProvider的加载过程:

    private static class Holder {static final SelectorProvider INSTANCE = provider();@SuppressWarnings("removal")static SelectorProvider provider() {PrivilegedAction<SelectorProvider> pa = () -> {SelectorProvider sp;if ((sp = loadProviderFromProperty()) != null)return sp;if ((sp = loadProviderAsService()) != null)return sp;return sun.nio.ch.DefaultSelectorProvider.get();};return AccessController.doPrivileged(pa);}...

SelectorProvider加载源码中我们可以看出,SelectorProvider的加载方式有三种,优先级如下:

  1. 通过系统变量-D java.nio.channels.spi.SelectorProvider指定SelectorProvider的自定义实现类全限定名。通过应用程序类加载器(Application Classloader)加载。

  2. 通过SPI方式加载。在工程目录META-INF/services下定义名为java.nio.channels.spi.SelectorProviderSPI文件,文件中第一个定义的SelectorProvider实现类全限定名就会被加载

  3. 如果以上两种方式均未被定义,那么就采用SelectorProvider系统默认实现sun.nio.ch.DefaultSelectorProvider。不同操作系统中JDK对于DefaultSelectorProvider会有所不同,可以看到,当我们在Mac下打开DefaultSelectorProvider的源码时,可以发现DefaultSelectorProvider自动适配了KQueue实现,为:KQueueSelectorProvider。在Windows下,DefaultSelectorProvider自动适配了Epoll实现,为WEPollSelectorProvider

附录二:再谈水平触发和边缘触发

网上有大量的关于这两种模式的讲解,大部分讲的比较模糊,感觉只是强行从概念上进行描述,看完让人难以理解。所以在这里,笔者想结合上边epoll的工作过程,再次对这两种模式做下自己的解读,力求清晰的解释出这两种工作模式的异同。

经过上边对epoll工作过程的详细解读,我们知道,当我们监听的socket上有数据到来时,软中断会执行epoll的回调函数ep_poll_callback,在回调函数中会将epoll中描述socket信息的数据结构epitem插入到epoll中的就绪队列rdllist中。随后用户进程从epoll的等待队列中被唤醒,epoll_waitIO就绪socket返回给用户进程,随即epoll_wait会清空rdllist

水平触发边缘触发最关键的区别就在于当socket中的接收缓冲区还有数据可读时。epoll_wait是否会清空rdllist

  • 水平触发:在这种模式下,用户线程调用epoll_wait获取到IO就绪的socket后,对Socket进行系统IO调用读取数据,假设socket中的数据只读了一部分没有全部读完,这时再次调用epoll_waitepoll_wait会检查这些Socket中的接收缓冲区是否还有数据可读,如果还有数据可读,就将socket重新放回rdllist。所以当socket上的IO没有被处理完时,再次调用epoll_wait依然可以获得这些socket,用户进程可以接着处理socket上的IO事件。

  • 边缘触发: 在这种模式下,epoll_wait就会直接清空rdllist,不管socket上是否还有数据可读。所以在边缘触发模式下,当你没有来得及处理socket接收缓冲区的剩下可读数据时,再次调用epoll_wait,因为这时rdlist已经被清空了,socket不会再次从epoll_wait中返回,所以用户进程就不会再次获得这个socket了,也就无法在对它进行IO处理了。除非,这个socket上有新的IO数据到达,根据epoll的工作过程,该socket会被再次放入rdllist中。

如果你在边缘触发模式下,处理了部分socket上的数据,那么想要处理剩下部分的数据,就只能等到这个socket上再次有网络数据到达。

Netty中实现的EpollSocketChannel默认的就是边缘触发模式。JDKNIO默认是水平触发模式。

参考:聊聊Netty那些事儿之Reactor在Netty中的实现(创建篇)

聊聊Netty那些事儿之从内核角度看IO模型

相关文章:

Netty中的Reactor模型实现

Netty版本&#xff1a;4.1.17 Reactor模型是Doug Lea在《Scalable IO in Java》提出的&#xff0c;主要是针对NIO的。 其中的主从Reactor模式在Netty中的配置如下&#xff1a; EventLoopGroup bossGroup new NioEventLoopGroup(1); EventLoopGroup workerGroup new NioEv…...

dll丢失应该怎么解决,总结5种解决DLL丢失问题的方法

在数字时代&#xff0c;我们与计算机的每一天都密不可分。然而&#xff0c;就像所有技术产品一样&#xff0c;我们的计算设备也时不时地会出现一些问题&#xff0c;让人头疼不已。就在上周&#xff0c;我遭遇了一个令人崩溃的技术挑战——DLL文件丢失。这个看似微不足道的小问题…...

dial tcp 10.96.0.1:443: connect: no route to host

1、创建Pod一直不成功&#xff0c;执行kubectl describe pod runtime-java-c8b465b98-47m82 查看报错 Warning FailedCreatePodSandBox 2m17s kubelet Failed to create pod sandbox: rpc error: code Unknown desc failed to setup network for…...

VScode创建ROS项目 ROS集成开发环境

ROS使用VScode创建项目步骤 1.创建ROS工作空间2.启动VScode3.VScode编译ROS4.创建ROS功能包C语言开发Python语言开发 本文章介绍了如何在Ubuntu18.04系统下搭建VScode 的ROS项目 搭建项目分为一下几个步骤&#xff1a; 1.创建ROS工作空间 创建一个demo的ROS工作空间&#xff0…...

nodejs从基础到实战学习笔记-nodejs简介

一、Node.js简介 • Node.js是一个能够在服务器端运行JavaScript的开放源代码、跨平台JavaScript运行环境。 • Node采用Google开发的V8引擎运行js代码&#xff0c;使用事件驱动、非阻塞和异步I/O模型等技术来提高性能&#xff0c;可优化应用程序的传输量和规模。 1.1 特性 …...

2024年最新版------二进制安装部署Kubernetes(K8S)集群

Kubernetes二进制集群部署 文章目录 Kubernetes二进制集群部署资源列表基础环境一、环境准备1.1、绑定映射关系1.2、所有主机安装Docker1.3、所有主机设置iptables防火墙 二、生成通信加密证书2.1、master上成功CA证书2.2.1、创建证书存放位置并安装证书生成工具2.2.2、拷贝证书…...

【mysql】关键词搜索实现

关键词搜索实现两种方式 -- 方式1 模糊匹配搜索 -- 场景一&#xff1a;搜索出来地址内包含‘李’和‘中国’的 select * from tn_md_cust_link where address like concat (%李%) or address like concat (%中国%) -- 场景二&#xff1a;搜索地址或者名称包含 ‘181’ 的 …...

Python面试十问2

一、如何使用列表创建⼀个DataFrame # 导入pandas库 import pandas as pd# 创建一个列表&#xff0c;其中包含数据 data [[A, 1], [B, 2], [C, 3]]# 使用pandas的DataFrame()函数将列表转换为DataFrame df pd.DataFrame(data, columns[Letter, Number]) # 列名# 显示创建的…...

C# OpenCvSharp 图像处理函数-颜色通道-cvtColor

使用 OpenCvSharp 中的 cvtColor 函数进行图像颜色转换 在图像处理领域,颜色空间转换是一个非常常见的操作。OpenCvSharp 提供了一个强大的函数 cvtColor 来处理这类转换。本文将详细介绍 cvtColor 函数的使用方法,并通过具体的示例演示如何在实际项目中应用这些知识。 函数…...

总结之LangChain(三)——模型IO缓存

一、聊天模型缓存 LangChain为聊天模型提供了一个可选的缓存层。这有两个好处&#xff1a; 如果您经常多次请求相同的完成结果&#xff0c;它可以通过减少您对LLM提供程序的API调用次数来帮您节省费用。 它可以通过减少您对LLM提供程序的API调用次数来加快您的应用程序速度。…...

判断一个Java服务是不是GateWay

方法 直接在对应服务的url后变加上后缀/actuator/gateway/routes&#xff0c;看是否会返回Gateway的路由信息。 如果返回了GateWay的路由列表&#xff0c;则该服务为Gateway服务。...

三次插值曲线--插值技术

三次插值曲线 1.1.三次样条曲线 三次样条曲线的基本思想是&#xff0c;在给定的一系列点&#xff08;称为控制点或数据点&#xff09;之间&#xff0c;通过一系列三次多项式曲线段来拟合这些点&#xff0c;使得整个曲线既平滑又准确地通过所有控制点。 1.1.1.数学定义 给定…...

python循环结构

1.while 循环 语句&#xff1a; while 循环条件表达式&#xff1a; 代码块 else&#xff1a; 代码块 小练&#xff1a; 设计一百以内的偶数相加 n 0 while n < 100:n 1if n % 2 0 :print(n) 判断是不是闰年&#xff08;四年一润和百年不润&#xff0c;或者四百年一润&am…...

深入理解Netty的Pipeline机制:原理与实践详解

深入理解Netty的Pipeline机制&#xff1a;原理与实践详解 Netty是一个基于Java的高性能异步事件驱动的网络应用框架&#xff0c;广泛应用于高并发网络编程。&#xff08;学习netty请参考&#xff1a;深入浅出Netty&#xff1a;高性能网络应用框架的原理与实践&#xff09;Nett…...

直方图均衡化示例

禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系列教材&#xff09;》 图3-17...

私域电商新纪元:消费增值模式的创新与成功实践

大家好&#xff0c;我是吴军&#xff0c;很高兴能够与您分享私域电商领域的魅力与机遇。今天&#xff0c;我将为大家呈现一个令人瞩目的成功案例&#xff0c;这个案例充分展现了私域电商的巨大潜力和无限可能。 在短短一个月的时间里&#xff0c;我们的客户成功实现了业绩的飞跃…...

Java——IO流(一)-(6/8):字节流-FileInputStream 每次读取多个字节(示例演示)、一次读取完全部字节(方式一、方式二,注意事项)

目录 文件字节输入流&#xff1a;每次读取多个字节 实例演示 注意事项 文件字节输入流&#xff1a;一次读取完全部字节 方式一 方式二 注意事项 文件字节输入流&#xff1a;每次读取多个字节 用到之前介绍过的常用方法&#xff1a; 实例演示 需求&#xff1a;用每次读取…...

服务器SSH 免密码登录

1. 背景 为了服务器的安全着想&#xff0c;设置的服务器密钥非常长。但是这导致每次连接服务器都需要输入一长串的密码&#xff0c;把人折腾的很痛苦&#xff0c;所以我就在想&#xff0c;能不能在终端SSH的时候无需输入密码。 windows 可以使用 xshell 软件&#xff0c;会自…...

Linux安装MySQL以及远程连接

1、Linux安装MySQL 1.1、准备解压包 MySQL5.x解压包 提取码&#xff1a;9y7n 1.2、通过rpm脚本安装 切记安装顺序&#xff1a;common --> libs --> client --> server 因为它们之间存在依赖关系&#xff0c;所以务必按照顺序安装 安装前请确保当前目录/文…...

SQL Server 数据库分页技术详解:选择最佳方法优化查询性能”。

当今数据驱动的应用程序中&#xff0c;数据库分页技术在优化查询性能和提升用户体验中扮演着重要角色。在 SQL Server 环境下&#xff0c;开发者面对大数据集时&#xff0c;常常需要选择合适的分页方法以平衡功能需求和性能优化。本文将详细介绍 SQL Server 中几种主要的分页技…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...