
某同学找到我问能不能帮他看看简历上那个基于 Redis 的缓存系统项目。我问Redis 的跳表怎么实现的他答用的 sorted set底层是跳表。我问那跳表的zslInsert是怎么维护 span 的沉默。然后他说我其实就是在项目里调了几个 Redis 命令底层是 Redis 帮我做的。这个场景我相信很多人都经历过或者会经历。会用 Redis和能讲清楚 Redis是两个完全不同的段位。今天这篇文章就是写给想进第二个段位的人的。为什么不能直接去啃 Redis 源码每次有人问我这个问题我都会说同一句话你先去数数 Redis 7.x 有多少行代码。答案是——约 10 万行。分布在数百个文件里充斥着 SDS 的内存布局技巧、dict 的渐进式 rehash 时机、ae 事件循环与 serverCron 之间的协调逻辑还有主从复制握手时的各种状态机……每一个细节单独拎出来都能写一篇长文。更致命的是你看的是一个已经完成的工程。你看不到它是怎么从第一行代码开始生长出来的。你不知道数据结构层做完之后为什么下一步是事件循环而不是先写命令分发。你不知道 RESP 协议解析是在哪个阶段接进去的为什么要先有 networking 层才能引入命令表。那个从0到1的过程才是真正值钱的东西。GitHub 上也有一些简化版 Redis——但它们大多参考 Redis 4.x 或 6.x 以前的版本跳表没有 spanlistpack 没有quicklist 的双编码更别提了。学完之后你对 Redis 7.x 的理解依然是断层的。于是我做了这件事从今年初开始我花了将近三个月写了一个叫Mini-Redis的项目。它基于Redis 7.2.x源码设计完全由我本人从空文件夹开始一行一行写出来核心代码约2 万行配套测试代码约1.3 万行用于保证每个模块的正确性。这不是对 Redis 的删减版也不是某个旧版 clone 的翻新——而是我参透 7.x 的设计逻辑之后重新推演、重新实现的一遍。先看压测用数据说话同等条件50 并发10 万请求Mini-Redis 与 Redis 7.2.11 正面对比 Mini-Redis (port 6379) SET: 164,203 ops/s GET: 159,489 ops/s INCR: 161,290 ops/s LPUSH: 160,771 ops/s HSET: 165,562 ops/s ZADD: 159,235 ops/s MSET(10): 158,730 ops/s Redis 7.2.11 (port 6380) SET: 164,744 ops/s GET: 162,866 ops/s INCR: 163,934 ops/s LPUSH: 159,744 ops/s HSET: 158,478 ops/s ZADD: 162,601 ops/s MSET(10): 158,478 ops/s跨所有命令Mini-Redis 的吞吐量与官方 Redis 7.2.11 基本持平p50 延迟相当。这不是教学玩具这是一个真实可用的高性能存储引擎。来看张图上图是 Mini-Redis 的完整架构从客户端接入到持久化与主从复制每一层都由我从0实现。下面来说说这36天具体走了哪些路。36 天这个项目是怎么长出来的整个教学分为 22 个模块36 天完成每天的代码都是对前一天的增量扩展每天结束都能独立编译运行。你跟着走完一遍相当于亲历了一个生产级项目的完整生长过程。上面是架构全貌下面说说每个阶段在做什么。第一阶段地基——数据结构层Day 1–11这一阶段的核心问题是Redis 为什么不用标准库你会手写 zmalloc 内存追踪分配器然后是 SDS 动态字符串五种 header 结构、O(1) 长度查询、贪婪扩容策略adlist 通用链表然后是重头戏——dict 渐进式哈希表双表结构、SipHash-2-4、安全与非安全迭代器的差异、dictScan 的倒序位游标算法。listpack、quicklist 的双编码逻辑是很多人看 Redis 7.x 时卡住的地方。这两个模块我花了两天把每一种编码的触发条件、边界处理、节点合并分裂的七条分支决策树全部拆清楚写出来。还有跳表zskiplist32 层前向指针、span 跨度、按分值范围和字典序范围的区间操作——这是 ZSet 命令能在 O(log N) 内完成排名查询的基础。最后是整数集合 intset三种编码的自动升级逻辑。到 Day 11你拥有一套完整的、经过测试的底层数据结构库。第二阶段心跳——事件驱动层Day 12–14ae 事件循环是 Redis 单线程高性能的秘密所在。你会实现 epoll 封装与 Channel 抽象然后是时间事件链表懒删除 refcount 保护 maxId 防递归触发最后是完整的 aeMain 驱动循环——aeProcessEvents如何把 I/O 超时时间设为最近定时器的倒计时、为什么先处理读事件再处理写事件。anet 模块封装 TCP 工具函数非阻塞连接、SO_REUSEADDR、TCP_NODELAY每一个选项背后都有理由。第三阶段骨架——服务器层Day 15–17Day 15 是整个课程的第一个里程碑服务器第一次能启动了。redisObject、redisDb、redisServer的核心字段确定main 函数把 initServer 和 aeMain 串起来acceptTcpHandler 开始接收连接serverCron 时间事件跑起来。Day 16 实现 RESP 协议解析层——processInputBuffer、inline 模式、multibulk 模式、双缓冲回复机制。Day 17 接入命令表和命令分发PING/ECHO/SELECT/DBSIZE/FLUSHDB 全部可用redis-cli 打上去能正常交互了。第四阶段血肉——五大数据类型命令Day 18–26StringSET 的 NX/XX/EX/GET 全选项、INCR 的 int encoding 原地修改优化、Listlistpack 与 quicklist 双编码的统一 API 层、LPOS 的 RANK/COUNT/MAXLEN 参数、Hash、Setintset → listpack → HT 三级编码升级、ZSet跳表 新版 ZRANGE 统一接口。每种类型的编码升级逻辑每个命令的边界 case测试代码全部覆盖。以 ZSet 为例Day 24–26 三天86 个测试全部通过。第五阶段可靠性——过期、持久化、事务、发布订阅Day 27–32expire 模块惰性删除 activeExpireCycle 慢速/快速双模式EXPIRE 命令的 NX/XX/GT/LT 选项TTL/PTTL/EXPIRETIME 全部实现。RDBrio I/O 抽象、五种数据类型的序列化/反序列化、BGSAVE fork 子进程 COW 机制、启动时自动加载。AOF三种 fsync 策略、fake client 回放、后台 bgrewrite 双缓冲增量同步、父子进程间的原子文件切换。Multi/EXEC 事务命令队列、WATCH 的 CAS 语义、脏标记处理。Pub/Sub精确匹配 glob 模式两路投递、客户端状态机限制、keyspace 通知。