Redis线程模型讨论

很多人常说,因为 Redis 是单线程的,所以它的操作就快、性能就好。但其实这个表述并不完全准确,因为 Redis 作为一个成熟的分布式缓存框架,它由很多模块组成,如网络请求模块、数据操作模块、存储模块、索引模块、高可用集群支撑模块等,除了网络请求模块和数据操作模块是单线程处理,其他模块都是多线程的,比如,Redis 中会有很多后台进程异步处理一些耗时较长的操作,如处理关闭文件、AOF 刷盘等。

并且在 Redis 6.0 版本开始,网络请求模块也被设计成了多线程。

也就是说, Redis 6.0 之前, Redis 中只有网络 IO 、读写命令的执行是单线程的 ( 主线程 ) ,其他的处理操作都是多线程。

在了解了上述知识后,接下来就对以下问题展开谈论。

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

一个计算机程序在执行的过程中,主要需要进行两种操作分别是读写操作、计算操作。其中读写操作主要是涉及到的就是I/O操作,其中包括网络I/O和磁盘I/O;计算操作主要涉及到CPU。

而对于 Redis 来说,其操作都是基于内存的,所以 CPU 并不是制约其性能的瓶颈,更多情况下是受到内存大小和I/O操作的限制。因此,要想提高 Redis 的性能,就必须提升 Redis 对 I/O 的利用率。

但是,提升I/O利用率,并不是只有采用多线程技术这一条路可以走!

虽然采用多线程可以帮助我们提升CPU和I/O的利用率,但是多线程带来的并发问题也给这些语言和框架带来了更多的复杂性。而且,多线程模型中,多个线程的互相切换也会带来一定的性能开销。

所以,在提升I/O利用率这个方面上,Redis 并没有采用多线程技术,而是选择了I/O多路复用技术。

小结:

Redis并没有在网络请求模块和数据操作模块中使用多线程模型,主要是基于以下四个原因:

  • Redis 操作基于内存,绝大多数操作的性能瓶颈不在 CPU
  • 使用单线程模型,可维护性更高,开发、调试和维护的成本更低
  • 单线程模型,避免了线程间切换带来的性能开销
  • 在单线程中使用I/O多路复用技术也能提升Redis的I/O利用率

二、I/O多路复用技术

Redis 通过I/O多路复用技术来监听大量的客户端连接,以此提升网络I/O的利用率,而且这种方式可以避免使用多线程来监听客户端连接,降低了资源的消耗。

Redis 基于 Reactor 模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器(file event handler)。文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。

当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。

虽然文件事件处理器以单线程方式运行,但通过使用 I/O 多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接,这保持了 Redis 内部单线程设计的简单性。

可以看出,文件事件处理器(file event handler)主要是包含 4 个部分:

  • 多个 socket(客户端连接)
  • IO 多路复用程序(支持多个客户端连接的关键)
  • 文件事件分派器(将 socket 关联到相应的事件处理器)
  • 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

三、为什么 Redis 设计成单线程也能这么快?

通过上述分析,我们得出 Redis 基于单线程使用I/O多路复用技术大大提升了网络I/O利用率,使得 Redis 命令执行快,但远不止这个原因。

Redis 之所以如此快,主要有以下几个方面的原因:

  • 基于内存:Redis 是一种基于内存的数据库,数据存储在内存中,数据的读写速度非常快,因为内存访问速度比硬盘访问速度快得多。
  • 单线程模型:Redis 使用单线程模型,这意味着它的所有操作都是在一个线程内完成的,不需要进行线程切换和上下文切换。这大大提高了 Redis 的运行效率和响应速度。
  • 多路复用 I/O 模型:Redis 在单线程的基础上,采用了I/O 多路复用技术,实现了单个线程同时处理多个客户端连接的能力,从而提高了 Redis 的并发性能。
  • 高效的数据结构:Redis 提供了多种高效的数据结构,如哈希表、有序集合、列表等,这些数据结构都被实现得非常高效,能够在 O(1) 的时间复杂度内完成数据读写操作,这也是 Redis 能够快速处理数据请求的重要因素之一。
  • 多线程的引入:在Redis 6.0中,为了进一步提升IO的性能,引入了多线程的机制。采用多线程,使得网络处理的请求并发进行,就可以大大的提升性能。多线程除了可以减少由于网络 I/O 等待造成的影响,还可以充分利用 CPU 的多核优势。

四、为什么Redis 6.0引入了多线程?

虽然 Redis 的主要工作(网络 I/O 和执行命令)一直是单线程模型,但是在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上。

所以为了进一步提高网络 I/O 的利用率,Redis 6.0 对于网络 I/O 采用多线程来处理,但是对于数据的读写命令,仍然是单线程处理的。

相关推荐
Warren981 小时前
Spring Boot 整合网易163邮箱发送邮件实现找回密码功能
数据库·vue.js·spring boot·redis·后端·python·spring
小花鱼20257 小时前
redis在Spring中应用相关
redis·spring
郭京京7 小时前
redis基本操作
redis·go
似水流年流不尽思念7 小时前
Redis 分布式锁和 Zookeeper 进行比对的优缺点?
redis·后端
郭京京7 小时前
go操作redis
redis·后端·go
Warren989 小时前
Spring Boot 拦截器返回中文乱码的解决方案(附全局优化思路)
java·网络·spring boot·redis·后端·junit·lua
XXD啊9 小时前
Redis 从入门到实践:Python操作指南与核心概念解析
数据库·redis·python
Java小混子1 天前
【Redis】缓存和分布式锁
redis·分布式·缓存
柯南二号1 天前
【Java后端】【可直接落地的 Redis 分布式锁实现】
java·redis·分布式
卑微的小鬼1 天前
如何保证数据库和缓存的一致性?
数据库·缓存