Redis 之所以能达到十万级甚至百万级 QPS 的超高性能,是从架构设计、数据存储、执行模型、底层细节四个维度深度优化的结果,每一个环节都围绕 "减少开销、提升效率" 展开。
一、核心架构:单线程 + 非阻塞 I/O 模型,规避多线程性能损耗
Redis 的核心命令执行逻辑(redis-server 的主线程)是单线程 的,这是它高性能的基石,同时结合 I/O 多路复用 技术处理并发连接,完美解决了 "单线程并发低" 的问题。
1. 单线程的优势:无线程切换与锁竞争开销
(1)避免上下文切换:多线程模型中,CPU 需要在多个线程间切换,保存 / 恢复线程的寄存器、栈信息,这会消耗大量 CPU 资源。Redis 单线程全程只执行一个任务流,没有切换成本。
(2)无锁竞争问题:多线程操作共享数据时,需要加锁(如互斥锁、读写锁)来保证线程安全,锁的获取、释放会带来额外开销,甚至可能引发死锁。Redis 单线程天然保证命令的原子性执行,无需加锁。
注意:Redis 6.0 引入了多线程 I/O,但仅用于处理网络请求的读写(如 socket 的 read/write 操作),核心的命令执行逻辑仍然是单线程,目的是提升大报文场景下的网络吞吐量,而非改变单线程执行模型。
2. 非阻塞 I/O + 多路复用:单线程处理上万并发连接
Redis 基于 ae 事件驱动框架 (自主实现),整合了 epoll(Linux)、kqueue(BSD)、select 等多路复用技术,其核心原理是:
(1)主线程通过一个事件循环,同时监听多个客户端的 socket 连接的 "读事件""写事件";
(2)当 socket 有数据可读 / 可写时,才触发对应的处理逻辑,而非阻塞等待;
(3)多路复用技术可以让单线程高效管理数万甚至数十万的并发连接,且资源消耗极低(远低于多线程模型)。
二、存储层:纯内存操作,摆脱磁盘 I/O 瓶颈
这是 Redis 快的最根本原因 ------ 数据全部存储在内存中,内存与磁盘的读写速度差距达到千倍甚至万倍:
| 存储介质 | 读写延迟 | 带宽 |
|---|---|---|
| 内存 | 纳秒级(~10ns) | GB/s 级别 |
| 机械硬盘 | 毫秒级(~10ms) | MB/s 级别 |
| SSD 硬盘 | 微秒级(~100μs) | 数百 MB/s 级别 |
(1)内存操作的低延迟:
Redis 的所有命令(如 GET/SET/HGET)都是直接操作内存中的数据结构,无需磁盘寻址、磁头转动等耗时操作;
(2)持久化不影响性能:
1.RDB:通过子进程生成内存快照,主线程不参与;
2.AOF:写命令先写入内存缓冲区,再由后台线程异步刷盘;
3.持久化操作与核心命令执行完全解耦,不会阻塞主线程,虽然Redis 支持 RDB、AOF 两种持久化方式,但都是异步执行的:
三、数据结构:定制化高效实现,兼顾性能与内存
Redis 没有直接使用 C 语言的原生数据结构(如链表、哈希表),而是针对缓存场景定制了轻量化、高性能的专属数据结构,在时间复杂度和空间复杂度上做到极致优化:
1. 基础数据结构的定制优化
| Redis 类型 | 底层数据结构 | 核心优化点 |
|---|---|---|
| String | 简单动态字符串(SDS) | 1. 预分配空间:扩容时预留冗余空间,减少内存重分配次数;2. 二进制安全:支持存储图片、视频等二进制数据;3. 记录长度:O (1) 获取字符串长度,无需遍历。 |
| Hash | 压缩列表(ziplist)→ 哈希表 | 1. 小数据量用 ziplist:连续内存存储,减少内存碎片和指针开销;2. 大数据量自动切换哈希表:查询 / 插入 / 删除 O (1) 复杂度。 |
| List | 压缩列表(ziplist)→ 双向链表 | 1. 双向链表支持首尾 O (1) 插入 / 删除;2. 配合 ziplist 优化小数据场景的内存占用。 |
| Set | 整数集合(intset)→ 哈希表 | 1. 元素为整数且数量少时用 intset:紧凑存储,无需哈希表的指针开销;2. 元素复杂时切换哈希表:保证 O (1) 去重和查询。 |
| ZSet | 压缩列表(ziplist)→ 跳表 + 哈希表 | 1. 跳表:查询 / 插入 / 删除平均 O (log n) 复杂度,实现简单(比红黑树少了旋转操作);2. 哈希表:O (1) 获取元素的 score 值;3. ziplist 优化小数据场景。 |
2. 高级数据结构的针对性设计
(1)Bitmaps:基于 String 实现,用一个二进制位表示一个状态,1MB 内存可存储 800 多万个状态,极大节省内存;
(2)HyperLogLog:固定占用 12KB 内存,实现海量数据的基数统计,无需存储具体元素;
(3)Geo:基于 ZSet 实现,将经纬度编码为 52 位整数作为 score,复用跳表的有序性实现范围查询。
四、执行层:极简命令流程,减少不必要的开销
Redis 的命令执行流程被极度精简,从 "请求接收" 到 "响应返回" 的每一步都没有冗余操作:
1. 无内核态 / 用户态切换的额外开销(部分场景)
Redis 的网络模型基于用户态的 I/O 多路复用,无需频繁切换到内核态处理 socket 读写,减少了系统调用的开销。
2. 命令的高效解析与执行
(1)命令协议简单 :Redis 采用 RESP 协议(Redis Serialization Protocol),这是一种简单的文本协议,解析速度极快,相比 JSON、Protobuf 等复杂协议,CPU 开销更低;
(2)命令执行无复杂逻辑 :Redis 的命令大多是原子性的简单操作(如 INCR/HGET),没有事务回滚、复杂查询优化等耗时逻辑;
(3)避免数据拷贝:在处理命令时,Redis 尽量减少内存数据的拷贝(如使用指针直接操作数据)。
五、其他细节优化
-
批量操作支持 :提供
MSET/HMSET/PIPELINE等命令,允许客户端一次性发送多个命令,减少网络往返次数(网络延迟是分布式场景的主要瓶颈之一); -
CPU 亲和性:Redis 支持设置 CPU 亲和性,将进程绑定到指定的 CPU 核心,避免 CPU 缓存失效(多核 CPU 中,进程切换核心会导致缓存数据丢失);
-
底层代码优化:Redis 核心代码用 C 语言编写,执行效率接近硬件原生性能,且代码精简(核心代码量不大),减少了不必要的函数调用和分支判断。
总而言之,Redis 的高性能是 "单线程非阻塞 I/O + 纯内存存储 + 定制化数据结构 + 极简执行流程" 四重优势叠加的结果。每一个设计决策都围绕 "减少开销、提升效率" 展开,最终实现了远超传统磁盘数据库的性能表现。