美团二面:Redis 究竟是单线程还是多线程?
Redis 一直以来都是高性能分布式缓存中间件的代表,我们经常说 Redis 是单线程的,也有人说 Redis 在 6.0 版本采用了多线程,那么 Redis 到底是采用单线程呢?还是多线程?本文我们来一探究竟。
Redis 到底是单线程还是多线程的?
首先,Redis 是一个高性能的分布式缓存中间件。其复杂性不言而喻,对于 Redis 整体而言肯定不是只有一个线程。
我们常说的 Redis 是单线程,主要是指 Redis 在网络 IO 和键值对读写是采用一个线程来完成的,这也是 Redis 对外提供键值存储服务的核心流程。但对于 Redis 的其他功能来说,比如持久化、异步删除、集群数据同步等,其实都是由额外的线程执行的。
为什么要融入多线程?
单线程的优势:
使用单线程可以避免频繁的上下文切换
Redis 中有各种类型的数据操作,甚至包括一些事务处理,如果采用多线程,还可能因为加锁导致软件复杂度提升,更有可能会因为加解锁,甚至出现死锁,造成的性能损耗,所以使用单线程反而性能会更好
单线程的劣势:
无法发挥多核 CPU 的优势
当删除大建,会导致服务阻塞
QPS 达到瓶颈
基于上诉劣势,Redis 也进行了相关优化,在 4.0 版本和 6.0 版本分别引入了 Lazy Free 和多线程 IO。
Redis 单线程模型
Redis 基于 Reactor 模式开发了网络事件处理器,这个处理器被称为文件事件处理器。
文件事件处理器的四个重要组成部分:
多个套接字请求
IO 多路复用器
文件事件派发器
事件处理器
Redis 客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程。其中执行命令阶段,由于 Redis 是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会进入一个队列中,然后逐个被执行。并且多个客户端发送的命令的执行顺序是不确定的。但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是 Redis 的单线程基本模型,如下图所示。
带你理解 Redis 处理流程
1. Redis 4.0 之前的事件处理流程
我们先介绍一下 Redis( 4.0 之前)的执行原理,我们通过 IO 多路复用器监听来自客户端的 socket 网络连接,然后由主线程进行 IO 请求的处理以及命令的处理,所有操作都是线性的,我们可以抽象的理解为下图。
2. Redis 4.0 之后加入 Lazy Free 机制
Redis 4.0 之前在处理客户端命令和 IO 操作时都是以单线程形式运行,期间不会响应其他客户端请求,但若客户端向 Redis 发送一条耗时较长的命令,比如删除一个含有上百万对象的 Set 键,或者执行 flushdb,flushall 操作,Redis 服务器需要回收大量的内存空间,这事就会导致 Redis 服务阻塞,对于负载较高的缓存系统来说将会是个灾难。为了解决这个问题,在 Redis 4.0 版本引入了 Lazy Free,目的是将慢操作异步化,这也是在事件处理上向多线程迈进了一步,其过程我们可以理解为下图。
3. Redis 6.0 之后将网络 IO 异步化
从以上的发展历程中,我们也能看出 Redis 的瓶颈并不在 CPU 上,即使是单线程 Redis 也能做到很快的响应,除非是遇到个别极其耗时的命令,这一块我们的 Redis 也在 4.0 版本做出了优化,但是我们是不是能更进一步优化 Redis 呢?从上图中我们可以看出主线程不光处理大量的命令,还需要处理大量的网络 IO,Redis6.0 就是基于此,将 IO 操作交由其他线程处理,抽象的理解如下图所示。
Redis6.0 的多线程默认是禁用的,只使用主线程。如需开启需要修改 redis.conf 配置文件:io-threads-do-reads yes
开启多线程后,还需要设置线程数,否则是不生效的。
线程数一定要小于机器核数。线程数并不是越大越好,官方认为超过了 8 个基本就没什么意义了
。
设置线程数,修改 redis.conf 配置文件: io-threads 6
作者:CoderJie
链接:https://juejin.cn/post/7065960336335044645
来源:稀土掘金
评论