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

处理流程:

  1. 监听多个客户端 socket
  2. 哪个 socket 有数据就绪
  3. 读取请求
  4. 执行命令
  5. 返回结果

因此 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)以及单线程命令执行 的架构设计,在避免锁竞争和线程切换开销的同时,实现了极高的并发处理能力。