Skip to main content

Redis 基础

Redis 为什么这么快?​

在后端开发的世界里,Redis 几乎是“高性能”的代名词。单机 QPS(每秒查询率)轻松破 10 万,这种极致的性能到底是怎么压榨出来的?

很多人会脱口而出:“因为它是在内存里操作的。” 没错,但这只是冰山一角。Redis 的快,是数据结构、线程模型、网络 IO 三者高度契合的结果。

1. 基于内存​

这是最直观的原因。传统的数据库(如 MySQL)数据存储在磁盘上,虽然有 Buffer Pool 等缓存机制,但最终还是难逃磁盘寻道时间的制约。

  • 内存读写速度:内存的访问延迟通常在 100 纳秒级别,而机械硬盘在 10 毫秒级别,两者相差 10 万倍。
  • 简单直接:Redis 跳过了磁盘寻址的物理开销,CPU 直接与内存对话,速度自然起飞。

2. IO 多路复用模型​

Redis 使用单线程事件循环配合 I/O 多路复用技术,让单个线程可以同时处理多个网络连接上的 I/O 事件(如读写), 避免了多线程模型中的上下文切换和锁竞争问题。虽然是单线程,但结合内存操作的高效性和 I/O 多路复用,使得 Redis 能轻松处理大量并发请求。

3. 极简的单线程模型​

看到这可能会有疑问:为什么单线程反而快?难道多核 CPU 不香吗?

其实,对于 Redis 这种纯内存操作的任务,CPU 往往不是瓶颈,内存带宽和网络延迟才是。使用单线程有三大绝招:

1.没有上下文切换:多线程在切换执行环境时,需要保存和恢复寄存器状态,这非常耗时。

2.避免锁竞争:在多线程环境下,为了保证数据安全,必须引入锁机制(如读写锁、互斥锁)。锁的申请、释放、以及等待锁导致的死锁问题,会极大拖慢速度。

3.代码更易维护:单线程逻辑简单,减少了不可预见的 Bug。

小贴士:Redis 6.0 引入了多线程,但那只是用来处理网络数据的读写和协议解析,执行命令的核心逻辑依然是单线程的。

4. 数据结构​

Redis 的开发者在数据结构上可谓“丧心病狂”。它没有直接使用标准的 C 语言字符串,而是自己造了一套:

  • SDS(简单动态字符串):获取字符串长度的时间复杂度是 O(1)O(1),且减少了内存重新分配的次数。
  • 跳表 (SkipList):在实现有序集合(ZSet)时,跳表提供了媲美红黑树的性能,但实现起来更简单,范围查询极其高效。
  • 压缩列表 (ZipList) / 紧凑列表 (Listpack):在数据量小时,通过连续的内存块存储,极大地提高了 CPU 缓存命中率。

5. 多线程的引入​

随着网络硬件的发展(比如 10G/100G 网卡),Redis 的瓶颈逐渐从“内存处理速度”转移到了 “网络 IO 读写” 上。 当并发量极高时,单线程在“读”和“写”网络数据上花费了太多时间,导致核心的“内存操作”被晾在一边。

Redis 6.0 引入的多线程被称为 Threaded IO。

  • 主线程(核心):依然负责执行所有的 SET、GET 等命令。这意味着你依然不需要担心并发竞争,不需要加锁。

  • IO 线程(辅助):专门负责从 Socket 中读取请求、解析协议,以及将处理结果写回 Socket。