Redis底層數據結構深度解析(基于Redis 7.2.5)
本文深入剖析Redis核心數據類型的底層實現機制,涵蓋String、Hash、List、Set、Zset的實現原理及版本演進差異。
一、Redis數據存儲核心機制
Redis所有數據以redisObject
結構統一封裝:
typedef struct redisObject {unsigned type:4; // 數據類型(string, hash等)unsigned encoding:4; // 底層編碼(int, embstr等)unsigned lru:LRU_BITS; // 緩存淘汰策略信息int refcount; // 引用計數void *ptr; // 指向實際數據的指針
} robj;
- 查看指令:
TYPE key
:返回數據類型OBJECT ENCODING key
:查看底層編碼
二、String類型底層結構
三種編碼方式:
- int編碼
- 條件:值為整數字符串(可轉為long)
- 特點:ptr直接存儲整數值(省去指針開銷)
- embstr編碼
- 條件:字符串長度 ≤ 44字節
- 特點:內存連續分配,RedisObject與SDS共享內存
- raw編碼
- 條件:字符串長度 > 44字節
- 特點:RedisObject與SDS分離存儲
SDS(Simple Dynamic String)
動態字符串結構,解決C字符串缺陷:
struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; // 已用長度uint8_t alloc; // 總空間unsigned char flags; // 類型標識char buf[]; // 數據存儲
};
優勢:
- O(1)復雜度獲取長度
- 二進制安全(允許存儲
\0
) - 預分配減少內存重分配
三、Hash類型底層結構
編碼切換規則:
條件 | 編碼方式 |
---|---|
所有鍵值對數量 ≤ hash-max-listpack-entries (默認512) 且 所有值長度 ≤ hash-max-listpack-value (默認64字節) | listpack |
任一條件不滿足 | hashtable |
Listpack(替代Redis6的ziplist)
連續內存結構解決ziplist連鎖更新問題:
字段 | 說明 |
---|---|
total-bytes (4B) | 總字節數 |
num-elements (2B) | 元素數量 |
entry (變長) | 數據節點(每個鍵值對) |
end-byte (1B) | 結束標識(0xFF) |
節點結構:
[編碼類型][數據長度][實際數據]
→ 無需記錄前驅節點長度,避免連鎖更新
四、List類型底層結構
編碼規則:
- listpack編碼:元素少且長度小
- quicklist編碼:元素多或長度大(默認切換閾值:
list-max-listpack-size = -2
即8KB)
Quicklist結構
雙向鏈表 + Listpack的復合結構:
typedef struct quicklist {quicklistNode *head;quicklistNode *tail;unsigned long count; // 總元素數unsigned long len; // 節點數...
} quicklist;typedef struct quicklistNode {struct quicklistNode *prev;struct quicklistNode *next;unsigned char *entry; // 指向listpacksize_t sz; // listpack字節大小...
} quicklistNode;
優勢:
- 鏈表結構:高效增刪(O(1))
- Listpack節點:內存連續,減少碎片
五、Set類型底層結構
編碼切換規則:
條件 | 編碼方式 |
---|---|
元素全為整數 & 元素數量 ≤ set-max-intset-entries (默認512) | intset |
元素數量 ≤ set-max-listpack-entries (默認128) 且 所有元素長度 ≤ set-max-listpack-value (默認64字節) | listpack |
任一條件不滿足 | hashtable |
Intset整數集合
typedef struct intset {uint32_t encoding; // 編碼方式(int16/int32/int64)uint32_t length; // 元素數量int8_t contents[]; // 數據存儲
} intset;
特點:元素有序存儲,二分查找效率高
六、Zset類型底層結構
編碼切換規則:
條件 | 編碼方式 |
---|---|
元素數量 ≤ zset-max-listpack-entries (默認128) 且 所有值長度 ≤ zset-max-listpack-value (默認64字節) | listpack |
任一條件不滿足 | skiplist |
Skiplist跳表
多層索引結構實現高效查找:
typedef struct zskiplistNode {sds ele; // 元素值double score; // 分值struct zskiplistNode *backward; // 后退指針struct zskiplistLevel {struct zskiplistNode *forward; // 前進指針unsigned long span; // 跨度} level[]; // 層級數組
} zskiplistNode;
性能:
- 查詢/插入/刪除:平均O(logN)
- 空間復雜度:O(N)
七、Redis版本數據結構對比
數據類型 | Redis 6 | Redis 7 |
---|---|---|
string | SDS | SDS |
hash | ziplist + hashtable | listpack + hashtable |
list | quicklist + ziplist | quicklist + listpack |
set | intset + hashtable | intset + listpack + hashtable |
zset | ziplist + skiplist | listpack + skiplist |
關鍵演進:Redis 7使用listpack全面替代ziplist,徹底解決連鎖更新問題。
附:Redis高性能核心要素
- 精細化數據結構:針對場景選擇最優編碼
- 內存連續存儲:SDS/listpack利用CPU緩存
- 惰性刪除:異步釋放避免阻塞
- 單線程模型:無鎖操作減少競爭
- IO多路復用:epoll/kqueue高效網絡處理