Redis:有序集合類(lèi)型zset實(shí)現(xiàn)原理

和上面的集合對(duì)象相比,有序集合對(duì)象是有序的。與列表使用索引下標(biāo)作為排序依據(jù)不同,有序集合為每個(gè)元素設(shè)置一個(gè)分?jǐn)?shù)(score)作為排序依據(jù)。

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

ziplist 編碼的有序集合對(duì)象使用壓縮列表作為底層實(shí)現(xiàn),每個(gè)集合元素使用兩個(gè)緊挨在一起的壓縮列表節(jié)點(diǎn)來(lái)保存,第一個(gè)節(jié)點(diǎn)保存元素的成員,第二個(gè)節(jié)點(diǎn)保存元素的分值。并且壓縮列表內(nèi)的集合元素按分值從小到大的順序進(jìn)行排列,小的放置在靠近表頭的位置,大的放置在靠近表尾的位置。

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

//存儲(chǔ)順序
存儲(chǔ)順序.png

skiplist 編碼的有序集合對(duì)象使用 zet 結(jié)構(gòu)作為底層實(shí)現(xiàn),一個(gè) zset 結(jié)構(gòu)同時(shí)包含一個(gè)字典和一個(gè)跳躍表:

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

字典的鍵保存元素的值,字典的值則保存元素的分值;跳躍表節(jié)點(diǎn)的 object 屬性保存元素的成員,跳躍表節(jié)點(diǎn)的 score 屬性保存元素的分值。

這兩種數(shù)據(jù)結(jié)構(gòu)會(huì)通過(guò)指針來(lái)共享相同元素的成員和分值,所以不會(huì)產(chǎn)生重復(fù)成員和分值,造成內(nèi)存的浪費(fèi)。

說(shuō)明:其實(shí)有序集合單獨(dú)使用字典或跳躍表其中一種數(shù)據(jù)結(jié)構(gòu)都可以實(shí)現(xiàn),但是這里使用兩種數(shù)據(jù)結(jié)構(gòu)組合起來(lái),原因是假如我們單獨(dú)使用 字典,雖然能以 O(1) 的時(shí)間復(fù)雜度查找成員的分值,但是因?yàn)樽值涫且詿o(wú)序的方式來(lái)保存集合元素,所以每次進(jìn)行范圍操作的時(shí)候都要進(jìn)行排序;假如我們單獨(dú)使用跳躍表來(lái)實(shí)現(xiàn),雖然能執(zhí)行范圍操作,但是查找操作有 O(1)的復(fù)雜度變?yōu)榱薕(logN)。因此Redis使用了兩種數(shù)據(jù)結(jié)構(gòu)來(lái)共同實(shí)現(xiàn)有序集合。

②、編碼轉(zhuǎn)換
當(dāng)有序集合對(duì)象同時(shí)滿(mǎn)足以下兩個(gè)條件時(shí),對(duì)象使用 ziplist 編碼:

1、保存的元素?cái)?shù)量小于128;

2、保存的所有元素長(zhǎng)度都小于64字節(jié)。

不能滿(mǎn)足上面兩個(gè)條件的使用 skiplist 編碼。以上兩個(gè)條件也可以通過(guò)Redis配置文件zset-max-ziplist-entries 選項(xiàng)和 zset-max-ziplist-value 進(jìn)行修改。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容