Redis是单线程还是多线程
redis 4.0 之前,redis 是完全单线程的。
redis 4.0 时,redis 引入了多线程,但是额外的线程只是用于后台处理,例如:删除对象,核心流程还是完全单线程的。这也是为什么有些人说 4.0 是单线程的,因为他们指的是核心流程是单线程的。这边的核心流程指的是 redis 正常处理客户端请求的流程,通常包括:接收命令、解析命令、执行命令、返回结果等。
而在最近,redis 6.0 版本又一次引入了多线程概念,与 4.0 不同的是,这次的多线程会涉及到上述的核心流程。redis 6.0 中,多线程主要用于网络 I/O 阶段,也就是接收命令和写回结果阶段,而在执行命令阶段,还是由单线程串行执行。
由于执行时还是串行,因此无需考虑并发安全问题。值得注意的时,redis 中的多线程组不会同时存在“读”和“写”,这个多线程组只会同时“读”或者同时“写”。
需要注意的是在 Redis6.0 中,多线程机制默认是关闭的,需要在 redis.conf 中完成以下两个设置才能启用多线程。
设置 io-thread-do-reads 配置项为 yes,表示启用多线程。
io-threads-do-reads yes
设置线程个数。⼀般来说,线程个数要小于Redis实例所在机器的CPU核数,例如,对于⼀个 8 核的机器来说,Redis 官⽅建议配置 6 个 IO 线程。
io-threads 6
主进程的其他线程
Redis 3.0 版本后,主进程中除了主线程处理网络 IO 和命令操作外,还有 3 个辅助 BIO 线程。这 3 个 BIO 线程分别负责处理,文件关闭、AOF 缓冲数据刷新到磁盘,以及清理对象这三个任务队列,从而避免这些任务对主 IO 线程的影响。
Redis 在启动时,会同时启动这三个 BIO 线程,但是 BIO 线程只有在需要执行相关类型后台任务时才会唤醒,其他时间会休眠等待任务。

Redis的多线程和单线程表现在哪里
Redis 的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,
这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。
简单来说,就是 “请求是多线程的,但核心的内存读写操作(或者说读写计算)仍然是单线程的”
除了主进程,在以下场景如果需要进行重负荷任务的处理,Redis 会 fork 一个子进程来处理:
- 收到 bgrewriteaof 命令:Redis fork 一个子进程,然后子进程往临时 AOF文件中写入重建数据库状态的所有命令。写入完毕后,子进程会通知父进程把新增的写操作追加到临时 AOF 文件。最后将临时文件替换旧的 AOF 文件,并重命名。
- 收到 bgsave 命令:Redis 构建子进程,子进程将内存中的所有数据通过快照做一次持久化落地,写入到 RDB 中。
- 当需要进行全量复制:master 启动一个子进程,子进程将数据库快照保存到 RDB 文件。在写完 RDB 快照文件后,master 会把 RDB 发给 slave,同时将后续新的写指令都同步给 slave。
Redis单线程为什么还性能那么高
-
无锁无竞争
在进行多线程编程时,不可避免的一个问题就是并发问题,当然,相应的解决方案也已经非常成熟。然而,无论是加锁也好,还是号称无锁的CAS也好,只要有并发处理,就一定会有性能开销,线程的切换也会有切换开销。Redis的单线程消费模式保证了这些开销统统都是不存在的。 -
底层数据结构
并非排除了多线程开销就一定能够拥有极致的性能。redis的几种常用数据类型的底层数据结构设计可以根据不同的场景进行合理的转换,如 hash数据结构里使用ziplist进行数据压缩,节省内存空间,hash渐进式扩容 -
非阻塞式IO和多路复用
redis使用epoll多路复用,监听I/O文件句柄,哪个端口收到了消息就将消息投递到消费模块中,由消费模块对消息进行处理。redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。 -
内存数据
所有的数据都在内存中,所有的运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题。正因为 Redis 是单线程,所以要小心使用 Redis 指令,对于那些耗时的指令(比如keys),一定要谨慎使用,一不小心就可能会导致 Redis 卡顿。(内存响应时间是100纳秒)
redis底层的I/O多路复用:

要想知道redis为什么采取这种模式,最重要的是要搞明白一个问题:redis的性能瓶颈到底在哪个部分。
真相只有一个,那就是网络。正如上面所说 Redis 是核心线程负责网络 IO ,命令处理以及写数据到缓冲,而随着网络硬件的性能提升,单个主线程处理⽹络请求的速度跟不上底层⽹络硬件的速度,导致网络 IO 的处理成为了 Redis 的性能瓶颈。
多线程流程
redis 6.0 加入多线程 I/O 之后,处理命令的核心流程如下:
- 当有读事件到来时,主线程将该客户端连接放到全局等待读队列
- 读取数据:1)主线程将等待读队列的客户端连接通过轮询调度算法分配给 I/O 线程处理;2)同时主线程也会自己负责处理一个客户端连接的读事件;3)当主线程处理完该连接的读事件后,会自旋等待所有 I/O 线程处理完毕
- 命令执行:主线程按照事件被加入全局等待读队列的顺序(这边保证了执行顺序是正确的),串行执行客户端命令,然后将客户端连接放到全局等待写队列
- 写回结果:跟等待读队列处理类似,主线程将等待写队列的客户端连接使用轮询调度算法分配给 I/O 线程处理,同时自己也会处理一个,当主线程处理完毕后,会自旋等待所有 I/O 线程处理完毕,最后清空队列。
大致流程图如下:
主线程执行完请求操作后,会把需要返回的结果写入缓冲区。然后,主线程会阻塞等待 IO 线程把这些结果回写到 Socket 中,并返回给客户端。等到 IO 线程回写 Socket 完毕,主线程会清空全局队列,等待客户端的后续请求。
总结:
我们说Redis是单线程,主要是因为在以前的版本中网络 IO 和键值对读写是由⼀个线程来完成的。而之所以说 Redis 是多线程,则是因为
Redis6.0 以后的版本里,网络 IO 的部分变为了多线程处理。而且除了主线程,还有 3 个辅助 BIO 线程,分别是 fsync线程、close 线程、清理回收线程。当然不能忘记的是,想要体验多线程机制,就得通过修改配置文件开启多线程功能。
Redis的单线程与多线程机制解析
Redis在4.0之前完全单线程,4.0引入多线程仅用于后台处理,6.0开始多线程应用于网络I/O。尽管存在多线程,但核心命令执行仍保持单线程,确保无锁并发问题,通过非阻塞IO和内存数据处理提高性能。Redis使用BIO线程处理文件关闭、AOF刷新和对象清理等任务,以减轻主IO线程负担。
1712

被折叠的 条评论
为什么被折叠?



