可以从github上拉一份redis来看,发现redis是用C语言来实现的。高性能kv数据库,为何高效呢?因为在内存,内存离CPU比磁盘更近,所以高效。
你可以先把 Redis 理解成一句话:
Redis 主线程不断从 socket 读命令,解析成 argv ,查命令表,调用对应函数,最后操作 db->keys 这个内存字典。
我们从第0层开始学习
cpp
客户端
│ (网络层)
▼
[1.网络/连接] ──→ [2.命令分发] ──→ [3.数据结构与对象]
ae.c server.c object.c + t_*.c
networking.c command table dict/sds/listpack...
│
▼
[4.数据库语义]
db.c / expire.c / evict.c
│
┌─────────────┼─────────────┐
▼ ▼ ▼
[5.持久化] [6.复制/高可用] [7.集群]
rdb.c/aof.c replication.c cluster.c
sentinel.c
存到内存的到底是什么
struct redisObject {
unsigned type:4; // 这是什么类型?string/list/hash/set/zset...
unsigned encoding:4; // 底层用什么结构存?(同一类型可以有多种存法)
unsigned refcount : 23; // 引用计数:有多少人在用我,降到0就释放
unsigned iskvobj : 1;
unsigned metabits :8;
unsigned lru:LRU_BITS; // 上次访问时间,用于 LRU/LFU 淘汰
void *ptr; // 真正的数据在这里(指向 sds、dict、quicklist...)
};
这是整个 Redis 最核心的一个结构。 你执行 SET a 1 ,那个 "1" 在内存里就是一个 robj 。理解它:
#define OBJ_STRING 0 // 字符串
#define OBJ_LIST 1 // 列表
#define OBJ_SET 2 // 集合
#define OBJ_ZSET 3 // 有序集合
#define OBJ_HASH 4 // 哈希
typedef struct redisDb {
kvstore *keys; // ★ 所有的 key→value 都在这里(这就是"数据库"本体)
kvstore *expires; // 设置了过期时间的 key 在这里
...
dict *watched_keys; // 被 WATCH 监视的 key(事务用)
int id; // 数据库编号 0~15
...
} redisDb;
struct redisObject {
unsigned type:4; // 这是什么类型?string/list/hash/set/zset...
unsigned encoding:4; // 底层用什么结构存?(同一类型可以有多种存法)
unsigned refcount : 23; // 引用计数:有多少人在用我,降到0就释放
unsigned iskvobj : 1;
unsigned metabits :8;
unsigned lru:LRU_BITS; // 上次访问时间,用于 LRU/LFU 淘汰
void *ptr; // 真正的数据在这里(指向 sds、dict、quicklist...)
};
cpp
1. 客户端发字节 "SET a 1"
│
2. 网络层读进来,解析成 argv = ["SET", "a", "1"] (robj 数组)
│
3. 拿 "SET" 查命令表 → 找到 redisCommand → 调用 proc = setCommand
│
4. setCommand 把值 "1" 包成一个 robj(用 INT 编码)
│
5. 把 "a" → robj("1") 写进当前 db->keys
│
6. 回复客户端 "+OK"
最值得学
cpp
最值得学
- 事件驱动模型 :Redis 用事件循环处理网络 IO、定时任务、后台状态推进,是理解高性能服务端的绝佳样本。
- 简单抽象叠复杂能力 :核心就是 client 、 redisCommand 、 redisDb 、对象系统、事件循环,但上面能长出事务、Lua、复制、AOF、集群。
- 数据结构工程化 :不是教科书里的 Hash/List/Skiplist,而是 SDS、dict、quicklist、listpack、intset、rax 这些"为内存和性能妥协过"的实现。
- 命令执行管线 :从网络协议到 argv ,再到命令表和函数指针分发,这是很多数据库、网关、RPC 框架都共通的设计。
- 持久化设计 :RDB 是快照,AOF 是日志,二者组合体现了数据库系统里性能、恢复速度、可靠性之间的取舍。
- 复制与高可用 :主从复制、PSYNC、backlog、Sentinel、failover,是理解分布式系统的好入口。
- 过期与内存淘汰 :懒删除、主动过期、LRU/LFU 近似算法,非常适合学习"如何在性能和准确性之间折中"。
- 渐进式维护 :渐进式 rehash、active expire、lazyfree,把大任务拆成小步做,是高性能系统非常核心的思想。
1.理解主循环、命令分发、GET/SET 读写路径
主循环
cpp
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
aeProcessEvents(eventLoop, AE_ALL_EVENTS|
AE_CALL_BEFORE_SLEEP|
AE_CALL_AFTER_SLEEP);
}
}
RDB和AOF
RDB的流程是fork一个子进程,利用虚拟内存地址的写实拷贝,去全量的把数据全部拿出来。
AOF的话类似于MYSQL的binlog,记录的命令执行过程。
现代生产环境一般是复合使用的。过一段时间先frok进程去全量RDB文件,然后在此期间产生的命令在以AOF的形式追加到文件的末尾。