为什么 Redis 设计为单线程?6.0 版本为何引入多线程?
为什么 Redis 设计为单线程?6.0 版本为何引入多线程?
回答重点
单线程设计原因:
- Redis 的操作是基于内存的,其大多数操作的性能瓶颈主要不是 CPU 导致的
- 使用单线程模型,代码简便的同时也减少了线程上下文切换带来的性能开销
- Redis 在单线程的情况下,使用 I/O 多路复用模型就可以提高 Redis 的 I/O 利用率了
6.0 版本引入多线程的原因:
- 随着数据规模的增长、请求量的增多,Redis 的执行瓶颈主要在于⽹络 I/O。引入多线程处理可以提高网络 I/O处理速度。
扩展知识
我们所说的 Redis 单线程,主要指的是 Redis 网络 I/O 和键值对读写这些操作是由一个线程完成的。(持久化、集群等机制其实是有后台线程执行的)
不过 Redis 并不是一直都单线程的,在 4.0 之后就开始引入了多线程指令,6.0 之后便正式引入了多线程的机制,不过 这里的多线程其只是针对网络请求过程使用多线程,其对于数据读写命令的处理依旧是单线程的。
为什么 Redis 前期不使用多线程的方式,等到 6.0 却又引入呢?
主要是因为我们对 Redis 的性能有了更高的要求,因为随着业务愈加复杂,公司需要的 QPS 就越高了,为了提升 QPS ,最直接的做法就是搭建 Redis 的集群,即提高 Redis 的机器数,但是这种做法的资源消耗是巨大的。
而 Redis 单线程执行命令的性能瓶颈在网络 I/O ,虽然它采用了多路复用技术,但 I/O 多路复用模型本质还是同步I/O。

从上面这个图中我们可以看到,I/O 多路复用在处理网络请求的时候,其调用 select(或是 epoll 等)后,如果来数据了,那么将数据从内核拷贝到用户空间这一步是同步的(关于 I/O 场景,阻塞、同步等名词意义请看扩展知识),即用户线程需要等待数据拷贝完成(在 redis 场景就是无法处理命令了),如果并发量很高的话,这个过程可能会成为瓶颈。
综上所示,我们可以发现,多路复用+单线程的设计并不能很好地解决网络 I/O 瓶颈的问题,这个时候就可以考虑利用 CPU 的多核优势,即利用多线程处理网络请求的方式来提高效率,然后对于读写命令, Redis 依旧采用单线程命令。
Redis 引入多线程之后,有没有带来什么线程安全问题呢?
没有,因为 Redis 6.0 只有针对网络请求模块采用的是多线程,对于读写命令部分还是采用单线程,所以所谓的线程安全问题就不存在了。
Redis 6.0 的多线程默认是禁⽤的,只使⽤主线程,因为大部分公司并发量实际上还是用不上这个。
如果要开启需要配置 io-threads-do-reads参数为 yes。