redis面试(四)ZSet数据结构

ops/2024/10/20 21:07:39/

Sorted Set

有序集合ZSet,但是有序集合的英文明明是sorted sets。 那这个“Z”代表什么意思,这点官网没有解释,但是gitHub上有人问过,作者是这样回答的

Hello. Z is as in XYZ, so the idea is, sets with another dimension: the
order. It’s a far association… I know 😃

这句话的本意是:这里的Z就像XYZ中的Z一样,所以这个概念是,集合中还有另一个维度:顺序。这是一个遥远的关联…

在我理解来的话,这应该只是为了和原本的Sets集合做一个区分,Z代表的就是原本顺序之外的一个规则,就像XYZ中的Z一样,是二维平面之外,另一个维度的规则。

结构

redis 7.0之前有两种编码:ziplist、skiplist
7.0之后是listpack、skiplist
主要区别就是ziplist和listpack

我们先来简单说一下两种格式:(如果了解跳表,可以直接跳转到 skiplist 看跳表的结构)

ziplist和listpack:都是一种压缩列表的实现,当保存的元素长度都小于64字节,同时数量小于128时,会使用该结构(可以认为就是有序列表 list )
与我们之前的理解list不同的地方是,他们占用的磁盘是连续的,没有节点之间的指针,而是将数据按照顺序一个个的排列。
那么查询的时候就要从第一个节点一个个的往后捋出来。虽然不会造成碎片空间,但这也是压缩列表的局限性。

ziplist

下面是这个ziplist列表的节点数据, 可以看到里面的属性 prevrawlensize,这个属性标记了前一个节点长度。

缺点就是 这个列表如果要更新第一个节点数据的话,可能会造成后面所有节点的长度数据全部更新。
(题外话:其实之前讲的redis的list结构中,每个节点Node里面都是一个ziplist,只不过我们只需要知道就可以了,在使用的时候不需要关心这些)

typedef struct zlentry {unsigned int prevrawlensize; /* 用于编码前一个节点字节长度*/unsigned int prevrawlen;     unsigned int lensize;        /* 用于编码此节点类型/长度的字节。例如,字符串有1、2或5个字节标题。整数总是使用一个字节。*/unsigned int len;            /* 用于表示节点实际的字节。对于字符串,这只是字符串长度而对于整数,它是1、2、3、4、8或0,具体取决于数字范围。 */unsigned int headersize;     /* prevrawlensize + lensize. */unsigned char encoding;      /* 设置为ZIP_STR_*或ZIP_INT_*,具体取决于节点编码。*/unsigned char *p;            /* 第一个节点的地址指针,prev-entry-len */
} zlentry;

listpack

listpack 列表最大的特点就是不再包含前一个节点的长度,那么在更新的时候就不会再造成连锁更新问题。
但是由于压缩列表本身的局限性,只能顺序查询,为了效率,在数据量超过64的时候,会变成跳表形式

typedef struct {/* 当使用string时,它具有长度(slen)。 */unsigned char *sval;uint32_t slen;/* 当使用integer时,“sval”为 NULL,lval 保存该值。*/long long lval;
} listpackEntry;

跳表zskiplist

跳表就是ZSets 有序列表的主要结构模式
skiplist 中也是包含两种结构,但是要注意,这里的两种结构是同时存在的 字典(dict)和跳跃表(zskiplist)存储方式。

dict就不说了,在上一章的Hash中说过,可以认为她就是一个k-v结构的数据。 里面的key是存储的数据,value是数据的score分数。
zskiplist:是一个具有跳跃节点能力的链表,给每个节点附加了一个level层级的属性,这个level会指向后面的 某一个节点,通过这个level层级可以直接越过中间的节点,减少查询的时间。
为了比较容易理解,这里画了一个示例图
在这里插入图片描述

L1、L2、L3… 这些就是每个节点的层级,规定了最高的层级是32层。 每个节点查询的时候,就可以通过高层直接跳跃到后面;
如果发现分数过大的话,可以通过低一些的层级少跳跃一些节点。

往里面放数据的时候,会给这个数据+分数封装为一个节点,然后给这个节点随机一个1~32范围内level的层高。
然后从头开始查询,通过level跳跃过N个节点,直接将节点放到对应的位置,然后给给每一层的level都添加一个指向下一个节点的指针。

具体实现结构如下:

typedef struct zskiplist {struct zskiplistNode *header, *tail;unsigned long length;int level;
} zskiplist;typedef struct zskiplistNode {struct zskiplistLevel {struct zskiplistNode *forward;unsigned int span;
} level[];
struct zskiplistNode *backward;
double score;
robj *obj;
} zskiplistNode;

Sorted Set 为什么使用跳跃表,而不是红黑树?

主要有以下几个原因:

  • 跳表的性能和红黑树差不多。
  • 插入速度非常快速,因为不需要进行旋转等操作来维持平衡性
  • 跳表更容易实现和调试。

跳表中的dict是什么用处?

通过上面的数据结构不难发下,跳表只适合单位查询,排序处理。但是不适合查询分数,以及判断成员是否存在这种操作。
那么这时候dict就派上用场了,之前说过,dict的结构是key-value键值对。
比如我们的数据是 周杰伦 100分、孙燕姿 99分、许嵩 98分
那在跳表zskiplist 中的数据是
(level:[], score:100分, value:周杰伦)
(level:[], score:99分, value:孙燕姿)
(level:[], score:98分, value:许嵩)

而在字典项中的数据是
(key:周杰伦, score:100分)
(key:孙燕姿,value:99分)
(key:许嵩, value:98分)

要查询某个数据是否存在,或者是查询分数的话,直接从dict的数据结构中通过key来取出分数就可以了,不需要在列表中查询。
这也是一种为了效率,把数据冗余一份的策略


http://www.ppmy.cn/ops/89021.html

相关文章

前端WebSocket入门,看这篇就够啦!!

在HTML5 的早期开发过程中,由于意识到现有的 HTTP 协议在实时通信方面的不足,开发者开始探索能够在 Web 环境下实现双向实时通信的新的通信协议,提出了 WebSocket 协议的概念。 一、什么是 WebSocket? WebSocket 是一种在单个 T…

DLMS/COSEM中的信息安全:DLMS/COSEM安全概念(下)

3.安全语境 安全语境定义了与加密转换有关的安全属性,并包括以下元素: ——安全组件,确定可用的安全算法。 ——安全策略,在AA内对所有xDLMS APDU确定将应用的那种保护; ——与给定的安全算法相关的安全资料,包含安全密钥、初始化向量、公共密钥证书等。由于安全资料是针…

项目比赛项目负责人的汇报技巧:如何让每一次汇报都清晰有力

项目比赛项目负责人的汇报技巧:如何让每一次汇报都清晰有力 前言MECE原则:确保全面性与互斥性SCQA结构:讲一个引人入胜的故事逻辑树思维模型:深入挖掘问题根源STAR法则:展示你的行动与成果PREP模型:清晰表达…

Day13--JavaWeb学习之Servlet后端渲染界面

基于Day12中登录页面实现的修改,这里实现的是如果登录成功,跳到LoginSuccess页面中展示后端查询到数据库中的信息,并实现在浏览器实现插入数据和删除数据(mybaits)。 当输入账号密码正确后进入LoginSuccess页面&#x…

人工智能课程学习--基本介绍

人工智能课程学习 线性回归 支持向量机 决策树 神经网络 贝叶斯 聚类算法 降维算法 特征选择 特征提取 关联规则 自编码器 生成对抗网络 强化学习 Q-learning SARSA 策略梯度 深度Q学习 评论家算法 强化学习综述 Flappy bird案例

GPT-4o mini一手测评:懂得不多,但答得极快

在性能方面,GPT-4o mini 在 MMLU 上的得分为 82%,在 LMSYS 排行榜的聊天方面分数优于 GPT-4。 OpenAI 突然上线新模型 GPT-4o mini, 声称要全面取代 GPT-3.5 Turbo。 在性能方面,GPT-4o mini 在 MMLU 上的得分为 82%,在 LMSYS 排行榜的聊天方面分数优于 GPT-4。 在价格…

天机学堂 第四天 高并发优化总结

前端每隔15秒就发起一次请求,将播放记录写入数据库。 但问题是,提交播放记录的业务太复杂了,其中涉及到大量的数据库操作: 如何进行优化 单机并发能力 变同步为异步 合并写请求 提高单机并发:优化SQL,尽…

python实现提取视频帧的图片

文章目录 1、需求痛点2、完整代码⭐3、代码分析3.1、需要改动的地方3.2、OpenCV库的使用3.3、多线程技术 4、执行效率5、效果展示⭐6、注意事项🔺7、总结 🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,专注…