高可用 Redis 之一:Redis 的单线程与多线程
在日常的使用、面试过程中,我们经常会被问到:Redis 是单线程的吗?网络上目前大部分的答案,都是十分肯定的告诉你:Redis 是单线程的。
但是,事实真的是这样的吗?事实上,Redis 早在 4.x 版本上就加了类多线程的操作,在 6.x 的版本中,正式支持了多线程。因此,对于Redis 是否是单线程这个问题,我们要这么回答:
- Redis 3.x 版本是单线程的;
- Redis 4.x 版本部分支持多线程;
- Redis 6.x 版本开始,是多线程的。
那么,为什么Redis 在6.x 之后开始使用多线程了呢?或者说,从当初的单线程到现在的多线程,Redis 的更新,是为了解决什么问题呢?
影响Redis 的因素
It's not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound. For instance, using pipelining Redis running on an average Linux system can deliver even 1 million requests per second, so if your application mainly uses O(N) or O(log(N)) commands, it is hardly going to use too much CPU. --Redis 官方FAQ
通过Redis 的官方FAQ,我们知道,影响 Redis 性能的只有内存大小、网络阻塞。CPU 的好坏并不会成为 Redis 性能的瓶颈。
因此,提高内存大小或者减少网络阻塞成为提高 Redis 性能的两个方向。内存可以直接直接买买买,故而如何提高网络阻塞的速度,就成为了 Redis 性能提升最关键的因素。这是首要前提,也是Redis 变为多线程最重要的因素之一。
单线程的弊端
在 Redis 3.x 阶段,由于IO多路复用、存放在内存、数据结构简单等特点,Redis 的性能已然能够吊打大多数市面上的KV数据库。
但是,无论怎么优化,单线程任务仍然是要前面任务完成、后面任务才能执行的过程。因此出现了这种情况:
如果存放了空间特别多的数据在value中,删除该key时,会不会占用时间,导致后续的任务要等待?
答案是会。
因此单线程的弊端很明显:当用户执行一个很耗费时间的命令时,后续的命令需要等待该命令执行完毕后才能进入执行阶段。
Redis 4.x
Redis 4.x 增加了异步删除的相关指令 unlink:元素不能被其它线程同步访问到,然后将big value交给异步线程回收。
但是 4.x 并不完全支持多线程,像是为了解决 单线程的加强版
Redis 6.x
Redis 6.x 发布后,Redis 宣布正式支持了多线程。但是需要注意:
Redis 工作线程是单线程的,对于整个Redis 来说,是多线程的
怎么理解呢?其实 6.x 的多线程,是为了解决网络阻塞造成的性能下降。它将I/O耗时的读写任务拆分给了一组独立的线程去执行,剩下的命令仍然由主线程串行执行并和内存的数据交互。
总结
- Redis 3.x 版本是单线程的,存在 大key 删除问题
- Redis 4.x 版本支持了部分多线程操作,主要是为了解决 3.x 的大key操作。
- Redis 6.x 版本是多线程的。目的是降低网络IO的时间消耗