Redis底層資料結構
-
Redis 是 key-value 儲存系統,其中key型別一般為字串,而 value 型別則為 redis 物件(RedisObject)。Redis 物件可以繫結各種型別的資料,譬如 string、list 和set。因此他能很好的將屬性和資料分離開。
typedef struct redisObject {
// 物件的型別
unsigned type:4;
// 編碼的方式
unsigned encoding:4;
/ 物件最後一次被訪問的時間
unsigned lru:22;
// 引用計數
int refcount;
// 資料指標
void *ptr;
} robj;為什麼要有一個RedisObject?而不直接使用五大型別物件?
-
通過不同型別的物件,Redis 可以在執行命令之前,根據物件的型別來判斷一個物件是否可以執行給定的命令。
-
我們可以針對不同的使用場景,為物件設定不同的實現,從而優化記憶體或查詢速度。
type 物件的型別
型別常量 物件的名稱 REDIS_STRING 字串物件 REDIS_LIST 列表物件 REDIS_HASH 雜湊物件 REDIS_SET 集合物件 REDIS_ZSET 有序集合物件 ptr 指標
指向實際儲存的物件的指標
encoding
encoding 表示 ptr 指向的具體資料結構,即這個物件使用了什麼資料結構作為底層實現。
編碼常量 編碼所對應的底層資料結構 REDIS_ENCODING_INT long型別的整數 REDIS_ENCODING_EMBSTR enbstr編碼的簡單動態字串 REDIS_ENCODING_RAW 簡單動態字串 REDIS_ENCODING_HT 字典 REDIS_ENCODING_LINKEDLIST 雙向連結串列 REDIS_ENCODING_ZIPLIST 壓縮列表 REDIS_ENCODING_INTLIST 整數集合 REDIS_ENCODING_SKIPLIST 跳錶 每種型別的物件都至少使用了兩種不同的編碼,物件和編碼的對應關係如下
refcount
引用計數器,當該值為0時,表示該物件已經不再被引用了,可以釋放進行記憶體回收。
lru
最近一次訪問時間
-
-
String
String型別的encoding方式有三種,分別是int、raw、enbstr。
-
如果儲存的資料是整數,且該整數是8個位元組能表示的資料,那麼該整數就可以直接儲存在ptr中。這種方式節約記憶體,且可以快速讀寫索引。其記憶體結構如下:
-
如果儲存的資料是字串,且該字串長度小於等於32位元組,那麼字串將使用enbstr的編碼方式來儲存資料。因為這種方式在申請記憶體空間時是一次申請的,所以需要分配記憶體空間一次,釋放也只需要一次,並且所有資料儲存在一塊連續的記憶體空間內,可以減少記憶體碎片的產生。
-
如果儲存的資料是字串,且該字串的長度大於32位元組,那麼字串將會使用raw的編碼方式來儲存資料。
-
-
Hash
雜湊型別的底層實現結構有倆種,壓縮列表以及hash表;
列表物件儲存的所有字串元素的長度都小於64位元組,列表物件儲存的元素數量小於512個使用壓縮列表,否則自動轉成hash表;
-
List
列表物件儲存的所有字串元素的長度都小於64位元組,列表物件儲存的元素數量小於512個使用壓縮列表,否則自動轉成linklist表;
列表使用的是雙向連結串列的實現形式實現的;
列表使用ziplist實現
列表使用linkedlist實現
3.2版本後引入了quicklist,快速列表,quicklist是使用ziplist和linkedlist結合實現的,它把linkedlist分成多段,每段使用ziplist實現保持資料的緊湊,多個ziplist使用雙向指標連線成連結串列;
列表使用quicklist實現
-
Set
集合分別使用整數陣列和雜湊表實現;
當集合長度小於512,且儲存的元素都是整數時,使用整數陣列,否則使用雜湊表儲存;
整數陣列優點是節省空間,缺點是索引慢,所以在資料量較少時使用這種方式實現;
-
ZSet
有序集合分別使用壓縮列表和zset實現;
當集合長度小於128時,且所有元素的長度小於64時使用壓縮列表實現,否則使用跳錶;
zset是使用跳錶和字典實現的;其資料結構如下圖:
跳錶是指通過維護多級索引,來優化查詢時的速度。
跳錶結構
資料結構時間複雜度
名稱 時間複雜度 雜湊表 O(1) 查詢時間穩定良好 跳錶 O(logN) 資料量越大,時間複雜度逐漸降低 雙向連結串列 O(N) 根據資料量線性增大 壓縮列表 O(N)根據資料量線性增大 整數陣列 O(N)根據資料量線性增大 各結構優點
名稱 時間複雜度 雜湊表 查詢快 跳錶 有序,資料量大時查詢快 雙向連結串列 頭尾節點訪問快,適合按序訪問 壓縮列表 節省空間記憶體,小資料量情況使用 整數陣列 節省空間記憶體,小資料量情況使用,無序