百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

8、Netty的Reactor模式与Scalable IO详解剖析

lipiwang 2024-11-26 06:05 7 浏览 0 评论

1、Reactor 与 Procator

  • Reactor 模式反应器,同时接收多个服务器请求,并且依次同步地处理它们的事件驱动程序
  • Procator 模式,异步接收和同时处理多个服务请求的事件驱动的程序
  • Netty整体框架是Reactor模式是一个完整体现

reactor论文1在线pdf在线下载

http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf


reactor论文2在线pdf在线下载

http://www.laputan.org/pub/sag/reactor.pdf

2、 Doug Lea 大神

  • Doug Lea 是Java并发主导者大神(1995的论文),可以说没有他的思想就没有java的NIO并发编程

NIO并发启发真谛论文在线下载

为什么Netty使用两个NioEventLoopGroup(重点面试可能问题)

采用Reactor设计模型

  • 一个是mainReactor(bossGroup/parentGroup)用于参数接收请求,不做任何事情处理
  • 一个是subReactor(workGroup/childrenGroup)用于参数对要实现对象处理
  • ServerBootstrap类group方法
 /**
     * 
设置EventLoopGroup的父(acceptor)和子(client)。 这些EventLoopGroup用于处理ServerChannel和Channel的所有事件和IO。
     */
    public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (childGroup == null) {
            throw new NullPointerException("childGroup");
        }
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = childGroup;
        return this;
    }

3、网络结构

  • 读请求 => 解码请求 => 进程服务 => 编码 => 发送响应

4、传统服务设计


  • 1、弊端: 多线程的模型设计,线程多,CPU开销大
  • 2、建议改良:
  • 优雅降级,可伸缩,将不同的任务分解最小的任务执行,事件驱动设计改良。在改良过程中也有它的缺点,
  • 分发较慢(需要手动绑定事件)跟踪状态,如:AWT Event Queue 图形事件队列
  • 加大带宽资源,调节资源服务质量

5、传统Reactor设计(单线程)

  • Reactor本身就是一个线程,Netty的EventLoopGroup的对象,第一个EventLoopGroup不做任何事情,交给第二个EventLoopGroup进行处理
  • 采用了java.nio的支持,在NiO的有Channel,Buffer,Selectors(SelectionKeys)三个重要概念、请看

NIO 深入详解和重要体系分析


Channels(通道)

  • 连接文件,Sockets,支持非阻塞读等操作

Buffers(缓存区)

  • 类似于数组的对象,可以通过管道Channel直接读或写操作

Selectors(选择器)

  • 告诉Channel通道有IO事件
  • SelectionKeys(事件选择处理)
  • 保持IO事件状态(SelectionKey.OP_ACCEPT连接事件,OP_READ读事件等)和绑定

6、Worker Thread Pools 工作线程池

  • Worker Thread Pools 工作线程池足够的处理来超过开销更难以与IO重叠处理,最好什么时候可以先将所有输入读入缓冲区使用线程池,因此可以协调和控制,通常需要比客户端少得多的线程Coordinating Tasks 协调任务切换:每个任务都启用,触发或调用下一个任务,通常最快但可能很脆弱回调:每个处理程序调度程序,设置状态,附件等,GoF Mediator模式的变体队列:例如,跨阶段传递缓冲区期待: 当每个任务产生结果时,协调分层在加入或等待/通知之上

Multiple Reactor Threads 复合Reactor线程

  • 使用Reactor池
  • 1、用于匹配CPU和IO速率
  • 2、静态或动态结构:每个都有自己的Selector,Thread,dispatch循环,主要接收器发布分配给其他Reactor

7、 Multiple Reactors 多个Reactor线程池(非常重要)


java.nio features 的使用(重点)

  • 每个Reactor都有自己多个的Selectors选择器,将不同的处理程序绑定到不同的IO事件,需要关注同步更要协调
  • File transfer文件传输 : 文件在网络的传输拷贝过程
  • Memory-mapped files 内存文件映射: 通过缓冲区访问文件
  • Direct buffers 直接缓冲:有时可以实现零拷贝传输,但是有设置和最终化开销,最适合具有长期连接的应用程序

基于连接的扩展

  • 1、客户端的连接
  • 2、客户端发送一系列消息/请求
  • 3、客户端断开连接
  • 4、例如:数据库和事务监视器,多人游戏,聊天等

可以扩展基本的网络服务模式

  • 1、处理更多相对长连接的客户端
  • 2、跟踪客户端和会话状态(包括丢弃)
  • 3、跨多个主机分发服务

API 场景使用

  • Buffer
  • ByteBuffer (CharBuffer, LongBuffer, etc not shown.)
  • Channel
  • SelectableChannel
  • SocketChannel
  • ServerSocketChannel
  • FileChannel
  • Selector
  • SelectionKey
  • 代码展示

Buffer

abstract class Buffer {
 int capacity();
 int position();
 Buffer position(int newPosition);
 int limit();
 Buffer limit(int newLimit);
 Buffer mark();
 Buffer reset();
 Buffer clear();
 Buffer flip();
 Buffer rewind();
 int remaining();
 boolean hasRemaining();
 boolean isReadOnly();
}

ByteBuffer

abstract class ByteBuffer extends Buffer {
 static ByteBuffer allocateDirect(int capacity);
 static ByteBuffer allocate(int capacity);
 static ByteBuffer wrap(byte[] src, int offset, int len);
 static ByteBuffer wrap(byte[] src);
 boolean isDirect();
 ByteOrder order();
 ByteBuffer order(ByteOrder bo);
 ByteBuffer slice();
 ByteBuffer duplicate();
 ByteBuffer compact();
 ByteBuffer asReadOnlyBuffer();
 byte get();
 byte get(int index);
 ByteBuffer get(byte[] dst, int offset, int length);
 ByteBuffer get(byte[] dst);
 ByteBuffer put(byte b);
 ByteBuffer put(int index, byte b);
 ByteBuffer put(byte[] src, int offset, int length);
 ByteBuffer put(ByteBuffer src);
 ByteBuffer put(byte[] src);
 char getChar();
 char getChar(int index);
 ByteBuffer putChar(char value);
 ByteBuffer putChar(int index, char value);
 CharBuffer asCharBuffer();
 
 short getShort();
 short getShort(int index);
 ByteBuffer putShort(short value);
 ByteBuffer putShort(int index, short value);
 ShortBuffer asShortBuffer();
 int getInt();
 int getInt(int index);
 ByteBuffer putInt(int value);
 ByteBuffer putInt(int index, int value);
 IntBuffer asIntBuffer();
 long getLong();
 long getLong(int index);
 ByteBuffer putLong(long value);
 ByteBuffer putLong(int index, long value);
 LongBuffer asLongBuffer();
 float getFloat();
 float getFloat(int index);
 ByteBuffer putFloat(float value);
 ByteBuffer putFloat(int index, float value);
 FloatBuffer asFloatBuffer();
 double getDouble();
 double getDouble(int index);
 ByteBuffer putDouble(double value);
 ByteBuffer putDouble(int index, double value);
 DoubleBuffer asDoubleBuffer();
}


Channel

interface Channel {
   boolean isOpen();
   void close() throws IOException;
}
interface ReadableByteChannel extends Channel {
   int read(ByteBuffer dst) throws IOException;
}
interface WritableByteChannel extends Channel {
   int write(ByteBuffer src) throws IOException;
}
interface ScatteringByteChannel extends ReadableByteChannel {
   int read(ByteBuffer[] dsts, int offset, int length)throws IOException;
   int read(ByteBuffer[] dsts) throws IOException;
}
interface GatheringByteChannel extends WritableByteChannel {
   int write(ByteBuffer[] srcs, int offset, int length)throws IOException;
   int write(ByteBuffer[] srcs) throws IOException;
}

SelectableChannel

abstract class SelectableChannel implements Channel {
 int validOps();
 boolean isRegistered();
 SelectionKey keyFor(Selector sel);
 SelectionKey register(Selector sel, int ops) throws ClosedChannelException;
 void configureBlocking(boolean block) throws IOException;
 boolean isBlocking();
 Object blockingLock();
}


8、Reactor Pattern设计模型

  • 根据IO事件进行分发与响应
  • Handlers非阻塞行为
  • 通过Handlers绑定到事件上

事件驱动模型

  • 选择更优的替代物,减少资源
  • 通常不需要每个客户端一个线程,减少开销
  • 减少上下文切换,通常减少锁定,但调度可能会更慢
  • 必须手动将操作绑定到事件
  • 通常难以编程,必须分解为简单的非阻塞操作与GUI事件驱动的操作类似
  • 无法消除所有阻塞:GC,页面错误等 必须跟踪逻辑服务状态

状态Handler与多复用线程模式

  • 处理器会减慢Reactor方法的速度,将非IO的线程交给其他线程处理

Multithreaded Designs(多线程设计)

  • 策略性地添加线程实现可伸缩性 ,主要适用于多处理器
  • 线程工作:Reactor应该快速触发handlers处理程序,但处理器会减慢Reactor方法的速度
  • Reactor线程可以使IO完全饱和将负载分配给其他反应器负载平衡以匹配CPU和IO速率

9、Reactor模型的角色构成(Reactor模型一共有5种角色构成、非常重点)

  • 图解关系
    *

1、Handle(句柄或是描述符):本质上表示一种资源,是有操作系统提供的,该资源用于表示一个一个的事件,比如说文件描述符,或是针对网络编程中
的Socket描述符,事件既可以来自于外部,也可以来自于内部,外部事件比如说是客户的连接请求,客户发送过来数据等,内部事件比如说操作系统产生的定时器
事件等,它本质上就是一个文件描述符,Handle是事件产生的发源地
2、
Synchronous Event Demultiplexer(同步事件风离器):它本身是一个系统调用,用于等待事件的发生(事件可能是一个,也可能是多个)调用方法调用
它的时候会被阻塞,一直阻塞到同步事件分离器上事件产生为止,对于Linux来说,同步事件分离器指的就是常用的 I/O 多复用机制,比如说:
select,pool,epoll等在Java NIO领域中同步事件分离器对应的组件就是Selector,对应的阻塞方法就是select方法
3、
Event Handler(事件处理器):本身有多个回调方法构成,这些回调方法构成了与应用相关的对于某个时间的反馈机制,Netty相比于Java NIO来说,该事件
处理器这个角色上进行了一个升级,它为我们开发者提供了大量的回调方法,供我们在特定事件产生时实现相应的回调方法进行业务逻辑的处理
4、
Concrete Event Handler(具体事件处理器):事件处理器的实现,它本身实现了事件处理器所提供的各个回调方法,从而实现了特定业务的逻辑,它本质上交所我们所编写的一个个的处理器实现
5、
Initiation Dispatcher(初始分发器):实际上就是Reactor角色,它本身定义了一些规范,这些规范用于控制事件的调度方法,同时又提供了应用进行事件处理器的注册,删除等设施,它本身是整个事件处理器的核心所在,Initiation Dispatcher 会通过同步事件分离器来等待事件的发生,一旦事件发生,Initiation Dispatcher手写会分离出每一个事件,然后调用事件处理器,最后调用相关的回调方法来处理这些事件

10、Reactor模型的流程(非常重要)

1、当Initiation Dispatcher注册具体的事件处理器时,应用会标识出该事件处理器希望 Initiation Dispatcher 在某个事件发生时向其通知的该事件,该事件与Handle关联
2、Initiation Dispatcher 会要求每个事件处理器向其传递内部的Handle,该handle向操作系统标识了事件处理器
3、当所有的事件处理器注册完毕后,应用会回调handle_events方法来启用Initiation Dispatcher的事件循环,这时,Initiation Dispatcher会将每个注册管理器Handle合并起来,并使用同步事件分离器等等这些事件的发生,比如说:TCP协议层会使用select同步事件分离器操作来等待客户端发生的数据到达连接socket handle上
4、当与某个事件源对应的handle变为ready状态时,(比如说,tcp socket变为等待读状态时)同步事件分离器就会通知Initiation Dispatcher
5、Initiation Dispatcher 会触发事件处理器的回调方法,从而影响整个处于ready状态的Handle,当事件发生时,Initiation Dispatcher 会将被事件源激活的Handle作为【key】来寻找并分发适当的事件处理器回调方法
6、Initiation Dispatcher 会回调事件处理器handle_events回调方法来执行特定于应用的功能,(开发者自己所编写的功能),从而响应整个事件,所发生的事件类型可以作为该方法参数并发被该方法内部使用来执行额外的特定于服务的分离和分发


11、 推荐学习文章

  • http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf
  • https://blog.csdn.net/caiwenfeng_for_23/article/details/8458299
  • https://www.cnblogs.com/binarylei/p/10117443.html
  • http://www.mamicode.com/info-detail-2552060.html
  • http://www.cnblogs.com/luxiaoxun/p/4331110.html
  • https://yq.aliyun.com/articles/50466

相关推荐

linux实例之设置时区的方式有哪些

linux系统下的时间管理是一个复杂但精细的功能,而时区又是时间管理非常重要的一个辅助功能。时区解决了本地时间和UTC时间的差异,从而确保了linux系统下时间戳和时间的准确性和一致性。比如文件的时间...

Linux set命令用法(linux cp命令的用法)

Linux中的set命令用于设置或显示系统环境变量。1.设置环境变量:-setVAR=value:设置环境变量VAR的值为value。-exportVAR:将已设置的环境变量VAR导出,使其...

python环境怎么搭建?小白看完就会!简简单单

很多小伙伴安装了python不会搭建环境,看完这个你就会了Python可应用于多平台包括Linux和MacOSX。你可以通过终端窗口输入"python"命令来查看本地是否...

Linux环境下如何设置多个交叉编译工具链?

常见的Linux操作系统都可以通过包管理器安装交叉编译工具链,比如Ubuntu环境下使用如下命令安装gcc交叉编译器:sudoapt-getinstallgcc-arm-linux-gnueab...

JMeter环境变量配置技巧与注意事项

通过给JMeter配置环境变量,可以快捷的打开JMeter:打开终端。执行jmeter。配置环境变量的方法如下。Mac和Linux系统在~/.bashrc中加如下内容:export...

C/C++|头文件、源文件分开写的源起及作用

1C/C++编译模式通常,在一个C++程序中,只包含两类文件——.cpp文件和.h文件。其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码;而.h文件则被称...

linux中内部变量,环境变量,用户变量的区别

unixshell的变量分类在Shell中有三种变量:内部变量,环境变量,用户变量。内部变量:系统提供,不用定义,不能修改环境变量:系统提供,不用定义,可以修改,可以利用export将用户变量转为环...

在Linux中输入一行命令后究竟发生了什么?

Linux,这个开源的操作系统巨人,以其强大的命令行界面而闻名。无论你是初学者还是经验丰富的系统管理员,理解在Linux终端输入一条命令并按下回车后发生的事情,都是掌握Linux核心的关键。从表面上看...

Nodejs安装、配置与快速入门(node. js安装)

Nodejs是现代JavaScript语言产生革命性变化的一个主要框架,它使得JavaScript从一门浏览器语言成为可以在服务器端运行、开发各种各样应用的通用语言。在不同的平台下,Nodejs的安装...

Ollama使用指南【超全版】(olaplex使用方法图解)

一、Ollama快速入门Ollama是一个用于在本地运行大型语言模型的工具,下面将介绍如何在不同操作系统上安装和使用Ollama。官网:https://ollama.comGithub:http...

linux移植(linux移植lvgl)

1uboot移植l移植linux之前需要先移植一个bootlader代码,主要用于启动linux内核,lLinux系统包括u-boot、内核、根文件系统(rootfs)l引导程序的主要作用将...

Linux日常小技巧参数优化(linux参数调优)

Linux系统参数优化可以让系统更加稳定、高效、安全,提高系统的性能和使用体验。下面列出一些常见的Linux系统参数优化示例,包括修改默认配置、网络等多方面。1.修改默认配置1.1修改默认编辑器默...

Linux系统编程—条件变量(linux 条件变量开销)

条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等...

面试题-Linux系统优化进阶学习(linux系统的优化)

一.基础必备优化:1.关闭SElinux2.FirewalldCenetOS7Iptables(C6)安全组(阿里云)3.网络管理服务||NetworkManager|network...

嵌入式Linux开发教程:Linux Shell

本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...

取消回复欢迎 发表评论: