前面我們看了Redis用到的主要數據結構,如簡單動態字元串(SDS)、雙向鏈表、字典、壓縮列表、整數集合等。 但是Redis並沒有直接使用這些數據結構來實現鍵值對,而是基於這些數據結構創建了一個對象系統,這個系統包括字元串對象、列表對象、哈希對象、集合對象、有序集合對象,除此之外,redis的對象系 ...
前面我們看了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設計與實現》,僅在此做學習與大家分享。