这是一个非常核心的问题。Redis 的速度之所以如此之快,可以归结为 “两大基石,四项优化”。
这两大基石是内存存储和单线程架构,四项优化包括高效的数据结构、I/O 多路复用、虚拟内存机制和其他巧妙的设计。
下面我们来详细分解:
两大基石
1. 基于内存(In-Memory)存储
这是 Redis 速度快的最根本原因。
- 物理限制:内存的读写速度远远高于磁盘(SSD 或 HDD)。磁盘操作涉及机械寻道(对于 HDD)、系统调用、数据拷贝等,其延迟是毫秒级(ms)的;而内存访问是纳秒级(ns)的,两者相差10万倍甚至更多。
- 避免磁盘 I/O:Redis 的所有数据操作都在内存中完成,这意味着没有磁盘 I/O 瓶颈。它之所以能持久化,是通过异步的方式将数据快照或追加命令写入磁盘,这个操作不影响主线程处理客户端请求。
2. 单线程架构(核心网络模型)
这是 Redis 最容易被误解,但却是其设计精妙之处。
- 避免上下文切换和竞争开销:多线程编程虽然能利用多核,但会带来巨大的开销:线程创建、销毁、上下文切换(Context Switching)、以及为了保证线程安全而引入的锁(Mutex)等机制。这些开销在极高的并发场景下会非常显著。Redis 的单线程模型完全避免了这些开销。
- 不存在锁竞争:所有的数据操作在同一个线程中顺序执行,不存在多线程同时修改数据带来的竞态条件问题,因此也不需要额外的锁机制,简化了实现,提升了性能。
- 保证了原子性:单线程使得每个命令都是天然的原子操作,这让开发者无需担心并发修改的问题。
误区澄清:Redis 真的是“单线程”吗?
- 对于核心的网络请求和数据读写(
数据读写/协议解析/命令执行)来说,是单线程的。- 但是,Redis 在后端还运行着其他线程,用于处理一些慢操作,例如:
- 持久化:
bgsave(创建 RDB 快照)和bgrewriteaof(重写 AOF 日志)由子进程或子线程执行,不阻塞主线程。- 异步删除:从 Redis 4.0 开始,
UNLINK、FLUSHALL ASYNC等大键删除操作由后台线程处理,避免阻塞主线程。- I/O 线程:Redis 6.0 引入了多线程 I/O,允许使用多个线程来处理网络数据的读取和解析(
read/write),但命令的执行(execution) 依然是单线程的。这进一步提升了对于超大规模并发连接的处理能力。
四项优化
1. 高效的数据结构(High-Efficiency Data Structures)
Redis 不仅仅是简单的 Key-Value 存储,它为每种数据类型都精心设计了底层数据结构,以实现时间和空间上的最优平衡。
- 动态字符串(SDS):比 C 原生字符串更安全、高效,支持常数复杂度获取长度、预分配空间减少内存重分配次数。
- 双向链表、压缩列表(ziplist)、跳跃表(skiplist):
List,Hash,Sorted Set等类型会根据存储数据的数量和大小,智能地选择最节省内存或最高效访问的内部编码。 - 哈希表(hashtable):使用性能极佳的哈希表作为底层实现,并采用渐进式 rehash 来避免大字典扩容时的卡顿。
2. I/O 多路复用(I/O Multiplexing)
单线程如何能处理成千上万的并发连接?答案就是 I/O 多路复用技术。
- 原理:利用操作系统提供的机制(如 Linux 中的
epoll),单个线程可以监视多个网络连接(Socket)的读写事件。当某个连接有数据可读或可写时,操作系统会通知 Redis 线程进行处理。 - 效果:Redis 不需要为每个连接创建一个线程,极大地节省了资源。它就像是一个高效的“调度员”,虽然只有一个人(单线程),但通过一个先进的监控系统(多路复用),能同时照看多个窗口(连接),哪个窗口有客户(事件)来了就去处理哪个,避免了无谓的等待。
3. 虚拟内存机制(巧妙的内存管理)
虽然数据全在内存,但 Redis 通过一些策略让内存使用更高效。
- 多种编码格式:如第1点所述,一个
Hash键在元素少且小时,使用紧凑的ziplist存储;当数据量大时,自动转换为hashtable以提升操作效率。这种“空间换时间”或“时间换空间”的自动转换策略优化了整体性能。
4. 其他优化
- 优化的协议:Redis 使用简单、高效的 RESP(Redis Serialization Protocol) 协议。协议简单意味着解析速度快,减少了 CPU 开销。
- 精心编码的 C 语言:Redis 用 C 语言实现,更贴近操作系统,执行效率极高。
总结
我们可以用一个比喻来总结:
想象 Redis 是一个超高效的五星级餐厅。
- 内存存储:就像所有食材都放在厨师手边的案台上,而不是放在遥远的仓库(磁盘)里,取用极快。
- 单线程主厨:餐厅只有一位顶级主厨(单线程)负责炒菜(执行命令)。他不需要和其他厨师沟通协调(无锁竞争),也不会被频繁打断去干别的(无上下文切换),所以专注且高效。
- I/O 多路复用:有一位超级能干的经理(
epoll),他时刻盯着所有餐桌(连接)的状态。哪桌点好菜了、哪桌要结账了(事件),他立刻准确地告诉主厨,主厨按顺序处理即可。避免了主厨自己一个个去问“您好了吗?”(阻塞 I/O)。 - 高效的数据结构:就像厨房里各种专业的工具和切配好的半成品,让主厨的操作行云流水。
正是这些设计的完美结合,才造就了 Redis 无与伦比的性能。

173万+

被折叠的 条评论
为什么被折叠?



