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設計與實現》,僅在此做學習與大家分享。
&n