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 采用多线程来处理,但是对于数据的读写命令,仍然是单线程处理的。

相关推荐
驾驭人生6 小时前
Hangfire.Redis.StackExchange 已归档停更!生产任务卡死、重复执行、网络抖动问题解决方案
数据库·redis·缓存
TDengine (老段)7 小时前
TDengine Catalog 与元数据缓存
大数据·数据库·物联网·缓存·时序数据库·tdengine
吃饱了得干活10 小时前
Redis 不是死脑筋,它是一套“会进化”的存储系统
redis·后端
盟道科技10 小时前
小程序电商订单超时自动取消的三种实现方案:定时扫描、Redis 过期监听、延迟消息对比与生产落地
数据库·redis·小程序
夕除10 小时前
redis--011
redis
hui-梦苑10 小时前
[Gromacs]核心性能梯度测试:GROMACS 多线程性能调优实验
缓存·性能优化·多线程·gromacs·动力学模拟
Lyyaoo.12 小时前
【链表】【中等】两数相加/倒N删除/两个交换/排序链表/LRU缓存
数据结构·链表·缓存
努力努力再努力wz13 小时前
【Redis入门系列】:从 RESP 协议到 redis-plus-plus:Redis 客户端编程与 C++ 接口设计
开发语言·数据库·c++·redis·分布式·缓存·架构
JavaPub-rodert1 天前
Redis 和 MySQL 如何保证数据一致性?从业务方案到底层原理完整讲解
数据库·redis·mysql
OH_TPC1 天前
【鸿蒙优选三方库】@react-native-ohos/react-native-fast-image:高性能图片加载与缓存组件
缓存·华为·harmonyos·鸿蒙