Redis的五大數據類型也稱五大數據對象;前面介紹過6大數據結構,Redis並無直接使用這些結構來實現鍵值對數據庫,而是使用這些結構構建了一個對象系統redisObject;這個對象系統包含了五大數據對象,字符串對象(string)、列表對象(list)、哈希對象(hash)、集合(set)對象和有序集合對象(zset);而這五大對象的底層數據編碼能夠用命令OBJECT ENCODING來進行查看。html
redisObject結構java
1 typedef struct redisObject { 2 // 類型 3 unsigned type:4; 4 // 編碼 5 unsigned encoding:4; 6 // 指向底層實現數據結構的指針 7 void *ptr; 8 // ... 9 } robj;
redis是以鍵值對存儲數據的,因此對象又分爲鍵對象和值對象,即存儲一個key-value鍵值對會建立兩個對象,鍵對象和值對象。redis
鍵對象老是一個字符串對象,而值對象能夠是五大對象中的任意一種。數據庫
表中列出了底層編碼常量及對應的OBJECT ENCODING 命令的輸出,前三項都是字符串結構緩存
咱們在存入key-value鍵值對時並不會指定對象的encoding,而是Redis會根據不統的使用場景來爲一個對象設置不一樣的編碼,能夠達到節約內存、加快訪問速度等目的。網絡
字符串對象底層數據結構實現爲簡單動態字符串(SDS)和直接存儲,但其編碼方式能夠是int、raw或者embstr,區別在於內存結構的不一樣。數據結構
(1)int編碼大數據
字符串保存的是整數值,而且這個正式能夠用long類型來表示,那麼其就會直接保存在redisObject的ptr屬性裏,並將編碼設置爲int,如圖:優化
(2)raw編碼編碼
字符串保存的大於32字節的字符串值,則使用簡單動態字符串(SDS)結構,並將編碼設置爲raw,此時內存結構與SDS結構一致,內存分配次數爲兩次,建立redisObject對象和sdshdr結構,如圖:
(3)embstr編碼
字符串保存的小於等於32字節的字符串值,使用的也是簡單的動態字符串(SDS結構),可是內存結構作了優化,用於保存頓消的字符串;內存分配也只須要一次就可完成,分配一塊連續的空間便可,如圖:
字符串對象總結:
列表對象的編碼能夠是ziplist和linkedlist之一。
(1) ziplist編碼
ziplist編碼的哈希隨想底層實現是壓縮列表,每一個壓縮裏列表節點保存了一個列表元素。
(2)linkedlist編碼
linkedlist編碼底層採用雙端鏈表實現,每一個雙端鏈表節點都保存了一個字符串對象,在每一個字符串對象內保存了一個列表元素。
列表對象編碼轉換:
哈希對象的編碼能夠是ziplist和hashtable之一。
(1)ziplist編碼
ziplist編碼的哈希對象底層實現是壓縮列表,在ziplist編碼的哈希對象中,key-value鍵值對是以緊密相連的方式放入壓縮鏈表的,先把key放入表尾,再放入value;鍵值對老是向表尾添加。
(2)hashtable編碼
hashtable編碼的哈希對象底層實現是字典,哈希對象中的每一個key-value對都使用一個字典鍵值對來保存。
字典鍵值對便是,字典的鍵和值都是字符串對象,字典的鍵保存key-value的key,字典的值保存key-value的value。
哈希對象編碼轉換:
集合對象的編碼能夠是intset和hashtable之一。
(1)intset編碼
intset編碼的集合對象底層實現是整數集合,全部元素都保存在整數集合中。
(2)hashtable編碼
hashtable編碼的集合對象底層實現是字典,字典的每一個鍵都是一個字符串對象,保存一個集合元素,不一樣的是字典的值都是NULL;能夠參考java中的hashset結構。
集合對象編碼轉換:
有序集合的編碼能夠是ziplist和skiplist之一。
(1)ziplist編碼
ziplist編碼的有序集合對象底層實現是壓縮列表,其結構與哈希對象相似,不一樣的是兩個緊密相連的壓縮列表節點,第一個保存元素的成員,第二個保存元素的分值,並且分值小的靠近表頭,大的靠近表尾。
(2)skiplist編碼
skiplist編碼的有序集合對象底層實現是跳躍表和字典兩種;
每一個跳躍表節點都保存一個集合元素,並按分值從小到大排列;節點的object屬性保存了元素的成員,score屬性保存分值;
字典的每一個鍵值對保存一個集合元素,字典的鍵保存元素的成員,字典的值保存分值。
爲什麼skiplist編碼要同時使用跳躍表和字典實現?
有序集合編碼轉換:
在Redis的五大數據對象中,string對象是惟一個能夠被其餘四種數據對象做爲內嵌對象的;
列表(list)、哈希(hash)、集合(set)、有序集合(zset)底層實現都用到了壓縮列表結構,而且使用壓縮列表結構的條件都是在元素個數比較少、字節長度較短的狀況下;
四種數據對象使用壓縮列表的優勢:
(1)節約內存,減小內存開銷,Redis是內存型數據庫,因此必定狀況下減小內存開銷是很是有必要的。
(2)減小內存碎片,壓縮列表的內存塊是連續的,並分配內存的次數一次便可。
(3)壓縮列表的新增、刪除、查找操做的平均時間複雜度是O(N),在N再必定的範圍內,這個時間幾乎是能夠忽略的,而且N的上限值是能夠配置的。
(4)四種數據對象都有兩種編碼結構,靈活性增長。
參考:
《Redis設計與實現》黃健宏著,網上對Redis的詳解等
此博客爲筆者使用redis好久以後,參考網絡上各種文章總結性書寫,原創手打,若有錯誤歡迎指正。
原文出處:https://www.cnblogs.com/MouseDong/p/11134039.html