一、线程模型基础类
Q1:Redis 是单线程还是多线程?
命令执行是单线程,这是 Redis 的核心设计。
但 Redis 并非完全单线程:
网络 IO:Redis 6 之前单线程,6.0 后可多线程。
持久化:RDB fork 子进程,AOF 重写 fork 子进程。
异步删除:
UNLINK、FLUSHALL ASYNC用后台线程。集群同步:后台线程处理。
所以准确说法是:主线程单线程处理命令,其他辅助功能多线程。
Q2:Redis 为什么用单线程?
避免锁竞争:单线程无并发问题,不需要加锁。
避免上下文切换:无线程切换开销。
实现简单:代码可维护性高。
瓶颈不在 CPU:Redis 瓶颈通常是内存和网络,不是 CPU。
原子性天然保证:单条命令天然原子。
Q3:单线程为什么还能高并发?
纯内存操作,单次命令执行极快(微秒级)。
IO 多路复用,一个线程管理大量连接。
非阻塞 IO,不让线程等待网络。
所以单线程也能支撑数万 QPS。
Q4:单线程有什么缺点?
无法利用多核 CPU:只能用一个核。
阻塞命令影响全局:如
KEYS、FLUSHALL会阻塞所有请求。大 key 操作慢:删除大集合会卡住主线程。
所以生产要避免阻塞命令。
二、IO 多路复用类
Q5:什么是 IO 多路复用?
一个线程同时监听多个文件描述符(fd)。
有事件就绪时通知程序处理,避免为每个连接创建线程。
Redis 用 epoll(Linux)实现。
Q6:select、poll、epoll 的区别?
Redis 在 Linux 用 epoll,其他平台用 kqueue、select 等。
Q7:epoll 的 LT 和 ET 模式?
LT(水平触发):只要 fd 可读/可写就一直通知。默认,简单。
ET(边缘触发):只在状态变化时通知一次,必须一次读完。
Redis 用 LT,简化处理。
Q8:Redis 的事件循环是什么?
主线程循环处理:
处理文件事件(网络 IO)。
处理时间事件(定时任务)。
阻塞在 epoll_wait 等待事件。
文件事件:读、写、连接、关闭。
时间事件:过期清理、持久化触发。
Q9:Redis 怎么处理客户端连接?
客户端连接后,注册到 epoll。
有数据可读时,事件循环调用读处理器。
解析 RESP 协议,执行命令,写回响应。
写完注册写事件,可写时发送。
三、Redis 6 多线程类
Q10:Redis 6 为什么引入多线程?
单线程网络 IO 成为瓶颈,尤其高并发下。
多线程处理网络读写和协议解析,提升吞吐。
命令执行仍单线程,保证原子性和简单性。
Q11:Redis 6 多线程具体做什么?
网络 IO:多线程读 socket、解析协议、写响应。
命令执行:仍由主线程单线程执行。
所以是“IO 多线程 + 命令单线程”。
Q12:Redis 6 多线程怎么配置?
io-threads N:IO 线程数,建议 CPU 核数,最多 8。io-threads-do-reads yes:读也多线程。默认关闭,
io-threads 1表示不启用。主线程也参与 IO,所以实际线程数 = io-threads。
Q13:多线程会带来并发问题吗?
不会。命令执行仍单线程,无共享数据竞争。
多线程只处理网络 IO,不碰数据。
所以不需要加锁。
Q14:为什么命令执行不也做成多线程?
会引入锁竞争、上下文切换、复杂度。
原子性难以保证。
单线程命令执行已足够快,瓶颈在网络 IO。
四、网络协议类
Q15:Redis 的通信协议是什么?
RESP(REgistered Simple Protocol)。
支持:简单字符串、错误、整数、批量字符串、数组。
RESP3(Redis 6)新增:Map、Set、Double、Boolean 等。
Q16:RESP 协议的特点?
简单、易解析、人类可读。
二进制安全。
请求是数组,响应按类型前缀。
例:
*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n
Q17:Redis 的 Pipeline 是什么?
一次发送多条命令,减少 RTT。
客户端打包命令,服务端依次执行,批量返回。
不是原子操作,中间可能插入其他命令。
注意批量大小,避免内存和阻塞。
Q18:Pipeline 和事务的区别?
Q19:Redis 的请求响应流程?
客户端发命令。
服务端 epoll 触发读事件。
解析 RESP,执行命令。
结果写入输出缓冲区。
epoll 触发写事件,发送响应。
五、阻塞与性能类
Q20:哪些操作会阻塞 Redis?
KEYS *:遍历所有 key。FLUSHALL、FLUSHDB:清库。DEL大 key:同步删除。HGETALL大 Hash。SORT、ZRANGE大集合。SAVE:同步持久化。Lua 脚本执行过长。
Q21:怎么避免阻塞?
用
SCAN替代KEYS。用
UNLINK替代DEL大 key。用
HSCAN、SSCAN分批。用
BGSAVE替代SAVE。Lua 脚本控制执行时间。
大 key 拆分。
Q22:SCAN 的原理?
游标遍历,每次返回部分 key。
不保证返回所有 key(rehash 期间可能重复)。
不阻塞,适合生产替代
KEYS。变体:
HSCAN、SSCAN、ZSCAN。
Q23:Redis 的 QPS 大概多少?
单机通常 10 万级 QPS,取决于命令复杂度。
Pipeline 可大幅提升。
瓶颈常在网络和内存,不在 CPU。
Q24:怎么提升 Redis 吞吐?
用 Pipeline 批量。
用多线程 IO(Redis 6)。
避免阻塞命令。
读写分离、集群分片。
合理设置连接数。
六、高频陷阱题
Q25:Redis 单线程,为什么还有并发问题?
命令执行单线程,单条命令原子。
但多条命令组合不是原子,如
GET后SET。需用事务、Lua、分布式锁保证。
Q26:Redis 6 多线程后,还需要单线程吗?
命令执行仍单线程,这是核心。
多线程只加速网络 IO。
所以“单线程”说法仍成立(指命令执行)。
Q27:io-threads 越大越好吗?
不是。建议不超过 CPU 核数,通常 4~8。
太大反而上下文切换开销大。
低并发时多线程无收益。
Q28:Pipeline 会阻塞 Redis 吗?
单次 Pipeline 命令太多会占用内存和主线程。
要控制批量大小,如每次几百条。
不会阻塞其他客户端,但会延迟处理。
Q29:Redis 为什么不用多线程处理命令?
锁竞争、上下文切换、复杂度高。
原子性难保证。
单线程已够快,瓶颈不在命令执行。
Q30:epoll 比 select 快在哪?
epoll 用红黑树管理 fd,O(1) 取就绪事件。
select 每次遍历所有 fd,O(n)。
epoll fd 无上限,select 有 1024 限制。
epoll 内核回调,无需轮询。
评论