Redis篇之redis是单线程

一、redis是单线程

Redis是单线程的,但是为什么还那么快?主要原因有下面3点原因:

  1. Redis是纯内存操作,执行速度非常快。

  2. 采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题。

  3. 使用I/O多路复用模型,非阻塞IO。

二、I/O多路复用

能解释一下I/O多路复用模型?

Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟 而不是执行速度, I/O多路复用模型主要就是实现了高效的网络请求。要解释I/O多路复用模型,需要从下面3个知识慢慢来:

  1. 用户空间和内核空间。

  2. 常见的IO模型:阻塞IO(Blocking IO)、非阻塞IO(Nonblocking IO)、IO多路复用(IO Multiplexing)。

  3. Redis网络模型。

三、用户空间和内核空间

1.作用

Linux系统中一个进程使用的内存情况划分两部分:内核空间、用户空间。

  1. 用户空间只能执行受限的命令(Ring3),而且不能直接调用系统资源,必须通过内核提供的接口来访问。

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

Linux系统为了提高IO效率,会在用户空间和内核空间都加入缓冲区:

  1. 写数据 时,要把用户缓冲数据拷贝到内核缓冲区,然后写入设备。

  2. 读数据 时,要从设备读取数据到内核缓冲区,然后拷贝到用户缓冲区。

2.会出现什么问题呢

  1. 当等待数据时,会浪费大量系统资源。

  2. 拷贝的过程比较繁琐。

3.如何解决

就是下面说到的IO模型。

四、常见的IO模型

1.阻塞IO模型

顾名思义,阻塞IO就是两个阶段都必须阻塞等待:

阶段一:

  1. 用户进程尝试读取数据(比如网卡数据)。

  2. 此时数据尚未到达,内核需要等待数据。

  3. 此时用户进程也处于阻塞状态。

阶段二:

  1. 数据到达并拷贝到内核缓冲区,代表已就绪。

  2. 将内核数据拷贝到用户缓冲区 拷贝过程中,用户进程依然阻塞等待。

  3. 拷贝完成,用户进程解除阻塞,处理数据。

结论:可以看到,阻塞IO模型中,用户进程在两个阶段都是阻塞状态。

2.非阻塞IO模型

顾名思义,非阻塞IO的recvfrom操作会立即返回结果而不是阻塞用户进程。

阶段一:

  1. 用户进程尝试读取数据(比如网卡数据)。

  2. 此时数据尚未到达,内核需要等待数据。

  3. 返回异常给用户进程。

  4. 用户进程拿到error后,再次尝试读取。

  5. 循环往复,直到数据就绪。

阶段二:

  1. 将内核数据拷贝到用户缓冲区。

  2. 拷贝过程中,用户进程依然阻塞等待。

  3. 拷贝完成,用户进程解除阻塞,处理数据。

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

3.IO多路复用

(1)基本原理

IO多路复用是利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。

阶段一:

  1. 用户进程调用select,指定要监听的Socket集合。

  2. 内核监听对应的多个socket。

  3. 任意一个或多个socket数据就绪则返回readable。

  4. 此过程中用户进程阻塞。

阶段二:

  1. 用户进程找到就绪的socket。

  2. 依次调用recvfrom读取数据。

  3. 内核将数据拷贝到用户空间。

  4. 用户进程处理数据。

(2)其他通知方法

IO多路复用是利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。不过监听Socket的方式、通知的方式又有多种实现,常见的有:select、poll、epoll。

差异:

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

  2. epoll则会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间。

五、Redis网络模型

Redis通过IO多路复用来提高网络性能,并且支持各种不同的多路复用实现,并且将这些实现进行封装, 提供了统一的高性能事件库。

核心就是:IO多路复用+事件派发。

六、面试时候的回答

面试官:Redis是单线程的,但是为什么还那么快?

候选人:这个有几个原因吧,

1、完全基于内存的,C语言编写。

2、采用单线程,避免不必要的上下文切换可竞争条件。

3、使用多路I/O复用模型,非阻塞IO。

例如:bgsave 和 bgrewriteaof 都是在后台执行操作,不影响主线程的正常使用,不会产生阻塞

面试官:能解释一下I/O多路复用模型?

候选人:I/O多路复用是指利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。目前的I/O多路复用都是采用的epoll模式实现,它会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不需要挨个遍历Socket来判断是否就绪,提升了性能。

其中Redis的网络模型就是使用I/O多路复用结合事件的处理器来应对多个Socket请求,比如,提供了连接应答处理器、命令回复处理器,命令请求处理器;

在Redis6.0之后,为了提升更好的性能,在命令回复处理器使用了多线程来处理回复事件,在命令请求处理器中,将命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程。

相关推荐
Rookie也要加油31 分钟前
01_SQLite
数据库·sqlite
liuxin3344556636 分钟前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
看山还是山,看水还是。1 小时前
MySQL 管理
数据库·笔记·mysql·adb
fishmemory7sec1 小时前
Koa2项目实战2(路由管理、项目结构优化)
数据库·mongodb·koa
momo小菜pa2 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke2 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
小宇成长录2 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.3 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构
程序猿小D3 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa