Redis之IO多路复用模型

Redis之IO多路复用模型

多路复用要解决的问题

解决同步阻塞IO模型下大量线程创建导致资源的浪费问题

同步阻塞IO模式的特点就是用一个进程来处理一个网络连接(一个用户请求),比如一段典型的示例代码如下。

直接调用 recv 函数从一个 socket 上读取数据。

int main()

{

recv(sock, …) //从用户角度来看非常简单,一个recv一用,要接收的数据就到我们手里了。

}

每个用户请求到来都得占用一个进程来处理,来一个请求就要分配一个进程跟进处理,显然在高并发的情况下会导致资源的浪费

所以必须要让一个进程能同时处理很多个 tcp 连接才行,省去进程切换,创建,销毁的资源

同步异步 阻塞非阻塞理解

小故事

上午开会,错过了公司食堂的饭点, 中午就和公司的首席架构师一起去楼下的米线店去吃米线。我们到了一看,果然很多人在排队。

架构师马上发话了:嚯,请求排队啊!你看这位收银点菜的,像不像nginx的反向代理?只收请求,不处理,把请求都发给厨去处理。

我们交了钱,拿着号离开了点餐收银台,找了个座位坐下等餐。

架构师:你看,这就是异步处理,我们下了单就可以离开等待,米线做好了会通过小喇叭“回调”我们去取餐;

如果同步处理,我们就得在收银台站着等餐,后面的请求无法处理,客户等不及肯定会离开了。

接下里构师盯着手中的纸质号牌。

架构师:你看,这个纸质号牌在后厨“服务器”那里也有,这不就是表示会话的ID吗?

有了它就可以把大家给区分开,就不会把我的排骨米线送给别人了。过了一会, 排队的人越来越多,已经有人表示不满了,可是收银员已经满头大汗,忙到极致了。

架构师:你看他这个系统缺乏弹性扩容, 现在这么多人,应该增加收银台,可以没有其他收银设备,老板再着急也没用。

老板看到在收银这里帮不了忙,后厨的订单也累积得越来越多, 赶紧跑到后厨亲自去做米线去了。

架构师又发话了:幸亏这个系统的后台有**并行处理能力,**可以随意地增加资源来处理请求(做米线)。

我说:他就这点儿资源了,除了老板没人再会做米线了。

不知不觉,我们等了20分钟, 但是米线还没上来。

架构师:你看,系统的处理能力达到极限,超时了吧。

这时候收银台前排队的人已经不多了,但是还有很多人在等米线。

老板跑过来让这个打扫卫生的去收银,让收银小妹也到后厨帮忙。打扫卫生的做收银也磕磕绊绊的,没有原来的小妹灵活。

架构师:这就叫服务降级,为了保证米线的服务,把别的服务都给关闭了。

又过了20分钟,后厨的厨师叫道:237号, 您点的排骨米线没有排骨了,能换成番茄的吗?

架构师低声对我说:瞧瞧, 人太多, 系统异常了。然后他站了起来:不行,系统得进行补偿操作:退费。

说完,他拉着我,饿着肚子,头也不回地走了。

同步

调用者一直等待调用结果的通知后才能进行后续的执行,等到出结果为止

异步

指被调用方先返回应答让调用方先回去,再计算调用结果,计算完后再通知调用方并返回结果

异步调用想要获取结果一般通过回调

同步和异步讨论的对象是被调用着,重点在于获取结果消息的通知方式上

阻塞

调用方一直在等待而什么事情也不做,当前线程会被挂起

非阻塞

调用方发送请求后,调用方可以去忙其他事情,不会阻塞当前线程

阻塞与非阻塞讨论的是调用者,重点在于等消息时候的行为

Redis的IO多路复用

Redis利用epoll函数来实现IO的多路复用,将连接信息和事件放在队列中,一次性放到文件事件分派器,事件分派器将事件分派给事件处理器

在这里插入图片描述

IO复用机制,就是通过一种机制,可以监听多个文件描述符,一旦文件描述符就绪,就会通知线程进行相应的读写操作,这种机制的使用需要 select 、 poll 、 epoll 来配合。多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。

在这里插入图片描述

Redis 服务采用 Reactor 的方式来实现文件事件处理器(每一个网络连接其实都对应一个文件描述符)

Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成结构为4部分:

多个套接字、

IO多路复用程序、

文件事件分派器、

事件处理器。

因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型

Reactor模式

基于 I/O 复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。

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

在这里插入图片描述

Reactor 模式中有 2 个关键组成:

1)Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。 它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人;

2)Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际办理人。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。

从Redis6开始,将网络数据读写、请求协议解析通过多个IO线程的来处理

在这里插入图片描述

大家都用过nginx,nginx使用epoll接收请求,ngnix会有很多链接进来, epoll会把他们都监视起来,然后像拨开关一样,谁有数据就拨向谁,然后调用相应的代码处理。redis类似同理

在这里插入图片描述

IO多路复用的具体实现

select

在这里插入图片描述

select 函数监视的文件描述符分3类,分别是readfds、writefds和exceptfds,将用户传入的数组拷贝到内核空间 调用后select函数会阻塞,直到有描述符就绪(有数据 可读、可写、或者有except)或超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。 当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。

select函数执行流程:

1.select是个阻塞函数,当没有数据时会一直阻塞到select那一行

2.当有数据时会将rset置为1

3.select函数返回不再阻塞

4.遍历文件描述符数组,判断哪个fd被置位了

5.读取数据然后处理

优点

select 其实就是把NIO中用户态要遍历的fd数组(我们的每一个socket链接,安装进ArrayList里面的那个)拷贝到了内核态,让内核态来遍历,因为用户态判断socket是否有数据还是要调用内核态的,所有拷贝到内核态后,这样遍历判断的时候就不用一直用户态和内核态频繁切换了

从代码中可以看出,select系统调用后,返回了一个置位后的&rset,这样用户态只需进行很简单的二进制比较,就能很快知道哪些socket需要read数据,有效提高了效率
在这里插入图片描述

缺点

1、bitmap最大1024位,一个进程最多只能处理1024个客户端

2、&rset不可重用,每次socket有数据就相应的位会被置位

3、文件描述符数组拷贝到了内核态(只不过无系统调用切换上下文的开销。(内核层可优化为异步事件通知)),仍然有开销。select 调用需要传入 fd 数组,需要拷贝一份到内核,高并发场景下这样的拷贝消耗的资源是惊人的。(可优化为不复制)

4、select并没有通知用户态哪一个socket有数据,仍然需要O(n)的遍历。select 仅仅返回可读文件描述符的个数,具体哪个可读还是要用户自己遍历。(可优化为只返回给用户就绪的文件描述符,无需用户做无效的遍历)

poll

在这里插入图片描述

poll的执行流程

1.将5个fd从用户态拷贝到内核态

2.poll为阻塞方法,执行poll方法,如果有数据会将fd对应的revents置为pollin

3.poll方法返回

4.遍历遍历fd数组,找到被置为pollin的fd

5.将revents重置为0

6.对置位的fd进行读取和处理

在这里插入图片描述

优点

1、poll使用pollfd数组来代替select中的bitmap,数组没有1024的限制,可以一次管理更多的client。它和 select 的主要区别就是,去掉了 select 只能监听 1024 个文件描述符的限制。

2、当pollfds数组中有事件发生,相应的revents置位为1,遍历的时候又置位回零,实现了pollfd数组的重用

缺点

poll 解决了select缺点中的前两条,其本质原理还是select的方法,还存在select中原来的问题

1、pollfds数组拷贝到了内核态,仍然有开销

2、poll并没有通知用户态哪一个socket有数据,仍然需要O(n)的遍历

epoll

epoll主要包含三个基本函数

epoll_create

int epoll_create(int size);

创建一个 epoll 对象,返回该对象的描述符(参数size并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议)

epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

操作控制 epoll 对象,主要涉及 epoll 红黑树上节点的一些操作,比如添加节点,删除节点,修改节点事件。

epfd:通过 epoll_create 创建的 epoll 对象句柄。

op:对红黑树的操作,添加节点、删除节点、修改节点监听的事件,分别对应 EPOLL_CTL_ADD,EPOLL_CTL_DEL,EPOLL_CTL_MOD。

添加事件:相当于往红黑树添加一个节点,每个客户端连接服务器后会有一个通讯套接字,每个连接的通讯套接字都不重复,所以这个通讯套接字就是红黑树的 key。

修改事件:把红黑树上监听的 socket 对应的监听事件做修改。

删除事件:相当于取消监听 socket 的事件。

fd:需要添加监听的 socket 描述符,可以是监听套接字,也可以是与客户端通讯的通讯套接字。

event:事件信息。

在这里插入图片描述

epoll_wait

int epoll_wait(int epid, struct epoll_event *events, int maxevents, int timeout);

功能说明 :阻塞一段时间并等待事件发生,返回事件集合,也就是获取内核的事件通知。说白了就是遍历双向链表,把双向链表里的节点数据拷贝出来,拷贝完毕后就从双向链表移除。

epid:epoll_create 返回的 epoll 对象描述符。

events:存放就绪的事件集合,这个是传出参数。

maxevents:代表可以存放的事件个数,也就是 events 数组的大小。

timeout:阻塞等待的时间长短,以毫秒为单位,如果传入 -1 代表阻塞等待。

epoll执行流程

epoll是非阻塞的

1.当有数据的时候会把相应的文件描述符“置位”,但epoll没有revent标志位,所以并不是真正的置位,这时会把有数据的文件描述符放置队首

2.epoll会返回有数据的文件描述符个数

3.根据返回的个数N读取前N个文件描述符

4.处理数据
在这里插入图片描述

结论

多路复用快的原因在于,操作系统提供了这样的系统调用,使得原来的 while 循环多次系统调用,变成了一次系统调用 + 内核层遍历这些文件描述符。

epoll是现在最先进的IO多路复用器,Redis、Nginx,linux中的Java NIO都使用的是epoll。

这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程

1、一个socket的生命周期中只有一次从用户态拷贝到内核态的过程,开销小

2、使用event事件通知机制,每次socket中有数据会主动通知内核,并加入到就绪链表中,不需要遍历所有的socket

在多路复用IO模型中,会有一个内核线程不断地去轮询多个 socket 的状态,只有当真正读写事件发送时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有真正有读写事件进行时,才会使用IO资源,所以它大大减少来资源占用。多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。 采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈

对比

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

语义分割 简介及数据集简介

参考文章 MS COCO数据集介绍以及pycocotools简单使用-CSDN博客

Linux7安装tomcat9.0.83教程

1.下载tomcat.tar.gz包 地址:Apache Tomcat - Apache Tomcat 9 Software Downloads 2.将包上传到linux服并解压 cd /home/local # 跳转到上传包的目录 tar -zxvf apache-tomcat-9.0.83.tar.gz # 解压包 mv apache-tomcat-9.0.83 tomcat # 重命名目录为tomcat cp …

【PUSDN】SpringBoot的jar进行解压后,替换其中的文件重新生成新的jar-SW

当你解压Spring Boot的JAR文件时,实际上是在打开一个压缩文件,类似于ZIP。你可以按照以下步骤进行替换文件并重新生成新的JAR: 解压原始的JAR文件: 使用任何ZIP工具(如WinRAR、7-Zip或命令行工具)&#xf…

详解异常 ! !(对异常有一个全面的认识)

【本章目标】 1. 异常概念与体系结构 2. 异常的处理方式 3. 异常的处理流程 4. 自定义异常类 1. 异常的概念与体系结构 1.1 异常的概念 在生活中,一个人表情痛苦,出于关心,可能会问:你是不是生病了,需要我陪你去看医…

在线测试http接口,为您解析最佳测试方法

您是否正在寻找一种方便、高效且可靠的方法来测试您的http接口?在这篇文章中,我们将为您介绍在线测试http接口的最佳方法,帮助您确保您的接口在各种情况下都能正常运行。 什么是http接口? 在开始介绍如何测试http接口之前&#x…

AG1KLPQ48 User Manual

1.)软件安装: 解压缩或执行安装文件,安装 Supra 软件。执行文件为 bin 目录中的 Supra.exe。 运行 Supra,选择菜单 File -> Import license,选择 license 文件并导入 License。 2.)新建项目:…

掌握iText:轻松处理PDF文档-进阶篇

简体中文写入 iText本身对简体中文的支持有限,但可以通过引入额外的字体包来增强其对简体中文的支持。例如,可以使用iTextAsian.jar这个亚洲字体包,它包含了几种简单的亚洲字体,其中包括简体中文字体。只需要将iTextAsian.jar放到…

Star CCM+ 停止并保存用命令行运行的计算

在 StarCCM 命令行运行 中介绍了命令行运行计算的方法,有网友询问停止计算的命令,但计算一旦提交之后应该是不能用命令结束的,除非是用 kill 或任务管理器直接结束进程。然而,直接结束进程不会自动保存计算结果。 问题 通常情况下…

tidb安装 centos7单机集群

安装 [rootlocalhost ~]# curl --proto https --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh [rootlocalhost ~]# source .bash_profile [rootlocalhost ~]# which tiup [rootlocalhost ~]# tiup playground v6.1.0 --db 2 --pd 3 --kv 3 --host 192.168.1…

【C++】C++中的String类详解及模拟实现示例

文章目录 string类简介string类的基本用法string类的常用方法string类的优势 string类的模拟实现存储结构头文件string.h源文件string.cpp源文件test.cpp string类简介 string类简介在C编程中,字符串是一种非常常见的数据类型,用于存储文本信息。C标准库…

用 Python 自动创建 Markdown 表格

更多资料获取 📚 个人网站:ipengtao.com Markdown表格是文档中整理和展示数据的重要方式之一。然而,手动编写大型表格可能会费时且容易出错。本文将介绍如何使用Python自动创建Markdown表格,通过示例代码详细展示各种场景下的创建…

Java 何时会触发一个类的初始化

Java 何时会触发一个类的初始化? 使用new关键字创建对象访问类的静态成员变量 或 对类的静态成员变量进行赋值调用类的静态方法反射调用类时,如 Class.forName()初始化子类时,会先初始化其父类(如果父类还没有进行过初始化的话&a…

【Java】I/O流—File类:从0到1的全面解析

🎊专栏【Java】 🌺每日一句:看不清楚未来时,就比别人坚持久一点 ⭐欢迎并且感谢大家指出我的问题 目录 1.File概述 2.File构造方法 (1).根据文件路径创建文件对象 (2).根据父路径名字符串和子路径名字符串创建对象 (3).根据父路径对应文件对象和子路…

关于性能测试,你不知道的事应用性能监控:SkyWalking

SkyWalking 简介 SkyWalking 是一款优秀的 APM 工具(Application Performance Monitoring,应用性能监控),专为微服务、云原生架构和基于容器(Docker、K8S、Mesos)的架构而设计,包含了分布式追踪…

14-1、IO流

14-1、IO流 lO流打开和关闭lO流打开模式lO流对象的状态 非格式化IO二进制IO读取二进制数据获取读长度写入二进制数据 读写指针 和 随机访问设置读/写指针位置获取读/写指针位置 字符串流 lO流打开和关闭 通过构造函数打开I/O流 其中filename表示文件路径,mode表示打…

【PWN】学习笔记(二)【栈溢出基础】

课程教学 课程链接:https://www.bilibili.com/video/BV1854y1y7Ro/?vd_source7b06bd7a9dd90c45c5c9c44d12e7b4e6 课程附件: https://pan.baidu.com/s/1vRCd4bMkqnqqY1nT2uhSYw 提取码: 5rx6 C语言函数调用栈 一个栈帧保存的是一个函数的状态信息&…

前端mp3文件转wav文件的实现

一、音频文件格式转换 1)安装fluent-ffmpeg和ffmpeg插件 npm install fluent-ffmpeg; npm install ffmpeg;2)mp3转wav test.js文件: const ffmpeg require(fluent-ffmpeg);ffmpeg(./test.mp3) .format(wav) .audioBitrate(16k) .audioFre…

Shutter的安装及使用

概要:本篇主要讲述截图软件Shutter的安装和使用,操作系统是Ubuntu22.04 一、安装 sudo apt install shutter 二、区域截图 1、打开Shutter,点击Selection 2、提示信息 3、框选矩形区域 按住鼠标左键,拖动鼠标,松…

基于SSM的健身房预约系统设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…

@Styles和@Extend的区别(鸿蒙开发)

如果每个组件的样式都需要单独设置,在开发过程中会出现大量代码在进行重复样式设置,虽然可以复制粘贴,但为了代码简洁性和后续方便维护,我们推出了可以提炼公共样式进行复用的装饰器Styles。 Styles装饰器可以将多条样式设置提炼成…