一、Redis 的核心設計哲學
Redis 的成功源于其?「用內存換時間」?的核心理念,圍繞以下三個核心原則構建:
-
極簡主義:單線程模型避免鎖競爭,代碼保持高度內聚。
-
性能至上:所有數據常駐內存,網絡層采用事件驅動模型。
-
可擴展性:模塊化設計,通過插件機制支持新功能。
二、源碼目錄結構解析
從 Redis 7.0 源碼看核心模塊:
redis/src
├── ae.c # 事件循環(核心)
├── anet.c # 網絡抽象層
├── dict.c # 哈希表實現
├── object.c # 數據類型封裝
├── rdb.c # RDB持久化
├── aof.c # AOF持久化
├── server.c # 服務端主邏輯
├── networking.c # 客戶端連接處理
└── modules # 模塊化擴展
三、核心模塊源碼深度解析
1.?事件驅動模型:單線程為何能扛10萬QPS?
Redis 采用?Reactor 模式?實現高并發,核心代碼在?ae.c
:
// 事件循環主邏輯(ae.c)
void aeMain(aeEventLoop *eventLoop) {eventLoop->stop = 0;while (!eventLoop->stop) {aeProcessEvents(eventLoop, AE_ALL_EVENTS | AE_CALL_BEFORE_SLEEP);}
}// 處理事件(精簡版)
int aeProcessEvents(aeEventLoop *eventLoop, int flags) {// 1. 獲取最近要到期的時間事件shortest = aeSearchNearestTimer(eventLoop);// 2. 等待文件事件(epoll_wait/kevent等)numevents = aeApiPoll(eventLoop, tvp);// 3. 處理文件事件(網絡請求)for (j = 0; j < numevents; j++) {fe = &eventLoop->events[eventLoop->fired[j].fd];fe->rfileProc(...); // 處理讀事件fe->wfileProc(...); // 處理寫事件}// 4. 處理時間事件(如過期鍵清理)processed += processTimeEvents(eventLoop);
}
技術要點:
-
基于?
epoll/kqueue
?實現多路復用 -
單線程順序處理事件,避免鎖開銷
-
時間事件與文件事件協同調度
2.?內存管理:如何實現高效數據存儲?
核心結構?redisObject
(object.c):
typedef struct redisObject {unsigned type:4; // 數據類型(string/hash等)unsigned encoding:4; // 編碼方式(優化存儲)unsigned lru:24; // LRU時間戳int refcount; // 引用計數void *ptr; // 數據指針
} robj;// 字符串類型示例(sds.h)
struct sdshdr {int len; // 已用長度int free; // 剩余空間char buf[]; // 柔性數組
};
編碼優化策略:
-
String
:int編碼(存儲整數時) vs embstr編碼(短字符串) vs raw編碼 -
Hash
:ziplist(元素少時) vs hashtable -
Sorted Set
:skiplist + dict 實現 O(logN) 查詢
3.?持久化機制:RDB與AOF如何協同工作?
RDB 快照生成(rdb.c):
// 異步生成RDB(fork子進程)
int rdbSaveBackground(char *filename, rdbSaveInfo *rsi) {if ((childpid = fork()) == 0) {// 子進程執行實際保存retval = rdbSave(filename,rsi);exitFromChild((retval == C_OK) ? 0 : 1);} else {// 父進程記錄狀態server.rdb_child_pid = childpid;}
}
AOF 重寫(aof.c):
// 重寫AOF文件(同樣fork子進程)
int rewriteAppendOnlyFileBackground(void) {if (aofCreatePipes() != C_OK) return C_ERR;if ((childpid = fork()) == 0) {// 子進程重寫if (rewriteAppendOnlyFile(tmpfile) == C_OK) {exitFromChild(0);}}
}
持久化流程對比:
RDB | AOF | |
---|---|---|
原理 | 內存快照 | 操作日志追加 |
優點 | 恢復快、文件小 | 數據丟失風險低 |
缺點 | 數據可能丟失 | 文件大、恢復慢 |
4.?數據結構:Sorted Set 如何實現高效排序?
核心代碼?t_zset.c
:
// 跳躍表節點定義
typedef struct zskiplistNode {sds ele; // 成員double score; // 分數struct zskiplistNode *backward; // 后退指針struct zskiplistLevel {struct zskiplistNode *forward; // 前進指針unsigned long span; // 跨度} level[]; // 層級數組
} zskiplistNode;// 插入節點核心邏輯
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {// 1. 隨機生成節點層級(冪次定律)level = zslRandomLevel();// 2. 查找插入位置for (i = zsl->level-1; i >= 0; i--) {while (x->level[i].forward && (x->level[i].forward->score < score || ... )) {x = x->level[i].forward;}update[i] = x;}// 3. 創建新節點并調整指針x = zslCreateNode(level,score,ele);for (i = 0; i < level; i++) {x->level[i].forward = update[i]->level[i].forward;update[i]->level[i].forward = x;}
}
性能優勢:
-
跳躍表平均 O(logN) 時間復雜度
-
結合哈希表實現 O(1) 成員存在性檢查
四、企業級應用源碼適配案例
案例1:分布式鎖實現(Redlock算法)
// 加鎖命令(基于SET命令)
SET lock_key $unique_id NX PX 30000// 解鎖Lua腳本(保證原子性)
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end
源碼支撐:
-
SET
?命令在?t_string.c
?實現 -
Lua 腳本執行邏輯在?
scripting.c
案例2:熱點數據緩存穿透防御
// 布隆過濾器實現(redisbloom模塊)
BF.ADD hot_items:filter "item_123"
BF.EXISTS hot_items:filter "item_456"
源碼擴展:
-
模塊化開發接口在?
redismodule.h
-
底層使用?
dablooms
?庫實現
五、Redis 核心架構圖
+-------------------+
| Client |
+-------------------+|| 發送命令v
+-------------------+
| Event Loop | <--- 文件事件(網絡I/O)
| (ae.c/ae_epoll.c) |
| | <--- 時間事件(過期鍵清理)
+-------------------+|| 命令路由v
+-------------------+
| Command Table | ---> 命令處理器(get/set等)
| (server.c/cmd) |
+-------------------+|| 數據操作v
+-------------------+
| Data Store | ---> 字符串/hash/有序集合等
| (object.c/t_*.c) |
+-------------------+|| 持久化觸發v
+-------------------+
| Persistence | ---> RDB(rdb.c) / AOF(aof.c)
+-------------------+
六、Redis 的局限與優化方向
-
內存限制:可通過 Redis Cluster 分片擴展
-
單線程瓶頸:Redis 6.0 引入多線程I/O(仍保持命令處理單線程)
-
持久化風險:建議 RDB+AOF 混合使用,定期備份
-
擴展性:通過 Module 機制集成新功能(如 RedisSearch)
七、總結
通過源碼分析可深入理解 Redis 的?高性能設計精髓:
-
事件驅動模型:單線程扛高并發
-
內存數據結構:精心優化的編碼方式
-
可擴展架構:模塊化設計支持二次開發
企業級應用建議:
-
性能敏感場景:結合跳躍表、哈希表特性設計數據結構
-
高可用要求:部署 Redis Cluster + Sentinel 監控
-
混合持久化:RDB 定期快照 + AOF 實時日志