当前位置: 首页 > 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 中几种主要的分页技…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...