关于Redis的一些问题
# 关于Redis的一些问题
# Redis单线程为什么还这么快
通常来说,使用多线程处理会比单线程快,就像有一堆一万斤的货物,如果选择“单线程”,那就只有一辆车运送,需要运送10次,如果是“多线程”,那就会有多辆车运行,比如:5辆车,那只需运送2次即可。
那为什么Redis选择单线程,处理数据的数据还这么快呢?或者说Redis为什么不选择多线程处理?
主要有以下几点原因:
# 1 内存访问
Redis 将所有数据存储在内存中,而不是磁盘上。内存访问速度远远高于磁盘访问速度,因此 Redis 能够实现非常高的读写速度,使Redis达到每秒万级别的处理类效率。
# 2 单线程避免了线程切换和竞态产生的消耗
因为是单线程,所以它就没有由于线程创建或销毁而产生的额外的CPU消耗
,减少了上下文切换带来的开销
,此外,单线程也不必考虑多线程中的锁的问题,更不用考虑锁对性能的影响;没有多线程并发问题,Redis 可以简化并发控制逻辑,从而减少额外的计算成本。而Java用多线程来提升性能是因为它的大多数操作都很复杂,消耗的时间远高于创建或销毁线程。
同时因为Redis的操作都比较简单,大多数操作可以在毫秒级甚至微秒级内完成。单线程模型在这种情况下能够充分利用这些简单操作的特点,避免多线程带来的复杂性。
# 3 非阻塞IO模型
还有一点就是,它虽然是单线程,但运行机制却是epoll作为I/O多路复用
,一次能执行多个任务,这也帮它实现了高性能读写。I/O 多路复用是一种技术,允许一个单一的进程同时监听多个文件。就像老师提问,它不是依次让每个同学回答,而是让同学们自己思考,想出来后,自行举手,老师看到有人举手后,再自行选择某个举手同学的回答。
redis在
4.0之前
是完全单线程,4.0时加入了多线程,但并不用于核心工作,只用于额外的后台处理。
6.0之前
是单线程。这是因为它的核心工作流程是单线程,即redis正常处理客户端请求的流程。通常如:接收命令,解析命令,执行命令,写回结果。多线程只用于额外的后台处理。redis6.0之后加入的多线程用于核心流程,即网络I/O阶段,用来处理 接收数据 和 返回结果 这两个流程,执行命令的核心模块还是单线程的
# 4 数据结构的优化
它的基本数据类型是String,list,hash,set,zset,但这5种数据结构对应的底层数据结构却经过精心设计,使得各种操作能够在内存中高效地执行。底层数据结构有:SDS
(Simple Dynamic String)(简单动态字符串)、 ziplist
(压缩列表)、双向链表(Doubly Linked List)、 intset
(整数集合)、 skiplist
(跳跃表)、 hashtable
(哈希表)、快速链表
(quicklist)...
而它之所以优化底层数据结构,还有一个原因:对于单线程,如果某个命令执行过长,会造成其他命令的阻塞,因此它必须优化。所以它是面向快速执行场景的数据库。
# 总结
最后总结下,redis虽然是单线程,但处理效率依旧快的原因主要有以下四点:
- 基于内存存储,执行快
- 优化的数据存储结构,使得执行更快
- 单线程架构,没有多线程带来的锁和上下文切换消耗
- 非阻塞IO:Redis 采用网络IO多路复用技术,来保证在多连接的时候系统的高吞吐量。可以让单个线程高效处理多个连接请求(尽量减少网络IO的时间消耗)