上文:redis底層數據結構
String底層結構
一、編碼方式
1.int編碼
-
**適用范圍:**64位整數(
long
) -
**實現:**直接將數據存儲在
redisObject
的ptr
指針位置。 -
內存布局:
2.embstr編碼
-
**適用條件:**字符串大小<44字節。
- **實現:**將
redisObject
與SDS
分配在連續內存中。
- **實現:**將
-
內存布局:
-
redisObject (16B) SDS頭 (3B) 字符串數據 (44B) 結尾'\0' (1B)
-
總占用:16 + 3 + 44 + 1 = 64字節(剛好利用
jemalloc
(按2的次方分配內存)的64B內存塊,減少碎片)。
-
-
特點:
- 內存連續,訪問高效(減少CPU緩存缺失)。
- 只讀設計,修改時自動轉為raw編碼。
3.raw編碼
- 適用條件:字符串長度 > 44字節或含二進制數據。
- 實現:
redisObject
與SDS
分兩次分配內存,ptr
指向獨立的SDS結構。 - 內存布局:
二、編碼轉換場景
1.int → raw
執行非整數操作(如APPEND
非數字字符)。
2.embstr → raw
修改embstr字符串(因embstr內存不可變)。
List底層結構
一、List的底層演進
Redis版本 | 底層結構 | 特點 |
---|---|---|
??.0 | ziplist 或 linkedlist | 小數據用ziplist(內存緊湊),大數據用linkedlist(操作高效) |
3.0~3.2 | quicklist(過渡階段) | 初步引入分段ziplist設計 |
≥3.2 | quicklist(默認統一實現) | 每個節點為ziplist,通過雙向鏈表連接,平衡內存與性能 |
Set底層結構
一、編碼方式
1.intset
- 適用條件:
- 所有元素均為 整數(int64_t 范圍)。
- 元素數量 ≤
set-max-intset-entries
(默認512
)。
- 特點:
- 內存緊湊:無指針開銷,連續存儲整數。
- 自動升級:插入超出當前編碼范圍的整數時,升級為更大編碼。
- 二分查找:元素有序,查找時間復雜度 O(log n)。
- 缺點:
- 不支持非整數類型元素
intset
設計初衷是存儲整數,只能保存整數。如果嘗試往intset
里添加非整數類型的數據(如字符串、浮點數等),Redis
會將intset
升級為hashtable
來存儲。 - 升級操作開銷大
當插入的新元素類型比 intset 現有元素類型長時,需要進行升級操作。整個升級過程涉及大量內存操作和數據類型轉換,時間復雜度為 O ( N ) O(N) O(N),在大數據量場景下,會帶來較大性能開銷。 - 查找效率在數據量增大時降低
intset 內部使用有序數組存儲元素,查找元素時采用二分查找算法,平均時間復雜度為 O ( l o g N ) O(log N) O(logN)。雖然二分查找效率較高,但隨著元素數量 N 不斷增加,查找時間也會相應變長。相比哈希表(平均查找時間復雜度為 O ( 1 ) O(1) O(1)),在大數據量場景下,intset 的查找效率會處于劣勢。 - 插入和刪除操作效率問題
插入和刪除元素時,為了保持數組的有序性,需要移動大量元素。插入或刪除操作的平均時間復雜度為 O ( N ) O(N) O(N),,在大數據量場景下,頻繁的插入和刪除操作會嚴重影響性能
- 不支持非整數類型元素
2.dict(hashtable)
-
適用條件:
- 元素包含 非整數。
- 元素數量 >
set-max-intset-entries
。
-
結構設計:
-
特點:
- O(1) 時間復雜度:插入、刪除、查找均高效且無
intset
升級操作。 - 內存開銷大:每個元素需存儲 Entry 結構(鍵指針 + next 指針)。
- O(1) 時間復雜度:插入、刪除、查找均高效且無
二、編碼轉換機制
1. intset → hashtable
- 觸發條件:
- 插入 非整數元素。
- 元素數量超過
set-max-intset-entries
。
三、內存與性能對比
維度 | intset | hashtable |
---|---|---|
內存占用 | 低(無指針,連續存儲) | 高(Entry 結構 + 指針) |
插入性能 | O(n)(需維護有序性) | O(1)(平均) |
查找性能 | O(log n)(二分查找) | O(1)(哈希查找) |
適用場景 | 小規模純整數集合 | 大規模或含非整數元素的集合 |
ZSet底層結構
一、編碼方式
1. ziplist(壓縮列表)
-
適用條件:
- 元素數量 ≤
zset-max-ziplist-entries
(默認128
)。 - 所有元素值(member)長度 ≤
zset-max-ziplist-value
(默認64
字節)。
- 元素數量 ≤
-
存儲方式:
-
元素(member)和分數(score)成對存儲,按分數升序排列。
-
結構示例:
特點:
-
內存緊湊:連續內存塊存儲,無指針開銷。
-
插入/刪除低效:需重分配內存并移動數據,時間復雜度 O(n),大數據量場景下性能低。
-
2. skiplist(跳躍表) + dict(哈希表)
- 適用條件:
- 元素數量或值大小超過上述閾值。
- 結構設計:
- 跳躍表(zskiplist):
- 按分數排序,支持 O(log n) 的插入、刪除和范圍查詢。
- 節點結構包含成員(member)、分數(score)、多層前向指針。
- 哈希表(dict):
- 鍵為成員(member),值為分數(score),支持 O(1) 的成員查找。
- 跳躍表(zskiplist):
- 協作機制:
- 插入:同時向跳躍表和哈希表插入數據,保證一致性。
- 查詢:哈希表快速定位分數(
zscore
),跳躍表處理范圍操作(zrange
zrevrange
zrangebyscore
)。
- 特點:
- 查詢效率高
- 內存開銷大
二、編碼轉換機制
- ziplist → skiplist:
- 觸發條件:插入元素導致數量或值大小超限。
- 過程:遍歷 ziplist,將所有元素插入跳躍表和哈希表。
Hash底層結構
Hash底層采用的編碼與Zset基本一致,只需要把排序有關的SkipList去掉即可。
一、編碼方式
1.ziplist
- 適用條件:
- 字段數量 ≤
hash-max-listpack-entries
(默認512
)。 - 每個字段的值長度 ≤
hash-max-listpack-value
(默認64
字節)。
- 字段數量 ≤
- 結構特點:
- 內存緊湊:連續存儲字段-值對,無指針開銷。
- 順序存儲:字段和值按添加順序排列,適合小數據量。
- 快速遍歷:支持線性遍歷,但隨機訪問需順序查找。
- 操作限制:
- 插入/刪除低效:需內存重分配和數據移動,時間復雜度 O(n)。
- 自動轉換:超出閾值時轉為hashtable。
2.hashtable(字典dict)
- 適用條件:
- 字段數量或值大小超過listpack/ziplist閾值。
- 結構設計:
- 哈希表:使用鏈地址法解決沖突,每個哈希節點存儲字段和值的指針。
- 快速操作:
- 查找/插入/刪除:平均 O(1) 時間復雜度。
- 支持大規模數據:動態擴容縮容,適應數據增長。
- 內存開銷:
- 每個字段需額外存儲指針和哈希表元數據,內存占用較高。
二、編碼轉換機制
- listpack/ziplist → hashtable:
- 觸發條件:字段數超限或單個值超長。