Redis 底层原理与性能
Redis 系统讲解第四篇:为什么快。书上看的原理篇读书笔记——SDS、渐进式 rehash、跳表、单线程模型、淘汰策略,最后落到"大 key / 热 key / 事务与 Lua"这些工程上真正会撞上的问题。
为什么单线程还能这么快
纯内存操作(微秒级) + 单线程无锁无上下文切换 + IO 多路复用(epoll 同时监听万个连接)
书里的经典比喻:多线程像多个窗口排队办业务(要协调),Redis 是一个超快的柜员 + 叫号系统(epoll)——瓶颈从"调度"转移到"单个操作的耗时",这就是为什么大 key 是毒瘤:一个操作慢,所有请求排队。
Redis 6.0 的多线程只用于网络读写和协议解析,命令执行仍是单线程——所以"单线程模型"的原子性结论至今成立。
SDS:Redis 自己的字符串
C 字符串的三个痛点 → SDS 的三个设计:
| C 字符串问题 | SDS 方案 |
|---|---|
strlen 要 O(n) 扫到 \0 |
头部记录 len,取长度 O(1) |
| 二进制不安全(\0 截断) | 按 len 读取,二进制安全(能存图片/序列化数据) |
| 拼接必 realloc | 空间预分配 + 惰性释放,减少 realloc |
dict 与渐进式 rehash
Redis 的全局键空间就是一张 dict。扩容时不一次搬完(百万 key 搬一夜就卡死),而是渐进式 rehash:新旧两张表同时挂着,每次增删改查顺手搬一个桶,后台定时任务也帮着搬——期间读先查旧表再查新表,写只进新表。
💡 这是"把一次大卡顿摊薄成无数次小卡顿"的经典设计——和 Redis 一贯的"不能阻塞主线程"哲学一脉相承。
跳表(skiplist):ZSet 的排序引擎
多层级链表:上层是下层的"快车道",查询从顶层往下贪心,期望 O(log n)。
书里对比过的"为什么不用平衡树/红黑树":跳表实现简单、范围查询天然友好(底层是有序链表,ZRANGE 顺着走就行)、增删只改前后指针不做旋转。Redis 作者的原话大意:功能差不多时,选好写的那个。
ZSet 实际是 skiplist + dict 双结构:dict 负责 member→score 的 O(1) 查分,skiplist 负责按 score 排序的范围查询——空间换时间。
listpack 与数据结构的"小数据紧凑化"
老版本用 ziplist(紧凑连续存储),缺陷是连锁更新(改一个元素可能引发后续所有节点的 prevlen 字段级联重写)。新版本逐步换成 listpack(每个元素只记自己的长度,天然无连锁更新)。配合 quicklist(List:双向链表把多个 listpack 串起来),构成"大数据用链式、小数据用紧凑"的通用思路。
内存淘汰策略八选一
| 策略 | 范围 | 算法 |
|---|---|---|
| noeviction(默认) | 不淘汰,内存满写报错 | — |
| allkeys-lru / volatile-lru | 全部 / 仅带 TTL | 最近最少使用 |
| allkeys-lfu / volatile-lfu | 同上 | 最不经常使用(4.0+,计数衰减) |
| allkeys-random / volatile-random | 同上 | 随机 |
| volatile-ttl | 仅带 TTL | 剩余寿命最短的先走 |
LRU 是近似实现(采样 5 个 key 挑最久未用的,省内存);LFU 用 lru 字段的前 16 位存对数计数器 + 衰减。
事务与 Lua:原子性但不回滚
MULTI ... EXEC 的两个反直觉点:
- 入队报错(命令不存在)→ 整个事务不执行
- 执行时出错(类型错误,如对 List 执行 LPUSH 到 String)→ 其他命令照常执行,不回滚——Redis 追求简单快速,不提供回滚
所以"逻辑性错误"防不住,Lua 脚本才是真正的原子利器:整段脚本单线程原子执行,还能做条件判断(锁校验、限流扣减都靠它)。脚本是原子的,但不是隔离的"事务"——脚本执行慢了照样阻塞所有人,Lua 里别写循环大逻辑。
大 key 与热 key 治理
| 问题 | 危害 | 治理 |
|---|---|---|
| 大 key | 读写阻塞、删除卡顿、迁移慢 | 拆分(Hash 分桶)、UNLINK 异步删、--bigkeys 排查 |
| 热 key | 单 key 打满单线程 | 本地缓存兜一层、key 加后缀打散(读时随机挑一份)、读写分离 |
💡 我的总记忆钩子:Redis 的性能哲学 = 永远别让主线程等——所以异步删(UNLINK)、渐进式 rehash、bgsave 子进程、6.0 把网络 IO 挪到辅助线程,全是同一句话的不同实现。
⬅️ 04-Redis 持久化与高可用 🏠 00-数据库 ➡️ 02-mongoDB
💬 评论