【Redis】底层原理解析(SDS / 跳表 / IO多路复用 / 单线程模型)

Redis 底层原理全解析(SDS / 跳表 / IO多路复用 / 单线程模型)

📌 本篇目标:

  • 从"会用 Redis" → "理解 Redis 为什么这么设计"
  • 掌握面试中的"底层原理问题"
  • 建立源码级思维

一、Redis 为什么快?

在前面我们说过 Redis 快,但这一篇我们从底层重新理解:


✅ 本质原因(升级版)

text 复制代码
Redis 快 = 数据结构优化 + IO模型优化 + 架构设计优化

拆解为 4 大核心

text 复制代码
1. 高效数据结构(SDS / 跳表)
2. 内存操作(无磁盘IO)
3. IO多路复用(高并发)
4. 单线程模型(无锁)

二、Redis 字符串底层:SDS


问题:为什么不用 C 原生字符串?

C 字符串:

c 复制代码
char str[] = "hello";

问题:

  • ❌ 需要遍历才能知道长度(O(n))
  • ❌ 容易缓冲区溢出
  • ❌ 不支持动态扩展

✅ Redis 解决方案:SDS(Simple Dynamic String)


SDS 结构(核心)
text 复制代码
struct sdshdr {
    int len;     // 已使用长度
    int free;    // 剩余空间
    char buf[];  // 数据
}

优势


1️⃣ 获取长度 O(1)
text 复制代码
直接读取 len

2️⃣ 防止缓冲区溢出

自动扩容


3️⃣ 空间预分配
text 复制代码
如果扩容 → 多分配一部分空间

好处:

减少频繁内存分配


4️⃣ 惰性释放

删除后不立即回收空间


面试回答模板

text 复制代码
Redis 使用 SDS 替代 C 字符串,

优势:
1. O(1) 获取长度
2. 防止缓冲区溢出
3. 空间预分配 + 惰性释放

三、Redis 有序集合底层:跳表(SkipList)


为什么不用红黑树?

Redis 选择跳表的原因:

text 复制代码
实现简单 + 性能接近平衡树

跳表结构理解

text 复制代码
Level 3:  1 ----------- 9
Level 2:  1 ------ 5 -- 9
Level 1:  1 -- 3 -- 5 -- 7 -- 9

数据结构组成

每个节点包含:

  • Key:存储的数据值(或分数)。
  • Forward Pointers:一个数组,指向该节点在每一层的下一个节点。
  • Level:该节点拥有的层数(高度)。

类似"多层索引"


查找过程

text 复制代码
从最高层 `max_level`开始:

1. 在当前层向右遍历,直到下一个节点的值大于等于目标值。
2. 如果当前节点值等于目标值,返回成功。
3. 否则,**下降一层**,重复步骤 1。
4. 如果下降到第 0 层仍未找到,返回失败。

时间复杂度

text 复制代码
查询 / 插入 / 删除:O(log n)

Redis 中的应用

ZSet(有序集合)


面试回答模板

text 复制代码
ZSet 使用跳表 + hash 表实现:

- 跳表 → 排序
- hash → 快速查找

四、Redis List 底层:QuickList


为什么不用普通链表?

问题:

  • ❌ 内存碎片多
  • ❌ 访问慢

✅ QuickList(链表 + 压缩列表)

text 复制代码
LinkedList + ZipList

结构

text 复制代码
[ziplist] <-> [ziplist] <-> [ziplist]

优势

  • 节省内存
  • 保持链表灵活性

五、Redis IO 模型:IO 多路复用


问题:Redis 如何处理高并发?

👉 单线程怎么处理上万连接?


✅ 答案:IO 多路复用


类比理解

text 复制代码
一个服务员同时负责多张桌子

常见实现

  • select(轮询通知)
  • poll(改进的轮询通知)
  • epoll(Linux 事件回调)
特性 Select Poll Epoll
底层机制 轮询(线性扫描) 轮询(线性扫描) 回调/就绪列表
效率 连接数多时,效率O(n),低下 连接数多时,效率O(n),低下 效率O(1),与活跃连接数相关,高并发下极高效
最大连接数 有限制(FD_SETSIZE,通常1024) 理论上无硬性限制 无硬性限制,受系统资源限制
工作模式 仅水平触发 仅水平触发 支持水平触发和边缘触发
内存与数据拷贝 每次调用需在内核和用户空间拷贝整个fd集合 每次调用需拷贝整个pollfd数组 使用内存映射,共享内存,减少拷贝开销
使用复杂度 较高(需管理epoll实例)
跨平台 几乎所有平台 大部分Unix-like系统 Linux特有

工作流程

text 复制代码
1. 监听多个 socket
2. 哪个有数据 → 处理哪个

优势

  • 不需要多线程
  • 高效处理大量连接

面试回答模板

text 复制代码
Redis 使用 IO 多路复用(epoll),

可以在单线程下高效处理大量连接请求

六、Redis 单线程模型


Redis 真的是单线程吗?

👉 面试陷阱题!


✅ 正确答案:

text 复制代码
核心命令执行是单线程

但:

  • 网络 IO → 多路复用
  • 持久化 → 子线程

为什么用单线程?


1️⃣ 避免锁竞争
text 复制代码
多线程 → 加锁 → 性能下降

2️⃣ 减少上下文切换

3️⃣ 内存操作本身就很快

❗ 面试加分点

text 复制代码
Redis 性能瓶颈 ≠ CPU  
而是:内存 + 网络

七、Redis 内存淘汰策略


问题:内存满了怎么办?


✅ 8 种策略(重点记 3 个)
策略 说明
noeviction 不删除
allkeys-lru ⭐ 最近最少使用
allkeys-random 随机
volatile-lru 有过期的 key 中淘汰

推荐
text 复制代码
allkeys-lru(最常用)

八、Redis 过期删除策略


Redis 如何删除过期 key?


✅ 三种方式

1️⃣ 定时删除 ❌(不用)

2️⃣ 惰性删除

用到才检查


3️⃣ 定期删除

随机抽查


面试总结

text 复制代码
Redis 使用:惰性删除 + 定期删除

九、Redis 线程模型演进


Redis 6 之后变化

引入:

text 复制代码
多线程处理 IO

但:

text 复制代码
命令执行仍然是单线程

十、终极面试总结


Redis 为什么这么快?

text 复制代码
1. 内存操作
2. 高效数据结构(SDS / 跳表)
3. IO 多路复用
4. 单线程避免锁竞争

Redis 底层核心结构

text 复制代码
String → SDS  
List → QuickList  
ZSet → 跳表  

Redis 线程模型

text 复制代码
核心单线程 + IO多路复用 + 后台线程
相关推荐
用户5757303346245 小时前
从 SQL 到对象:Prisma 如何成为全栈开发的“降维打击”利器
数据库
三更两点5 小时前
智能代理工具包:MCP vs. Agent Skills vs. AGENTS.md
数据库·人工智能
Chasing Aurora5 小时前
整理常用的开发工具使用问题和小贴士(二)——软件和浏览器
redis·python·mysql·maven
丸辣,我代码炸了5 小时前
PostgreSQL 大数据查询与索引优化核心总结
大数据·数据库·postgresql
停水咋洗澡6 小时前
Redis Sentinel高可用实战:主从自动故障转移
java·redis·sentinel
等....6 小时前
Redis使用
数据库·redis·mybatis
betazhou6 小时前
记一次Oracle REDO在线日志损坏故障修复
数据库·oracle·redo·ora-00600
一只小bit6 小时前
Redis 初步入门教程:简单介绍和安装配置
数据库·redis·缓存
ChatInfo6 小时前
Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模
数据库·人工智能·mysql
SPC的存折6 小时前
6、MySQL设置TLS加密访问
linux·运维·服务器·数据库·mysql