Redis的5種類型對象與底層實現(xiàn)

Redis的5種類型對象與底層實現(xiàn)

redis在日常coding中使用的場景越來越多,關于redis的背景鋪墊就不在此贅述,獻上官方介紹。

Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.


本篇主要講解redis的五種類型對象及底層的實現(xiàn)原理,并簡單總結redis在實現(xiàn)過程中的部分優(yōu)化方式。

redis的對象都可以用以下結構表示

typedef struct redisObject{
   //類型
   unsigned tyep:4;
   //編碼
   unsingned encoding:4;
   //指向底層實現(xiàn)的數(shù)據(jù)結構的指針
   void *ptr;
   //...
}

其中的類型屬性(type)即我們通常說的五種類型對象分別為:STRING,LIST,HASH,SET以及ZSET。而encoding屬性記錄對象所使用的編碼,即底層的實現(xiàn),每種類型屬性都對應著兩種以上編encoding屬性。Redis的類型與底層編碼共有以下的對應關系

類型對象 編碼 中文釋義
STRING INT 使用整數(shù)值實現(xiàn)的對象
STRING EMBSTR 使用embstr編碼的sds字符串對象
STRING RAW sds
LIST ZIPLIST 壓縮列表
LIST LIKEDLIST 雙端列表
HASH ZIPLIST 壓縮列表
HASH HASHTABLE 字典
SET INTSET 整數(shù)集合
SET HASHTABLE 字典
ZSET ZIPLIST 壓縮列表
ZSET SKIPLIST 跳躍表+字典

String

編碼格式

String 的底層實現(xiàn)為int,sds(simple dynamic string)和embrStr,其中embtSds是sds的優(yōu)化版。其中embstr是只讀的,對string對象的任何修改都會使embstr升級為sds.
1、當存儲對象為整數(shù),且可以被表現(xiàn)為long類型時,redis會使用int存儲對象。
2、當存儲對象為string,且長度小于等于32字節(jié)時候,會使用embstr存儲對象。
3、當存儲對象為string,且長度大于32字節(jié)時會使用sds存儲對象。
embstr與sds的區(qū)別在于redisObject對象創(chuàng)建時只生成一次,redisObject與ptr對象排列在一起,而sds編碼格式下會生成兩次,首先創(chuàng)建redisObject,再創(chuàng)建*ptr對象。

優(yōu)化點

SDS屬于redis實現(xiàn)的str,具有其基本格式如下


sds示例.png

sds具有以下特點
1、存在參數(shù)表示sds的長度,求長度時間復雜度O(1)
2、存在預分配策略,新增字段不需要頻繁分配內存,不存在緩沖區(qū)溢出風險(string小于1M,未分配長度等于已分配長度,string大于1M, 未分配長度為1M),且存在惰性釋放的能力。

List

list底層基于linledList和zipList
linkedlist屬于雙端無環(huán)鏈表

ziplist即壓縮列表,當list健對象只存在少量node節(jié)點,且每個節(jié)點值也比較短,會使用壓縮列表作為底層編碼。壓縮列表的組成如下
壓縮列表組成部分.png

單個entry格式如下
壓縮節(jié)點組成部分.png
其中content為值,previous可以算出前一個節(jié)點的位置,encoding表示存儲的是int還是string。

為什么說壓縮列表的壓縮體現(xiàn)在哪里?
如上圖所示:字段與字段之間是是緊密排列在一起的,通過previous可以定位到前一個節(jié)點,實現(xiàn)從后到前的遍歷。而linkedlist通過pre next指針指向下一個節(jié)點,兩個指針至少占用16個字節(jié)。

Hash

hash底層基于ziplist或hashtable
其中ziplist如list中介紹,其中的區(qū)別在于作為hash的底層實現(xiàn)時候,key與value緊密存儲在一起,其他與作為list底層一致。

hashtable結構如下
hash表結構.png
其中hash表存在一個數(shù)組,用來做ReHash用,關于ReHash的操作可以參考相關資料,其中dictht的結構如下
hashtable示意.png
如同所示,hashtable包括包括四個部分,1)table為一個dictEntry的數(shù)組,每個dictEntry s包括key,value以及next, 2)size為entry數(shù)組的長度,sizemask為長度減一,用來計算在數(shù)組中的位置,used表示hashtable目前有的節(jié)點數(shù)。

Set

set底層基于intSet以及hashTable,其中intSet為只存儲數(shù)字的結構,關于整數(shù)集合結構如下圖所示
整數(shù)集合.png

而hashTable存儲時候,將相關值存儲在key上,value為null

ZSet

zset底層基于ziplist以及 skipList與hashTable的結合。其中zipList中集合的元素按分值從小到大排序,分值較小的元素放在左邊,元素值與分值緊密排列在一起。

有需集合對象在skipList與hashTable存在格式如下
有序集合同時保存在字典和跳躍表中.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容