Redis 6.0 引入多线程模型的核心目的是解决网络 IO 瓶颈问题,通过多线程并行处理网络读写请求提升吞吐量,同时保持命令执行的单线程特性以避免并发问题。 以下是详细解读:
一、Redis 6.0 之前为何不使用多线程?- 性能瓶颈不在 CPU:Redis 的性能主要受内存和网络限制,而非 CPU。在普通 Linux 系统上,通过 pipelining 技术,Redis 单线程即可每秒处理 100 万请求,且 O(N) 或 O(log(N)) 命令的 CPU 占用极低。
- 单线程维护性高:多线程会引入执行顺序不确定性、并发读写冲突、线程切换开销等问题,增加系统复杂度。单线程模型避免了锁竞争和死锁风险,使 Hash 惰性 Rehash、Lpush 等操作可无锁执行。
- 事件模型高效:Redis 通过 AE 事件模型和 IO 多路复用(如 epoll)实现高并发处理,无需多线程即可满足需求。
二、Redis 6.0 之前的“单线程”具体指什么?- 主线程处理全流程:Redis 主线程负责接收客户端请求(Socket 读)、解析命令、执行命令、返回结果(Socket 写)等全流程操作。
- 命令排队执行:所有命令进入 Socket 队列后,主线程按顺序逐个执行,确保线程安全。
- 后台线程/子进程:部分操作(如数据删除、RDB 快照生成、AOF 重写)由后台线程或子进程完成,避免阻塞主线程。
三、Redis 6.0 为何引入多线程?四、主线程与 IO 多线程协作流程- 连接建立与队列分配:主线程接收客户端连接请求,获取 Socket 并放入全局等待读队列。
- Socket 分配:主线程轮询将可读 Socket 分配给 IO 线程。
- 并行读取:IO 线程并行读取 Socket 数据并解析为 Redis 命令。
- 命令执行:主线程阻塞等待所有 IO 线程完成后,按顺序执行解析出的命令。
- 结果回写:主线程阻塞等待 IO 线程将执行结果回写到 Socket。
- 队列清空:主线程清空全局队列,等待后续请求。
核心思路:将网络读写任务拆分到独立线程,实现 Socket 并行处理,但命令执行仍由主线程串行完成。
五、如何开启多线程?六、多线程模型的缺陷- 非标准 Multi-Reactors 模型:IO 线程仅负责读取和解析命令,不执行命令,主线程仍需等待所有 IO 线程完成,多核利用率有限。
- 主线程忙轮询:主线程在分配任务后需忙轮询等待 IO 线程,可能引入额外延迟。
- 折中方案:该模型在兼容性和性能间取得平衡,但未完全发挥多核优势。
七、总结与思考