Redis 线程模型
Redis 以高性能著称,其核心原因之一就是其独特的 线程模型设计。很多人听说 Redis 是“单线程”,但实际上 Redis 的线程模型在不同版本中已经发生了演进。理解 Redis 的线程模型,对于理解其高性能原理、以及在高并发场景中的使用方式非常重要。
本文将从 Redis 单线程设计、事件驱动模型、IO 多路复用以及 Redis 6 之后的多线程改进几个方面进行介绍。
Redis 为什么选择单线程
Redis 早期版本(Redis 6 之前)的核心执行模型是 单线程处理命令。
也就是说:
- 所有客户端请求
- 所有命令执行
- 数据读写
都由 一个主线程完成。
但需要注意的是:
Redis 的单线程 只指命令执行单线程,并不是整个 Redis 进程只有一个线程。例如:
- RDB 持久化
- AOF rewrite
- 异步删除
- BIO 线程
这些其实都是后台线程。
Redis 的核心线程只负责:
- 网络 IO
- 命令解析
- 命令执行
- 返回结果
单线程为什么依然很快
很多人会疑惑:单线程为什么还能支撑几十万 QPS?
Redis 的高性能主要来自以下几个原因。
内存数据库:Redis 所有数据都在内存中,避免了磁盘 IO。内存速度和磁盘速度不是一个数量级的。
避免线程切换开销:单线程执行命令,避免了加锁,竞争,复杂并发控制
IO 多路复用
Redis 并不是一次只处理一个连接,而是使用 IO 多路复用模型。
Redis 使用的 IO 模型包括:
- epoll(Linux)
- kqueue(MacOS / BSD)
- select
- evport
Redis 会通过事件循环监听所有客户端连接:
┌───────────────┐
Client 1 ───▶│ │
Client 2 ───▶│ │
Client 3 ───▶│ IO Multiplex │
Client N ───▶│ │
└───────┬───────┘
│
▼
Redis EventLoop
│
▼
Command Execute处理流程:
- 监听多个客户端 socket
- 哪个 socket 有数据就绪
- 读取请求
- 执行命令
- 返回结果
因此 Redis 可以用 单线程同时处理大量连接。
Redis 6 的多线程改进
随着硬件发展,CPU 核数越来越多,Redis 的单线程模型在某些场景下会遇到瓶颈,瓶颈主要在 网络 IO。
例如:
- 大量客户端连接
- 网络数据收发量巨大
因此 Redis 6 引入了 IO 多线程。
执行流程变为:
Client Request
│
▼
IO Threads (read)
│
▼
Main Thread Execute Command
│
▼
IO Threads (write)因此:
- 命令执行仍然是单线程
- IO 操作可以并行
Redis 单线程的使用建议
由于 Redis 命令执行是单线程,因此需要注意以下几点:
避免慢命令
例如:
KEYS *这类命令会阻塞 Redis。
应该使用:
SCAN控制大 Key
大 Key 会导致:
- 网络阻塞
- CPU 执行时间变长
建议:
- 拆分数据
- 使用 hash / set
使用 Pipeline
Pipeline 可以减少网络往返:
client -> redis -> client提升整体吞吐量。
总结
Redis 通过 内存操作、IO 多路复用、事件驱动(Event Loop)以及单线程命令执行 的架构设计,在避免锁竞争和线程切换开销的同时,实现了极高的并发处理能力。