跳过正文
  1. 面试题库/

03|Redis 执行

·2034 字·5 分钟
目录
Redis面试题库 - 这篇文章属于一个选集。
§ 3: 本文

1. Redis 是单线程还是多线程?
#

分析

核心处理逻辑,Redis 一直都是单线程的,其它辅助模块也会有一些多线程、多进程的功能,比如:

  • 复制模块用的多进程;
  • 某些异步流程从 4.0 开始用的多线程,例如 UNLINK、FLUSHALL ASYNC、FLUSHDB ASYNC 等非阻塞的删除操作;
  • 网络 I/O 解包从 6.0 开始用的是多线程。

但是这种分支模块,都只是辅助,最核心的还是处理架构,这块 Redis 始终是单线程的。

回答

Redis 核心处理是单线程的,在 6.0 中使用了多线程进行 I/O 解包、回包。其他一些边缘点的,比如使用多线程进行删除数据等异步任务,这个倒是 4.0 就引入了。

2. Redis 为什么选择单线程做核心处理?
#

分析

为什么用单线程,潜台词其实对应的是为什么不用多线程。

很多同学只说多线程有多大成本、多复杂,这样就容易被追问多线程这么多问题,那为什么 MySQL 等很多组件都是用多线程呢,总有优势吧?为啥 Redis 不利用这种优势?

所以这里需要从投入产出比分析,我们先看产出:

首先 Redis 的定位,是内存 k-v 存储,是做短平快的热点数据处理,一般来说执行会很快,执行本身不应该成为瓶颈,而瓶颈通常在网络 I/O,处理逻辑多线程并不会有太大收益。

再看投入:

引入多线程带来极大的复杂度,比如原来的顺序执行特性就不复存在,为了支持事务的原子性、隔离性,Redis 就不得不引入一些很复杂的实现,多线程模式也使得程序调试更加复杂和麻烦,会带来额外的开发成本及运营成本,也更容易犯错。同时,也带来上下文切换成本、同步机制的开销、线程本身也占据内存大小等投入成本。

回答

我们从投入产出来看。首先如果引入多线程,主要是希望充分利用多核的性能,但 Redis 的定位,是内存 k-v 存储,是做短平快的热点数据处理,一般来说执行会很快,执行本身不应该成为瓶颈,而瓶颈通常在网络 I/O,处理逻辑多线程并不会有太大收益。同时,支持多线程的话,我们需要付出更大的复杂度、以及多线程上下文切换、同步机制的开销等成本。这样综合来看,成本高且收益不大,所以最终选择了不做,事实也证明,单线程的 Redis 也确实足够高效。

3. Redis 单线程性能如何?
#

分析

这个主要考察直观的认知,Redis 实际表现为单机(普通 8 核 16G 的机器)读 10 多万,写几万,非常炸裂。可以说自己也用过 redis-benchmark 来测试过。

命令:
redis-benchmark -h 127.0.0.1 -p 6379 -t set,get -n 10000 -q

结果:
SET: 108695.65 requests per second
GET: 149253.73 requests per second

回答

Redis 单线程的性能是很好的,在普通机器每秒能 10 多万的读性能、几万的写性能。我在我自己的 mac 上也有用 redis-benchmark 来测试过,写性能高达 11 万,读性能高达 15 万。

4. 为什么单线程还能这么快?
#

分析

这里很多同学都能答到内存存储、高效的数据结构,但是遗漏 I/O 多路复用,其实某种意义上 I/O 复用是非常核心的,因为 Redis 使用单线程的核心,是瓶颈在 I/O 而不是 CPU,那 I/O 复用正好能对症下药。

  • 基于内存操作:Redis 的绝大部分操作在内存里就可以实现,数据也存在内存中,与传统的磁盘文件操作相比减少了 IO,提高了操作的速度;
  • 高效的数据结构:Redis 有专门设计了 STRING、LIST、HASH 等高效的数据结构,依赖各种数据结构提升了读写的效率;
  • 采用单线程:单线程操作省去了上下文切换带来的开销和 CPU 的消耗,同时不存在资源竞争,避免了死锁现象的发生;
  • I/O 多路复用:采用 I/O 多路复用机制同时监听多个 Socket,根据 Socket 上的事件来选择对应的事件处理器进行处理。

回答

我认为有三点,一个是内存存储,这是 Redis 的定位也是快的前提,一个是高效的数据结构,Redis 的数据结构可以说是追求极致,持续调优,最后一个是 I/O 多路复用,Redis 的瓶颈在 I/O 而不是 CPU,那 I/O 复用正好能对症下药。

5. Redis 6.0 之后引入了多线程,你知道为什么吗?
#

分析

其实大多数面试官,并不知道哪个版本引入了啥东西,除了 6.0 引入多线程,因为这个事情噱头很大,而且是动了核心处理逻辑的一部分。

要回答这个问题,就要回归到 Redis 瓶颈所在:是 I/O 而不是 CPU,但是随着互联网发展,请求量巨大的时候单线程在进行同步读写 I/O 的时间,单核 CPU 有时候也是不够用了。

回答

Redis 主要瓶颈是 I/O 而不是 CPU,但随着互联网的高速发展,在部分高并发场景,单核 CPU 也不见得处理得过来了,所以针对核心处理流程中的解包、发包这两个 CPU 耗时操作,进行了多线程优化,充分发挥多核优势。

6. Redis 6.0 的多线程是默认开启的吗?
#

分析

这个主要是想看你是否真的了解过 6.0 多线程。

如果能答出对默认关闭的看法,可能会加分。

回答

默认是关闭的,如果想要开启需要用户在 redis.conf 配置文件中修改。默认关闭一方面是为了兼容以前的,毕竟很多用户的认知中,Redis 是单线程的,第二可能也是认为多线程并不是必要的,在大多数场景不开启也是完全够用的。

7. Redis 6.0 的多线程主要负责命令执行的哪一块?
#

分析

Redis 主要瓶颈是 I/O 而不是 CPU,但随着互联网的高速发展,在部分高并发场景,单核 CPU 也不见得处理得过来了,所以针对核心处理流程中的解包、发包这两个 CPU 耗时操作,进行了多线程优化,充分发挥多核优势。

回答

原来核心流程中的 I/O 处理,包括解包和回包,也就是读写客户端 socket 的 I/O,这两部分都消耗 CPU 时间,多线程的引入主要也是为了解决单核 CPU 在大数据下还是不够用的问题。

Redis面试题库 - 这篇文章属于一个选集。
§ 3: 本文