Redis篇——超详细、超细节I/O多路复用介绍,回答Redis为什么单线程这么快!涵盖阻塞I/O模型、Linux内核空间以及Redis网络模型等常见技术点,一篇文章帮你彻底拿下!

简单了解Redis为什么单线程还这么快!

redis为什么能够在单线程的情况下,轻松应对高并发的访问,Redis提供的I/O多路复用功不可没!
Redis 使用 I/O 多路复用来处理连接,这意味着它不会为每个连接创建一个新的线程。而是使用一个主线程来监听多个连接,并在需要时进行处理。这种设计减少了线程切换的开销,并允许 Redis 在高并发场景下保持高性能。

补充一下其他的帮助redis处理高并发请求的小帮手!
事件驱动:Redis 使用事件驱动模型来处理请求。它监听套接字的 I/O 事件,一旦有数据可用,就立即处理。这使得 Redis 能够快速地处理大量并发连接。
单线程操作:由于 Redis 是单线程的,它避免了多线程环境下的线程同步和切换问题。所有操作都在一个线程上顺序执行,这使得 Redis 的执行路径非常清晰,并且更容易进行优化。
高效的内存管理:Redis 将所有数据存储在内存中,这使得读写操作非常快。此外,Redis 使用了一种称为内存碎片回收的技术,可以有效地管理内存空间,避免内存浪费。
数据结构优化:Redis 支持多种数据结构,如字符串、列表、集合、哈希表等。这些数据结构经过优化,可以在内存中高效地存储和访问。这使得 Redis 在处理复杂查询时能够保持高性能。
数据持久化:虽然 Redis 主要用于缓存和内存数据库,但它也支持将数据持久化到磁盘。通过使用 RDB 或 AOF 持久化机制,Redis 可以定期将数据写入磁盘,以确保在系统崩溃时数据不会丢失。这有助于提高系统的可靠性和容错性。
尽管 Redis 是单线程的,但通过这些机制,它仍然能够有效地处理高并发问题。然而,对于非常高的并发请求,可能需要使用一些扩展技术,如使用 Redis 集群来分散负载。

下面详细介绍下Redis的I/O多路复用~~~

用户空间和内核空间

在Linux系统中一个进程的内存情况划分为两个部分:内核空间和用户空间
1、用户空间
只能执行受限的命令(Ring3),而不能直接调用系统资源,必须通过内核提供的接口来访问

2、内核空间
可以执行特权命令(Ring0),调用一切系统资源

与此同时,Linux系统为了提高I/O效率,会在用户空间和内核空间都加入了缓冲区
1、写数据的时候,要把用户缓冲区数据拷贝到内核缓冲区,然后写入到设备
2、读数据的时候,要从设备读取数据到内核空间,然后拷贝到用户缓冲区

常见的I/O模型

阻塞I/O

用户读取数据分为两个阶段
阶段一
1、用户进程尝试读取数据(比如网卡中的数据)
2、此时数据尚未到达,内核需要等待数据
3、此时用户进程也处于阻塞状态

阶段二
1、数据到达并且拷贝到内核空间,代表已就绪
2、将内核数据拷贝到用户缓冲区
3、拷贝过程中,用户进程依然阻塞等待
4、拷贝完成,用户进程解除阻塞,处理数据

以上两个阶段可以看出,阻塞I/O模型中,用户进程在两个节点都是处于阻塞的状态

非阻塞I/O

用户读取数据分为两个阶段
阶段一
1、用户进程尝试读取数据(比如网卡中的数据)
2、此时数据尚未到达,内核需要等待数据
3、返回异常给用户进程
4、用户进程拿到异常error后,尝试再次读取
5、循环往复,直到数据就绪

阶段二
1、将内核数据拷贝到用户缓冲区
2、拷贝过程中,用户进程依然阻塞等待
3、拷贝完成,用户进程解除阻塞,处理数据

以上两个阶段可以看出,非阻塞I/O模型中,用户进程在第一个阶段是非阻塞,第二个阶段是阻塞状态。虽然是非阻塞,但性能并没有得到提高。而且忙等机制会导致CPU的空转,CPU使用率暴增!

再补充一个案例介绍阻塞和非阻塞I/O模型:
1、同步阻塞和同步非阻塞

上面这个例子生动形象的介绍了同步阻塞和同步非阻塞的流程

1、同步阻塞代码演示
以下面这段代码为案例,一步步debug

1)首先服务端进行初始化,走到这个while地方会阻塞,等待客户端的连接

2)客户端进行初始化,在连接执行connect方法的时候进行阻塞(成功连接前都会阻塞),等待三次握手,四次挥手流程后建立连接才会继续往下走

3)连接成功后,服务端会执行read方法,读取客户端的请求参数,此时如果客户端还没有传递参数,那么服务端也会阻塞在read方法这里

4)客户端发送数据,客户端在发送数据的时候,也会阻塞在write方法这里

5)客户端发送数据成功,服务端继续执行业务代码,但是自始至终客户端2始终是阻塞在connect连接方法这里

6)此时客户端1的业务流程执行完毕,服务端代码又回到了while的位置。注意到此,客户端2还是处于一个阻塞的状态,因为之前都是一直在处理客户端1的业务

同步阻塞总结:
单线程:某个socket阻塞,会影响到其他的socket处理
多线程:客户端较多时,会造成资源的浪费,全部socket中可能每个时刻中有几个就绪。同时,线程调度。行下文切换乃至他们占用的内存,可能会成为瓶颈

2、同步非阻塞代码演示
以两段代码为案例

1)同步非阻塞的场景下,服务端没有读取客户参数的方法了,会直接调用accept方法获取一个accept_fd,流程是这样的,如果客户端没有发送连接请求,那么服务端获取到的accept_fd是非法的(可能是-1),直到客户端成功发送请求后,会拿到一个合法的accept_fd,才会执行往fd列表中添加fd的方法。如果没有soket连接或者合法的fd,那么服务端会一直轮询下去,直到有合法的fd

I/O多路复用

认识I/O多路复用:就是利用单线程来同时监听多个Socket连接,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源

针对上图流程图,做解释说明:
阶段一
1、用户进程调用select,指定要监听的Socket集合
2、内核监听对应的多个Socket集合
3、任意一个或者多个Socket数据就绪就返回readable
4、此过程中用户进程阻塞

阶段二
1、用户进程找到就绪的Socket
2、依次调用recvfrom读取数据
3、内核将数据拷贝到用户缓冲区
4、用户进程处理数据
 

I/O多路复用实现方式

以餐馆点餐为例,用户下单则亮灯,服务员通过亮灯找到用户下的订单

(一)select和poll
select和poll的实现方式就是当用户点餐下单,服务员的灯亮了,服务员会去所有的顾客中进行一次询问,依次询问是不是您下的单,这样就会造成每次下单都会将所有的用户都遍历一遍

总结:
select和poll只会通知用户进程有Socket就绪,但不能确定具体是哪一个Socket,需要用户进程逐个遍历Socket来确认

(二)epoll
这种实现方式灯泡则就是一个提示,当灯泡亮后,服务员就能知道是哪一桌的用户下的单了,而不用一次次的去遍历

总结:
epoll会在通知用户进程Socket就绪的同时,把已经就绪的Socket写入用户空间,直接处理即可

Redis网络模型

Redis的底层是用使用了I/O多路复用+事件派发机制(多个不同事件处理器)来应对多个Socket请求
下面了解下事件派发机制:
Redis的事件派发是其事件机制的核心部分。Redis服务器是一个事件驱动程序,主要处理两类事件:文件事件和时间事件。
文件事件是对套接字操作的抽象,每当一个套接字准备好执行连接应答、读取、写入、关闭等操作时,就会产生一个文件事件。因为一个服务器通常会连接多个套接字,所以多个文件事件可能并发出现。
文件事件处理器是Redis基于Reactor模式开发的网络时间处理器,它使用I/O多路复用程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。当被监听的套接字准备好执行相关操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
文件事件处理器的结构主要包括套接字、I/O多路复用程序、文件事件分派器和事件处理器。I/O多路复用程序负责监听多个套接字,并向文件事件派发器传递那些产生了事件的套接字。文件事件分派器根据套接字产生的事件类型,调用相应的事件处理器。这些事件处理器是一种函数,定义了某个事件发生时,服务器应该执行的动作。
对于时间事件,服务器的一些操作需要在给定的时间点执行,而时间事件就是对这类定时操作的抽象。例如生成RDB文件和清除过期数据等任务。

特别注意:Redis是直接操作内存的,所以I/O则是限制Redis性能的最大根源,所以Redis在处理多个Socket请求的时候,分别在命令请求处理器和命令回复处理器的位置使用了多线程来提高处理的效率。
1、在Redis6.0后,命令请求处理器使用多线程是因为多个Socket连接可能会同时发出请求数据,数据转换相对来说比较耗时,所以就引入了多线程
那为什么不在后面执行相关命令并将结果写入缓存中的时候使用多线程呢?
因为Redis在串行执行这些命令的时候还是很快的,单线程足矣!并且保证了线程的安全
2、在Redis6.0后,命令回复处理器使用多线程是为了提高给用户的响应效率,更好的提高性能

至此,关于Redis的常见I/O模型以及Redis多路复用的细节等等介绍完毕,再赘述一下,本篇文章质量很高,内容点较多,希望同学们可以反复的学习,不断加深对Redis的多路复用的理解,期待同学们早日成为技术大佬。

后续还会持续更新相关技术点,敬请期待!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Be explorer

若认可笔者文章,手头富裕望支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值