Redis 的单线程:一个在面试中反复被误解的设计
我在面试里其实挺喜欢问 Redis 的,尤其是那种简历上写着“高并发系统设计”“缓存中台”“QPS 十万+”的同学。问题通常不复杂,甚至有点老掉牙:“你怎么看 Redis 的单线程?”
答案往往也很整齐: “Redis 是单线程的,所以性能有限,但靠内存弥补。”听到这里,我心里基本已经有个分数区间了。
不是说错,而是说得太像背的。
很多人对 Redis 的理解,停留在一句被反复引用的话上:Redis 是单线程的。但真正在生产里踩过坑、扛过流量、被报警叫醒过的人,通常会下意识补一句:
“准确说,只有命令执行是单线程的。”
这句话一出来,味道就不一样了。
Redis 的主线程确实只负责一件事:顺序执行命令。这一点非常坚定,几乎是它整个设计的锚点。但网络收发、磁盘刷盘、AOF 重写、RDB 保存,这些活并不是挤在同一个线程里完成的。后台线程一直都在,只是它们被刻意藏在“你不需要操心”的地方。
我见过不少候选人把 Redis 描述成“完全单线程”,那种说法听着就像把一辆现代汽车理解成“只有一个方向盘”。对,但明显不够。
另一个在面试中经常出现的误区是: Redis 用不了多核 CPU。
这个说法在几年前或许还能勉强成立,但现在基本属于“信息没更新”。
当我听到有人主动提到 I/O threads,而且不是顺口一提,而是知道它干什么、解决什么问题,我通常会在心里默默加分。
Redis 并没有把命令执行拆成多线程,但它确实在 I/O 层 上做了让步。启用 io-threads 之后,网络读写可以分摊到多个核心上。真实的基准测试里,吞吐量提升不是象征性的,而是实打实的——三四成,甚至翻倍。
这时候如果你还坚持“Redis 只能吃一个核”,那就有点像在用 2026 年的服务器,讲 2015 年的故事。
还有一个我特别爱追问的点: “单线程是不是就一定慢?”
这个问题的陷阱在于,它考的不是 Redis,而是你对系统性能的直觉。
很多人会下意识把“多线程 = 快”当成常识,但只要你真的在 JVM 里和锁、上下文切换、缓存失效搏斗过,就会对这个等号保持警惕。
Redis 的单线程之所以快,恰恰是因为它什么都没做:
没有锁竞争,没有线程切换,没有为了同步而牺牲 CPU cache 的一致性。
数据就在内存里,命令短得像眨眼。
在高并发、小操作的场景下,这种“极端克制”的设计,反而比很多花里胡哨的多线程方案跑得更稳、更可预期。
所以当有人在面试里说:“单线程其实是 Redis 的性能优势”,而不是缺点,我通常会抬头认真听。
当然,也别把话说满。我偶尔也会听到另一种极端:“Redis 单线程,所以根本不可能有竞态条件。”
这时候我一般会轻轻追一句:“你说的是哪一层?”
是的,单条命令是原子的,这是 Redis 给你的保证。但如果你把几个命令拆开,在不同客户端里交错执行,那该乱的还是会乱。
Redis 没替你兜住“命令序列”的一致性,它只保证自己那一步不出错。
能意识到这层边界的人,通常是真的用过,而不是只读过。
**还有一个小点,在面试里特别容易暴露经验值: BLOP 会不会把 Redis 卡死?
新手通常会犹豫,老手几乎都会摇头。阻塞的是客户端,不是服务器。
Redis 早就把这种“看起来很危险”的命令,做成了对系统本身无害的形态。你卡在那儿等数据,不代表别人不能继续用。
这类问题,本质上考的是你敢不敢用这些命令,而不是知不知道它们存在。
*说到最后,其实绕不开一个问题: Redis 为什么这么执着于单线程?
如果一个线程在 LPUSH,另一个线程在 LPOP,你为了并发要加多少锁?值不值?列表、集合、有序集合、流,这些结构一旦并发修改,复杂度会指数级上升。
Redis 选择了更“笨”的路: 一个厨师只负责做菜,备料和收拾交给助手。
这样代码更简单,行为更确定,也更不容易在凌晨三点把人叫醒。
在面试中,我从来不指望有人把这些话说得多漂亮,但我很容易听出来:
你是在复述“Redis 是单线程”,
还是你真的理解了,它为什么坚持这样做。
这两者,差得不止一个问题的分数。