Redis:有序集合類型zset實現原理

和上面的集合對象相比,有序集合對象是有序的。與列表使用索引下標作為排序依據不同,有序集合為每個元素設置一個分數(score)作為排序依據。

①、編碼
有序集合的編碼可以是 ziplist 或者 skiplist。

ziplist 編碼的有序集合對象使用壓縮列表作為底層實現,每個集合元素使用兩個緊挨在一起的壓縮列表節點來保存,第一個節點保存元素的成員,第二個節點保存元素的分值。并且壓縮列表內的集合元素按分值從小到大的順序進行排列,小的放置在靠近表頭的位置,大的放置在靠近表尾的位置。

//操作
ZADD price 8.5 apple 5.0 banana 6.0 cherry

//存儲順序
存儲順序.png

skiplist 編碼的有序集合對象使用 zet 結構作為底層實現,一個 zset 結構同時包含一個字典和一個跳躍表:

typedef struct zset{
     //跳躍表
     zskiplist *zsl;
     //字典
     dict *dice;
} zset;

字典的鍵保存元素的值,字典的值則保存元素的分值;跳躍表節點的 object 屬性保存元素的成員,跳躍表節點的 score 屬性保存元素的分值。

這兩種數據結構會通過指針來共享相同元素的成員和分值,所以不會產生重復成員和分值,造成內存的浪費。

說明:其實有序集合單獨使用字典或跳躍表其中一種數據結構都可以實現,但是這里使用兩種數據結構組合起來,原因是假如我們單獨使用 字典,雖然能以 O(1) 的時間復雜度查找成員的分值,但是因為字典是以無序的方式來保存集合元素,所以每次進行范圍操作的時候都要進行排序;假如我們單獨使用跳躍表來實現,雖然能執行范圍操作,但是查找操作有 O(1)的復雜度變為了O(logN)。因此Redis使用了兩種數據結構來共同實現有序集合。

②、編碼轉換
當有序集合對象同時滿足以下兩個條件時,對象使用 ziplist 編碼:

1、保存的元素數量小于128;

2、保存的所有元素長度都小于64字節。

不能滿足上面兩個條件的使用 skiplist 編碼。以上兩個條件也可以通過Redis配置文件zset-max-ziplist-entries 選項和 zset-max-ziplist-value 進行修改。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容