Reactor 在 Netty 中是如何实现的

Reactor与Proactor reactor,proactor 阅读详情

Netty 的 Reactor

我们都知道 Netty 可以有两个线程组,一个是 bossGroup,一个是 workerGroup。

之前也提到了 bossGroup 主要是接待新连接(老板接活),workerGroup 否则负责重新连接后续的一切 I/O (员工干活)

对应到 Reactor 模型中,bossGroup 中的 eventLoop 就是主 Reactor。它的任务就是监听等待连接事件的到来,即 OP_ACCEPT。

然后创建的 channel ,从 workerGroup 中选择一个 eventLoop ,将子 channel 与这个 eventLoop 绑定,之后这个子 channel 对应的 I/O事件,都由这个 eventLoop 负责。

而这个 workerGroup 中的 eventLoop 就是所谓的子 Reactor,它的任务就是负责已经建连完毕的连接之后的所有 I/O 请求。

其实从 eventLoop 从这个名字就能看出,它的作用就是 loop event,说白了就是一个线程,死循环地等待事件的发生,然后根据不同的事件类型进行不一样的后续处理,仅此而已。

正常情况下 bossGroup 只会配置一个 eventLoop,即一个线程,因为一般服务只会暴露一个端口,所以只要一个 eventLoop 监听这个端口,然后 accept 连接。

而 workerGroup 在 Netty 中,默认是 cpu 核心数*2,例如 4 核 CPU ,默认会在 workerGroup 建 8 个 eventLoop,所以就有 8 个子 Reactor。

所以正常 Netty 服务端的配置是,1个主 Reactor,多个从 Reactor,这就是所谓的主从 Reactor。

基本上现在的主流配置都是主从 Reactor。

关于 Reactor 模型的演进

在深入 Netty 的 Reactor 实现之前,我们先来看看,为什么会演变成主从 Reactor?

最开始的模型是 单 Reactor 单线程 ,你可以理解成一个线程来监听新的连接,又要响应老的连接的请求,如果逻辑处理得很快,那没有问题,看看人家 redis 就算够用,但是如果逻辑处理得慢,那就会阻塞其他请求。

所以就有了 单 Reactor 多线程 ,还是由一个线程来监听所有的底层 Socket,但是一些耗时的操作可以分配给线程池进行业务处理,这样就不会因为逻辑处理慢导致 Reactor 的阻塞。

但是这个模型还会有瓶颈,即监听新的连接和响应老的连接的请求都由一个线程处理,积累的老连接多了,有很多事件需要响应,就会影响新连接的接入,这就不太舒服了,况且我们现在都是多核 CPU,还差这么一个线程吗?

所以就又演进成 主从 Reactor ,有一个线程,即主 Reactor 专门等待新连接的建连,然后创建多个线程作为子 Reactor,均匀的负责已经接入的老连接,这样一来既不会影响接待新连接的速度,也能更好的利用多核 CPU 的能力响应老连接的请求。

这就是关于 Reactor 模型的演进了。

好了,接下来我们再看看 Netty 实现 Reactor 核心类,我们现在一般都是用 NIO ,所以我们看 NioEventLoop 这个类。

友情提示,有条件建议在PC端看下面的内容,源码类的手机上看不太舒服

NioEventLoop

前面我们已经提到一个问题 NioEventLoop 就是一个线程,那线程的核心肯定就是它的 run 方法。

基于我们的理解,我们知道这个 run 方法的主基调肯定是死循环等待 I/O 事件产生,然后处理事件。

事实也是如此, NioEventLoop 主要做了三件事:

  1. select 等待 I/O 事件的发生
  2. 处理发生的 I/O 事件
  3. 处理提交至线程中的任务,包括提交的异步任务、定时任务、尾部任务。

首先折叠下代码,可以看到妥妥的死循环,这也是 Reactor 线程的标配,这辈子无限只为了等待事件发生且处理事件。

在 Netty 的实现里,NioEventLoop 线程不仅要处理 I/O 事件,还需要处理提交的异步任务、定时任务和尾部任务,所以这个线程需要平衡 I/O 事件处理和任务处理的时间。

因此有个 selectStrategy 这样的策略,根据判断当前是否有任务在等待被执行,如果有则立即进行一次不会阻塞的 select 来尝试获取 I/O 事件,如果没任务则会选择 SelectStrategy.SELECT 这个策略。

从图中也可以看到,这个策略会根据最近将要发生的定时任务的执行时间来控制 select 最长阻塞的时间。

从下面的代码可以看到,根据定时任务即将执行的时间还预留了 5 微秒的时间窗口,如果 5 微秒内就要到了,那就不阻塞了,直接进行一个非阻塞的 select 立刻尝试获取 I/O 事件。

经过上面的这个操作,select 算是完毕了,最终会把就绪的 I/O 事件个数赋值给 strategy,如果没有的话那 strategy 就是 0 ,接着就该处理 I/O 事件和任务了。

上面代码我把重点几个部分都框出来了,这里有个 selectCnt 来统计 select 的次数,这个用于处理 JDK Selector 空轮询的 bug ,下面会提。

ioRatio 这个参数用来控制 I/O 事件执行的时间和任务执行时间的占比,毕竟一个线程要做多个事情,要做到 雨露均沾 对吧,不能冷落了谁。

可以看到,具体的实现是记录 I/O 事件的执行时间,然后再根据比例算出任务能执行的最长的时间来控制任务的执行。

I/O 事件的处理

我们来看看 I/O 事件具体是如何处理的,也就是 processSelectedKeys 方法。

点进去可以看到,实际上会有两种处理的方法,一种是优化版,一种是普通版。

这两个版本的逻辑都是一样的,区别就在于优化版会替换 selectedKeys 的类型,JDK 实现的 selectedKeys 是 set 类型,而 Netty 认为这个类型的选择还是有优化的余地的。

Netty 用 SelectedSelectionKeySet 类型来替换了 set 类型,其实就是用数组来替换了 set

相比 set 类型而言,数组的遍历更加高效,其次数组尾部添加的效率也高于 set,毕竟 set 还可能会有 hash冲突。当然这是 Netty 为追求底层极致优化所做的,我们平日的代码没必要这般“斤斤计较”,意义不大。

那 Netty 是通过什么办法替换了这个类型呢?

反射 。

看下代码哈,不是很复杂:

这也能给我们提供一些思路,比方你调用三方提供的 jar 包,你无法修改它的源码,但是你又想对它做一些增强,那么就可以仿照 Netty 的做法,通过反射来替换之~

我们打个断点看下替换前后 selectedKey 的类型,之前是 HashSet:

替换了后就变成了 SelectedSelectionKeySet 了。

ok,现在我们再看下优化版的处理 I/O 事件的遍历方法,和普通版逻辑一样的,只是遍历是利用数组罢了。

没啥好说的,就那个帮助 GC 可以提一下,如果你看过很多开源软件你就会发现有很多这样的实现,直接置为 null 的语句,这是为了帮助 GC。

紧接着看下真正处理 I/O 事件的方法 processSelectedKey

可以看到,这个方法本质就是根据不同的事件进行不同的处理,实际上会将事件在对应的 channel 的 pipeline 上面传播,并且触发各种相应的自定义事件,我拿 OP_ACCEPT 事件作为例子分析。

针对 OP_ACCEPT 事件,unsafe.read 实际会调用 NioMessageUnsafe#read 方法。

从上面代码来看,逻辑并不复杂,主要就是循环读取新建立的子 channel,并触发 ChannelRead 和 ChannelReadComplete 事件,使之在 pipeline 中传播,期间就会触发之前添加的 ServerBootstrapAcceptor#channelRead,将其分配给 workerGroup 中的 eventLoop ,即子 Reactor 线程。

当然,我们自定义的 handler 也可以实现这两个事件方法,这样对应的事件到来后,我们能进行相应的逻辑处理。

好了,Netty 的 OP_ACCEPT 事件处理分析到此结束,其他事件也是类似的,都会触发相应的事件,然后在 pipeline 中传递,触发不同 Channelhandler 的方法,进行逻辑处理。

以上,就是 Netty 实现的主从 Reactor 模型。

当然,Netty 也支持单 Reactor,无非就是不要 workerGroup,至于线程数也可以自行配置,十分灵活,不过现在一般用的都是主从 Reactor 模型。

Reactive响应式编程系列:解密reactor-netty如何实现响应式 ​Reactor 设计模式的基本思想是:当有事件发生时,Reactor 将事件分发给对应的 Handler 处理器,由 Handler 处理器来具体处理事件。Reactor 设计模式 和 Reactive 响应式编程有一定相似之处,两者的核心思想都是事件驱动,通过异步处理来解决高并发下阻塞操作带来的资源消耗和性能下降问题,让我们来探究下 reactor-netty 是如何帮助 Netty 实现响应式的! 阅读详情

相关推荐

老面试官竟问我 Reactor 在 Netty 中是如何实现的

这篇不仅讲了 Netty 的 Reactor 实现,也把 Netty 是如何处理 I/O 操作的部分也囊括了。下篇关于 Netty 的再盘盘 pipeline 机制,这个责任链模式也是很重要的,很有启发性。等 pipeline 写完之后,你对 Netty 整体应该有一个比较清晰的认识了,然后会开始写一些粘包半包、内存管理等内容,包括一些 Netty 的“高级”用法啥的,总之大概还有一半的内容没写,等写完之后,完整的回顾一遍,出去可以拿 Netty “吹”了。

m0_71777195的博客 264

【netty学习】之主从Reactor

【netty学习】之主从Reactor

lc_23333的博客 539

MaixCAM2 4K AI相机硬件解析与开发实战

嵌入式AI视觉开发中,边缘计算设备的选择直接影响项目落地效果。以NPU为核心的AI加速技术通过专用指令集优化,可在低功耗下实现10+TOPS算力,典型应用包括工业质检、智能门禁等实时场景。MaixCAM2作为新一代4K AI相机,搭载AX630 SoC芯片,其双核Cortex-A53与NPU的异构架构,在运行YOLOv11n模型时可达113FPS,显著优于传统方案。开发时需注意模型量化部署技巧,如INT8量化需500+张校准图片覆盖多光照条件,避免准确率下降。设备扩展性方面,PMOD接口支持热成像、ToF传

weixin_30819085的博客 692

Netty源码解析-响应式实现(Reactor模式)

我们看到上面通过channelFactory构造了channel,最下面一行通过config().group().register(channel)注册channel。那么我们进入group()看一下mainReactor需要自己定义,即是ServerBootstrap的两个EventLoopGroup中的parentGroup,初始化的时候设置进去。然后在bind的时候将Group注册到channel上,同时只会注册一个。

qq_36037795的博客 1014

别再让步进电机‘发烧’了!用FOC闭环驱动实现精准力矩控制(基于P0斩波恒流版)

本文详细介绍了如何利用FOC闭环驱动技术(基于P0斩波恒流版)解决步进电机过热和力矩控制不精准的问题。通过对比传统开环控制的缺陷,展示了FOC在降低温度、提升精度和能效方面的显著优势,并提供了硬件配置、软件实现及性能优化的完整方案。

weixin_30872157的博客 568

汽水音乐自动化薅羊毛教程:从零搭建稳定赚钱脚本

📖 前言:为什么要学习自动化脚本?在数字时代,时间就是金钱。汽水音乐等App通过观看广告奖励用户金币的模式,本质上是将我们的时间转化为收益。本教程将教你如何用Python自动化这个过程,让程序为你"打工",实现被动收入。通过本教程,你将学到:移动端自动化测试的核心技术Python在自动化领域的实际应用如何将重复性任务转化为自动化流程创造属于自己的"数字员工"第一章:环境准备与基础配置1.1 硬件要求Android手机一部(建议使用备用机)USB数据线。

weixin_44947827的博客 5821

Reactor Netty (一)netty服务器配置启动流程封装设计源码解读

reactor-netty 简介 在SpringCloud微服务体系中,有个很重要的组件就是网关,在2.x版本中SpringCloud自己研发了一个网关替代Zuul,那就是SpringCloud Gateway,而Gateway是支持WebFlux的函数式(流式)编程的,WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在Netty上,并且SpringCloud Gateway 默认容器就是netty,但是netty本身并不支持

u013171997的专栏 2988

esp32移植canopen协议栈(二)

本文续接上一篇文章,之前我们已经搭建好了esp32的开发环境,以及初始工程。接下来我们开始实现can驱动相关,以及使用c++封装can接口。本文使用esp32实现c++实现can驱动层的封装。下一步移植canopen!!!嘻嘻。

qq_50267418的博客 1909

Netty 是如何实现 Reactor 的?

之前已经写了一篇对 Reactor 的理解,这篇我们来看看 Netty 是如何实现 Reactor 的。 我们都知道 Netty 可以有两个线程组,一个是 bossGroup,一个是 workerGroup,之前也提到了 bossGroup 主要是接待新连接(老板接活),workerGroup 是负责新连接后续的一切 I/O (员工干活) 对应到 Reactor 模型中,bossGroup 中的 eventLoop 就是主 Reactor,它的任务就是监听等待连接事件的到来,即 OP_ACCEPT,然后创建

yes 783

MODIS 遥感数据批量下载(使用Cygwin)

MODIS 遥感数据批量下载(使用Cygwin)包含Cygwin的下载教程

weixin_45913084的博客 917

第二十届全国大学生智能汽车竞赛极速光电组:MicroPython与恩智浦RT1021的硬件编程实战指南

本文为参加第二十届全国大学生智能汽车竞赛极速光电组的同学提供了一份详尽的MicroPython与恩智浦RT1021硬件编程实战指南。文章深入剖析了选择MicroPython与RT1021这对组合的优势,详细讲解了从开发环境搭建、基础硬件控制(如GPIO、PWM、编码器、CCD)到系统集成(平衡控制、循迹算法)与多任务调试的全过程,旨在帮助参赛者降低嵌入式开发门槛,高效备赛。

wdx0123456的博客 847

Netty如何实现Reactor模式

在前面的文章中(Reactor模型详解),我们讲解了Reactor模式的各种演变形式,本文主要讲解的则是Netty是如何实现Reactor模式的。这里关于Netty实现的Reactor模式,需要说明的是,其实现的模式如下图所示: image.png 对于Netty使用的Reactor模式,其主要特点如下: 使用一个线程作为mainReactor,专门用于监听客户端的连接事件,当获取...

weixin_30540691的博客 409

【编译原理】LL(1)分析方法 生成语法树(c++实现)

基本流程 输入文法->消除左递归->提取左公共因子->求FIRST集->求FOLLOW集->LL(1)分析表->表驱动的预测语法分析过程->输出语法分析结果和语法树

qq_43417265的博客 1万+

Netty Reactor模式实现原理详解

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33781606的博客 994

LTspice进阶技巧-031.一键加密仿真模型:LTspice Encrypt Tool实战指南

本文详细介绍了LTspice Encrypt Tool的使用方法,帮助工程师一键加密LTspice仿真模型,保护知识产权。通过图形化界面简化操作流程,支持批量加密和兼容性处理,适用于电路设计中的模型保护需求。

weixin_28304023的博客 204

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Netty中的Reactor实现

一. 各种IO对应的实现 BIO:Thread-Per-Connection NIO:Reactor AIO: Proactor 二. I/O多路复用(技术术语:Reactor): 当多条连接共用一个阻塞对象后,进程只需要在一个阻塞对象上等待,而无需再轮训所有连接,常见的实现方式有select,epoll,kqueue等。 当某条连接有新的数据可以处理时,操作系统会通知进程,进程从阻塞状态返回,开始进行业务处理。 Reactor是一种开发模式,Reactor中文翻译为:反应堆。不是物理上的核反应堆,

topsion的博客 311

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Netty中的Reactor模型实现

其中Linux kernel 在5.1版本引入的异步IO库io_uring正在netty中孵化。有着不同的实现,我们只需要切换不同的实现类就可以完成对Netty。比如Linux 2.6版本以上用的是。根据操作系统以及版本的不同选择对应的。Netty版本:4.1.17。,2.6版本以下用的是。IO多路复用技术实现。

u013771019的专栏 612

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Netty:一文搞懂Reactor模型与实现

在网络IOReactor模型和Proactor模型。Reactor基于同步IO模式,Proactor基于异步IO模式。Netty网络框架,Redis等中间件中都有使用到Reactor模型。本文将对Reactor模型的如下三种分类进行学习和实现。单Reactor单线程模型;单Reactor多线程模型;主从Reactor多线程模型。如果不具备网络IO的相关知识,建议先阅读Java网络IO模型分析与实现。Reactor模型主要就是监听事件,分发事件和处理事件。其中Reactor角色会负责监听事件和。

z1ztai的博客 1344

深入解析Netty的Reactor模型及其实现:详解与代码示例

Netty是一个高性能、异步事件驱动的网络应用框架,采用了Reactor模型来实现高并发处理。Reactor模型是处理多路复用I/O操作的一种设计模式,它可以在一个或多个线程中调度多个I/O事件。本文将详细介绍Netty的Reactor模型及其在代码中的实现。

微笑听雨 5426

[Netty] Selector选择器以及Reactor实现 (七)

Nio中的Selector选择器和Netty的选择器的实现和reactor的netty实现

959 939

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

本文介绍了首先介绍了Netty对各种IO模型的支持以及如何轻松切换各种IO模型。还花了大量的篇幅介绍Netty服务端的核心引擎主从Reactor线程组的创建过程。在这个过程中,我们还提到了Netty对各种细节进行的优化,展现了Netty对性能极致的追求。好了,Netty服务端的骨架已经搭好,剩下的事情就该绑定端口地址然后接收连接了,我们下篇文章再见~~~

m0_53157173的博客 391

java reactor模式例子_Netty Reactor模式实现原理详解

在前面的文章中(Reactor模型详解),我们讲解了Reactor模式的各种演变形式,本文主要讲解的则是Netty是如何实现Reactor模式的。这里关于Netty实现的Reactor模式,需要说明的是,其实现的模式如下图所示: 对于Netty使用的Reactor模式,其主要特点如下:使用一个线程作为mainReactor,专门用于监听客户端的连接事件,当获取到事件之后就将该事件交由Accepto...

weixin_39923623的博客 645

Reactor模式的详细介绍以及netty对其的具体实现

 关于Reactor与Proactor模式在上一篇文章中有过简单的介绍,本文想主要介绍一下Reactor模式,因为无论是java的Nio还是netty都很好的使用了Reactor模式,可见这种模式的重要作用,本文主要参考了并发大神Doug Lea在《Scalable IO in Java》一文中的一些讲解,同时也参考了 Jim Coplien 和Douglas C. Schmidt在95年发表在的...

TankyZhang的博客 769

Reactor 线程模型与 Netty 实现

本文介绍了Reactor线程模型及其在Netty中的实现。Reactor是一种事件驱动的设计模式,通过分离I/O事件监听和处理来提高并发性能。文章详细分析了三种Reactor演进模型:单线程模型(所有操作在单线程完成)、单Reactor多线程模型(主线程监听,线程池处理业务)和多Reactor多线程模型(主从Reactor分工协作)。每种模型都配有结构图示和代码示例,并分析了其优缺点。最后还介绍了Netty如何基于多Reactor多线程模型进行优化实现。这些内容为理解高性能网络编程提供了重要理论基础。

Sakuraaaaaaa的博客 443
上一篇: 当Synchronized遇到这玩意儿,有个大坑,要注意
下一篇: 如何将jdk12的源码导入idea
JavaMonsterr
博客等级 码龄4年 211粉丝 481原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值