一文看懂Redis引入的多线程到底在哪里体现了

Redis不是单线程吗?怎么又有人说Redis是多线程?

Redis是目前广为人知的一个内存数据库,在各个场景中都有着非常丰富的应用,自Redis推出了6.0的版本后,采用了多线程模型。

所以Redis到底是单线程还是多线程?这个问题你心里的答案是什么呢?

我的回答是:Redis本质就是单线程的,自6.0版本后引入了多线程,但这并不代表Redis的操作都是多线程的,具体为什么大家可以看看我的分析

Redis为什么一开始被设计成单线程

很多人说Redis是单线程的,就认为Redis中所有模块的操作都是单线程的,其实并不是这样

我们所说的Redis单线程,指的是"其网络IO和键值对读写是由一个线程完成的 ",也就是说,Redis中只有网络请求模块和数据操作模块是单线程的。而其他的如持久化存储模块、集群支撑模块等是多线程的。

所以说,Redis中并不是没有多线程模型的,早在Redis 4.0的时候就已经针对部分命令做了多线程化。

那么,为什么网络操作模块和数据存储模块最初并没有使用多线程呢?

多线程的适用场景

一个计算机程序在执行的过程中,主要需要进行两种操作分别是读写操作和计算操作。

其中读写操作主要是涉及到的就是I/O操作,其中包括网络I/O和磁盘I/O。计算操作主要涉及到CPU。

而多线程的目的,就是通过并发的方式来提升I/O的利用率和CPU的利用率。

那么,Redis需不需要通过多线程的方式来提升提升I/O的利用率和CPU的利用率呢?

首先,我们可以肯定的说,Redis不需要提升CPU利用率,因为Redis的操作基本都是基于内存的,CPU资源根本就不是Redis的性能瓶颈。

所以,通过多线程技术来提升Redis的CPU利用率这一点是完全没必要的。

那么,使用多线程技术来提升Redis的I/O利用率呢?是不是有必要呢?

Redis确实是一个I/O操作密集的框架,他的数据操作过程中,会有大量的网络I/O和磁盘I/O的发生。要想提升Redis的性能,是一定要提升Redis的I/O利用率的,这一点毋庸置疑。

  • 既然多线程可用提升Redis的I/O利用率,那么为什么Redis不采用多线程设计而是采用单线程设计呢?
  1. 避免竞态条件:Redis 采用单线程模型可以避免多线程环境下的竞态条件,简化了并发控制的复杂性。通过串行执行客户端的命令请求,Redis 可以确保数据的一致性和可靠性。
  2. 避免锁开销:在多线程环境下,读写操作需要使用锁来保护共享数据的一致性。频繁加锁、释放锁会带来额外的开销,降低了并发性能。Redis 通过单线程模型避免了锁的开销,提高了并发性能。
  3. 充分利用 CPU 缓存:Redis 在内存中存储数据,单线程模型可以使得 CPU 缓存更加高效地处理数据。多线程环境下,频繁切换线程会导致 CPU 缓存失效,降低了性能。单线程模型减少了线程切换的开销,提高了 CPU 缓存的利用率。

那Redis是如何提高I/O利用率的? --- IO多路复用,可以参考我这篇文章:

为什么Redis6.0引入在网络IO模块引入多线程

Redis 6.0中的多线程,也只是针对处理网络请求过程采用了多线程,而数据的读写命令,仍然是单线程处理的

随着越来越复杂的业务场景,有些公司动不动就上亿的交易量,因此需要更大的 QPS。

为了提升QPS,很多公司的做法是部署Redis集群,并且尽可能提升Redis机器数。但是这种做法的资源消耗是巨大的。

而经过分析,限制Redis的性能的主要瓶颈出现在网络IO的处理上,虽然之前采用了多路复用技术。但是我们前面也提到过,多路复用的IO模型本质上仍然是同步阻塞型IO模型

在多路复用的IO模型中,在处理网络请求时,调用 select (其他函数同理)的过程是阻塞的,也就是说这个过程会阻塞线程,如果并发量很高,此处可能会成为瓶颈。

虽然现在很多服务器都是多个CPU核的,但是对于Redis来说,因为使用了单线程,在一次数据操作的过程中,有大量的CPU时间片是耗费在了网络IO的同步处理上的,并没有充分的发挥出多核的优势。

如果能采用多线程,使得网络处理的请求并发进行,就可以大大的提升性能。多线程除了可以减少由于网络 I/O 等待造成的影响,还可以充分利用 CPU 的多核优势。

所以,Redis 6.0采用多个IO线程来处理网络请求,网络请求的解析可以由其他线程完成,然后把解析后的请求交由主线程进行实际的内存读写。提升网络请求处理的并行度,进而提升整体性能。

Redis如何解决并发带来的线程安全问题

这就是为什么我们前面多次提到的"Redis 6.0的多线程只用来处理网络请求,而数据的读写还是单线程"的原因。

Redis 6.0 只有在网络请求的接收和解析,以及请求后的数据通过网络返回给时,使用了多线程。而数据读写操作还是由单线程来完成的,所以,这样就不会出现并发问题了。

即Redis并没有并发的线程安全问题

总结

文件事件处理器使用I/O多路复用来同时监听多个套接字,并根据套接字执行的任务关联到不同的事件处理器。 文件事件以单线程方式运行,但通过使用I/O多路复用程序来监听多个套接字,文件事件处理器实现了高性能的网络通信模型。 Redis 在处理客户端的请求时,包括接收(socket读)、解析、执行、发送(socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的单线程。

相关推荐
测试杂货铺3 分钟前
外包干了2年,快要废了。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
王佑辉3 分钟前
【redis】redis缓存和数据库保证一致性的方案
redis·面试
真忒修斯之船10 分钟前
大模型分布式训练并行技术(三)流水线并行
面试·llm·aigc
ZL不懂前端31 分钟前
Content Security Policy (CSP)
前端·javascript·面试
杜杜的man40 分钟前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*41 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu43 分钟前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s43 分钟前
Golang--协程和管道
开发语言·后端·golang
为什么这亚子1 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
想进大厂的小王1 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构