Redis 真的是“单线程”吗?
不完全正确!
我们常说的“Redis 是单线程”,指的是:
Redis 的核心数据操作(如 GET、SET、DEL、INCR 等)
而 Redis 的其他线程包括:
- 后台线程:用于 持久化(bgsave、bgrewriteaof)
- 后台线程:用于 异步释放内存(lazyfree)
- Redis 6.0+:网络 I/O 多线程(但仍由主线程调度)
📌 所以更准确的说法是:
Redis 核心逻辑是单线程 + I/O 多路复用 + 事件驱动
核心原理:I/O 多路复用(I/O Multiplexing)
什么是 I/O 多路复用?
在高并发场景下,传统阻塞 I/O 模型需要为每个连接创建一个线程,成本极高。
而 I/O 多路复用 允许:
一个线程同时监听多个 socket 连接的 I/O 事件(如可读、可写)
当某个 socket 有数据可读时,操作系统通知 Redis 主线程,然后处理该请求。
事件驱动模型:Redis 如何处理请求?
Redis 的事件循环(Event Loop)是其高性能的核心。流程如下:
+------------------+| 客户端连接 |+--------+---------+|v+------------------+| epoll_wait() | ← 监听所有 socket+--------+---------+|v+------------------+| 有事件就绪?(是) | → 处理可读/可写事件+--------+---------+|v+------------------+| 执行命令(GET/SET)| ← 单线程执行,原子性+--------+---------+|v+------------------+| 返回响应给客户端 |+------------------+
关键优势:
优势 | 说明 |
✅ 无锁竞争 | 单线程操作数据,无需加锁 |
✅ 原子性保证 | 命令执行是原子的 |
✅ 低上下文切换开销 | 无需线程调度 |
✅ 高吞吐 | 快速响应大量小请求 |
为什么 KEYS *
会阻塞 Redis?
虽然 Redis 使用 I/O 多路复用处理网络,但命令执行仍在主线程。
KEYS *
该命令会:
- 遍历整个键空间
- 如果有 100 万个 key,可能耗时数百毫秒
- 在此期间,主线程被占用,无法处理其他请求
📌 结果:
所有其他客户端请求被阻塞,导致 服务雪崩!
✅ 正确做法:使用 SCAN
命令增量遍历:
SCAN 0 MATCH * COUNT 1000
Redis 6.0 多线程:为什么又引入了多线程?
从 Redis 6.0 开始,引入了 I/O 多线程(默认关闭):
# redis.conf
io-threads 4
io-threads-do-only-io yes
多线程负责什么?
- ✅ 网络 I/O 读写(接收请求、发送响应)
- ❌ 不负责命令执行(仍由主线程完成)
为什么引入?
- 现代服务器 CPU 核心多,单线程无法充分利用
- 网络 I/O 成为瓶颈(尤其大 value 传输)
- 多线程处理 I/O,主线程专注命令执行
📌 性能提升:在高并发大 value 场景下,QPS 可提升 2~3 倍。