Mini-Redis (AI Edition)
🤖 Gemini 3.0 Pro 从零构建 Redis:人机结对编程实录 🚀
Java 17 × Netty × 核心原理复刻
不仅仅是 KV 存储,更是对 Redis 灵魂的致敬。
项目简介 • 硬核技术栈 • 持久化机制 • 性能测试 • 开发实录 • 快速开始 • 路线图
github地址:github.com/muma0413/Bu…
下周上传和Gemini 3 pro对话的全部过程,欢迎大家star 一起学习
📖 项目简介
Mini-Redis 不仅仅是一个 KV 存储引擎,它是 AI 辅助编程 (AI-Native Development) 极限能力的试金石。
本项目由 Gemini 3.0 Pro 全程深度参与构建。从一行代码都没有的空白仓库,到拥有 MP-AOF、QuickList、SkipList 的工业级存储引擎,每一行代码都凝聚了 人类程序员思维 与 AI 极致执行力 的碰撞。
为什么它不是“又一个玩具”?
不同于市面上仅封装 HashMap 的简单实现,我们追求技术深度的 1:1 复刻。我们不仅实现了基础功能,更挑战了 Redis 7.0+ 的前沿特性(如 Multi-Part AOF 增量重写、SINTERCARD、LPOP Count 等)。
基于 Java 17 和 Netty 的高性能 Reactor 模型,证明了在现代 JVM 上复刻工业级 C 语言中间件的可行性与惊人性能。
🛠️ 硬核技术栈 & 核心特性
1. 🏗️ 高性能通信架构
- Reactor 模型: 基于 Netty 4.1 实现非阻塞 I/O,单机吞吐量对标原生 Redis。
- 无锁化设计 (Lock-Free): 采用 "IO 多线程 + 业务单线程" 架构,彻底消除
synchronized锁竞争,写性能提升 5 倍以上。 - RESP 协议栈: 纯手写 RESP 解析器与编码器,支持递归解析数组与 BulkString。
- Context 上下文: 引入
RedisContext传递连接状态,为未来 ACL、事务和多数据库支持预留了优雅的扩展点。
2. 📡 分布式与高可用 (Replication) 【NEW】
实现了对标 Redis 2.8+ 的 PSYNC 主从复制协议,具备生产级的高可用能力:
- 全量复制 (Full Resync): 利用
BGSAVE生成 RDB 快照,通过 NettyChunkedFile实现零拷贝流式传输,无内存溢出风险。 - 增量复制 (Partial Resync): 基于 Replication Backlog (环形缓冲区) 实现断点续传,完美应对网络抖动,避免昂贵的全量重传。
- 级联复制 (Cascading): 支持
Master -> Slave A -> Slave B链式拓扑,减轻 Master 负载。 - 心跳保活: 完整的
PING/REPLCONF ACK机制,自动检测连接失效并触发重连。
3. 🧠 数据结构:极致优化与双引擎
我们实现了 Redis 最引以为傲的**“自适应存储策略”**,根据数据量大小动态切换底层结构:
🔹 String (字符串)
- 二进制安全: 底层基于
byte[],完美支持图片、视频等二进制数据。 - 原子计数器: 完整实现
INCR,DECRBY,INCRBY,保证并发安全。 - 位图操作 (Bitmap): 支持
SETBIT,BITCOUNT,BITOP等位操作指令,轻松应对亿级用户签到场景。 - 高阶特性: 支持 Redis 6.2
GETEX(Get and Expire) 及SETNX分布式锁原语。
🔹 List (列表)
- QuickList 架构: 抛弃传统的 LinkedList,实现 QuickList (双向链表 + ZipList) 混合结构,平衡内存与性能。
- 阻塞队列 (Blocking Queue): 深度复刻
BLPOP,BRPOP,BRPOPLPUSH。- 实现 Global Blocking Registry,支持精确唤醒与超时处理。
- 完美解决并发下的虚假唤醒 (Spurious Wakeup) 问题。
- 批量操作: 支持
LPOP/RPOP的 count 参数 (Redis 6.2+)。
🔹 Hash (哈希)
- 双引擎切换 (Dual-Engine):
- ZipList: 小数据量下使用紧凑数组,极大节省内存。
- HashTable: 大数据量下自动升级,保证 O(1) 查询。
- 高频指令: 支持
HINCRBY原子递增及HSCAN游标遍历(基于 Snapshot 模拟)。
🔹 Set (集合)
- IntSet 优化: 当集合元素均为整数时,采用二分查找的有序数组存储,内存占用降低 10x。
- 集合运算: 实现
SUNION,SINTER,SDIFF及其 Store 变体。 - Redis 7.0 特性: 首发支持
SINTERCARD,利用基数估算与 Limit 截断,极大提升大集合交集计算性能。
🔹 Sorted Set (有序集合)
- SkipList (跳表) 引擎: 纯手写 Java 版跳表,包含核心的 Span (跨度) 维护。
- 支持 O(logN) 的
ZRANK(排名查询)。 - 支持 O(logN) 的
ZRANGE(范围查询)。
- 支持 O(logN) 的
- 复杂查询: 实现了
ZREVRANGE(倒序),ZRANGEBYSCORE(分数范围),ZCOUNT(利用 Rank 相减优化)。 - 防御性编程: 针对大 Key 扫描 (
ZRANGE 0 -1) 植入了日志预警机制。
4. 🛡️ 稳定性与健壮性
- 双模持久化:
- AOF: 支持 Redis 7.0 MP-AOF (Multi-Part) 架构,实现增量重写 (Incremental Rewrite),无阻塞。
- RDB: 支持自动快照 (
save 900 1),生成紧凑二进制文件。
- 过期策略: 惰性删除 (Lazy) + 定期扫描 (Active) 双管齐下,杜绝内存泄漏。
- 类型安全: 全局采用
RedisData<T>泛型封装,杜绝ClassCastException。
🤖 开发实录 (The AI Journey)
我们将整个开发过程的对话记录整理成了 PDF,这是一份珍贵的现代软件工程实录。
| 阶段 | 核心内容 | 记录下载 |
|---|---|---|
| Phase 1 | 通信骨架: Netty, RESP, Dispatcher | [Coming Soon] |
| Phase 2 | 内存引擎: String 原子性, Hash 策略模式 | [Coming Soon] |
| Phase 3 | 高阶结构: 手写 SkipList, QuickList, 阻塞队列 | [Coming Soon] |
🚀 快速开始
环境要求
- JDK 17+
- Maven 3.8+
构建与运行
git clone https://github.com/muma0413/Build-Redis-from-Scratch-with-AI.git
cd mini-redis
mvn clean package
java -jar target/mini-redis-1.0-SNAPSHOT.jar
连接测试
你可以使用官方 redis-cli 或任何可视化客户端(如 ARDM)连接:
redis-cli -p 6379
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> SET user:1 "Gemini"
OK
127.0.0.1:6379> ZADD rank 100 "Player1"
(integer) 1
127.0.0.1:6379> ZRANK rank "Player1"
(integer) 0
🛣️ 路线图 (Roadmap)
我们正在按照严格的工程标准迭代本项目,目前已完成核心内存数据库的所有功能。
-
Phase 1: 骨架与协议
- Netty 非阻塞 Reactor 模型搭建
- RESP 协议纯手写解析器与编码器
- Command Dispatcher 命令分发系统
-
Phase 2: 内存数据结构 (Memory Engine)
- String: 基础读写、原子计数 (
INCRBY)、位操作 (SETBIT/BITCOUNT)、GETEX - Hash: ZipList/HashTable 动态切换策略、
HSCAN、集合运算 - List: QuickList (双向链表+ZipList) 架构、
BLPOP/BRPOP阻塞队列实现 - Set: IntSet/HashTable 动态切换、
SINTERCARD(Redis 7.0)、集合运算 (SUNION/SDIFF) - ZSet: SkipList (跳表) 核心引擎、Span 排名计算、
ZRANGEBYSCORE、ZREVRANGE
- String: 基础读写、原子计数 (
-
Phase 3: 架构重构与优化
- 引入
RedisContext上下文传递 - 泛型
RedisData<T>类型安全改造 - 无锁化重构: IO多线程+业务单线程,QPS 提升 500%
- 引入
-
Phase 4: 持久化 (Persistence)
- MP-AOF: Redis 7.0 多分片 AOF,支持增量重写 (Incremental Rewrite)
- RDB: 二进制快照保存与加载,支持自动触发策略 (
save 900 1)
-
Phase 5: 分布式与高可用 (Replication)
- PSYNC 协议: 智能全量/增量同步判定
- Replication Backlog: 环形缓冲区实现断点续传
- 级联复制: 支持 Master -> Slave -> Slave 链式传播
- 心跳保活: PING / REPLCONF ACK 机制
-
Phase 6: 运维与扩展 (Ops & Future)
- Dockerization: 提供标准 Dockerfile 及 Docker Compose 编排,一键启动集群。
- Observability: 实现
INFO(增强版),MONITOR,SLOWLOG等监控指令。 - Cluster: 探索基于 Gossip 协议的分片集群。
- LSM-Tree: 探索基于磁盘的存储引擎 (RocksDB 风格)。
📊 性能基准测试 (Benchmark Report)
我们在单机环境下对 Mini-Redis 进行了全方位的压力测试,以验证 "Netty I/O 多线程 + 业务单线程无锁" 架构的极限吞吐量。
测试环境
- 硬件: 开发笔记本 (Environment Dependent)
- JVM: JDK 17 (G1GC, Default Tuning)
- 工具: 自研 Netty 压测客户端 (基于 Pipeline 流水线模式)
- 策略: 50 并发连接,每连接 10,000 请求 (共 50w/轮),3 轮预热 + 5 轮均值统计。
核心指标 (QPS)
| 模块 | 写指令 (Write) | QPS | 读指令 (Read) | QPS | 备注 |
|---|---|---|---|---|---|
| String | SET | 254,277 | GET | 396,291 | 纯内存操作,基准水位 |
INCR | 250,030 | MGET | 188,774 | 批量读协议开销较大 | |
| Hash | HSET | 250,906 | HGET | 344,534 | HashTable O(1) 查找 |
HINCRBY | 261,319 | HSCAN | 173,682 | 遍历拷贝开销 | |
| List | LPUSH | 260,345 | LINDEX | 318,721 | QuickList 局部性优势 |
LPOP | 258,299 | LRANGE | 89,841 | 协议序列化瓶颈 (10 elements) | |
| Set | SADD | 269,550 | SISMEMBER | 291,287 | IntSet/HashTable 混合引擎 |
SPOP | 266,670 | SINTER | 276,661 | 集合运算高效算法 | |
| ZSet | ZADD | 266,844 | ZSCORE | 332,778 | Dict O(1) 查找 |
ZRANGE | 210,744 | SkipList O(logN) 遍历 |
📈 性能深度剖析
-
写性能 (Write Throughput):
- 所有写操作稳定在 25万 ~ 27万 QPS。
- 架构胜利: 得益于无锁化架构,消除了
synchronized的上下文切换,写操作达到了 Netty IO 处理能力的物理上限。 - 数据结构优化: 即使是复杂的
ZADD(SkipList) 和LPUSH(QuickList),性能并未显著低于简单的SET,证明了底层数据结构实现的极低 Overhead。
-
读性能 (Read Throughput):
- 单点查询 (
GET,HGET,ZSCORE) 突破 30万 ~ 40万 QPS。 - 内存寻址: 读操作不需要分配新对象(写操作需要创建 Entry),GC 压力更小,且 CPU 缓存命中率更高。
- 单点查询 (
-
协议开销 (Protocol Overhead):
LRANGE和MGET的 QPS 相对较低 (9万 ~ 18万)。这是因为 Redis RESP 协议在返回数组时需要大量的字节拼接和内存拷贝,网络带宽和序列化成为了主要瓶颈,而非数据结构本身。
(注:以上数据为本地 Loopback 压测结果,实际网络环境下受带宽延迟影响会有所不同)
📚 源码深度解析
想知道 Mini-Redis 内部是如何工作的?我们准备了深度的架构剖析文档:
- 总体架构设计: Netty 线程模型与命令分发流程。
- 数据结构解密:
- 为什么 ZSet 要用 SkipList?Span 是如何计算排名的?
- QuickList 是如何通过“链表+数组”平衡内存与性能的?
- Set 的 IntSet 优化策略。
- 并发与阻塞机制: 深度解析
BLPOP是如何利用 Netty 实现非阻塞挂起与异步唤醒的。
📡 主从复制 (Replication)
Mini-Redis 实现了一套完整的、对标 Redis 2.8+ 协议的主从复制机制,支持全量同步、增量同步、级联复制及自动故障恢复。
1. 原理介绍 (Architecture)
Redis 的复制机制是基于 异步复制 (Asynchronous Replication) 的。其核心流程如下:
- 握手 (Handshake): Slave 连接 Master,发送
PING,REPLCONF等指令建立信任。 - 同步 (Synchronization):
- 全量复制 (Full Resync): Master 执行
BGSAVE生成 RDB 快照发送给 Slave。Slave 清空内存并加载 RDB。 - 增量复制 (Partial Resync): 如果 Slave 只是短暂断线,Master 通过 Replication Backlog 补发断线期间的增量命令,避免昂贵的全量 RDB 传输。
- 全量复制 (Full Resync): Master 执行
- 传播 (Propagation): Master 将后续所有的写命令 (Write Commands) 异步转发给所有在线的 Slave,保持数据最终一致性。
2. 核心功能 (Features)
Mini-Redis 目前支持:
- ✅ SLAVEOF 命令: 动态切换主从角色,支持
SLAVEOF NO ONE提升为 Master。 - ✅ PSYNC 协议: 支持 Redis 2.8+ 的
PSYNC,智能判断全量或增量同步。 - ✅ RDB 流式传输: 利用 Netty
ChunkedFile实现 RDB 文件的零拷贝流式发送,无内存溢出风险。 - ✅ Replication Backlog: 维护环形缓冲区,支持断点续传。
- ✅ 级联复制 (Cascading): 支持
Master -> Slave A -> Slave B的链式拓扑。 - ✅ 心跳保活: Master 定时发送
PING,Slave 定时发送REPLCONF ACK。 - ✅ 故障自动重连: Slave 断线后自动重连并尝试增量同步。
3. 实现原理与流程 (Implementation)
3.1 核心组件
ReplicationManager: 上帝类。负责维护复制状态机 (State Machine)、管理 Slave 连接、处理 PSYNC 逻辑。ReplicationBacklog: 固定大小的 RingBuffer,存储最近的写命令字节流。RedisSlaveHandler: Slave 端的 Netty Handler,处理握手响应和 RDB 数据流。
3.2 流程图解
A. 全量同步流程
[Slave] [Master]
| SLAVEOF host port |
| -------------------------> |
| PSYNC ? -1 |
| -------------------------> | (Check Backlog: Miss)
| +FULLRESYNC id off | (Trigger BGSAVE)
| <------------------------- |
| | (Buffer new commands to Pending List)
| $ <len>\r\n<RDB> | (Send RDB via Zero-Copy)
| <========================= |
| (Flush DB & Load RDB) |
| | (Promote Slave to Online)
| (Command Stream) | (Send Buffered Commands)
| <------------------------- |
4. 使用说明 (Usage)
方式一:配置文件启动
在 redis.properties 中配置:
# =========================================================
# Mini-Redis 核心配置文件 (redis.properties)
# =========================================================
# --- 网络与连接 (Network) ---
# 服务器监听端口 (默认: 6379)
server.port=6379
# Netty Worker 线程数 (0 = 自动设置为 CPU 核心数 * 2)
# 调大此值可提升高并发下的 IO 吞吐量
server.worker_threads=0
# 最大客户端连接数限制
server.max_clients=10000
# --- 存储引擎策略 (Storage Backend) ---
# 集合(Set) 和 哈希(Hash) 的底层实现策略
# JDK_HASHMAP: 吞吐量极高,但扩容时可能会有瞬间卡顿 (STW)
# REDIS_DICT: 自研实现,支持渐进式 Rehash,延迟极低且平滑 (推荐生产环境)
backend.set_dict=REDIS_DICT
# --- 持久化: AOF (Append Only File) ---
# 是否开启 AOF 持久化 (yes/no)
# 建议开启以保证数据安全性,重启时优先加载 AOF
appendonly=yes
# AOF 刷盘策略
# always: 每条写命令都刷盘 (最安全,性能最低)
# everysec: 每秒刷盘一次 (推荐,折中方案,最多丢1秒数据)
# no: 操作系统决定 (最快,不安全)
appendfsync=everysec
# AOF 文件存储目录 (相对于工作目录)
appenddirname=appendonlydir
# AOF 主文件名
appendfilename=appendonly.aof
# 是否使用 RDB 混合格式头 (暂未启用,预留配置)
aof-use-rdb-preamble=no
# AOF 自动重写触发条件
# 当 AOF 文件大小增长率超过此百分比时触发重写
auto-aof-rewrite-percentage=100
# 允许触发重写的最小文件体积 (避免小文件频繁重写)
auto-aof-rewrite-min-size=64mb
# --- 持久化: RDB (Snapshot) ---
# 快照自动保存策略 (格式: <seconds> <changes>)
# 900秒内有1次修改,或300秒内10次,或60秒内10000次
save=900 1 300 10 60 10000
# RDB 文件名
dbfilename=dump.rdb
# --- 主从复制 (Replication) ---
# 如果配置了以下项,当前实例启动后将自动连接 Master 成为 Slave
# slaveof=127.0.0.1 6379
# 断线重连间隔 (毫秒)
repl-retry-interval=1000
# --- 工作目录 (Working Directory) ---
# RDB 文件和 AOF 目录将存放于此
# 默认为当前启动目录 (.)
dir=.
方式二:运行时动态挂载
启动两个实例后,在 Slave 端执行:
redis-cli -p 6380
> SLAVEOF 127.0.0.1 6379
OK
验证同步
1.Master: SET k1 v1
2.Slave: GET k1 -> "v1"
3.断线测试: 杀掉 Slave 再重启(或使用 DEBUG REPL_BREAK),观察日志是否触发 Partial resync。
🐳 Docker 部署
不想配置 Java 环境?使用 Docker 一键启动!
1. 构建镜像
docker build -t mini-redis .
🤝 贡献 (Contribution)
本项目是一个探索 "AI Pair Programming" (AI 结对编程) 边界的实验性项目。我们欢迎任何形式的贡献!
如何参与?
- Fork 本仓库:将代码克隆到你的本地。
- 选择任务:从上面的 路线图 中选择未完成的特性(如持久化模块)。
- 提交 PR:
- 请确保你的代码风格与现有项目保持一致。
- 必须包含单元测试:所有新功能都需经过 JUnit 测试验证。
- Issue 讨论:如果你发现了 Bug 或有更好的架构建议(比如 SkipList 的随机算法优化),欢迎提 Issue 讨论。
特别感谢:本项目的所有代码与架构决策均由水平非常一般的程序员与 AI 高级助手 (Gemini 3 PRO) 共同完成。