Redis數(shù)據(jù)結(jié)構(gòu)SortedSet的底層原理解析
概述
一些常用命令
- 存儲(chǔ):zadd key score value
- 獲?。?strong>zrange key start end
- 獲?。和瑫r(shí)獲取分?jǐn)?shù):zrange key start end with score
- 刪除:zrem key value
存儲(chǔ)的時(shí)候我們可以發(fā)現(xiàn),是有一個(gè)score(分?jǐn)?shù))的,這個(gè)就是用來排序的字段。
實(shí)現(xiàn)
先說結(jié)論,SortedSet底層,根據(jù)配置會(huì)在不同的時(shí)候選用兩種不同的數(shù)據(jù)結(jié)構(gòu)zset,或ziplist進(jìn)行存儲(chǔ):
首先,我們來看幾個(gè)參數(shù):
zset-max-ziplist-entries 128 zset-max-ziplist-value 64
if (
field-value對(duì)的數(shù)量 > ziplist.entries.size ||
任意一個(gè)filed或value長度 > zset-max-ziplist-value
) {
// 使用 zset 進(jìn)行存儲(chǔ)
} else {
// 使用 ziplist 進(jìn)行存儲(chǔ)zset的結(jié)構(gòu)如下:
typedef struct zset {
dict *dict;
zskiplist *zsl;
} zset可以發(fā)現(xiàn),是由字典+跳躍表實(shí)現(xiàn)的。
zset結(jié)構(gòu)體里有兩個(gè)元素,一個(gè)是 dict,用來維護(hù) 數(shù)據(jù) 到 分?jǐn)?shù) 的關(guān)系,一個(gè)是 zskiplist,用來維護(hù) 分?jǐn)?shù)所在鏈表 的關(guān)系dict里通過維護(hù) 哈希表 存儲(chǔ)了 張三=>100,李四=>90 的分?jǐn)?shù)關(guān)系。
而跳表則是排序的關(guān)鍵
跳躍表
先上圖:

我們知道,鏈表的檢索效率是非常低的,如果要拿到100條數(shù)據(jù)中間的數(shù)據(jù),則需要遍歷50個(gè)數(shù)據(jù)才行,為了解決這個(gè)問題,跳表應(yīng)運(yùn)而生
如上圖,就是常規(guī)的跳表,會(huì)在原有的數(shù)據(jù)上加上若干層,指向當(dāng)前層的下一個(gè)節(jié)點(diǎn)。
跳表的插入

如上圖所示:其實(shí)每個(gè)節(jié)點(diǎn)的層數(shù)是隨機(jī)的,而且新插入一個(gè)節(jié)點(diǎn)不會(huì)影響其它節(jié)點(diǎn)的層數(shù)。因此,插入操作只需要修改插入節(jié)點(diǎn)前后的指針,而不需要對(duì)很多節(jié)點(diǎn)都進(jìn)行調(diào)整。這就降低了插入操作的復(fù)雜度。實(shí)際上,這是skiplist跳表的一個(gè)很重要的特性,這讓它在插入性能上明顯優(yōu)于平衡樹的方案。
如下圖,假如我們需要查詢23,查詢的路徑如下。

事實(shí)上,在插入之前也要先經(jīng)歷一個(gè)類似的查找過程,在確定插入位置后,再完成插入操作。
這也是SortedSet實(shí)現(xiàn)排序的原理。
壓縮列表
壓縮列表 ziplist 是為 Redis 節(jié)約內(nèi)存而開發(fā)的。
壓縮列表是由一系列特殊編碼的連續(xù)內(nèi)存塊組成的順序型數(shù)據(jù)結(jié)構(gòu),一個(gè)壓縮列表可以包含任意多個(gè)節(jié)點(diǎn) (entry),每個(gè)節(jié)點(diǎn)可以保存 一個(gè)字節(jié)數(shù)組 或者 一個(gè)整數(shù)值 。

1、zl bytes:用于記錄整個(gè)壓縮列表占用的內(nèi)存字節(jié)數(shù)
2、zl tail:記錄要列表尾節(jié)點(diǎn)距離壓縮列表的起始地址有多少字節(jié)
3、zl len:記錄了壓縮列表包含的節(jié)點(diǎn)數(shù)量。
4、entryX:要說列表包含的各個(gè)節(jié)點(diǎn)
5、zl end:用于標(biāo)記壓縮列表的末端
壓縮列表是一種為了節(jié)約內(nèi)存而開發(fā)的順序型數(shù)據(jù)結(jié)構(gòu)
壓縮列表被用作列表鍵和哈希鍵的底層實(shí)現(xiàn)之一
壓縮列表可以包含多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)可以保存一個(gè)字節(jié)數(shù)組或者整數(shù)值
添加新節(jié)點(diǎn)到壓縮列表,可能會(huì)引發(fā)連鎖更新操作。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
redis反序列化報(bào)錯(cuò)原因分析以及解決方案
這篇文章主要介紹了redis反序列化報(bào)錯(cuò)原因分析以及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
redis 替代php文件存儲(chǔ)session的實(shí)例
這篇文章主要介紹了redis 替代php文件存儲(chǔ)session的實(shí)例的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握這樣的方法,需要的朋友可以參考下2017-10-10
redis的hGetAll函數(shù)的性能問題(記Redis那坑人的HGETALL)
這篇文章主要介紹了redis的hGetAll函數(shù)的性能問題,需要的朋友可以參考下2016-02-02
從一個(gè)小需求感受Redis的獨(dú)特魅力(需求設(shè)計(jì))
Redis在實(shí)際應(yīng)用中使用的非常廣泛,本篇文章就從一個(gè)簡單的需求說起,為你講述一個(gè)需求是如何從頭到尾開始做的,又是如何一步步完善的2019-12-12
Redis底層數(shù)據(jù)結(jié)構(gòu)SkipList的實(shí)現(xiàn)
本文主要介紹了Redis底層數(shù)據(jù)結(jié)構(gòu)SkipList的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
Redis中set類型實(shí)現(xiàn)交集并集差集
本文主要介紹了Redis中set類型實(shí)現(xiàn)交集并集差集,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06

