前面我們看了Redis用到的主要資料結構,如簡單動態字串(SDS)、雙向鏈表、字典、壓縮串列、整數集合等,
但是Redis并沒有直接使用這些資料結構來實作鍵值對,而是基于這些資料結構創建了一個物件系統,這個系統包括字串物件、串列物件、哈希物件、集合物件、有序集合物件,除此之外,redis的物件系統還實作了基于計數技術的記憶體回識訓制,另外redis還通過參考計數技術實作了物件共享機制(適當條件下,多個資料庫鍵共享同一個物件來節約記憶體),
最后,redis的物件帶有訪問時間記錄資訊,該資訊可以用于計算資料庫鍵的空轉時長,在服務器啟用了maxmemory功能的情況下,空轉時長較大的鍵會優先被服務器洗掉,
1、Redis中的每個結構都是由redisObject結構標識,包含ptr(指向底層實作的資料結構)、encoding(決定用那種底層資料結構)、type等屬性,
2、當我們創建一個鍵值對時,我們至少會創建兩個物件:鍵物件(字串物件),值物件(物種型別),
3、字串物件的編碼可以是整數、raw或者enbstr、sds
-
enbstr(短字串長度小于32)呼叫一次分配記憶體函式,分配一個連續的記憶體包含redisObject結構與sdshdr結構,不包含修改命令,執行任何修改命令會轉為raw物件,
-
sds(字串長度超過32),
-
raw 會呼叫兩次記憶體分配分別創建redisObject結構與sdshdr結構,
4、串列物件,串列物件的編碼可以是ziplist或者linkedlist
-
ziplist使用壓縮串列作為底層實作,串列物件保存的所有字串元素長度都小于64位元組,元素數量小于512個時使用壓縮串列做為底層實作,
-
linkedlist編碼串列物件使用雙向鏈表作為底層實作,每個雙向鏈表節點都保存一個字串物件,
5、哈希物件
-
哈希物件的編碼可以是ziplist或者hashtable
-
ziplist編碼的哈希物件使用壓縮表作為底層實作,當由新的鍵值對加入到hash物件時,程式會先將保存了鍵的壓縮串列節點推入到壓縮串列的表尾,然后將保存了值的壓縮串列節點推入到壓縮串列的表尾,
-
使用hashtable作為編碼的哈希物件使用字典作為底層實作,鍵使用字串物件,值使用字串物件,
6、集合物件
-
集合物件的編碼可以是 intset或者是hashtable
-
intset編碼的集合物件使用整數集合作為底層實作,
-
hashtable編碼的集合物件使用字典作為底層實作,字典的每個鍵都是一個字串物件,每個字串物件包含一個集合元素,而欄位的值則全部設定為null,

-
物件轉換 ,intset轉hashtable條件:元素中不全是整數或者元素數量超過512.
7、有序集合物件
-
有序集合的編碼可以是ziplist 或者skiplist
-
ziplist編碼的壓縮串列物件使用壓縮串列作為底層實作,每個集合元素使用兩個挨在一起的壓縮串列節點來保存,第一個節點保存元素的成員(member)第二個元素則保存元素的分值(score),
-
skiplist編碼的有序集合物件使用zset結構作為底層實作,一個zset結構同時包含一個字典和一個跳躍表,
-
typedef struct zset{ zskiplist *zsl; dict *dict;//保存從成員到分值的映射,鍵保存元素成員 值保存了分數, }
-
解釋下為什么同時使用字典與跳躍表來實作有序集合:雖然用兩種結構的任意一種都能實作有序集合,但是當我們只是用字典來實作有序集合時,由于字典是一個無序的保存元素,當我們實行范圍操作時,需要先對所有的元素進行排序,這里所使用的時間復雜度至少為O(NlogN),并且有額外的記憶體消費;另外如果只使用跳躍表來實作有序集合時,雖然范圍操作的優勢被保留,但是沒有了字典根據成員查找分值時這一操作的復雜度將從O(1)提升到O(logN),
-
編碼轉換,當元素的數量小于128,且每個元素的長度都小于64位元組時,使用ziplist,
8、記憶體回收
-
每個物件的參考技術資訊由redisObject結構的refcount屬性記錄,
-
創建物件時,計數值會被默認初始化為1,被程式使用時,計數器加一,不再被使用時,計數器減一,當計數器為0時,物件占用的記憶體會被釋放,
9、物件空轉時長
-
物件空轉時長使用redisObjet結構中的lru屬性記錄,該屬性記錄物件最后一次被訪問的時間,
--------- end --------
每天學一點,總會有識訓,
說明:尊重作者知識產權,文中內容參考《Redis設計與實作》,僅在此做學習與大家分享,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/3167.html
標籤:NoSQL
上一篇:Redis簡介
